From a6558c9f25fe31907f138f3126b1cd4b2e770757 Mon Sep 17 00:00:00 2001 From: NezumiRonin Date: Wed, 10 Mar 2021 23:09:31 -0600 Subject: [PATCH 01/19] Create diamond.pl Ported to Perl! --- 32 Diamond/perl/diamond.pl | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 32 Diamond/perl/diamond.pl diff --git a/32 Diamond/perl/diamond.pl b/32 Diamond/perl/diamond.pl new file mode 100644 index 00000000..62311c14 --- /dev/null +++ b/32 Diamond/perl/diamond.pl @@ -0,0 +1,37 @@ +#!/usr/bin/perl +use strict; + +################ +# PORTING NOTES: +# * In basic "Tab" function are not spaces, but absolute col position on screen. +# * It was too dificult to port this one, couldn't figure out the original algorithm. +# * So the algorithm was remake. +# + +print ' 'x 33 . "DIAMOND\n"; +print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n"; print "\n"; print "\n"; +print "FOR A PRETTY DIAMOND PATTERN,\n"; +print "TYPE IN AN ODD NUMBER BETWEEN 5 AND 21? "; chomp(my $R = ); print "\n"; + + +my $Wid= int(60/$R)+1; +my $Dia="CC". "!" x ($R-2); + +for (my $J=1; $J<$Wid; $J++) { + for (my $K=1; $K<($R+2)*2-4; $K+=2) { + my $Size= $K; + if ($K>$R) { $Size=$R+($R-$K); } + my $Chunk= substr($Dia, 0, $Size); + for (my $L=1; $L<$Wid; $L++) { + my $Space= " " x (($R-$Size)/2); + if ($L>1) { $Space.=$Space; } + print $Space.$Chunk; + } + print "\n"; + } + } + +exit; + + From 1e41a764a33f6bce63432bc8a05fc54f261720dd Mon Sep 17 00:00:00 2001 From: nanochess Date: Fri, 12 Mar 2021 16:56:05 -0600 Subject: [PATCH 02/19] Ported KING to Javascript --- 53 King/javascript/king.html | 9 + 53 King/javascript/king.js | 376 +++++++++++++++++++++++++++++++++++ 2 files changed, 385 insertions(+) create mode 100644 53 King/javascript/king.html create mode 100644 53 King/javascript/king.js diff --git a/53 King/javascript/king.html b/53 King/javascript/king.html new file mode 100644 index 00000000..56b5e7e2 --- /dev/null +++ b/53 King/javascript/king.html @@ -0,0 +1,9 @@ + + +KING + + +

+
+
+
diff --git a/53 King/javascript/king.js b/53 King/javascript/king.js
new file mode 100644
index 00000000..faaeb253
--- /dev/null
+++ b/53 King/javascript/king.js	
@@ -0,0 +1,376 @@
+// KING
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+function hate_your_guts()
+{
+    print("\n");
+    print("\n");
+    print("OVER ONE THIRD OF THE POPULATION HAS DIED SINCE YOU\n");
+    print("WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\n");
+    print("HATE YOUR GUTS.\n");
+}
+
+// Main program
+async function main()
+{
+    print(tab(34) + "KING\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("DO YOU WANT INSTRUCTIONS");
+    str = await input();
+    n5 = 8;
+    if (str == "AGAIN") {
+        while (1) {
+            print("HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED");
+            x5 = parseInt(await input());
+            if (x5 == 0)
+                return;
+            if (x5 < 8)
+                break;
+            print("   COME ON, YOUR TERM IN OFFICE IS ONLY " + n5 + " YEARS.\n");
+        }
+        print("HOW MUCH DID YOU HAVE IN THE TREASURY");
+        a = parseInt(await input());
+        if (a < 0)
+            return;
+        print("HOW MANY COUNTRYMEN");
+        b = parseInt(await input());
+        if (b < 0)
+            return;
+        print("HOW MANY WORKERS");
+        c = parseInt(await input());
+        if (c < 0)
+            return;
+        while (1) {
+            print("HOW MANY SQUARE MILES OF LAND");
+            d = parseInt(await input());
+            if (d < 0)
+                return;
+            if (d > 1000 && d <= 2000)
+                break;
+            print("   COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\n");
+            print("   AND 10,000 SQ. MILES OF FOREST LAND.\n");
+        }
+    } else {
+        if (str.substr(0, 1) != "N") {
+            print("\n");
+            print("\n");
+            print("\n");
+            print("CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\n");
+            print("DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\n");
+            print("JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\n");
+            print("MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\n");
+            print("THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100\n");
+            print("RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\n");
+            print("FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\n");
+            print("FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\n");
+            print("WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\n");
+            print("TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\n");
+            print("THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\n");
+            print("SQUARE MILE TO PLANT.\n");
+            print("YOUR GOAL IS TO COMPLETE YOUR " + n5 + " YEAR TERM OF OFFICE.\n");
+            print("GOOD LUCK!\n");
+        }
+        print("\n");
+        a = Math.floor(60000 + (1000 * Math.random()) - (1000 * Math.random()));
+        b = Math.floor(500 + (10 * Math.random()) - (10 * Math.random()));
+        c = 0;
+        d = 2000;
+        x5 = 0;
+    }
+    v3 = 0;
+    b5 = 0;
+    x = false;
+    while (1) {
+        w = Math.floor(10 * Math.random() + 95);
+        print("\n");
+        print("YOU NOW HAVE " + a + " RALLODS IN THE TREASURY.\n");
+        print(b + " COUNTRYMEN, ");
+        v9 = Math.floor(((Math.random() / 2) * 10 + 10));
+        if (c != 0)
+            print(c + " FOREIGN WORKERS, ");
+        print("AND " + Math.floor(d) + " SQ. MILES OF LAND.\n");
+        print("THIS YEAR INDUSTRY WILL BUY LAND FOR " + w + " ");
+        print("RALLODS PER SQUARE MILE.\n");
+        print("LAND CURRENTLY COSTS " + v9 + " RALLODS PER SQUARE MILE TO PLANT.\n");
+        print("\n");
+        while (1) {
+            print("HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY");
+            h = parseInt(await input());
+            if (h < 0)
+                continue;
+            if (h <= d - 1000)
+                break;
+            print("***  THINK AGAIN. YOU ONLY HAVE " + (d - 1000) + " SQUARE MILES OF FARM LAND.\n");
+            if (x == false) {
+                print("\n");
+                print("(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\n");
+                print("FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\n");
+                print("THICKER TOP SOIL, ETC.)\n");
+                x = true;
+            }
+        }
+        d = Math.floor(d - h);
+        a = Math.floor(a + (h * w));
+        while (1) {
+            print("HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN");
+            i = parseInt(await input());
+            if (i < 0)
+                continue;
+            if (i < a)
+                break;
+            if (i == a) {
+                j = 0;
+                k = 0;
+                a = 0;
+                break;
+            }
+            print("   THINK AGAIN. YOU'VE ONLY " + a + " RALLODS IN THE TREASURY\n");
+        }
+        if (a) {
+            a = Math.floor(a - i);
+            while (1) {
+                print("HOW MANY SQUARE MILES DO YOU WISH TO PLANT");
+                j = parseInt(await input());
+                if (j < 0)
+                    continue;
+                if (j <= b * 2) {
+                    if (j <= d - 1000) {
+                        u1 = Math.floor(j * v9);
+                        if (u1 > a) {
+                            print("   THINK AGAIN. YOU'VE ONLY " + a + " RALLODS LEFT IN THE TREASURY.\n");
+                            continue;
+                        } else if (u1 == a) {
+                            k = 0;
+                            a = 0;
+                        }
+                        break;
+                    }
+                    print("   SORRY, BUT YOU'VE ONLY " + (d - 1000) + " SQ. MILES OF FARM LAND.\n");
+                    continue;
+                }
+                print("   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\n");
+            }
+        }
+        if (a) {
+            a -= u1;
+            while (1) {
+                print("HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL");
+                k = parseInt(await input());
+                if (k < 0)
+                    continue;
+                if (k <= a)
+                    break;
+                print("   THINK AGAIN. YOU ONLY HAVE " + a + " RALLODS REMAINING.\n");
+            }
+        }
+        if (h == 0 && i == 0 && j == 0 && k == 0) {
+            print("GOODBYE.\n");
+            print("(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER\n");
+            print("'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START\n");
+            print("OF THE GAME).\n");
+            return;
+        }
+        print("\n");
+        print("\n");
+        a = Math.floor(a - k);
+        a4 = a;
+        if (Math.floor(i / 100 - b) < 0) {
+            if (i / 100 < 50) {
+                hate_your_guts();
+                break;
+            }
+            print(Math.floor(b - (i / 100)) + " COUNTRYMEN DIED OF STARVATION\n");
+        }
+        f1 = Math.floor(Math.random() * (2000 - d));
+        if (k >= 25)
+            f1 = Math.floor(f1 / (k / 25));
+        if (f1 > 0)
+            print(f1 + " COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION\n");
+        funeral = false;
+        if (Math.floor((i / 100) - b) >= 0) {
+            if (f1 > 0) {
+                print("   YOU WERE FORCED TO SPEND " + Math.floor(f1 * 9) + " RALLODS ON ");
+                print("FUNERAL EXPENSES.\n");
+                b5 = f1;
+                a = Math.floor(a - (f1 * 9));
+                funeral = true;
+            }
+        } else {
+            print("   YOU WERE FORCED TO SPEND " + Math.floor((f1 + (b - (i / 100))) * 9));
+            print(" RALLODS ON FUNERAL EXPENSES.\n");
+            b5 = Math.floor(f1 + (b - (i / 100)));
+            a = Math.floor(a - ((f1 + (b - (i / 100))) * 9));
+            funeral = true;
+        }
+        if (funeral) {
+            if (a < 0) {
+                print("   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\n");
+                d = Math.floor(d + (a / w));
+                a = 0;
+            }
+            b = Math.floor(b - b5);
+        }
+        c1 = 0;
+        if (h != 0) {
+            c1 = Math.floor(h + (Math.random() * 10) - (Math.random() * 20));
+            if (c <= 0)
+                c1 += 20;
+            print(c1 + " WORKERS CAME TO THE COUNTRY AND ");
+        }
+        p1 = Math.floor(((i / 100 - b) / 10) + (k / 25) - ((2000 - d) / 50) - (f1 / 2));
+        print(Math.abs(p1) + " COUNTRYMEN ");
+        if (p1 >= 0)
+            print("CAME TO");
+        else
+            print("LEFT");
+        print(" THE ISLAND.\n");
+        b = Math.floor(b + p1);
+        c = Math.floor(c + c1);
+        u2 = Math.floor(((2000 - d) * ((Math.random() + 1.5) / 2)));
+        if (c != 0) {
+            print("OF " + Math.floor(j) + " SQ. MILES PLANTED,");
+        }
+        if (j <= u2)
+            u2 = j;
+        print(" YOU HARVESTED " + Math.floor(j - u2) + " SQ. MILES OF CROPS.\n");
+        if (u2 != 0 && t1 < 2) {
+            print("   (DUE TO ");
+            if (t1 != 0)
+                print("INCREASED ");
+            print("AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\n");
+        }
+        q = Math.floor((j - u2) * (w / 2));
+        print("MAKING " + q + " RALLODS.\n");
+        a = Math.floor(a + q);
+        v1 = Math.floor(((b - p1) * 22) + (Math.random() * 500));
+        v2 = Math.floor((2000 - d) * 15);
+        print(" YOU MADE " + Math.abs(Math.floor(v1 - v2)) + " RALLODS FROM TOURIST TRADE.\n");
+        if (v2 != 0 && v1 - v2 < v3) {
+            print("   DECREASE BECAUSE ");
+            g1 = 10 * Math.random();
+            if (g1 <= 2)
+                print("FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\n");
+            else if (g1 <= 4)
+                print("AIR POLLUTION IS KILLING GAME BIRD POPULATION.\n");
+            else if (g1 <= 6)
+                print("MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\n");
+            else if (g1 <= 8)
+                print("UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\n");
+            else if (g1 <= 10)
+                print("HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\n");
+        }
+        v3 = Math.floor(a + v3);    // Probable bug from original game
+        a = Math.floor(a + v3);
+        if (b5 > 200) {
+            print("\n");
+            print("\n");
+            print(b5 + " 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 = Math.floor(Math.random() * 10);
+            if (m6 <= 3)
+                print("ALSO HAD YOUR LEFT EYE GOUGED OUT!\n");
+            else if (m6 <= 6)
+                print("HAVE ALSO GAINED A VERY BAD REPUTATION.\n");
+            else
+                print("HAVE ALSO BEEN DECLARED NATIONAL FINK.\n");
+            print("\n");
+            print("\n");
+            return;
+        }
+        if (b < 343) {
+            hate_your_guts();
+            break;
+        }
+        if (a4 / 100 > 5 && b5 - f1 >= 2) {
+            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");
+            print("\n");
+            print("\n");
+            return;
+        }
+        if (c > b) {
+            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");
+            break;
+        }
+        if (n5 - 1 == x5) {
+            print("\n");
+            print("\n");
+            print("CONGRATULATIONS!!!!!!!!!!!!!!!!!!\n");
+            print("YOU HAVE SUCCESFULLY COMPLETED YOUR " + n5 + " 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");
+            print("\n");
+            print("\n");
+            return;
+        }
+        x5++;
+        b5 = 0;
+    }
+    if (Math.random() <= 0.5) {
+        print("YOU HAVE BEEN ASSASSINATED.\n");
+    } else {
+        print("YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\n");
+        print("RESIDING IN PRISON.\n");
+    }
+    print("\n");
+    print("\n");
+}
+
+main();

From bb8cfe9fb4a8ce53fa3ed8ed1727dbe64efc16c1 Mon Sep 17 00:00:00 2001
From: nanochess 
Date: Fri, 12 Mar 2021 21:35:46 -0600
Subject: [PATCH 03/19] Ported LEM to Javascript

---
 59 Lunar LEM Rocket/javascript/lem.html   |   9 +
 59 Lunar LEM Rocket/javascript/lem.js     | 326 +++++++++++++++++++
 59 Lunar LEM Rocket/javascript/lunar.html |   9 +
 59 Lunar LEM Rocket/javascript/lunar.js   | 376 ++++++++++++++++++++++
 4 files changed, 720 insertions(+)
 create mode 100644 59 Lunar LEM Rocket/javascript/lem.html
 create mode 100644 59 Lunar LEM Rocket/javascript/lem.js
 create mode 100644 59 Lunar LEM Rocket/javascript/lunar.html
 create mode 100644 59 Lunar LEM Rocket/javascript/lunar.js

diff --git a/59 Lunar LEM Rocket/javascript/lem.html b/59 Lunar LEM Rocket/javascript/lem.html
new file mode 100644
index 00000000..717ae005
--- /dev/null
+++ b/59 Lunar LEM Rocket/javascript/lem.html	
@@ -0,0 +1,9 @@
+
+
+LEM
+
+
+

+
+
+
diff --git a/59 Lunar LEM Rocket/javascript/lem.js b/59 Lunar LEM Rocket/javascript/lem.js
new file mode 100644
index 00000000..4f5ffd30
--- /dev/null
+++ b/59 Lunar LEM Rocket/javascript/lem.js	
@@ -0,0 +1,326 @@
+// LEM
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+// Main program
+async function main()
+{
+    print(tab(34) + "LEM\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    // ROCKT2 is an interactive game that simulates a lunar
+    // landing is similar to that of the Apollo program.
+    // There is absolutely no chance involved
+    zs = "GO";
+    b1 = 1;
+    while (1) {
+        m = 17.95;
+        f1 = 5.25;
+        n = 7.5;
+        r0 = 926;
+        v0 = 1.29;
+        t = 0;
+        h0 = 60;
+        r = r0 + h0;
+        a = -3,425;
+        r1 = 0;
+        a1 = 8.84361e-4;
+        r3 = 0;
+        a3 = 0;
+        m1 = 7.45;
+        m0 = m1;
+        b = 750;
+        t1 = 0;
+        f = 0;
+        p = 0;
+        n = 1;
+        m2 = 0;
+        s = 0;
+        c = 0;
+        if (zs == "YES") {
+            print("\n");
+            print("OK, DO YOU WANT THE COMPLETE INSTRUCTIONS OR THE INPUT -\n");
+            print("OUTPUT STATEMENTS?\n");
+            while (1) {
+                print("1=COMPLETE INSTRUCTIONS\n");
+                print("2=INPUT-OUTPUT STATEMENTS\n");
+                print("3=NEITHER\n");
+                b1 = parseInt(await input());
+                qs = "NO";
+                if (b1 == 1)
+                    break;
+                qs = "YES";
+                if (b1 == 2 || b1 == 3)
+                    break;
+            }
+        } else {
+            print("\n");
+            print("LUNAR LANDING SIMULATION\n");
+            print("\n");
+            print("HAVE YOU FLOWN AN APOLLO/LEM MISSION BEFORE");
+            while (1) {
+                print(" (YES OR NO)");
+                qs = await input();
+                if (qs == "YES" || qs == "NO")
+                    break;
+                print("JUST ANSWER THE QUESTION, PLEASE, ");
+            }
+        }
+        if (qs == "YES") {
+            print("\n");
+            print("INPUT MEASUREMENT OPTION NUMBER");
+        } else {
+            print("\n");
+            print("WHICH SYSTEM OF MEASUREMENT DO YOU PREFER?\n");
+            print(" 1=METRIC     0=ENGLISH\n");
+            print("ENTER THE APPROPIATE NUMBER");
+        }
+        while (1) {
+            k = parseInt(await input());
+            if (k == 0 || k == 1)
+                break;
+            print("ENTER THE APPROPIATE NUMBER");
+        }
+        if (k == 1) {
+            z = 1852.8;
+            ms = "METERS";
+            g3 = 3.6;
+            ns = " KILOMETERS";
+            g5 = 1000;
+        } else {
+            z = 6080;
+            ms = "FEET";
+            g3 = 0.592;
+            ns = "N.MILES";
+            g5 = z;
+        }
+        if (b1 != 3) {
+            if (qs != "YES") {
+                print("\n");
+                print("  YOU ARE ON A LUNAR LANDING MISSION.  AS THE PILOT OF\n");
+                print("THE LUNAR EXCURSION MODULE, YOU WILL BE EXPECTED TO\n");
+                print("GIVE CERTAIN COMMANDS TO THE MODULE NAVIGATION SYSTEM.\n");
+                print("THE ON-BOARD COMPUTER WILL GIVE A RUNNING ACCOUNT\n");
+                print("OF INFORMATION NEEDED TO NAVIGATE THE SHIP.\n");
+                print("\n");
+                print("\n");
+                print("THE ATTITUDE ANGLE CALLED FOR IS DESCRIBED AS FOLLOWS.\n");
+                print("+ OR -180 DEGREES IS DIRECTLY AWAY FROM THE MOON\n");
+                print("-90 DEGREES IS ON A TANGENT IN THE DIRECTION OF ORBIT\n");
+                print("+90 DEGREES IS ON A TANGENT FROM THE DIRECTION OF ORBIT\n");
+                print("0 (ZERO) DEGREES IS DIRECTLY TOWARD THE MOON\n");
+                print("\n");
+                print(tab(30) + "-180|+180\n");
+                print(tab(34) + "^\n");
+                print(tab(27) + "-90 < -+- > +90\n");
+                print(tab(34) + "!\n");
+                print(tab(34) + "0\n");
+                print(tab(21) + "<<<< DIRECTION OF ORBIT <<<<\n");
+                print("\n");
+                print(tab(20) + "------ SURFACE OF MOON ------\n");
+                print("\n");
+                print("\n");
+                print("ALL ANGLES BETWEEN -180 AND +180 DEGREES ARE ACCEPTED.\n");
+                print("\n");
+                print("1 FUEL UNIT = 1 SEC. AT MAX THRUST\n");
+                print("ANY DISCREPANCIES ARE ACCOUNTED FOR IN THE USE OF FUEL\n");
+                print("FOR AN ATTITUDE CHANGE.\n");
+                print("AVAILABLE ENGINE POWER: 0 (ZERO) AND ANY VALUE BETWEEN\n");
+                print("10 AND 100 PERCENT.\n");
+                print("\n");
+                print("NEGATIVE THRUST OR TIME IS PROHIBITED.\n");
+                print("\n");
+            }
+            print("\n");
+            print("INPUT: TIME INTERVAL IN SECONDS ------ (T)\n");
+            print("       PERCENTAGE OF THRUST ---------- (P)\n");
+            print("       ATTITUDE ANGLE IN DEGREES ----- (A)\n");
+            print("\n");
+            if (qs != "YES") {
+                print("FOR EXAMPLE:\n");
+                print("T,P,A? 10,65,-60\n");
+                print("TO ABORT THE MISSION AT ANY TIME, ENTER 0,0,0\n");
+                print("\n");
+            }
+            print("OUTPUT: TOTAL TIME IN ELAPSED SECONDS\n");
+            print("        HEIGHT IN " + ms + "\n");
+            print("        DISTANCE FROM LANDING SITE IN " + ms + "\n");
+            print("        VERTICAL VELOCITY IN " + ms + "/SECOND\n");
+            print("        HORIZONTAL VELOCITY IN " + ms + "/SECOND\n");
+            print("        FUEL UNITS REMAINING\n");
+            print("\n");
+        }
+        while (1) {
+            for (i = 1; i <= n; i++) {
+                if (m1 != 0) {
+                    m1 -= m2;
+                    if (m1 <= 0) {
+                        f = f * (1 + m1 / m2);
+                        m2 = m1 + m2;
+                        print("YOU ARE OUT OF FUEL.\n");
+                        m1 = 0;
+                    }
+                } else {
+                    f = 0;
+                    m2 = 0;
+                }
+                m = m - 0.5 * m2;
+                r4 = r3;
+                r3 = -0.5 * r0 * Math.pow(v0 / r, 2) + r * a1 * a1;
+                r2 = (3 * r3 - r4) / 2 + 0.00526 * f1 * f * c / m;
+                a4 = a3;
+                a3 = -2 * r1 * a1 / r;
+                a2 = (3 * a3 - a4) / 2 + 0.0056 * f1 * f * s / (m * r);
+                x = r1 * t1 + 0.5 * r2 * t1 * t1;
+                r = r + x;
+                h0 = h0 + x;
+                r1 = r1 + r2 * t1;
+                a = a + a1 * t1 + 0.5 * a2 * t1 * t1;
+                a1 = a1 + a2 * t1;
+                m = m - 0.5 * m2;
+                t = t + t1;
+                if (h0 < 3.287828e-4)
+                    break;
+            }
+            h = h0 * z;
+            h1 = r1 * z;
+            d = r0 * a * z;
+            d1 = r * a1 * z;
+            t2 = m1 * b / m0;
+            print(" " + t + "\t" + h + "\t" + d + "\t" + h1 + "\t" + d1 + "\t" + t2 + "\n");
+            if (h0 < 3.287828e-4) {
+                if (r1 < -8.21957e-4 || Math.abs(r * a1) > 4.93174e-4 || h0 < -3.287828e-4) {
+                    print("\n");
+                    print("CRASH !!!!!!!!!!!!!!!!\n");
+                    print("YOUR IMPACT CREATED A CRATER " + Math.abs(h) + " " + ms + " DEEP.\n");
+                    x1 = Math.sqrt(d1 * d1 + h1 * h1) * g3;
+                    print("AT CONTACT YOU WERE TRAVELING " + x1 + " " + ns + "/HR\n");
+                    break;
+                }
+                if (Math.abs(d) > 10 * z) {
+                    print("YOU ARE DOWN SAFELY - \n");
+                    print("\n");
+                    print("BUT MISSED THE LANDING SITE BY " + Math.abs(d / g5) + " " + ns + ".\n");
+                    break;
+                }
+                print("\n");
+                print("TRANQUILITY BASE HERE -- THE EAGLE HAS LANDED.\n");
+                print("CONGRATULATIONS -- THERE WAS NO SPACECRAFT DAMAGE.\n");
+                print("YOU MAY NOW PROCEED WITH SURFACE EXPLORATION.\n");
+                break;
+            }
+            if (r0 * a > 164.474) {
+                print("\n");
+                print("YOU HAVE BEEN LOST IN SPACE WITH NO HOPE OF RECOVERY.\n");
+                break;
+            }
+            if (m1 > 0) {
+                while (1) {
+                    print("T,P,A");
+                    str = await input();
+                    t1 = parseFloat(str);
+                    f = parseFloat(str.substr(str.indexOf(",") + 1));
+                    p = parseFloat(str.substr(str.lastIndexOf(",") + 1));
+                    f = f / 100;
+                    if (t1 < 0) {
+                        print("\n");
+                        print("THIS SPACECRAFT IS NOT ABLE TO VIOLATE THE SPACE-");
+                        print("TIME CONTINUUM.\n");
+                        print("\n");
+                    } else if (t1 == 0) {
+                        break;
+                    } else if (Math.abs(f - 0.05) > 1 || Math.abs(f - 0.05) < 0.05) {
+                        print("IMPOSSIBLE THRUST VALUE ");
+                        if (f < 0) {
+                            print("NEGATIVE\n");
+                        } else if (f - 0.05 < 0.05) {
+                            print("TOO SMALL\n");
+                        } else {
+                            print("TOO LARGE\n");
+                        }
+                        print("\n");
+                    } else if (Math.abs(p) > 180) {
+                        print("\n");
+                        print("IF YOU WANT TO SPIN AROUND, GO OUTSIDE THE MODULE\n");
+                        print("FOR AN E.V.A.\n");
+                        print("\n");
+                    } else {
+                        break;
+                    }
+                }
+                if (t1 == 0) {
+                    print("\n");
+                    print("MISSION ABENDED\n");
+                    break;
+                }
+            } else {
+                t1 = 20;
+                f = 0;
+                p = 0;
+            }
+            n = 20;
+            if (t1 >= 400)
+                n = t1 / 20;
+            t1 = t1 / n;
+            p = p * 3.14159 / 180;
+            s = Math.sin(p);
+            c = Math.cos(p);
+            m2 = m0 * t1 * f / b;
+            r3 = -0.5 * r0 * Math.pow(v0 / r, 2) + r * a1 * a1;
+            a3 = -2 * r1 * a1 / r;
+        }
+        print("\n");
+        while (1) {
+            print("DO YOU WANT TO TRY IT AGAIN (YES/NO)?\n");
+            zs = await input();
+            if (zs == "YES" || zs == "NO")
+                break;
+        }
+        if (zs != "YES")
+            break;
+    }
+    print("\n");
+    print("TOO BAD, THE SPACE PROGRAM HATES TO LOSE EXPERIENCED\n");
+    print("ASTRONAUTS.\n");
+}
+
+main();
diff --git a/59 Lunar LEM Rocket/javascript/lunar.html b/59 Lunar LEM Rocket/javascript/lunar.html
new file mode 100644
index 00000000..cdcabc2d
--- /dev/null
+++ b/59 Lunar LEM Rocket/javascript/lunar.html	
@@ -0,0 +1,9 @@
+
+
+LUNAR
+
+
+

+
+
+
diff --git a/59 Lunar LEM Rocket/javascript/lunar.js b/59 Lunar LEM Rocket/javascript/lunar.js
new file mode 100644
index 00000000..faaeb253
--- /dev/null
+++ b/59 Lunar LEM Rocket/javascript/lunar.js	
@@ -0,0 +1,376 @@
+// KING
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+function hate_your_guts()
+{
+    print("\n");
+    print("\n");
+    print("OVER ONE THIRD OF THE POPULATION HAS DIED SINCE YOU\n");
+    print("WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\n");
+    print("HATE YOUR GUTS.\n");
+}
+
+// Main program
+async function main()
+{
+    print(tab(34) + "KING\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("DO YOU WANT INSTRUCTIONS");
+    str = await input();
+    n5 = 8;
+    if (str == "AGAIN") {
+        while (1) {
+            print("HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED");
+            x5 = parseInt(await input());
+            if (x5 == 0)
+                return;
+            if (x5 < 8)
+                break;
+            print("   COME ON, YOUR TERM IN OFFICE IS ONLY " + n5 + " YEARS.\n");
+        }
+        print("HOW MUCH DID YOU HAVE IN THE TREASURY");
+        a = parseInt(await input());
+        if (a < 0)
+            return;
+        print("HOW MANY COUNTRYMEN");
+        b = parseInt(await input());
+        if (b < 0)
+            return;
+        print("HOW MANY WORKERS");
+        c = parseInt(await input());
+        if (c < 0)
+            return;
+        while (1) {
+            print("HOW MANY SQUARE MILES OF LAND");
+            d = parseInt(await input());
+            if (d < 0)
+                return;
+            if (d > 1000 && d <= 2000)
+                break;
+            print("   COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\n");
+            print("   AND 10,000 SQ. MILES OF FOREST LAND.\n");
+        }
+    } else {
+        if (str.substr(0, 1) != "N") {
+            print("\n");
+            print("\n");
+            print("\n");
+            print("CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\n");
+            print("DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\n");
+            print("JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\n");
+            print("MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\n");
+            print("THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100\n");
+            print("RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\n");
+            print("FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\n");
+            print("FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\n");
+            print("WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\n");
+            print("TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\n");
+            print("THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\n");
+            print("SQUARE MILE TO PLANT.\n");
+            print("YOUR GOAL IS TO COMPLETE YOUR " + n5 + " YEAR TERM OF OFFICE.\n");
+            print("GOOD LUCK!\n");
+        }
+        print("\n");
+        a = Math.floor(60000 + (1000 * Math.random()) - (1000 * Math.random()));
+        b = Math.floor(500 + (10 * Math.random()) - (10 * Math.random()));
+        c = 0;
+        d = 2000;
+        x5 = 0;
+    }
+    v3 = 0;
+    b5 = 0;
+    x = false;
+    while (1) {
+        w = Math.floor(10 * Math.random() + 95);
+        print("\n");
+        print("YOU NOW HAVE " + a + " RALLODS IN THE TREASURY.\n");
+        print(b + " COUNTRYMEN, ");
+        v9 = Math.floor(((Math.random() / 2) * 10 + 10));
+        if (c != 0)
+            print(c + " FOREIGN WORKERS, ");
+        print("AND " + Math.floor(d) + " SQ. MILES OF LAND.\n");
+        print("THIS YEAR INDUSTRY WILL BUY LAND FOR " + w + " ");
+        print("RALLODS PER SQUARE MILE.\n");
+        print("LAND CURRENTLY COSTS " + v9 + " RALLODS PER SQUARE MILE TO PLANT.\n");
+        print("\n");
+        while (1) {
+            print("HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY");
+            h = parseInt(await input());
+            if (h < 0)
+                continue;
+            if (h <= d - 1000)
+                break;
+            print("***  THINK AGAIN. YOU ONLY HAVE " + (d - 1000) + " SQUARE MILES OF FARM LAND.\n");
+            if (x == false) {
+                print("\n");
+                print("(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\n");
+                print("FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\n");
+                print("THICKER TOP SOIL, ETC.)\n");
+                x = true;
+            }
+        }
+        d = Math.floor(d - h);
+        a = Math.floor(a + (h * w));
+        while (1) {
+            print("HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN");
+            i = parseInt(await input());
+            if (i < 0)
+                continue;
+            if (i < a)
+                break;
+            if (i == a) {
+                j = 0;
+                k = 0;
+                a = 0;
+                break;
+            }
+            print("   THINK AGAIN. YOU'VE ONLY " + a + " RALLODS IN THE TREASURY\n");
+        }
+        if (a) {
+            a = Math.floor(a - i);
+            while (1) {
+                print("HOW MANY SQUARE MILES DO YOU WISH TO PLANT");
+                j = parseInt(await input());
+                if (j < 0)
+                    continue;
+                if (j <= b * 2) {
+                    if (j <= d - 1000) {
+                        u1 = Math.floor(j * v9);
+                        if (u1 > a) {
+                            print("   THINK AGAIN. YOU'VE ONLY " + a + " RALLODS LEFT IN THE TREASURY.\n");
+                            continue;
+                        } else if (u1 == a) {
+                            k = 0;
+                            a = 0;
+                        }
+                        break;
+                    }
+                    print("   SORRY, BUT YOU'VE ONLY " + (d - 1000) + " SQ. MILES OF FARM LAND.\n");
+                    continue;
+                }
+                print("   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\n");
+            }
+        }
+        if (a) {
+            a -= u1;
+            while (1) {
+                print("HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL");
+                k = parseInt(await input());
+                if (k < 0)
+                    continue;
+                if (k <= a)
+                    break;
+                print("   THINK AGAIN. YOU ONLY HAVE " + a + " RALLODS REMAINING.\n");
+            }
+        }
+        if (h == 0 && i == 0 && j == 0 && k == 0) {
+            print("GOODBYE.\n");
+            print("(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER\n");
+            print("'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START\n");
+            print("OF THE GAME).\n");
+            return;
+        }
+        print("\n");
+        print("\n");
+        a = Math.floor(a - k);
+        a4 = a;
+        if (Math.floor(i / 100 - b) < 0) {
+            if (i / 100 < 50) {
+                hate_your_guts();
+                break;
+            }
+            print(Math.floor(b - (i / 100)) + " COUNTRYMEN DIED OF STARVATION\n");
+        }
+        f1 = Math.floor(Math.random() * (2000 - d));
+        if (k >= 25)
+            f1 = Math.floor(f1 / (k / 25));
+        if (f1 > 0)
+            print(f1 + " COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION\n");
+        funeral = false;
+        if (Math.floor((i / 100) - b) >= 0) {
+            if (f1 > 0) {
+                print("   YOU WERE FORCED TO SPEND " + Math.floor(f1 * 9) + " RALLODS ON ");
+                print("FUNERAL EXPENSES.\n");
+                b5 = f1;
+                a = Math.floor(a - (f1 * 9));
+                funeral = true;
+            }
+        } else {
+            print("   YOU WERE FORCED TO SPEND " + Math.floor((f1 + (b - (i / 100))) * 9));
+            print(" RALLODS ON FUNERAL EXPENSES.\n");
+            b5 = Math.floor(f1 + (b - (i / 100)));
+            a = Math.floor(a - ((f1 + (b - (i / 100))) * 9));
+            funeral = true;
+        }
+        if (funeral) {
+            if (a < 0) {
+                print("   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\n");
+                d = Math.floor(d + (a / w));
+                a = 0;
+            }
+            b = Math.floor(b - b5);
+        }
+        c1 = 0;
+        if (h != 0) {
+            c1 = Math.floor(h + (Math.random() * 10) - (Math.random() * 20));
+            if (c <= 0)
+                c1 += 20;
+            print(c1 + " WORKERS CAME TO THE COUNTRY AND ");
+        }
+        p1 = Math.floor(((i / 100 - b) / 10) + (k / 25) - ((2000 - d) / 50) - (f1 / 2));
+        print(Math.abs(p1) + " COUNTRYMEN ");
+        if (p1 >= 0)
+            print("CAME TO");
+        else
+            print("LEFT");
+        print(" THE ISLAND.\n");
+        b = Math.floor(b + p1);
+        c = Math.floor(c + c1);
+        u2 = Math.floor(((2000 - d) * ((Math.random() + 1.5) / 2)));
+        if (c != 0) {
+            print("OF " + Math.floor(j) + " SQ. MILES PLANTED,");
+        }
+        if (j <= u2)
+            u2 = j;
+        print(" YOU HARVESTED " + Math.floor(j - u2) + " SQ. MILES OF CROPS.\n");
+        if (u2 != 0 && t1 < 2) {
+            print("   (DUE TO ");
+            if (t1 != 0)
+                print("INCREASED ");
+            print("AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\n");
+        }
+        q = Math.floor((j - u2) * (w / 2));
+        print("MAKING " + q + " RALLODS.\n");
+        a = Math.floor(a + q);
+        v1 = Math.floor(((b - p1) * 22) + (Math.random() * 500));
+        v2 = Math.floor((2000 - d) * 15);
+        print(" YOU MADE " + Math.abs(Math.floor(v1 - v2)) + " RALLODS FROM TOURIST TRADE.\n");
+        if (v2 != 0 && v1 - v2 < v3) {
+            print("   DECREASE BECAUSE ");
+            g1 = 10 * Math.random();
+            if (g1 <= 2)
+                print("FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\n");
+            else if (g1 <= 4)
+                print("AIR POLLUTION IS KILLING GAME BIRD POPULATION.\n");
+            else if (g1 <= 6)
+                print("MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\n");
+            else if (g1 <= 8)
+                print("UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\n");
+            else if (g1 <= 10)
+                print("HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\n");
+        }
+        v3 = Math.floor(a + v3);    // Probable bug from original game
+        a = Math.floor(a + v3);
+        if (b5 > 200) {
+            print("\n");
+            print("\n");
+            print(b5 + " 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 = Math.floor(Math.random() * 10);
+            if (m6 <= 3)
+                print("ALSO HAD YOUR LEFT EYE GOUGED OUT!\n");
+            else if (m6 <= 6)
+                print("HAVE ALSO GAINED A VERY BAD REPUTATION.\n");
+            else
+                print("HAVE ALSO BEEN DECLARED NATIONAL FINK.\n");
+            print("\n");
+            print("\n");
+            return;
+        }
+        if (b < 343) {
+            hate_your_guts();
+            break;
+        }
+        if (a4 / 100 > 5 && b5 - f1 >= 2) {
+            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");
+            print("\n");
+            print("\n");
+            return;
+        }
+        if (c > b) {
+            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");
+            break;
+        }
+        if (n5 - 1 == x5) {
+            print("\n");
+            print("\n");
+            print("CONGRATULATIONS!!!!!!!!!!!!!!!!!!\n");
+            print("YOU HAVE SUCCESFULLY COMPLETED YOUR " + n5 + " 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");
+            print("\n");
+            print("\n");
+            return;
+        }
+        x5++;
+        b5 = 0;
+    }
+    if (Math.random() <= 0.5) {
+        print("YOU HAVE BEEN ASSASSINATED.\n");
+    } else {
+        print("YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\n");
+        print("RESIDING IN PRISON.\n");
+    }
+    print("\n");
+    print("\n");
+}
+
+main();

From e8ebdb3b84acf44e0a7e0d98138b5ba8893aca25 Mon Sep 17 00:00:00 2001
From: nanochess 
Date: Fri, 12 Mar 2021 22:02:32 -0600
Subject: [PATCH 04/19] Ported LUNAR to Javascript

---
 59 Lunar LEM Rocket/javascript/lunar.js | 429 +++++++-----------------
 1 file changed, 122 insertions(+), 307 deletions(-)

diff --git a/59 Lunar LEM Rocket/javascript/lunar.js b/59 Lunar LEM Rocket/javascript/lunar.js
index faaeb253..f95d1d16 100644
--- a/59 Lunar LEM Rocket/javascript/lunar.js	
+++ b/59 Lunar LEM Rocket/javascript/lunar.js	
@@ -1,4 +1,4 @@
-// KING
+// LUNAR
 //
 // Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
 //
@@ -42,335 +42,150 @@ function tab(space)
     return str;
 }
 
-function hate_your_guts()
+var l;
+var t;
+var m;
+var s;
+var k;
+var a;
+var v;
+var i;
+var j;
+var q;
+var g;
+var z;
+var d;
+
+function formula_set_1()
 {
-    print("\n");
-    print("\n");
-    print("OVER ONE THIRD OF THE POPULATION HAS DIED SINCE YOU\n");
-    print("WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)\n");
-    print("HATE YOUR GUTS.\n");
+    l = l + s;
+    t = t - s;
+    m = m - s * k;
+    a = i;
+    v = j;
+}
+
+function formula_set_2()
+{
+    q = s * k / m;
+    j = v + g * s + z * (-q - q * q / 2 - Math.pow(q, 3) / 3 - Math.pow(q, 4) / 4 - Math.pow(q, 5) / 5);
+    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);
+}
+
+function formula_set_3()
+{
+    while (s >= 5e-3) {
+        d = v + Math.sqrt(v * v + 2 * a * (g - z * k / m));
+        s = 2 * a / d;
+        formula_set_2();
+        formula_set_1();
+    }
 }
 
 // Main program
 async function main()
 {
-    print(tab(34) + "KING\n");
+    print(tab(33) + "LUNAR\n");
     print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
     print("\n");
     print("\n");
     print("\n");
-    print("DO YOU WANT INSTRUCTIONS");
-    str = await input();
-    n5 = 8;
-    if (str == "AGAIN") {
-        while (1) {
-            print("HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED");
-            x5 = parseInt(await input());
-            if (x5 == 0)
-                return;
-            if (x5 < 8)
-                break;
-            print("   COME ON, YOUR TERM IN OFFICE IS ONLY " + n5 + " YEARS.\n");
-        }
-        print("HOW MUCH DID YOU HAVE IN THE TREASURY");
-        a = parseInt(await input());
-        if (a < 0)
-            return;
-        print("HOW MANY COUNTRYMEN");
-        b = parseInt(await input());
-        if (b < 0)
-            return;
-        print("HOW MANY WORKERS");
-        c = parseInt(await input());
-        if (c < 0)
-            return;
-        while (1) {
-            print("HOW MANY SQUARE MILES OF LAND");
-            d = parseInt(await input());
-            if (d < 0)
-                return;
-            if (d > 1000 && d <= 2000)
-                break;
-            print("   COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND\n");
-            print("   AND 10,000 SQ. MILES OF FOREST LAND.\n");
-        }
-    } else {
-        if (str.substr(0, 1) != "N") {
-            print("\n");
-            print("\n");
-            print("\n");
-            print("CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS\n");
-            print("DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR\n");
-            print("JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE\n");
-            print("MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.\n");
-            print("THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100\n");
-            print("RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES\n");
-            print("FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT\n");
-            print("FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND\n");
-            print("WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD\n");
-            print("TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT\n");
-            print("THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER\n");
-            print("SQUARE MILE TO PLANT.\n");
-            print("YOUR GOAL IS TO COMPLETE YOUR " + n5 + " YEAR TERM OF OFFICE.\n");
-            print("GOOD LUCK!\n");
-        }
-        print("\n");
-        a = Math.floor(60000 + (1000 * Math.random()) - (1000 * Math.random()));
-        b = Math.floor(500 + (10 * Math.random()) - (10 * Math.random()));
-        c = 0;
-        d = 2000;
-        x5 = 0;
-    }
-    v3 = 0;
-    b5 = 0;
-    x = false;
+    print("THIS IS A COMPUTER SIMULATION OF AN APOLLO LUNAR\n");
+    print("LANDING CAPSULE.\n");
+    print("\n");
+    print("\n");
+    print("THE ON-BOARD COMPUTER HAS FAILED (IT WAS MADE BY\n");
+    print("XEROX) SO YOU HAVE TO LAND THE CAPSULE MANUALLY.\n");
     while (1) {
-        w = Math.floor(10 * Math.random() + 95);
         print("\n");
-        print("YOU NOW HAVE " + a + " RALLODS IN THE TREASURY.\n");
-        print(b + " COUNTRYMEN, ");
-        v9 = Math.floor(((Math.random() / 2) * 10 + 10));
-        if (c != 0)
-            print(c + " FOREIGN WORKERS, ");
-        print("AND " + Math.floor(d) + " SQ. MILES OF LAND.\n");
-        print("THIS YEAR INDUSTRY WILL BUY LAND FOR " + w + " ");
-        print("RALLODS PER SQUARE MILE.\n");
-        print("LAND CURRENTLY COSTS " + v9 + " RALLODS PER SQUARE MILE TO PLANT.\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");
         print("\n");
+        print("CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,500 LBS.\n");
+        print("\n");
+        print("\n");
+        print("\n");
+        print("GOOD LUCK\n");
+        l = 0;
+        print("\n");
+        print("SEC\tMI + FT\t\tMPH\tLB FUEL\tBURN RATE\n");
+        print("\n");
+        a = 120;
+        v = 1;
+        m = 33000;
+        n = 16500;
+        g = 1e-3;
+        z = 1.8;
         while (1) {
-            print("HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY");
-            h = parseInt(await input());
-            if (h < 0)
-                continue;
-            if (h <= d - 1000)
-                break;
-            print("***  THINK AGAIN. YOU ONLY HAVE " + (d - 1000) + " SQUARE MILES OF FARM LAND.\n");
-            if (x == false) {
-                print("\n");
-                print("(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE\n");
-                print("FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,\n");
-                print("THICKER TOP SOIL, ETC.)\n");
-                x = true;
-            }
-        }
-        d = Math.floor(d - h);
-        a = Math.floor(a + (h * w));
-        while (1) {
-            print("HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN");
-            i = parseInt(await input());
-            if (i < 0)
-                continue;
-            if (i < a)
-                break;
-            if (i == a) {
-                j = 0;
-                k = 0;
-                a = 0;
-                break;
-            }
-            print("   THINK AGAIN. YOU'VE ONLY " + a + " RALLODS IN THE TREASURY\n");
-        }
-        if (a) {
-            a = Math.floor(a - i);
+            print(l + "\t" + Math.floor(a) + " + " + Math.floor(5280 * (a - Math.floor(a))) + " \t" + Math.floor(3600 * v * 100) / 100 + "\t" + (m - n) + "\t");
+            k = parseFloat(await input());
+            t = 10;
+            should_exit = false;
             while (1) {
-                print("HOW MANY SQUARE MILES DO YOU WISH TO PLANT");
-                j = parseInt(await input());
-                if (j < 0)
-                    continue;
-                if (j <= b * 2) {
-                    if (j <= d - 1000) {
-                        u1 = Math.floor(j * v9);
-                        if (u1 > a) {
-                            print("   THINK AGAIN. YOU'VE ONLY " + a + " RALLODS LEFT IN THE TREASURY.\n");
-                            continue;
-                        } else if (u1 == a) {
-                            k = 0;
-                            a = 0;
-                        }
-                        break;
-                    }
-                    print("   SORRY, BUT YOU'VE ONLY " + (d - 1000) + " SQ. MILES OF FARM LAND.\n");
-                    continue;
-                }
-                print("   SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.\n");
-            }
-        }
-        if (a) {
-            a -= u1;
-            while (1) {
-                print("HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL");
-                k = parseInt(await input());
-                if (k < 0)
-                    continue;
-                if (k <= a)
+                if (m - n < 1e-3)
                     break;
-                print("   THINK AGAIN. YOU ONLY HAVE " + a + " RALLODS REMAINING.\n");
+                if (t < 1e-3)
+                    break;
+                s = t;
+                if (m < n + s * k)
+                    s = (m - n) / k;
+                formula_set_2();
+                if (i <= 0) {
+                    formula_set_3();
+                    should_exit = true;
+                    break;
+                }
+                if (v > 0) {
+                    if (j < 0) {
+                        do {
+                            w = (1 - m * g / (z * k)) / 2;
+                            s = m * v / (z * k * (w + Math.sqrt(w * w + v / z))) + 0.05;
+                            formula_set_2();
+                            if (i <= 0) {
+                                formula_set_3();
+                                should_exit = true;
+                                break;
+                            }
+                            formula_set_1();
+                            if (j > 0)
+                                break;
+                        } while (v > 0) ;
+                        if (should_exit)
+                            break;
+                        continue;
+                    }
+                }
+                formula_set_1();
             }
-        }
-        if (h == 0 && i == 0 && j == 0 && k == 0) {
-            print("GOODBYE.\n");
-            print("(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER\n");
-            print("'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START\n");
-            print("OF THE GAME).\n");
-            return;
-        }
-        print("\n");
-        print("\n");
-        a = Math.floor(a - k);
-        a4 = a;
-        if (Math.floor(i / 100 - b) < 0) {
-            if (i / 100 < 50) {
-                hate_your_guts();
+            if (should_exit)
+                break;
+            if (m - n < 1e-3) {
+                print("FUEL OUT AT " + l + " SECOND\n");
+                s = (-v * Math.sqrt(v * v + 2 * a * g)) / g;
+                v = v + g * s;
+                l = l + s;
                 break;
             }
-            print(Math.floor(b - (i / 100)) + " COUNTRYMEN DIED OF STARVATION\n");
         }
-        f1 = Math.floor(Math.random() * (2000 - d));
-        if (k >= 25)
-            f1 = Math.floor(f1 / (k / 25));
-        if (f1 > 0)
-            print(f1 + " COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION\n");
-        funeral = false;
-        if (Math.floor((i / 100) - b) >= 0) {
-            if (f1 > 0) {
-                print("   YOU WERE FORCED TO SPEND " + Math.floor(f1 * 9) + " RALLODS ON ");
-                print("FUNERAL EXPENSES.\n");
-                b5 = f1;
-                a = Math.floor(a - (f1 * 9));
-                funeral = true;
-            }
+        w = 3600 * v;
+        print("ON MOON AT " + l + " SECONDS - IMPACT VELOCITY " + w + " MPH\n");
+        if (w <= 1.2) {
+            print("PERFECT LANDING!\n");
+        } else if (w <= 10) {
+            print("GOOD LANDING (COULD BE BETTER)\n");
+        } else if (w <= 60) {
+            print("CRAFT DAMAGE... YOU'RE STRANDED HERE UNTIL A RESCUE\n");
+            print("PARTY ARRIVES. HOPE YOU HAVE ENOUGH OXYGEN!\n");
         } else {
-            print("   YOU WERE FORCED TO SPEND " + Math.floor((f1 + (b - (i / 100))) * 9));
-            print(" RALLODS ON FUNERAL EXPENSES.\n");
-            b5 = Math.floor(f1 + (b - (i / 100)));
-            a = Math.floor(a - ((f1 + (b - (i / 100))) * 9));
-            funeral = true;
+            print("SORRY THERE WERE NO SURVIVORS. YOU BLEW IT!\n");
+            print("IN FACT, YOU BLASTED A NEW LUNAR CRATER " + (w * 0.227) + " FEET DEEP!\n");
         }
-        if (funeral) {
-            if (a < 0) {
-                print("   INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD\n");
-                d = Math.floor(d + (a / w));
-                a = 0;
-            }
-            b = Math.floor(b - b5);
-        }
-        c1 = 0;
-        if (h != 0) {
-            c1 = Math.floor(h + (Math.random() * 10) - (Math.random() * 20));
-            if (c <= 0)
-                c1 += 20;
-            print(c1 + " WORKERS CAME TO THE COUNTRY AND ");
-        }
-        p1 = Math.floor(((i / 100 - b) / 10) + (k / 25) - ((2000 - d) / 50) - (f1 / 2));
-        print(Math.abs(p1) + " COUNTRYMEN ");
-        if (p1 >= 0)
-            print("CAME TO");
-        else
-            print("LEFT");
-        print(" THE ISLAND.\n");
-        b = Math.floor(b + p1);
-        c = Math.floor(c + c1);
-        u2 = Math.floor(((2000 - d) * ((Math.random() + 1.5) / 2)));
-        if (c != 0) {
-            print("OF " + Math.floor(j) + " SQ. MILES PLANTED,");
-        }
-        if (j <= u2)
-            u2 = j;
-        print(" YOU HARVESTED " + Math.floor(j - u2) + " SQ. MILES OF CROPS.\n");
-        if (u2 != 0 && t1 < 2) {
-            print("   (DUE TO ");
-            if (t1 != 0)
-                print("INCREASED ");
-            print("AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)\n");
-        }
-        q = Math.floor((j - u2) * (w / 2));
-        print("MAKING " + q + " RALLODS.\n");
-        a = Math.floor(a + q);
-        v1 = Math.floor(((b - p1) * 22) + (Math.random() * 500));
-        v2 = Math.floor((2000 - d) * 15);
-        print(" YOU MADE " + Math.abs(Math.floor(v1 - v2)) + " RALLODS FROM TOURIST TRADE.\n");
-        if (v2 != 0 && v1 - v2 < v3) {
-            print("   DECREASE BECAUSE ");
-            g1 = 10 * Math.random();
-            if (g1 <= 2)
-                print("FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION.\n");
-            else if (g1 <= 4)
-                print("AIR POLLUTION IS KILLING GAME BIRD POPULATION.\n");
-            else if (g1 <= 6)
-                print("MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION.\n");
-            else if (g1 <= 8)
-                print("UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS.\n");
-            else if (g1 <= 10)
-                print("HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT.\n");
-        }
-        v3 = Math.floor(a + v3);    // Probable bug from original game
-        a = Math.floor(a + v3);
-        if (b5 > 200) {
-            print("\n");
-            print("\n");
-            print(b5 + " 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 = Math.floor(Math.random() * 10);
-            if (m6 <= 3)
-                print("ALSO HAD YOUR LEFT EYE GOUGED OUT!\n");
-            else if (m6 <= 6)
-                print("HAVE ALSO GAINED A VERY BAD REPUTATION.\n");
-            else
-                print("HAVE ALSO BEEN DECLARED NATIONAL FINK.\n");
-            print("\n");
-            print("\n");
-            return;
-        }
-        if (b < 343) {
-            hate_your_guts();
-            break;
-        }
-        if (a4 / 100 > 5 && b5 - f1 >= 2) {
-            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");
-            print("\n");
-            print("\n");
-            return;
-        }
-        if (c > b) {
-            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");
-            break;
-        }
-        if (n5 - 1 == x5) {
-            print("\n");
-            print("\n");
-            print("CONGRATULATIONS!!!!!!!!!!!!!!!!!!\n");
-            print("YOU HAVE SUCCESFULLY COMPLETED YOUR " + n5 + " 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");
-            print("\n");
-            print("\n");
-            return;
-        }
-        x5++;
-        b5 = 0;
+        print("\n");
+        print("\n");
+        print("\n");
+        print("TRY AGAIN??\n");
     }
-    if (Math.random() <= 0.5) {
-        print("YOU HAVE BEEN ASSASSINATED.\n");
-    } else {
-        print("YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW\n");
-        print("RESIDING IN PRISON.\n");
-    }
-    print("\n");
-    print("\n");
 }
 
 main();

From 990dd614d4565172f375970c42157ec257d9fa32 Mon Sep 17 00:00:00 2001
From: Aldrin Misquitta 
Date: Sat, 13 Mar 2021 14:51:42 +0400
Subject: [PATCH 05/19] Ported 66 Number to Java

---
 66 Number/java/Number.java | 62 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 62 insertions(+)
 create mode 100644 66 Number/java/Number.java

diff --git a/66 Number/java/Number.java b/66 Number/java/Number.java
new file mode 100644
index 00000000..2e481fca
--- /dev/null
+++ b/66 Number/java/Number.java	
@@ -0,0 +1,62 @@
+import java.util.Scanner;
+
+public class Number {
+
+	public static void main(String[] args) {
+		printIntro();
+		int points = 100; //start with 100 points for the user
+
+		Scanner scan = new Scanner(System.in);
+		boolean done = false;
+		while (!done) {
+			System.out.print("GUESS A NUMBER FROM 1 TO 5? ");
+			int g = scan.nextInt();
+
+			//Initialize 5 random numbers between 1-5
+			var r = randomNumber(1);
+			var s = randomNumber(1);
+			var t = randomNumber(1);
+			var u = randomNumber(1);
+			var v = randomNumber(1);
+
+			if (r == g) {
+				points -= 5;
+			} else if (s == g) {
+				points += 5;
+			} else if (t == g) {
+				points += points;
+			} else if (u == g) {
+				points += 1;
+			} else if (v == g) {
+				points -= points * 0.5;
+			} else {
+				continue; //Doesn't match any of our random numbers, so just ask for another guess
+			}
+
+			if (points > 500) {
+				done = true;
+			} else {
+				System.out.println("YOU HAVE " + points + " POINTS.");
+			}
+		}
+
+		System.out.println("!!!!YOU WIN!!!! WITH " + points + " POINTS.\n");
+	}
+
+	private static int randomNumber(int x) {
+		//Note: 'x' is totally ignored as was in the original basic listing
+		return (int) (5 * Math.random() + 1);
+	}
+
+	private static void printIntro() {
+		System.out.println("                                NUMBER");
+		System.out.println("              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+		System.out.println("\n\n\n");
+		System.out.println("YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU");
+		System.out.println("CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO");
+		System.out.println("A RANDOM NUMBER SELECTED BY THE COMPUTER.");
+		System.out.println("\n");
+		System.out.println("YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)");
+		System.out.println("YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS.");
+	}
+}

From 4e5d65b621bad96621c2e06fac8e97098f85b384 Mon Sep 17 00:00:00 2001
From: Aldrin Misquitta 
Date: Sat, 13 Mar 2021 14:52:18 +0400
Subject: [PATCH 06/19] Deleted main.class. Not sure what it is doing here

---
 66 Number/java/main.class | 69 ---------------------------------------
 1 file changed, 69 deletions(-)
 delete mode 100644 66 Number/java/main.class

diff --git a/66 Number/java/main.class b/66 Number/java/main.class
deleted file mode 100644
index c3df4ebf..00000000
--- a/66 Number/java/main.class	
+++ /dev/null
@@ -1,69 +0,0 @@
-
-import java.time.temporal.ValueRange;
-import java.util.Arrays;
-import java.util.Random;
-import java.util.Scanner;
-
-public class Number {
-
-    public static int points = 0;
-
-    public static void printempty() { System.out.println(" "); }
-
-    public static void print(String toprint) { System.out.println(toprint); }
-
-    public static void main(String[] args) {
-        print("YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU");
-        print("CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO");
-        print("A RANDOM NUMBER SELECTED BY THE COMPUTER.");
-        printempty();
-        print("YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)");
-        print("YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS.");
-        printempty();
-
-        try {
-            while (true) {
-                print("GUESS A NUMBER FROM 1 TO 5");
-
-
-                Scanner numbersc = new Scanner(System.in);
-                String numberstring = numbersc.nextLine();
-
-                int number = Integer.parseInt(numberstring);
-
-                if (!(number < 1| number > 5)) {
-
-                    Random rand = new Random();
-
-                    int randomNum = rand.nextInt((5 - 1) + 1) + 1;
-
-                    if (randomNum == number) {
-                        print("YOU HIT THE JACKPOT!!!");
-                        points = points * 2;
-                    } else if(ValueRange.of(randomNum, randomNum + 1).isValidIntValue(number)) {
-                        print("+5");
-                        points = points + 5;
-                    } else if(ValueRange.of(randomNum - 1, randomNum + 2).isValidIntValue(number)) {
-                        print("+1");
-                        points = points + 1;
-                    } else if(ValueRange.of(randomNum - 3, randomNum + 1).isValidIntValue(number)) {
-                        print("-1");
-                        points = points - 1;
-                    } else {
-                        print("-half");
-                        points = (int) (points * 0.5);
-                    }
-
-                    print("YOU HAVE " + points + " POINTS.");
-                }
-
-                if (points >= 500) {
-                    print("!!!!YOU WIN!!!! WITH " + points + " POINTS.");
-                    return;
-                }
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-}

From 8ef694996f2d83d06b7f51481a056bb781a19dfa Mon Sep 17 00:00:00 2001
From: Chris Reuter 
Date: Sat, 13 Mar 2021 14:58:08 -0500
Subject: [PATCH 07/19] Added ruby implemention of Checkers.

Also added my annotated version of the BASIC source code on the off
chance that it would be useful.
---
 23 Checkers/README.md              |   5 +-
 23 Checkers/checkers.annotated.bas | 315 ++++++++++++++
 23 Checkers/ruby/README.md         |   5 +
 23 Checkers/ruby/checkers.rb       | 651 +++++++++++++++++++++++++++++
 4 files changed, 975 insertions(+), 1 deletion(-)
 create mode 100644 23 Checkers/checkers.annotated.bas
 create mode 100644 23 Checkers/ruby/checkers.rb

diff --git a/23 Checkers/README.md b/23 Checkers/README.md
index 05681815..0a3c57a2 100644
--- a/23 Checkers/README.md	
+++ b/23 Checkers/README.md	
@@ -6,10 +6,13 @@ https://www.atariarchives.org/basicgames/showpage.php?page=40
 Downloaded from Vintage Basic at
 http://www.vintage-basic.net/games.html
 
+The file `checkers.annotated.bas` contains an indented and annotated
+version of the source code.  This is no longer valid BASIC code but
+should be more readable.
 
 ## Known Issues In the Original BASIC Code
  - If the computer moves a checker to the bottom row, it promotes, but
    leaves the original checker in place. (See line 1240)
  - Human players may move non-kings as if they were kings. (See lines 1590 to 1810)
+ - Human players are not required to jump if it is possible.
  - Curious writing to "I" variable without ever reading it. (See lines 1700 and 1806)
- 
\ No newline at end of file
diff --git a/23 Checkers/checkers.annotated.bas b/23 Checkers/checkers.annotated.bas
new file mode 100644
index 00000000..af8ffabc
--- /dev/null
+++ b/23 Checkers/checkers.annotated.bas	
@@ -0,0 +1,315 @@
+     # Annotated version of CHECKERS.BAS, modified to improve readability.
+     #
+     # I've made the following changes:
+     #
+     #  1. Added many comments and blank lines.
+     #  2. Separated each statement into its own line.
+     #  3. Indented loops, conditionals and subroutines.
+     #  4. Turned *SOME* conditionals and loops into
+     #     structured-BASIC-style if/endif and loop/endloop blocks.
+     #  5. Switched to using '#' to delimit comments.
+     #  6. Subroutines now begin with "Sub_Start"
+     #  7. All non-string text has been converted to lower-case
+     #  8. All line numbers that are not jump destinations have been removed.
+     #
+     # This has helped me make sense of the code.  I hope it will also help you.
+     #
+
+     # Print the banner
+     print tab(32);"CHECKERS"
+     print tab(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+     print
+     print
+     print
+     print "THIS IS THE GAME OF CHECKERS.  THE COMPUTER IS X,"
+     print "AND YOU ARE O.  THE COMPUTER WILL MOVE FIRST."
+     print "SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM."
+     print "(0,0) IS THE LOWER LEFT CORNER"
+     print "(0,7) IS THE UPPER LEFT CORNER"
+     print "(7,0) IS THE LOWER RIGHT CORNER"
+     print "(7,7) IS THE UPPER RIGHT CORNER"
+     print "THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER"
+     print "JUMP.  TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP."
+     print
+     print
+     print
+
+     # Declare the "globals":
+
+     # The current move: (rating, current x, current y, new x, new y)
+     # 'rating' represents how good the move is; higher is better.
+     dim r(4)
+     r(0)=-99       # Start with minimum score
+
+     # The board.  Pieces are represented by numeric values:
+     #
+     #      - 0     = empty square
+     #      - -1,-2 = X (-1 for regular piece, -2 for king)
+     #      - 1,2   = O (1 for regular piece, 2 for king)
+     #
+     # This program's player ("me") plays X.
+     dim s(7,7)
+
+     g=-1           # constant holding -1
+
+     # Initialize the board.  Data is 2 length-wise strips repeated.
+     data 1,0,1,0,0,0,-1,0,0,1,0,0,0,-1,0,-1,15
+     for x=0 to 7
+       for y=0 to 7
+         read j
+         if j=15 then 180
+         s(x,y)=j
+         goto 200
+180      restore
+         read s(x,y)
+200  next y,x
+
+230  # Start of game loop.  First, my turn.
+
+     # For each square on the board, search for one of my pieces
+     # and if it can make the best move so far, store that move in 'r'
+     for x=0 to 7
+       for y=0 to 7
+
+         # Skip if this is empty or an opponent's piece
+         if s(x,y) > -1 then 350
+
+         # If this is one of my ordinary pieces, analyze possible
+         # forward moves.
+         if s(x,y) = -1 then
+           for a=-1 to 1 step 2
+             b=g
+             gosub 650
+           next a
+         endif
+
+         # If this is one of my kings, analyze possible forward
+         # and backward moves.
+         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
+         endif
+
+350  next y,x
+     goto 1140  # Skip the subs
+
+
+     # Analyze a move from (x,y) to (x+a, y+b) and schedule it if it's
+     # the best candidate so far.
+650  Sub_Start
+       u=x+a
+       v=y+b
+
+       # Done if it's off the board
+       if u<0 or u>7 or v<0 or v>7 then 870
+
+       # Consider the destination if it's empty
+       if s(u,v) = 0 then
+         gosub 910
+         goto 870
+       endif
+
+       # If it's got an opponent's piece, jump it instead
+       if s(u,v) > 0
+
+           # Restore u and v, then return if it's off the board
+           u=u+a
+           v=v+b
+           if u<0 or v<0 or u>7 or v>7 then 870
+
+           # Otherwise, consider u,v
+           if s(u,v)=0 then gosub 910
+       endif           
+870  return
+
+     # Evaluate jumping (x,y) to (u,v).
+     #
+     # Computes a score for the proposed move and if it's higher
+     # than the best-so-far move, uses that instead by storing it
+     # and its score in array 'r'.
+910  Sub_Start
+
+       # q is the score; it starts at 0
+
+       # +2 if it promotes this piece
+       if v=0 and s(x,y)=-1 then q=q+2
+
+       # +5 if it takes an opponent's piece
+       if abs(y-v)=2 then q=q+5
+
+       # -2 if the piece is moving away from the top boundary
+       if y=7 then q=q-2
+
+       # +1 for putting the piece against a vertical boundary
+       if u=0 or u=7 then q=q+1
+
+       for c=-1 to 1 step 2
+         if u+c < 0 or u+c > 7 or v+g < 0 then 1080
+
+         # +1 for each adjacent friendly piece
+         if s(u+c, v+g) < 0 then
+           q=q+1
+           goto 1080
+         endif
+
+         # Prevent out-of-bounds testing
+         if u-c < 0 or u-c > 7 or v-g > 7 then 1080
+
+         # -2 for each opponent piece that can now take this piece here
+         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
+1080   next c
+
+       # Use this move if it's better than the previous best
+       if q>r(0) then
+         r(0)=q
+         r(1)=x
+         r(2)=y
+         r(3)=u
+         r(4)=v
+       endif
+
+       q=0  # reset the score
+     return
+
+1140 if r(0)=-99 then 1880  # Game is lost if no move could be found.
+
+     # Print the computer's move.  (Note: chr$(30) is an ASCII RS
+     # (record separator) code; probably no longer relevant.)
+     print chr$(30)"FROM"r(1);r(2)"TO"r(3);r(4);
+     r(0)=-99
+
+     # Make the computer's move.  If the piece finds its way to the
+     # end of the board, crown it.
+1240 if r(4)=0 then
+       s(r(3),r(4))=-2
+       goto 1420
+     endif
+     s(r(3),r(4))=s(r(1),r(2))
+     s(r(1),r(2))=0
+
+     # If the piece has jumped 2 squares, it means the computer has
+     # taken an opponents' piece.
+     if abs(r(1)-r(3)) == 2 then
+       s((r(1)+r(3))/2,(r(2)+r(4))/2)=0     # Delete the opponent's piece
+
+       # See if we can jump again.  Evaluate all possible moves.
+       x=r(3)
+       y=r(4)
+       for a=-2 to 2 step 4
+         if s(x,y)=-1 then
+           b=-2
+           gosub 1370
+         endif
+         if s(x,y)=-2 then
+           for b=-2 to 2 step 4
+             gosub 1370
+           next b
+         endif
+       next a
+
+       # If we've found a move, go back and make that one as well
+       if r(0) <> -99 then
+         print "TO" r(3); r(4);
+         r(0)=-99
+         goto 1240
+       endif
+
+       goto 1420   # Skip the sub
+
+       # If (u,v) is in the bounds, evaluate it as a move using
+       # the sub at 910
+1370   Sub_Start
+         u=x+a
+         v=y+b
+         if u<0 or u>7 or v<0 or v>7 then 1400
+         if s(u,v)=0 and s(x+a/2,y+b/2)>0 then gosub 910
+1400   return
+
+1420 endif
+
+     # Now, print the board
+     print
+     print
+     print
+     for y=7 to 0 step-1
+       for x=0 to 7
+         i=5*x
+         print tab(i);
+         if s(x,y)=0 then print".";
+         if s(x,y)=1 then print"O";
+         if s(x,y)=-1 then print"X";
+         if s(x,y)=-2 then print"X*";
+         if s(x,y)=2 then print"O*";
+       next x
+       print" "
+       print
+     next y
+     print
+
+     # Check if either player is out of pieces.  If so, announce the
+     # winner.
+     for l=0 to 7
+       for m=0 to 7
+         if s(l,m)=1 or s(l,m)=2 then z=1
+         if s(l,m)=-1 or s(l,m)=-2 then t=1
+       next m
+     next l
+     if z<>1 then 1885
+     if t<>1 then 1880
+
+     # Prompt the player for their move.
+     z=0
+     t=0
+1590 input "FROM";e,h
+     x=e
+     y=h
+     if s(x,y)<=0 then 1590
+1670 input "TO";a,b
+     x=a
+     y=b
+     if s(x,y)=0 and abs(a-e)<=2 and abs(a-e)=abs(b-h)then 1700
+     print chr$(7)chr$(11);     # bell, vertical tab; invalid move
+     goto 1670
+
+1700 i=46       # Not used; probably a bug
+1750 loop
+       # Make the move and stop unless it might be a jump.
+       s(a,b) = s(e,h)
+       s(e,h) = 0
+       if abs(e-a) <> 2 then break
+
+       # Remove the piece jumped over
+       s((e+a)/2,(h+b)/2) = 0
+
+       # Prompt for another move; -1 means player can't, so I've won.
+       # Keep prompting until there's a valid move or the player gives
+       # up.
+1802   input "+TO";a1,b1
+       if a1 < 0 then break
+       if s(a1,b1) <> 0 or abs(a1-a) <>2  or abs(b1-b) <> 2 then 1802
+
+       # Update the move variables to correspond to the next jump
+       e=a
+       h=b
+       a=a1
+       b=b1
+
+       i=i+15   # Not used; probably a bug
+     endloop
+
+     # If the player has reached the end of the board, crown this piece
+1810 if b=7 then s(a,b)=2
+
+     # And play the next turn.
+     goto 230
+
+     # Endgame:
+1880 print
+     print "YOU WIN."
+     end
+
+1885 print
+     print "I WIN."
+     end
diff --git a/23 Checkers/ruby/README.md b/23 Checkers/ruby/README.md
index fb32811e..3b53879b 100644
--- a/23 Checkers/ruby/README.md	
+++ b/23 Checkers/ruby/README.md	
@@ -1,3 +1,8 @@
 Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
 
 Conversion to [Ruby](https://www.ruby-lang.org/en/)
+
+This version preserves the underlying algorithms and functionality of
+the original while using more modern programming constructs
+(functions, classes, symbols) and providing much more detailed
+comments.  It also fixes some (but not all) of the bugs.
diff --git a/23 Checkers/ruby/checkers.rb b/23 Checkers/ruby/checkers.rb
new file mode 100644
index 00000000..cac0ab06
--- /dev/null
+++ b/23 Checkers/ruby/checkers.rb	
@@ -0,0 +1,651 @@
+#!/usr/bin/env ruby
+
+# Checkers in Ruby, Version 1
+#
+# This version of the game attempts to preserve the underlying
+# algorithm(s) and feel of the BASIC version while using more modern
+# coding techniques.  Specifically:
+#
+# 1. The major data structures (the board and current move, known as S
+#    and R in the BASIC version) have been turned into classes.  In
+#    addition, I made a class for coordinates so that you don't always
+#    have to deal with pairs of numbers.
+#
+# 2. Much of the functionality associated with this data has been moved
+#    into methods of these classes in line with the philosophy that objects
+#    are smart data.
+#
+# 3. While I've kept the board as a single object (not global, though),
+#    this program will create many Move objects (i.e. copies of the move
+#    under consideration) rather than operating on a single global
+#    instance.
+#
+# 4. The rest of the code has been extracted into Ruby functions with
+#    all variables as local as reasonably possible.
+#
+# 5. Pieces are now represented with Symbols instead of integers; this
+#    made it *much* easier to understand what was going on.
+#
+# 6. There are various internal sanity checks.  They fail by throwing
+#    a string as an exception.  (This is generally frowned upon if
+#    you're going to catch the exception later but we never do that;
+#    an exception here means a bug in the software and the way to fix
+#    that is to fix the program.)
+#
+# And probably other stuff.
+#
+
+
+# Note: I've ordered the various major definitions here from (roughly)
+# general to specific so that if you read the code starting from the
+# beginning, you'll (hopefully) get a big-picture view first and then
+# get into details.  Normally, I'd order things by topic and define
+# things before using them, which is a better ordering.  So in this
+# case, do what I say and not what I do.
+
+
+#
+# Some global constants
+#
+
+BOARD_TEXT_INDENT = 30  # Number of spaces to indent the board when printing
+
+# Various constants related to the game of Checkers.
+#
+# (Yes, they're obvious but if you see BOARD_WIDTH, you know this is
+# related to board dimensions in a way that you wouldn't if you saw
+# '8'.)
+BOARD_WIDTH = 8
+KING_ROW_X = 0
+KING_ROW_Y = BOARD_WIDTH - 1
+
+
+
+# This is the mainline routine of the program.  Ruby doesn't require
+# that you put this in a function but this way, your local variables
+# are contained here.  It's also neater, IMO.
+#
+# The name 'main' isn't special; it's just a function.  The last line
+# of this program is a call to it.
+def main
+  print < move.from.y
+      return false if !is_me && move.to.y < move.from.y
+    end
+
+    # If jumping, that there's an opponent's piece between the start
+    # and end.
+    return false if
+      move.jump? &&
+      (empty_at?(move.midpoint) || opponent_at?(move.midpoint) != is_me)
+
+    # Otherwise, it's legal
+    return true
+  end
+
+  # Perform 'move' on the board.  'move' must be legal; the player
+  # performing it is determined by the move's starting ('from')
+  # position.
+  def make_move!(move)
+    piece = self[move.from]
+
+    # Sanity check
+    raise "Illegal move: #{move}" unless legal_move?(piece.downcase == :x,move)
+
+    # Promote the piece if it's reached the end row
+    piece = piece.upcase if
+      (piece == :x && move.to.y == KING_ROW_X) ||
+      (piece == :o && move.to.y == KING_ROW_Y)
+
+    # And do the move
+    self[move.to] = piece
+    self[move.from] = :_
+
+    # Remove the piece jumped over if this is a jump
+    self[move.midpoint] = :_ if move.jump?
+  end
+
+
+  # Return the best (i.e. likely to win) move possible for the
+  # piece (mine) at 'coord'.
+  def bestMoveFrom(coord, mustJump)
+    so_far = Move.invalid
+    return so_far unless coord.valid?
+
+    offsets = [ [-1, -1], [1, -1]]
+    offsets += [ [-1, 1], [1, 1]] if king_at?(coord)
+
+    for ofx, ofy in offsets
+      new_coord = coord.by(ofx, ofy)
+
+      if opponent_at?(new_coord)
+        new_coord = new_coord.by(ofx, ofy)
+      elsif mustJump
+        next
+      end
+
+      next unless new_coord.valid?
+
+      so_far = so_far.betterOf( ratedMove(coord, new_coord) )
+    end
+
+    return so_far
+  end
+
+
+  # Create and return a move for *me* from Coords 'from' to 'to' with
+  # its 'rating' set to how good the move looks according to criteria
+  # used by the BASIC version of this program.  If the move is
+  # illegal, returns an invalid Move object.
+  def ratedMove(from, to)
+    return Move.invalid unless legal_move?(true, Move.new(from, to))
+
+    rating = 0
+
+    # +2 if it promotes this piece
+    rating += 2 if to.y == 0
+
+    # +50 if it takes the opponent's piece.  (Captures are mandatory
+    # so we ensure that a capture will always outrank a non-capture.)
+    rating += 4 if (from.y - to.y).abs == 2
+
+    # -2 if we're moving away from the king row
+    rating -= 2 if from.y == BOARD_WIDTH - 1
+
+    # +1 for putting the piece against a vertical boundary
+    rating += 1 if to.x == 0 || to.x == BOARD_WIDTH - 1
+
+    # +1 for each friendly piece behind this one
+    [-1, 1].each {|c|
+      rating += 1 if mine_at?( to.by(c, -1) )
+    }
+
+    # -2 for each opponent's piece that can now capture this one.
+    # (This includes a piece that may be captured when moving here;
+    # this is a bug.)
+    [ -1, 1].each {|c|
+      there = to.by(c, -1)
+      opposite = to.by(-c, 1)
+      rating -= 2 if
+        opponent_at?(there) && (empty_at?(opposite) || opposite == from)
+    }
+
+    return Move.new(from, to, rating)
+  end
+end
+
+
+# Class to hold the X and Y coordinates of a position on the board.
+#
+# Coord objects are immutable--that is, they never change after
+# creation.  Instead, you will always get a modified copy back.
+class Coord
+
+  # Coordinates are readable
+  attr_reader :x, :y
+
+  # Initialize
+  def initialize(x, y)
+    @x, @y = [x,y]
+  end
+
+  # Test if this move is on the board.
+  def valid?
+    return x >= 0 && y >= 0 && x < BOARD_WIDTH && y < BOARD_WIDTH
+  end
+
+  # Test if this Coord is equal to another Coord.
+  def ==(other)
+    return other.class == self.class && other.x == @x && other.y == y
+  end
+
+  # Return a string that describes this Coord in a human-friendly way.
+  def to_s
+    return "(#{@x},#{@y})"
+  end
+
+  # Return a new Coord whose x and y coordinates have been adjusted by
+  # arguments 'x' and 'y'.
+  def by(x, y)
+    return Coord.new(@x + x, @y + y)
+  end
+end
+
+
+# Class to represent a move by a player between two positions,
+# possibly with a rating that can be used to select the best of a
+# collection of moves.
+#
+# An (intentionally) invalid move will have a value of nil for both
+# 'from' and 'to'.  Most methods other than 'valid?' assume the Move
+# is valid.
+class Move
+  # Readable fields:
+  attr_reader :from, :to, :rating
+
+  # The initializer; -99 is the lowest rating from the BASIC version
+  # so we use that here as well.
+  def initialize(from, to, rating = -99)
+    @from, @to, @rating = [from, to, rating]
+
+    # Sanity check; the only invalid Move tolerated is the official
+    # one (i.e. with nil for each endpoint.)
+    raise "Malformed Move: #{self}" if @from && @to && !valid?
+  end
+
+  # Return an invalid Move object.
+  def self.invalid
+    return self.new(nil, nil, -99)
+  end
+
+  # Return true if this is a valid move (i.e. as close to legal as we
+  # can determine without seeing the board.)
+  def valid?
+    # Not valid if @from or @to is nil
+    return false unless @from && @to
+
+    # Not valid unless both endpoints are on the board
+    return false unless @from.valid? && @to.valid?
+
+    # Not valid unless it's a diagonal move by 1 or 2 squares
+    dx, dy = delta
+    return false if dx.abs != dy.abs || (dx.abs != 1 && dx.abs != 2)
+
+    # Otherwise, valid
+    return true
+  end
+
+  # Return true if this move is a jump, false otherwise
+  def jump?
+    return valid? && magnitude() == 2
+  end
+
+  # Return the coordinates of the piece being jumped over by this
+  # move.
+  def midpoint
+    raise "Called 'midpoint' on a non-jump move!" unless jump?
+    dx, dy = delta
+    return @from.by(dx / dx.abs, dy / dy.abs)
+  end
+
+  # Return the better-rated of self or otherMove.
+  def betterOf(otherMove)
+    return otherMove if !valid?
+    return rating > otherMove.rating ? self : otherMove
+  end
+
+  # Return a human-friendly string representing this move.
+  def to_s
+    return "[NOMOVE]" if !@from && !@to     # Well-known invalid move
+
+    jumpover = jump? ?
+                 "-> #{midpoint} ->"
+               : "->"
+
+    return "#{@from} #{jumpover} #{to}#{valid? ? '' : ' [INVALID]'}"
+  end
+
+  private
+
+  # Return the distance (x, y) between the 'from' and 'to' locations.
+  def delta
+    return [to.x - from.x, to.y - from.y]
+  end
+
+  # Return the number of squares this move will take the piece (either
+  # 1 or 2).
+  def magnitude
+    # Note: we assume that this move is a legal move (and therefore
+    # diagonal); otherwise, this may not be correct.
+    return (to.x - from.x).abs
+  end
+end
+
+
+
+# Start the game
+main()

From e7078460917963bea1a780e50fe687e46d62ec59 Mon Sep 17 00:00:00 2001
From: Todd Kaiser 
Date: Sat, 13 Mar 2021 16:17:49 -0700
Subject: [PATCH 08/19] Copied functions from Jupyter notebook to salvo.py.
 Started adding interactive player interface.

---
 77 Salvo/python/salvo.ipynb |  55 ++++---
 77 Salvo/python/salvo.py    | 279 +++++++++++++++++++++++++++++++-----
 2 files changed, 273 insertions(+), 61 deletions(-)

diff --git a/77 Salvo/python/salvo.ipynb b/77 Salvo/python/salvo.ipynb
index 0c8287af..7b98691b 100644
--- a/77 Salvo/python/salvo.ipynb	
+++ b/77 Salvo/python/salvo.ipynb	
@@ -24,7 +24,7 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 715,
+   "execution_count": 727,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -33,7 +33,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 716,
+   "execution_count": 728,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -57,7 +57,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 717,
+   "execution_count": 729,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -80,14 +80,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 718,
+   "execution_count": 730,
    "metadata": {},
    "outputs": [
     {
      "output_type": "stream",
      "name": "stdout",
      "text": [
-      "8 4\n"
+      "5 3\n"
      ]
     }
    ],
@@ -98,7 +98,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 719,
+   "execution_count": 731,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -155,14 +155,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 720,
+   "execution_count": 732,
    "metadata": {},
    "outputs": [
     {
      "output_type": "stream",
      "name": "stdout",
      "text": [
-      "BATTLESHIP       5 [(9, 2), (8, 3), (7, 4), (6, 5), (5, 6)]\nCRUISER          3 [(3, 8), (2, 9), (1, 10)]\nDESTROYER     2 [(3, 5), (3, 6)]\nDESTROYER     2 [(6, 5), (7, 4)]\n"
+      "BATTLESHIP       5 [(10, 2), (10, 3), (10, 4), (10, 5), (10, 6)]\nCRUISER          3 [(9, 4), (8, 4), (7, 4)]\nDESTROYER     2 [(2, 5), (1, 5)]\nDESTROYER     2 [(7, 8), (7, 9)]\n"
      ]
     }
    ],
@@ -175,7 +175,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 721,
+   "execution_count": 733,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -186,7 +186,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 722,
+   "execution_count": 734,
    "metadata": {},
    "outputs": [
     {
@@ -221,7 +221,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 723,
+   "execution_count": 735,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -232,25 +232,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 724,
+   "execution_count": 736,
    "metadata": {},
    "outputs": [
     {
      "output_type": "stream",
      "name": "stdout",
      "text": [
-      "DESTROYER     2 [(1, 7), (2, 6), (3, 5), (4, 4), (5, 3)]\n",
-      "    1  2  3  4  5  6  7  8  9 10\n",
-      " 1                    0         \n",
-      " 2                 0            \n",
-      " 3              0               \n",
-      " 4           0                  \n",
-      " 5        0                     \n",
-      " 6                              \n",
-      " 7                              \n",
-      " 8                              \n",
-      " 9                              \n",
-      "10                              \n"
+      "DESTROYER     2 [(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]\n    1  2  3  4  5  6  7  8  9 10\n 1     0                        \n 2        0                     \n 3           0                  \n 4              0               \n 5                 0            \n 6                              \n 7                              \n 8                              \n 9                              \n10                              \n"
      ]
     }
    ],
@@ -265,14 +254,24 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 725,
+   "execution_count": 737,
    "metadata": {},
    "outputs": [
     {
      "output_type": "stream",
      "name": "stdout",
      "text": [
-      "    1  2  3  4  5  6  7  8  9 10\n 1           1           0      \n 2        1           0         \n 3     1           0            \n 4              0               \n 5        2  0                  \n 6     2                        \n 7                 3  3         \n 8                              \n 9                              \n10                              \n"
+      "    1  2  3  4  5  6  7  8  9 10\n",
+      " 1                              \n",
+      " 2              1               \n",
+      " 3                 1  2         \n",
+      " 4                    1  2      \n",
+      " 5  0                           \n",
+      " 6     0                        \n",
+      " 7        0                     \n",
+      " 8           0                  \n",
+      " 9              0           3   \n",
+      "10                       3      \n"
      ]
     }
    ],
@@ -305,14 +304,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 726,
+   "execution_count": 738,
    "metadata": {},
    "outputs": [
     {
      "output_type": "stream",
      "name": "stdout",
      "text": [
-      "[(4, 4), (2, 8), (10, 6), (2, 4), (10, 7)]\n"
+      "[(4, 1), (3, 6), (6, 10), (10, 6), (4, 5)]\n"
      ]
     }
    ],
diff --git a/77 Salvo/python/salvo.py b/77 Salvo/python/salvo.py
index 3d36dcbd..2061943d 100644
--- a/77 Salvo/python/salvo.py	
+++ b/77 Salvo/python/salvo.py	
@@ -1,6 +1,12 @@
 import re
+import random
+
+###################
+#
+# static variables
+#
+###################
 
-# declare static variables
 BOARD_WIDTH = 10
 BOARD_HEIGHT = 10
 
@@ -9,17 +15,64 @@ SHIPS = [("BATTLESHIP", 5),
          ("DESTROYER", 2),
          ("DESTROYER", 2)]
 
-VALID_MOVES = [[-1, 0],
-               [-1, 1],
-               [0, 1],
-               [1, 1],
-               [1, 0],
-               [1, -1],
-               [0, -1],
-               [1, -1]]
+VALID_MOVES = [[-1, 0],   # North
+               [-1, 1],   # North East
+               [0, 1],    # East
+               [1, 1],    # South East
+               [1, 0],    # South
+               [1, -1],   # South West
+               [0, -1],   # West
+               [-1, -1]]  # North West
 
 COORD_REGEX = '[ \t]{0,}(-?[0-9]{1,3})[ \t]{0,},[ \t]{0,}(-?[0-9]{1,2})'
 
+####################
+#
+# global variables
+#
+####################
+
+# array of BOARD_HEIGHT arrays, BOARD_WIDTH in length,
+# representing the human player and computer
+player_board = []
+computer_board = []
+
+# array representing the coordinates
+# for each ship for player and computer
+# array is in the same order as SHIPS
+player_ship_coords = []
+computer_ship_coords = []
+
+# keep track of the turn
+current_turn = 0
+
+# flag indicating if computer's shots are
+# printed out during computer's turn
+print_computer_shots = False
+
+####################
+#
+# game functions
+#
+####################
+
+# random number functions
+#
+# seed the random number generator
+random.seed()
+
+
+# random_x_y
+#
+# generate a valid x,y coordinate on the board
+# returns: x,y
+#   x: integer between 1 and BOARD_HEIGHT
+#   y: integer between 1 and BOARD WIDTH
+def random_x_y():
+    x = random.randrange(1, BOARD_WIDTH+1)
+    y = random.randrange(1, BOARD_HEIGHT+1)
+    return (x, y)
+
 
 # input_coord
 #
@@ -51,32 +104,192 @@ def input_coord():
     return x, y
 
 
-# input_ship_coords
-#
-# ask the user for coordinates for each
-# ship on their board. uses input_coord()
-# to read each coord.
-# returns an array of arrays, one array for
-# each ship's coordinates, which is an array 
-# of (x,y) sets.
-def input_ship_coords():
-    print("ENTER COORDINATES FOR...")
+# TODO: add an optional starting coordinate for testing
+#       purposes
+def generate_ship_coordinates(ship):
+    # randomly generate starting x,y coordinates
+    start_x, start_y = random_x_y()
 
-    coords = []
-    for ship in SHIPS:
-        print(ship[0])
-        list = []
-        for i in range(ship[1]):
-            x, y = input_coord()
-            list.append((x, y))
-        coords.append(list)
+    # using starting coordinates and the ship type,
+    # generate a vector of possible directions the ship
+    # could be placed. directions are numbered 0-7 along
+    # points of the compass (N, NE, E, SE, S, SW, W, NW)
+    # clockwise. a vector of valid directions where the
+    # ship does not go off the board is determined
+    ship_len = SHIPS[ship][1] - 1
+    dirs = [False for x in range(8)]
+    dirs[0] = (start_x - ship_len) >= 1
+    dirs[2] = (start_y + ship_len) <= BOARD_WIDTH
+    dirs[1] = dirs[0] and dirs[2]
+    dirs[4] = (start_x + ship_len) <= BOARD_HEIGHT
+    dirs[3] = dirs[2] and dirs[4]
+    dirs[6] = (start_y - ship_len) >= 1
+    dirs[5] = dirs[4] and dirs[6]
+    dirs[7] = dirs[6] and dirs[0]
+    directions = [p for p in range(len(dirs)) if dirs[p]]
+
+    # using the vector of valid directions, pick a
+    # random direction to place the ship
+    dir_idx = random.randrange(len(directions))
+    direction = directions[dir_idx]
+
+    # using the starting x,y, direction and ship
+    # type, return the coordinates of each point
+    # of the ship. VALID_MOVES is a staic array
+    # of coordinate offsets to walk from starting
+    # coordinate to the end coordinate in the
+    # chosen direction
+    ship_len = SHIPS[ship][1] - 1
+    d_x = VALID_MOVES[direction][0]
+    d_y = VALID_MOVES[direction][1]
+
+    coords = [(start_x, start_y)]
+    x_coord = start_x
+    y_coord = start_y
+    for i in range(ship_len):
+        x_coord = x_coord + d_x
+        y_coord = y_coord + d_y
+        coords.append((x_coord, y_coord))
     return coords
 
 
-# print out the title 'screen'
-print('{0:>38}'.format("SALVO"))
-print('{0:>57s}'.format("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"))
-print('\n\n')
+# create_blank_board
+#
+# helper function to create a game board
+# that is blank
+def create_blank_board():
+    return [[None for y in range(BOARD_WIDTH)]
+            for x in range(BOARD_HEIGHT)]
+
+
+def print_board(board):
+
+    # print board header (column numbers)
+    print('  ', end='')
+    for z in range(BOARD_WIDTH):
+        print(f'{z+1:3}', end='')
+    print('')
+
+    for x in range(len(board)):
+        print(f'{x+1:2}', end='')
+        for y in range(len(board[x])):
+            if(board[x][y] is None):
+                print(f"{' ':3}", end='')
+            else:
+                print(f"{board[x][y]:3}", end='')
+        print('')
+
+
+# place_ship
+#
+# place a ship on a given board. updates
+# the board's row,column value at the given
+# coordinates to indicate where a ship is
+# on the board.
+#
+# inputs: board - array of BOARD_HEIGHT by BOARD_WIDTH
+#         coords - array of sets of (x,y) coordinates of each
+#                  part of the given ship
+#         ship - integer repreesnting the type of ship (given in SHIPS)
+def place_ship(board, coords, ship):
+    for coord in coords:
+        board[coord[0]-1][coord[1]-1] = ship
+
+
+# NOTE: A little quirk that exists here and in the orginal
+#       game: Ships are allowed to cross each other!
+#       For example: 2 destroyers, length 2, one at
+#       [(1,1),(2,2)] and other at [(2,1),(1,2)]
+def generate_board():
+    board = create_blank_board()
+
+    ship_coords = []
+    for ship in range(len(SHIPS)):
+        placed = False
+        coords = []
+        while not placed:
+            coords = generate_ship_coordinates(ship)
+            clear = True
+            for coord in coords:
+                if board[coord[0]-1][coord[1]-1] is not None:
+                    clear = False
+                    break
+            if clear:
+                placed = True
+        place_ship(board, coords, ship)
+        ship_coords.append(coords)
+    return board, ship_coords
+
+
+# initialize
+#
+# function to initialize global variables used
+# during game play.
+def initialize_game():
+
+    # initialize the global player and computer
+    # boards
+    global player_board
+    player_board = create_blank_board()
+
+    # generate the ships for the computer's
+    # board
+    global computer_board
+    global computer_ship_coords
+    computer_board, computer_ship_coords = generate_board()
+
+    # print out the title 'screen'
+    print('{0:>38}'.format("SALVO"))
+    print('{0:>57s}'.format("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"))
+    print('\n\n')
+
+
+######################
+#
+# main game flow
+#
+######################
+
+# initialize the player and computer
+# boards
+initialize_game()
+
+# ask the player for ship coordinates
+print("ENTER COORDINATES FOR...")
+ship_coords = []
+for ship in SHIPS:
+    print(ship[0])
+    list = []
+    for i in range(ship[1]):
+        x, y = input_coord()
+        list.append((x, y))
+    ship_coords.append(list)
+
+# add ships to the user's board
+for ship in range(len(SHIPS)):
+    place_ship(player_board, ship_coords[ship], ship)
+
+# see if the player wants the computer's ship
+# locations printed out and if the player wants to
+# start
+input_loop = True
+player_start = "YES"
+while input_loop:
+    player_start = input("DO YOU WANT TO START? ")
+    if player_start == "WHERE ARE YOUR SHIPS?":
+        for ship in range(len(SHIPS)):
+            print(SHIPS[ship][0])
+            coords = computer_ship_coords[ship]
+            for coord in coords:
+                x = coord[0]
+                y = coord[1]
+                print('{0:2}'.format(x), '{0:2}'.format(y))
+    else:
+        input_loop = False
+
+# ask the player if they want the computer's shots
+# printed out each turn
+see_computer_shots = input("DO YOU WANT TO SEE MY SHOTS? ")
+if see_computer_shots.lower() == "yes":
+    print_computer_shots = True
 
-# ask the user for ship coordinates
-coords = input_ship_coords()

From 1726f79336bc429cb224c3b18b3916bfa4cbddb2 Mon Sep 17 00:00:00 2001
From: John Welch 
Date: Sat, 13 Mar 2021 23:46:49 +0000
Subject: [PATCH 09/19] CivilWar in C#

---
 27 Civil War/civilwar.bas                     |   4 +-
 27 Civil War/csharp/CivilWar/CivilWar.sln     |  25 ++
 27 Civil War/csharp/CivilWar/CivilWar/Army.cs | 261 ++++++++++++++++++
 .../csharp/CivilWar/CivilWar/Battle.cs        |  40 +++
 .../csharp/CivilWar/CivilWar/CivilWar.csproj  |   9 +
 .../csharp/CivilWar/CivilWar/ConsoleUtils.cs  | 105 +++++++
 .../csharp/CivilWar/CivilWar/GameOptions.cs   |  55 ++++
 .../csharp/CivilWar/CivilWar/Program.cs       | 119 ++++++++
 8 files changed, 616 insertions(+), 2 deletions(-)
 create mode 100644 27 Civil War/csharp/CivilWar/CivilWar.sln
 create mode 100644 27 Civil War/csharp/CivilWar/CivilWar/Army.cs
 create mode 100644 27 Civil War/csharp/CivilWar/CivilWar/Battle.cs
 create mode 100644 27 Civil War/csharp/CivilWar/CivilWar/CivilWar.csproj
 create mode 100644 27 Civil War/csharp/CivilWar/CivilWar/ConsoleUtils.cs
 create mode 100644 27 Civil War/csharp/CivilWar/CivilWar/GameOptions.cs
 create mode 100644 27 Civil War/csharp/CivilWar/CivilWar/Program.cs

diff --git a/27 Civil War/civilwar.bas b/27 Civil War/civilwar.bas
index 5720d767..7f192414 100644
--- a/27 Civil War/civilwar.bas	
+++ b/27 Civil War/civilwar.bas	
@@ -221,7 +221,7 @@
 2330  PRINT "CONFEDERATE:"INT(100*(C5/C1)+.5)"% OF THE ORIGINAL"
 2340  PRINT "UNION:      "INT(100*(C6/C2)+.5)"% OF THE ORIGINAL"
 2350  PRINT
-2360  REM - 1 WHO ONE
+2360  REM - 1 WHO WON
 2370  IF U <> 1 THEN 2380
 2375  IF U2=1 THEN 2460
 2380  IF U=1 THEN 2420
@@ -295,7 +295,7 @@
 3050  PRINT
 3060  PRINT "UNION INTELLIGENCE SUGGESTS THAT THE SOUTH USED "
 3070  PRINT "STRATEGIES 1, 2, 3, 4 IN THE FOLLOWING PERCENTAGES"
-3080  PRINT S(1);S2(2);S(3);S(4)
+3080  PRINT S(1);S(2);S(3);S(4)
 3090  REM---------------------------------
 3100  STOP
 3110  REM - UNION STRATEGY IS COMPUTER CHOSEN
diff --git a/27 Civil War/csharp/CivilWar/CivilWar.sln b/27 Civil War/csharp/CivilWar/CivilWar.sln
new file mode 100644
index 00000000..17da385e
--- /dev/null
+++ b/27 Civil War/csharp/CivilWar/CivilWar.sln	
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31005.135
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CivilWar", "CivilWar\CivilWar.csproj", "{09C22BBE-8480-4B8C-9A07-E2DAA24B692B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{09C22BBE-8480-4B8C-9A07-E2DAA24B692B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{09C22BBE-8480-4B8C-9A07-E2DAA24B692B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{09C22BBE-8480-4B8C-9A07-E2DAA24B692B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{09C22BBE-8480-4B8C-9A07-E2DAA24B692B}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {59BCA2DE-D5C7-40F7-BB99-B5C8D2416D8B}
+	EndGlobalSection
+EndGlobal
diff --git a/27 Civil War/csharp/CivilWar/CivilWar/Army.cs b/27 Civil War/csharp/CivilWar/CivilWar/Army.cs
new file mode 100644
index 00000000..5b8441a0
--- /dev/null
+++ b/27 Civil War/csharp/CivilWar/CivilWar/Army.cs	
@@ -0,0 +1,261 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace CivilWar
+{
+    public class Army
+    {
+        private enum Resource
+        {
+            Food,
+            Salaries,
+            Ammunition
+        }
+
+        public Army(Side side)
+        {
+            Side = side;
+        }
+
+        public Side Side { get; }
+
+        // Cumulative
+        public int Wins { get; private set; } // W, L
+        public int Losses { get; private set; } // L, W
+        public int Draws { get; private set; } // W0
+        public int BattlesFought => Wins + Draws + Losses;
+        public bool Surrendered { get; private set; } // Y, Y2 == 5
+
+        public int CumulativeHistoricCasualties { get; private set; } // P1, P2
+        public int CumulativeSimulatedCasualties { get; private set; } // T1, T2
+        public int CumulativeHistoricMen { get; private set; } // M3, M4
+
+        private int income; // R1, R2
+        private int moneySpent; // Q1, Q2
+
+        private bool IsFirstBattle => income == 0;
+
+        // This battle
+        private int historicMen; // M1, M2
+        public int HistoricCasualties { get; private set; }
+
+        public int Money { get; private set; } // D(n)
+        public int Men { get; private set; } // M5, M6
+        public int Inflation { get; private set; } // I1, I2
+        public int InflationDisplay => Side == Side.Confederate ? Inflation + 15 : Inflation; // Confederate inflation is shown with 15 added - no idea why!
+
+        private readonly Dictionary allocations = new(); // F(n), H(n), B(n) for food, salaries, ammunition
+
+        public int Strategy { get; protected set; } // Y1, Y2
+
+        public double Morale => (2.0 * allocations[Resource.Food] * allocations[Resource.Food] + allocations[Resource.Salaries] * allocations[Resource.Salaries]) / (reducedAvailableMen * reducedAvailableMen + 1); // O, O2
+
+        public int Casualties { get; protected set; } // C5, C6
+        public int Desertions { get; protected set; } // E, E2
+        public int MenLost => Casualties + Desertions;
+        public bool AllLost { get; private set; } // U, U2
+
+        private double reducedAvailableMen; // F1
+
+        protected virtual double FractionUnspent => (income - moneySpent) / (income + 1.0);
+
+        public void PrepareBattle(int men, int casualties)
+        {
+            historicMen = men;
+            HistoricCasualties = casualties;
+            Inflation = 10 + (Losses - Wins) * 2;
+            Money = 100 * (int)(men * (100 - Inflation) / 2000.0 * (1 + FractionUnspent) + 0.5);
+            Men = (int)(men * 1 + (CumulativeHistoricCasualties - CumulativeSimulatedCasualties) / (CumulativeHistoricMen + 1.0));
+            reducedAvailableMen = men * 5.0 / 6.0;
+        }
+
+        public virtual void AllocateResources()
+        {
+            Console.WriteLine($"{Side} General ---\nHow much do you wish to spend for");
+            while (true)
+            {
+                foreach (Resource resource in Enum.GetValues())
+                {
+                    if (EnterResource(resource))
+                        break;
+                }
+                if (allocations.Values.Sum() <= Money)
+                    return;
+                Console.WriteLine($"Think again! You have only ${Money}");
+            }
+        }
+
+        private bool EnterResource(Resource resource)
+        {
+            while (true)
+            {
+                Console.WriteLine($" - {resource}");
+                switch ((int.TryParse(Console.ReadLine(), out int val), val))
+                {
+                    case (false, _):
+                        Console.WriteLine("Not a valid number");
+                        break;
+                    case (_, < 0):
+                        Console.WriteLine("Negative values not allowed");
+                        break;
+                    case (_, 0) when IsFirstBattle:
+                        Console.WriteLine("No previous entries");
+                        break;
+                    case (_, 0):
+                        Console.WriteLine("Assume you want to keep same allocations");
+                        return true;
+                    case (_, > 0):
+                        allocations[resource] = val;
+                        return false;
+                }
+            }
+        }
+
+        public virtual void DisplayMorale()
+        {
+            Console.WriteLine($"{Side} morale is {Morale switch { < 5 => "Poor", < 10 => "Fair", _ => "High" }}");
+        }
+
+        public virtual bool ChooseStrategy(bool isReplay) => EnterStrategy(true, "(1-5)");
+
+        protected bool EnterStrategy(bool canSurrender, string hint)
+        {
+            Console.WriteLine($"{Side} strategy {hint}");
+            while (true)
+            {
+                switch ((int.TryParse(Console.ReadLine(), out int val), val))
+                {
+                    case (false, _):
+                        Console.WriteLine("Not a valid number");
+                        break;
+                    case (_, 5) when canSurrender:
+                        Surrendered = true;
+                        Console.WriteLine($"The {Side} general has surrendered");
+                        return true;
+                    case (_, < 1 or >= 5):
+                        Console.WriteLine($"Strategy {val} not allowed.");
+                        break;
+                    default:
+                        Strategy = val;
+                        return false;
+                }
+            }
+        }
+
+        public virtual void CalculateLosses(Army opponent)
+        {
+            AllLost = false;
+            int stratFactor = 2 * (Math.Abs(Strategy - opponent.Strategy) + 1);
+            Casualties = (int)Math.Round(HistoricCasualties * 0.4 * (1 + 1.0 / stratFactor) * (1 + 1 / Morale) * (1.28 + reducedAvailableMen / (allocations[Resource.Ammunition] + 1)));
+            Desertions = (int)Math.Round(100 / Morale);
+
+            // If losses > men present, rescale losses
+            if (MenLost > Men)
+            {
+                Casualties = 13 * Men / 20;
+                Desertions = Men - Casualties;
+                AllLost = true;
+            }
+        }
+
+        public void RecordResult(Side winner)
+        {
+            if (winner == Side)
+                Wins++;
+            else if (winner == Side.Both)
+                Draws++;
+            else
+                Losses++;
+
+            CumulativeSimulatedCasualties += MenLost;
+            CumulativeHistoricCasualties += HistoricCasualties;
+            moneySpent += allocations.Values.Sum();
+            income += historicMen * (100 - Inflation) / 20;
+            CumulativeHistoricMen += historicMen;
+
+            LearnStrategy();
+        }
+
+        protected virtual void LearnStrategy() { }
+
+        public void DisplayWarResult(Army opponent)
+        {
+            Console.WriteLine("\n\n\n\n");
+            Console.WriteLine($"The {Side} general has won {Wins} battles and lost {Losses}");
+            Side winner = (Surrendered, opponent.Surrendered, Wins < Losses) switch
+            {
+                (_, true, _) => Side,
+                (true, _, _) or (_, _, true) => opponent.Side,
+                _ => Side
+            };
+            Console.WriteLine($"The {winner} general has won the war\n");
+        }
+
+        public virtual void DisplayStrategies() { }
+    }
+
+    class ComputerArmy : Army
+    {
+        public int[] StrategyProb { get; } = { 25, 25, 25, 25 }; // S(n)
+        private readonly Random strategyRng = new();
+
+        public ComputerArmy(Side side) : base(side) { }
+
+        protected override double FractionUnspent => 0.0;
+
+        public override void AllocateResources() { }
+
+        public override void DisplayMorale() { }
+
+        public override bool ChooseStrategy(bool isReplay)
+        {
+            if (isReplay)
+                return EnterStrategy(false, $"(1-4; usually previous {Side} strategy)");
+
+            // 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.
+            int strategyChosenProb = strategyRng.Next(100); // 0-99
+            int sumProbs = 0;
+            for (int i = 0; i < 4; i++)
+            {
+                sumProbs += StrategyProb[i];
+                if (strategyChosenProb < sumProbs)
+                {
+                    Strategy = i + 1;
+                    break;
+                }
+            }
+            Console.WriteLine($"{Side} strategy is {Strategy}");
+            return false;
+        }
+
+        protected override void LearnStrategy()
+        {
+            // Learn  present strategy, start forgetting old ones
+            // - present strategy gains 3 * s, others lose s probability points, unless a strategy falls below 5 %.
+            const int s = 3;
+            int presentGain = 0;
+            for (int i = 0; i < 4; i++)
+            {
+                if (StrategyProb[i] >= 5)
+                {
+                    StrategyProb[i] -= s;
+                    presentGain += s;
+                }
+            }
+            StrategyProb[Strategy - 1] += presentGain;
+        }
+
+        public override void CalculateLosses(Army opponent)
+        {
+            Casualties = (int)(17.0 * HistoricCasualties * opponent.HistoricCasualties / (opponent.Casualties * 20));
+            Desertions = (int)(5 * opponent.Morale);
+        }
+
+        public override void DisplayStrategies()
+        {
+            ConsoleUtils.WriteWordWrap($"\nIntelligence suggests that the {Side} general used strategies 1, 2, 3, 4 in the following percentages:");
+            Console.WriteLine(string.Join(", ", StrategyProb));
+        }
+    }
+}
diff --git a/27 Civil War/csharp/CivilWar/CivilWar/Battle.cs b/27 Civil War/csharp/CivilWar/CivilWar/Battle.cs
new file mode 100644
index 00000000..8b5acb79
--- /dev/null
+++ b/27 Civil War/csharp/CivilWar/CivilWar/Battle.cs	
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+
+namespace CivilWar
+{
+    public enum Side { Confederate, Union, Both }
+    public enum Option { Battle, Replay, Quit }
+
+    public record Battle(string Name, int[] Men, int[] Casualties, Side Offensive, string Description)
+    {
+        public static readonly List Historic = new()
+        {
+            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."),
+            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."),
+            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."),
+            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."),
+            new("Antietam", new[] { 40000, 50000 }, new[] { 10000, 12000 }, Side.Both, "Sept 17, 1862.  The south failed to incorporate Maryland into the confederacy."),
+            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."),
+            new("Murfreesboro", new[] { 38000, 45000 }, new[] { 11000, 12000 }, Side.Union, "Dec 31, 1862.  The south under Gen. Bragg won a close battle."),
+            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."),
+            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."),
+            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."),
+            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."),
+            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."),
+            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."),
+            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."),
+        };
+
+        public static (Option, Battle?) SelectBattle()
+        {
+            Console.WriteLine("\n\n\nWhich battle do you wish to simulate?");
+            return int.Parse(Console.ReadLine() ?? "") switch
+            {
+                0 => (Option.Replay, null),
+                >0 and <15 and int n  => (Option.Battle, Historic[n-1]),
+                _ => (Option.Quit, null)
+            };
+        }
+    }
+}
diff --git a/27 Civil War/csharp/CivilWar/CivilWar/CivilWar.csproj b/27 Civil War/csharp/CivilWar/CivilWar/CivilWar.csproj
new file mode 100644
index 00000000..d75be916
--- /dev/null
+++ b/27 Civil War/csharp/CivilWar/CivilWar/CivilWar.csproj	
@@ -0,0 +1,9 @@
+
+
+  
+    Exe
+    net5.0
+    enable
+  
+
+
diff --git a/27 Civil War/csharp/CivilWar/CivilWar/ConsoleUtils.cs b/27 Civil War/csharp/CivilWar/CivilWar/ConsoleUtils.cs
new file mode 100644
index 00000000..5c5c9f05
--- /dev/null
+++ b/27 Civil War/csharp/CivilWar/CivilWar/ConsoleUtils.cs	
@@ -0,0 +1,105 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace CivilWar
+{
+    static class ConsoleUtils
+    {
+        public static bool InputYesOrNo()
+        {
+            while (true)
+            {
+                var answer = Console.ReadLine();
+                switch (answer?.ToLower())
+                {
+                    case "no":
+                        return false;
+                    case "yes":
+                        return true;
+                    default:
+                        Console.WriteLine("(Answer Yes or No)");
+                        break;
+                }
+            }
+        }
+
+        public static void WriteWordWrap(string text)
+        {
+            var line = new StringBuilder(Console.WindowWidth);
+            foreach (var paragraph in text.Split(Environment.NewLine))
+            {
+                line.Clear();
+                foreach (var word in paragraph.Split(' '))
+                {
+                    if (line.Length + word.Length < Console.WindowWidth)
+                    {
+                        if (line.Length > 0)
+                            line.Append(' ');
+                        line.Append(word);
+                    }
+                    else
+                    {
+                        Console.WriteLine(line.ToString());
+                        line.Clear().Append(word);
+                    }
+                }
+                Console.WriteLine(line.ToString());
+            }
+        }
+
+        public static void WriteTable(ICollection items, List> rows, bool transpose = false)
+        {
+            int cols = items.Count + 1;
+            var content = rows.Select(r => r.Format(items)).ToList();
+            if (transpose)
+            {
+                content = Enumerable.Range(0, cols).Select(col => content.Select(r => r[col]).ToArray()).ToList();
+                cols = rows.Count;
+            }
+            var colWidths = Enumerable.Range(0, cols).Select(col => content.Max(c => c[col].Length)).ToArray();
+
+            foreach (var row in content)
+            {
+                for (int col = 0; col < cols; col++)
+                {
+                    var space = new string(' ', colWidths[col] - row[col].Length);
+                    row[col] = col == 0 ? row[col] + space : space + row[col]; // left-align first col; right-align other cols
+                }
+            }
+
+            var sb = new StringBuilder();
+            var horizBars = colWidths.Select(w => new string('═', w)).ToArray();
+
+            void OneRow(string[] cells, char before, char between, char after)
+            {
+                sb.Append(before);
+                sb.AppendJoin(between, cells);
+                sb.Append(after);
+                sb.AppendLine();
+            }
+
+            OneRow(horizBars, '╔', '╦', '╗');
+            bool first = true;
+            foreach (var row in content)
+            {
+                if (first)
+                    first = false;
+                else
+                    OneRow(horizBars, '╠', '╬', '╣');
+                OneRow(row, '║', '║', '║');
+            }
+            OneRow(horizBars, '╚', '╩', '╝');
+
+            Console.WriteLine(sb.ToString());
+        }
+
+        public record TableRow(string Name, Func Data, string Before = "", string After = "")
+        {
+            private string FormatItem(T item) => $" {Before}{Data(item)}{After} ";
+
+            public string[] Format(IEnumerable items) => items.Select(FormatItem).Prepend($" {Name} ").ToArray();
+        }
+    }
+}
diff --git a/27 Civil War/csharp/CivilWar/CivilWar/GameOptions.cs b/27 Civil War/csharp/CivilWar/CivilWar/GameOptions.cs
new file mode 100644
index 00000000..9e7e4b31
--- /dev/null
+++ b/27 Civil War/csharp/CivilWar/CivilWar/GameOptions.cs	
@@ -0,0 +1,55 @@
+using System;
+
+using static CivilWar.ConsoleUtils;
+
+namespace CivilWar
+{
+    public record GameOptions(bool TwoPlayers, bool ShowDescriptions)
+    {
+        public static GameOptions Input()
+        {
+            Console.WriteLine(
+@"                          Civil War
+               Creative Computing, Morristown, New Jersey
+
+
+Do you want instructions?");
+
+            const string instructions = @"This is a civil war simulation.
+To play type a response when the computer asks.
+Remember 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!!
+
+The object of the game is to win as many battles as possible.
+
+Your choices for defensive strategy are:
+        (1) artillery attack
+        (2) fortification against frontal attack
+        (3) fortification against flanking maneuvers
+        (4) falling back
+Your choices for offensive strategy are:
+        (1) artillery attack
+        (2) frontal attack
+        (3) flanking maneuvers
+        (4) encirclement
+You may surrender by typing a '5' for your strategy.";
+
+            if (InputYesOrNo())
+                WriteWordWrap(instructions);
+
+            Console.WriteLine("\n\nAre there two generals present?");
+            bool twoPlayers = InputYesOrNo();
+            if (!twoPlayers)
+                Console.WriteLine("\nYou are the confederacy.  Good luck!\n");
+
+            WriteWordWrap(
+            @"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.
+
+Note: a negative Food$ entry causes the program to use the entries from the previous battle
+
+After requesting a battle, do you wish battle descriptions (answer yes or no)");
+            bool showDescriptions = InputYesOrNo();
+
+            return new GameOptions(twoPlayers, showDescriptions);
+        }
+    }
+}
diff --git a/27 Civil War/csharp/CivilWar/CivilWar/Program.cs b/27 Civil War/csharp/CivilWar/CivilWar/Program.cs
new file mode 100644
index 00000000..c79d1a3a
--- /dev/null
+++ b/27 Civil War/csharp/CivilWar/CivilWar/Program.cs	
@@ -0,0 +1,119 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using CivilWar;
+
+var options = GameOptions.Input();
+var armies = new List { new Army(Side.Confederate), options.TwoPlayers ? new Army(Side.Union) : new ComputerArmy(Side.Union) };
+
+Battle? battle = null;
+while (OneBattle(ref battle)) { }
+DisplayResult();
+
+bool OneBattle(ref Battle? previous)
+{
+    var (option, selected) = Battle.SelectBattle();
+    var (battle, isReplay, quit) = option switch
+    {
+        Option.Battle => (selected!, false, false),
+        Option.Replay when previous != null => (previous, true, false), // can't replay if no previous battle
+        _ => (null!, false, true),
+    };
+    if (quit)
+        return false;
+
+    if (!isReplay)
+    {
+        Console.WriteLine($"This is the battle of {battle.Name}.");
+        if (options.ShowDescriptions)
+            ConsoleUtils.WriteWordWrap(battle.Description);
+        armies.ForEach(a => a.PrepareBattle(battle.Men[(int)a.Side], battle.Casualties[(int)a.Side]));
+    }
+
+    ConsoleUtils.WriteTable(armies, new()
+    {
+        new("", a => a.Side),
+        new("Men", a => a.Men),
+        new("Money", a => a.Money, Before: "$"),
+        new("Inflation", a => a.InflationDisplay, After: "%")
+    });
+
+    armies.ForEach(a => a.AllocateResources());
+    armies.ForEach(a => a.DisplayMorale());
+
+    string offensive = battle.Offensive switch
+    {
+        Side.Confederate => "You are on the offensive",
+        Side.Union => "You are on the defensive",
+        _ => "Both sides are on the offensive"
+    };
+    Console.WriteLine($"Confederate general---{offensive}");
+
+    if (armies.Any(a => a.ChooseStrategy(isReplay)))
+    {
+        return false; // someone surrendered
+    }
+    armies[0].CalculateLosses(armies[1]);
+    armies[1].CalculateLosses(armies[0]);
+
+    ConsoleUtils.WriteTable(armies, new()
+    {
+        new("", a => a.Side),
+        new("Casualties", a => a.Casualties),
+        new("Desertions", a => a.Desertions),
+    });
+    if (options.TwoPlayers)
+    {
+        var oneDataCol = new[] { 1 };
+        Console.WriteLine($"Compared to the actual casualties at {battle.Name}");
+        ConsoleUtils.WriteTable(oneDataCol, armies.Select(a => new ConsoleUtils.TableRow(
+            a.Side.ToString(),
+            _ => $"{(double)a.Casualties / battle.Casualties[(int)a.Side]}", After: "% of the original")
+        ).ToList());
+    }
+
+    Side winner;
+    switch (armies[0].AllLost, armies[1].AllLost, armies[0].MenLost - armies[1].MenLost)
+    {
+        case (true, true, _) or (false, false, 0):
+            Console.WriteLine("Battle outcome unresolved");
+            winner = Side.Both; // Draw
+            break;
+        case (false, true, _) or (false, false, < 0):
+            Console.WriteLine($"The Confederacy wins {battle.Name}");
+            winner = Side.Confederate;
+            break;
+        case (true, false, _) or (false, false, > 0):
+            Console.WriteLine($"The Union wins {battle.Name}");
+            winner = Side.Union;
+            break;
+    }
+    if (!isReplay)
+    {
+        armies.ForEach(a => a.RecordResult(winner));
+    }
+    Console.WriteLine("---------------");
+    previous = battle;
+    return true;
+}
+
+void DisplayResult()
+{
+    armies[0].DisplayWarResult(armies[1]);
+
+    int battles = armies[0].BattlesFought;
+    if (battles > 0)
+    {
+        Console.WriteLine($"For the {battles} battles fought (excluding reruns)");
+
+        ConsoleUtils.WriteTable(armies, new()
+        {
+            new("", a => a.Side),
+            new("Historical Losses", a => a.CumulativeHistoricCasualties),
+            new("Simulated Losses", a => a.CumulativeSimulatedCasualties),
+            new("  % of original", a => ((double)a.CumulativeSimulatedCasualties / a.CumulativeHistoricCasualties).ToString("p2"))
+        }, transpose: true);
+
+        armies[1].DisplayStrategies();
+    }
+}
\ No newline at end of file

From 9e07a5a2e9429c43fbc0a4cc79430ae678e32b04 Mon Sep 17 00:00:00 2001
From: nanochess 
Date: Sat, 13 Mar 2021 20:50:17 -0600
Subject: [PATCH 10/19] Ported QUEEN to Javascript

---
 72 Queen/javascript/queen.html |   9 ++
 72 Queen/javascript/queen.js   | 237 +++++++++++++++++++++++++++++++++
 2 files changed, 246 insertions(+)
 create mode 100644 72 Queen/javascript/queen.html
 create mode 100644 72 Queen/javascript/queen.js

diff --git a/72 Queen/javascript/queen.html b/72 Queen/javascript/queen.html
new file mode 100644
index 00000000..ce191813
--- /dev/null
+++ b/72 Queen/javascript/queen.html	
@@ -0,0 +1,9 @@
+
+
+QUEEN
+
+
+

+
+
+
diff --git a/72 Queen/javascript/queen.js b/72 Queen/javascript/queen.js
new file mode 100644
index 00000000..0adee46c
--- /dev/null
+++ b/72 Queen/javascript/queen.js	
@@ -0,0 +1,237 @@
+// QUEEN
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+var sa = [,81,  71,  61,  51,  41,  31,  21,  11,
+           92,  82,  72,  62,  52,  42,  32,  22,
+          103,  93,  83,  73,  63,  53,  43,  33,
+          114, 104,  94,  84,  74,  64,  54,  44,
+          125, 115, 105,  95,  85,  75,  65,  55,
+          136, 126, 116, 106,  96,  86,  76,  66,
+          147, 137, 127, 117, 107,  97,  87,  77,
+          158, 148, 138, 128, 118, 108,  98,  88];
+
+var m;
+var m1;
+var u;
+var t;
+var u1;
+var t1;
+
+function show_instructions()
+{
+    print("WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS\n");
+    print("MOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,\n");
+    print("DOWN, OR DIAGONALLY DOWN AND TO THE LEFT.\n");
+    print("\n");
+    print("THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER\n");
+    print("LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE\n");
+    print("COMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS.\n");
+    print("\n");
+    print("YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES\n");
+    print("ON THE TOP ROW OR RIGHT HAND COLUMN.\n");
+    print("THAT WILL BE YOUR FIRST MOVE.\n");
+    print("WE ALTERNATE MOVES.\n");
+    print("YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.\n");
+    print("BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.\n");
+    print("\n");
+    print("\n");
+}
+
+function show_map()
+{
+    print("\n");
+    for (var a = 0; a <= 7; a++) {
+        for (var b = 1; b <= 8; b++) {
+            i = 8 * a + b;
+            print(" " + sa[i] + " ");
+        }
+        print("\n");
+        print("\n");
+        print("\n");
+    }
+    print("\n");
+}
+
+function test_move()
+{
+    m = 10 * t + u;
+    if (m == 158 || m == 127 || m == 126 || m == 75 || m == 73)
+        return true;
+    return false;
+}
+
+function random_move()
+{
+    // Random move
+    z = Math.random();
+    if (z > 0.6) {
+        u = u1 + 1;
+        t = t1 + 1;
+    } else if (z > 0.3) {
+        u = u1 + 1;
+        t = t1 + 2;
+    } else {
+        u = u1;
+        t = t1 + 1;
+    }
+    m = 10 * t + u;
+}
+
+function computer_move()
+{
+    if (m1 == 41 || m1 == 44 || m1 == 73 || m1 == 75 || m1 == 126 || m1 == 127) {
+        random_move();
+        return;
+    }
+    for (k = 7; k >= 1; k--) {
+        u = u1;
+        t = t1 + k;
+        if (test_move())
+            return;
+        u += k;
+        if (test_move())
+            return;
+        t += k;
+        if (test_move())
+            return;
+    }
+    random_move();
+}
+
+// Main program
+async function main()
+{
+    print(tab(33) + "QUEEN\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    
+    while (1) {
+        print("DO YOU WANT INSTRUCTIONS");
+        str = await input();
+        if (str == "YES" || str == "NO")
+            break;
+        print("PLEASE ANSWER 'YES' OR 'NO'.\n");
+    }
+    if (str == "YES")
+        show_instructions();
+    while (1) {
+        show_map();
+        while (1) {
+            print("WHERE WOULD YOU LIKE TO START");
+            m1 = parseInt(await input());
+            if (m1 == 0) {
+                print("\n");
+                print("IT LOOKS LIKE I HAVE WON BY FORFEIT.\n");
+                print("\n");
+                break;
+            }
+            t1 = Math.floor(m1 / 10);
+            u1 = m1 - 10 * t1;
+            if (u1 == 1 || u1 == t1)
+                break;
+            print("PLEASE READ THE DIRECTIONS AGAIN.\n");
+            print("YOU HAVE BEGUN ILLEGALLY.\n");
+            print("\n");
+        }
+        while (m1) {
+            if (m1 == 158) {
+                print("\n");
+                print("C O N G R A T U L A T I O N S . . .\n");
+                print("\n");
+                print("YOU HAVE WON--VERY WELL PLAYED.\n");
+                print("IT LOOKS LIKE I HAVE MET MY MATCH.\n");
+                print("THANKS FOR PLAYING--I CAN'T WIN ALL THE TIME.\n");
+                print("\n");
+                break;
+            }
+            computer_move();
+            print("COMPUTER MOVES TO SQUARE " + m + "\n");
+            if (m == 158) {
+                print("\n");
+                print("NICE TRY, BUT IT LOOKS LIKE I HAVE WON.\n");
+                print("THANKS FOR PLAYING.\n");
+                print("\n");
+                break;
+            }
+            print("WHAT IS YOUR MOVE");
+            while (1) {
+                m1 = parseInt(await input());
+                if (m1 == 0)
+                    break;
+                t1 = Math.floor(m1 / 10);
+                u1 = m1 - 10 * t1;
+                p = u1 - u;
+                l = t1 - t;
+                if (m1 <= m || p == 0 && l <= 0 || p != 0 && l != p && l != 2 * p) {
+                    print("\n");
+                    print("Y O U   C H E A T . . .  TRY AGAIN");
+                    continue;
+                }
+                break;
+            }
+            if (m1 == 0) {
+                print("\n");
+                print("IT LOOKS LIKE I HAVE WON BY FORFEIT.\n");
+                print("\n");
+                break;
+            }
+        }
+        while (1) {
+            print("ANYONE ELSE CARE TO TRY");
+            str = await input();
+            print("\n");
+            if (str == "YES" || str == "NO")
+                break;
+            print("PLEASE ANSWER 'YES' OR 'NO'.\n");
+        }
+        if (str != "YES")
+            break;
+    }
+    print("\n");
+    print("OK --- THANKS AGAIN.\n");
+}
+
+main();

From 80f557a7b78b9a8134c7b478dc940c2a9662c0b2 Mon Sep 17 00:00:00 2001
From: nanochess 
Date: Sat, 13 Mar 2021 21:09:33 -0600
Subject: [PATCH 11/19] Ported TICTACTOE1 to Javascript

---
 89 Tic-Tac-Toe/javascript/tictactoe1.html |   9 ++
 89 Tic-Tac-Toe/javascript/tictactoe1.js   | 147 ++++++++++++++++++++++
 2 files changed, 156 insertions(+)
 create mode 100644 89 Tic-Tac-Toe/javascript/tictactoe1.html
 create mode 100644 89 Tic-Tac-Toe/javascript/tictactoe1.js

diff --git a/89 Tic-Tac-Toe/javascript/tictactoe1.html b/89 Tic-Tac-Toe/javascript/tictactoe1.html
new file mode 100644
index 00000000..7aafc617
--- /dev/null
+++ b/89 Tic-Tac-Toe/javascript/tictactoe1.html	
@@ -0,0 +1,9 @@
+
+
+TIC TAC TOE 1
+
+
+

+
+
+
diff --git a/89 Tic-Tac-Toe/javascript/tictactoe1.js b/89 Tic-Tac-Toe/javascript/tictactoe1.js
new file mode 100644
index 00000000..fce4b7da
--- /dev/null
+++ b/89 Tic-Tac-Toe/javascript/tictactoe1.js	
@@ -0,0 +1,147 @@
+// TIC TAC TOE 1
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+function mf(x)
+{
+    return x - 8 * Math.floor((x - 1) / 8);
+}
+
+function computer_moves()
+{
+    print("COMPUTER MOVES " + m + "\n");
+}
+
+var m;
+
+// Main control section
+async function main()
+{
+    print(tab(30) + "TIC TAC TOE\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    //
+    // This program plays Tic Tac Toe
+    // The machine goes first
+    print("THE GAME BOARD IS NUMBERED:\n");
+    print("\n");
+    print("1  2  3\n");
+    print("8  9  4\n");
+    print("7  6  5\n");
+    print("\n");
+    //
+    // Main program
+    while (1) {
+        print("\n");
+        print("\n");
+        a = 9;
+        m = a;
+        
+        computer_moves();
+        print("YOUR MOVE");
+        m = parseInt(await input());
+        
+        p = m;
+        b = mf(p + 1);
+        m = b;
+        
+        computer_moves();
+        print("YOUR MOVE");
+        m = parseInt(await input());
+        
+        q = m;
+        if (q != mf(b + 4)) {
+            c = mf(b + 4);
+            m = c;
+            computer_moves();
+            print("AND WINS ********\n");
+            continue;
+        }
+        
+        c = mf(b + 2);
+        m = c;
+
+        computer_moves();
+        print("YOUR MOVE");
+        m = parseInt(await input());
+
+        r = m;
+        if (r != mf(c + 4)) {
+            d = mf(c + 4);
+            m = d;
+            computer_moves();
+            print("AND WINS ********\n");
+            continue;
+        }
+        
+        if (p % 2 == 0) {
+            d = mf(c + 7);
+            m = d;
+            computer_moves();
+            print("AND WINS ********\n");
+            continue;
+        }
+        
+        d = mf(c + 3);
+        m = d;
+        
+        computer_moves();
+        print("YOUR MOVE");
+        m = parseInt(await input());
+        
+        s = m;
+        if (s != mf(d + 4)) {
+            e = mf(d + 4);
+            m = e;
+            computer_moves();
+        }
+        e = mf(d + 6);
+        m = e;
+        computer_moves();
+        print("THE GAME IS A DRAW.\n");
+    }
+}
+
+main();

From 7e1576809a0f0049660ed91053847a0bf25baf5c Mon Sep 17 00:00:00 2001
From: nanochess 
Date: Sat, 13 Mar 2021 21:55:16 -0600
Subject: [PATCH 12/19] Ported TICTACTOE2 to Javascript

---
 89 Tic-Tac-Toe/javascript/tictactoe2.html |   9 +
 89 Tic-Tac-Toe/javascript/tictactoe2.js   | 288 ++++++++++++++++++++++
 2 files changed, 297 insertions(+)
 create mode 100644 89 Tic-Tac-Toe/javascript/tictactoe2.html
 create mode 100644 89 Tic-Tac-Toe/javascript/tictactoe2.js

diff --git a/89 Tic-Tac-Toe/javascript/tictactoe2.html b/89 Tic-Tac-Toe/javascript/tictactoe2.html
new file mode 100644
index 00000000..418bf65c
--- /dev/null
+++ b/89 Tic-Tac-Toe/javascript/tictactoe2.html	
@@ -0,0 +1,9 @@
+
+
+TIC TAC TOE 2
+
+
+

+
+
+
diff --git a/89 Tic-Tac-Toe/javascript/tictactoe2.js b/89 Tic-Tac-Toe/javascript/tictactoe2.js
new file mode 100644
index 00000000..beab1df6
--- /dev/null
+++ b/89 Tic-Tac-Toe/javascript/tictactoe2.js	
@@ -0,0 +1,288 @@
+// TIC TAC TOE 2
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+var s = [];
+
+function who_win(piece)
+{
+    if (piece == -1) {
+        print("I WIN, TURKEY!!!\n");
+    } else if (piece == 1) {
+        print("YOU BEAT ME!! GOOD GAME.\n");
+    }
+}
+
+function show_board()
+{
+    print("\n");
+    for (i = 1; i <= 9; i++) {
+        print(" ");
+        if (s[i] == -1) {
+            print(qs + " ");
+        } else if (s[i] == 0) {
+            print("  ");
+        } else {
+            print(ps + " ");
+        }
+        if (i == 3 || i == 6) {
+            print("\n");
+            print("---+---+---\n");
+        } else if (i != 9) {
+            print("!");
+        }
+    }
+    print("\n");
+    print("\n");
+    print("\n");
+    for (i = 1; i <= 7; i += 3) {
+        if (s[i] && s[i] == s[i + 1] && s[i] == s[i + 2]) {
+            who_win(s[i]);
+            return true;
+        }
+    }
+    for (i = 1; i <= 3; i++) {
+        if (s[i] && s[i] == s[i + 3] && s[i] == s[i + 6]) {
+            who_win(s[i]);
+            return true;
+        }
+    }
+    if (s[1] && s[1] == s[5] && s[1] == s[9]) {
+        who_win(s[1]);
+        return true;
+    }
+    if (s[3] && s[3] == s[5] && s[3] == s[7]) {
+        who_win(s[3]);
+        return true;
+    }
+    for (i = 1; i <= 9; i++) {
+        if (s[i] == 0)
+            break;
+    }
+    if (i > 9) {
+        print("IT'S A DRAW. THANK YOU.\n");
+        return true;
+    }
+    return false;
+}
+
+// Main control section
+async function main()
+{
+    print(tab(30) + "TIC-TAC-TOE\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    for (i = 1; i <= 9; i++)
+        s[i] = 0;
+    print("THE BOARD IS NUMBERED:\n");
+    print(" 1  2  3\n");
+    print(" 4  5  6\n");
+    print(" 7  8  9\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("DO YOU WANT 'X' OR 'O'");
+    str = await input();
+    if (str == "X") {
+        ps = "X";
+        qs = "O";
+        first_time = true;
+    } else {
+        ps = "O";
+        qs = "X";
+        first_time = false;
+    }
+    while (1) {
+        if (!first_time) {
+            g = -1;
+            h = 1;
+            if (s[5] == 0) {
+                s[5] = -1;
+            } else if (s[5] == 1 && s[1] == 0) {
+                s[1] = -1;
+            } else if (s[5] != 1 && s[2] == 1 && s[1] == 0 || s[5] != 1 && s[4] == 1 && s[1] == 0) {
+                s[1] = -1;
+            } else if (s[5] != 1 && s[6] == 1 && s[9] == 0 || s[5] != 1 && s[8] == 1 && s[9] == 0) {
+                s[9] = -1;
+            } else {
+                while (1) {
+                    played = false;
+                    if (g == 1) {
+                        j = 3 * Math.floor((m - 1) / 3) + 1;
+                        if (3 * Math.floor((m - 1) / 3) + 1 == m)
+                            k = 1;
+                        if (3 * Math.floor((m - 1) / 3) + 2 == m)
+                            k = 2;
+                        if (3 * Math.floor((m - 1) / 3) + 3 == m)
+                            k = 3;
+                    } else {
+                        j = 1;
+                        k = 1;
+                    }
+                    while (1) {
+                        if (s[j] == g) {
+                            if (s[j + 2] == g) {
+                                if (s[j + 1] == 0) {
+                                    s[j + 1] = -1;
+                                    played = true;
+                                    break;
+                                }
+                            } else {
+                                if (s[j + 2] == 0 && s[j + 1] == g) {
+                                    s[j + 2] = -1;
+                                    played = true;
+                                    break;
+                                }
+                            }
+                        } else {
+                            if (s[j] != h && s[j + 2] == g && s[j + 1] == g) {
+                                s[j] = -1;
+                                played = true;
+                                break;
+                            }
+                        }
+                        if (s[k] == g) {
+                            if (s[k + 6] == g) {
+                                if (s[k + 3] == 0) {
+                                    s[k + 3] = -1;
+                                    played = true;
+                                    break;
+                                }
+                            } else {
+                                if (s[k + 6] == 0 && s[k + 3] == g) {
+                                    s[k + 6] = -1;
+                                    played = true;
+                                    break;
+                                }
+                            }
+                        } else {
+                            if (s[k] != h && s[k + 6] == g && s[k + 3] == g) {
+                                s[k] = -1;
+                                played = true;
+                                break;
+                            }
+                        }
+                        if (g == 1)
+                            break;
+                        if (j == 7 && k == 3)
+                            break;
+                        k++;
+                        if (k > 3) {
+                            k = 1;
+                            j += 3;
+                            if (j > 7)
+                                break;
+                        }
+                    }
+                    if (!played) {
+                        if (s[5] == g) {
+                            if (s[3] == g && s[7] == 0) {
+                                s[7] = -1;
+                                played = true;
+                            } else if (s[9] == g && s[1] == 0) {
+                                s[1] = -1;
+                                played = true;
+                            } else if (s[7] == g && s[3] == 0) {
+                                s[3] = -1;
+                                played = true;
+                            } else if (s[9] == 0 && s[1] == g) {
+                                s[9] = -1;
+                                played = true;
+                            }
+                        }
+                        if (!played) {
+                            if (g == -1) {
+                                g = 1;
+                                h = -1;
+                            }
+                        }
+                    }
+                    if (played)
+                        break;
+                }
+                if (!played) {
+                    if (s[9] == 1 && s[3] == 0 && s[1] != 1) {
+                        s[3] = -1;
+                    } else {
+                        for (i = 2; i <= 9; i++) {
+                            if (s[i] == 0) {
+                                s[i] = -1;
+                                break;
+                            }
+                        }
+                        if (i > 9) {
+                            s[1] = -1;
+                        }
+                    }
+                }
+            }
+            print("\n");
+            print("THE COMPUTER MOVES TO...");
+            if (show_board())
+                break;
+        }
+        first_time = false;
+        while (1) {
+            print("\n");
+            print("WHERE DO YOU MOVE");
+            m = parseInt(await input());
+            if (m == 0) {
+                print("THANKS FOR THE GAME.\n");
+                break;
+            }
+            if (m >= 1 && m <= 9 && s[m] == 0)
+                break;
+            print("THAT SQUARE IS OCCUPIED.\n");
+            print("\n");
+            print("\n");
+        }
+        g = 1;
+        s[m] = 1;
+        if (show_board())
+            break;
+    }
+}
+
+main();

From 486e336224efd8ff8fd49a54ffc0562591b83422 Mon Sep 17 00:00:00 2001
From: Todd Kaiser 
Date: Sun, 14 Mar 2021 12:11:03 -0600
Subject: [PATCH 13/19] Refactored main flow, added function and loop for
 executing turns.

---
 77 Salvo/python/salvo.py | 154 +++++++++++++++++++++++++++++----------
 1 file changed, 117 insertions(+), 37 deletions(-)

diff --git a/77 Salvo/python/salvo.py b/77 Salvo/python/salvo.py
index 2061943d..73ff55ec 100644
--- a/77 Salvo/python/salvo.py	
+++ b/77 Salvo/python/salvo.py	
@@ -50,6 +50,16 @@ current_turn = 0
 # printed out during computer's turn
 print_computer_shots = False
 
+# keep track of the number
+# of available computer shots
+# inital shots are 7
+num_computer_shots = 7
+
+# keep track of the number
+# of available player shots
+# initial shots are 7
+num_player_shots = 7
+
 ####################
 #
 # game functions
@@ -162,6 +172,10 @@ def create_blank_board():
             for x in range(BOARD_HEIGHT)]
 
 
+# print_board
+#
+# print out the game board for testing
+# purposes
 def print_board(board):
 
     # print board header (column numbers)
@@ -221,6 +235,15 @@ def generate_board():
     return board, ship_coords
 
 
+# execute_shot
+#
+# given a board and x, y coordinates,
+# execute a shot. returns True if the shot
+# is valid, False if not
+def execute_shot(board, x, y):
+    print("execute shot:", x, y)
+
+
 # initialize
 #
 # function to initialize global variables used
@@ -243,6 +266,93 @@ def initialize_game():
     print('{0:>57s}'.format("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"))
     print('\n\n')
 
+    # ask the player for ship coordinates
+    print("ENTER COORDINATES FOR...")
+    ship_coords = []
+    for ship in SHIPS:
+        print(ship[0])
+        list = []
+        for i in range(ship[1]):
+            x, y = input_coord()
+            list.append((x, y))
+        ship_coords.append(list)
+
+    # add ships to the user's board
+    for ship in range(len(SHIPS)):
+        place_ship(player_board, ship_coords[ship], ship)
+
+    # see if the player wants the computer's ship
+    # locations printed out and if the player wants to
+    # start
+    input_loop = True
+    player_start = "YES"
+    while input_loop:
+        player_start = input("DO YOU WANT TO START? ")
+        if player_start == "WHERE ARE YOUR SHIPS?":
+            for ship in range(len(SHIPS)):
+                print(SHIPS[ship][0])
+                coords = computer_ship_coords[ship]
+                for coord in coords:
+                    x = coord[0]
+                    y = coord[1]
+                    print('{0:2}'.format(x), '{0:2}'.format(y))
+        else:
+            input_loop = False
+
+    # ask the player if they want the computer's shots
+    # printed out each turn
+    global print_computer_shots
+    see_computer_shots = input("DO YOU WANT TO SEE MY SHOTS? ")
+    if see_computer_shots.lower() == "yes":
+        print_computer_shots = True
+
+    global first_turn
+    global second_turn
+    if player_start.lower() != "yes":
+        first_turn = computer_turn
+        second_turn = player_turn
+
+
+####################################
+#
+# Turn Control
+#
+# define functions for executing the turns for
+# the player and the computer. By defining this as
+# functions, we can easily start the game with
+# either computer or player and alternate back and
+# forth, replicating the gotos in the original game
+def player_turn():
+    print("YOU HAVE", num_computer_shots, "SHOTS.")
+
+    shots = []
+    for shot in range(num_player_shots):
+        valid_shot = False
+        while not valid_shot:
+            x, y = input_coord()
+            valid_shot = execute_shot(player_board, x, y)
+            shots.append((x, y))
+
+    print(shots)
+
+
+# initialize the first_turn function to the
+# player's turn
+first_turn = player_turn
+
+
+def computer_turn():
+    print("I HAVE", num_computer_shots, "SHOTS.")
+
+
+# initialize the second_turn to the computer's
+# turn
+second_turn = computer_turn
+
+#
+# Turn Control
+#
+######################################
 
 ######################
 #
@@ -254,42 +364,12 @@ def initialize_game():
 # boards
 initialize_game()
 
-# ask the player for ship coordinates
-print("ENTER COORDINATES FOR...")
-ship_coords = []
-for ship in SHIPS:
-    print(ship[0])
-    list = []
-    for i in range(ship[1]):
-        x, y = input_coord()
-        list.append((x, y))
-    ship_coords.append(list)
+# execute turns until someone wins or we run
+# out of squares to shoot
 
-# add ships to the user's board
-for ship in range(len(SHIPS)):
-    place_ship(player_board, ship_coords[ship], ship)
-
-# see if the player wants the computer's ship
-# locations printed out and if the player wants to
-# start
-input_loop = True
-player_start = "YES"
-while input_loop:
-    player_start = input("DO YOU WANT TO START? ")
-    if player_start == "WHERE ARE YOUR SHIPS?":
-        for ship in range(len(SHIPS)):
-            print(SHIPS[ship][0])
-            coords = computer_ship_coords[ship]
-            for coord in coords:
-                x = coord[0]
-                y = coord[1]
-                print('{0:2}'.format(x), '{0:2}'.format(y))
-    else:
-        input_loop = False
-
-# ask the player if they want the computer's shots
-# printed out each turn
-see_computer_shots = input("DO YOU WANT TO SEE MY SHOTS? ")
-if see_computer_shots.lower() == "yes":
-    print_computer_shots = True
+current_turn = current_turn + 1
+print("\n")
+print("TURN", current_turn)
 
+first_turn()
+second_turn()

From 4e7374d89c4601fc510e15d6826dba969bc44fba Mon Sep 17 00:00:00 2001
From: Darren Cardenas <53984972+darrencardenas@users.noreply.github.com>
Date: Sun, 14 Mar 2021 16:35:20 -0400
Subject: [PATCH 14/19] Add Java port of Tower.

---
 90 Tower/java/Tower.java | 527 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 527 insertions(+)
 create mode 100644 90 Tower/java/Tower.java

diff --git a/90 Tower/java/Tower.java b/90 Tower/java/Tower.java
new file mode 100644
index 00000000..ed4c454f
--- /dev/null
+++ b/90 Tower/java/Tower.java	
@@ -0,0 +1,527 @@
+import java.lang.Math;
+import java.util.Scanner;
+
+/**
+ * Game of Tower
+ * 

+ * Based on the BASIC game of Tower here + * https://github.com/coding-horror/basic-computer-games/blob/main/90%20Tower/tower.bas + *

+ * Note: The idea was to create a version of the 1970's BASIC game in Java, without introducing + * new features - no additional text, error checking, etc has been added. + * + * Converted from BASIC to Java by Darren Cardenas. + */ + +public class Tower { + + private final static int MAX_DISK_SIZE = 15; + + private final static int MAX_NUM_COLUMNS = 3; + + private final static int MAX_NUM_MOVES = 128; + + private final static int MAX_NUM_ROWS = 7; + + private final Scanner scan; // For user input + + // Represent all possible disk positions + private int[][] positions; + + private enum Step { + INITIALIZE, SELECT_TOTAL_DISKS, SELECT_DISK_MOVE, SELECT_NEEDLE, CHECK_SOLUTION + } + + + public Tower() { + + scan = new Scanner(System.in); + + // Row 0 and column 0 are not used + positions = new int[MAX_NUM_ROWS + 1][MAX_NUM_COLUMNS + 1]; + + } // End of constructor Tower + + + public class Position { + + public int row; + public int column; + + public Position(int row, int column) { + this.row = row; + this.column = column; + + } // End of constructor Position + + } // End of inner class Position + + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + + private void showIntro() { + + System.out.println(" ".repeat(32) + "TOWERS"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + } // End of method showIntro + + + private void startGame() { + + boolean diskMoved = false; + + int column = 0; + int disk = 0; + int needle = 0; + int numDisks = 0; + int numErrors = 0; + int numMoves = 0; + int row = 0; + + Step nextStep = Step.INITIALIZE; + + String userResponse = ""; + + Position diskPosition = new Position(0, 0); + + // Begin outer while loop + while (true) { + + switch (nextStep) { + + + case INITIALIZE: + + // Initialize error count + numErrors = 0; + + // Initialize positions + for (row = 1; row <= MAX_NUM_ROWS; row++) { + for (column = 1; column <= MAX_NUM_COLUMNS; column++) { + positions[row][column] = 0; + } + } + + // Display description + System.out.println(""); + System.out.println("TOWERS OF HANOI PUZZLE.\n"); + System.out.println("YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT"); + System.out.println("TOWER, ONE AT A TIME, NEVER PUTTING A LARGER DISK ON A"); + System.out.println("SMALLER DISK.\n"); + + nextStep = Step.SELECT_TOTAL_DISKS; + break; + + + case SELECT_TOTAL_DISKS: + + while (numErrors <= 2) { + + // Get user input + System.out.print("HOW MANY DISKS DO YOU WANT TO MOVE (" + MAX_NUM_ROWS + " IS MAX)? "); + numDisks = scan.nextInt(); + System.out.println(""); + + numMoves = 0; + + // Ensure the number of disks is valid + if ((numDisks < 1) || (numDisks > MAX_NUM_ROWS)) { + + numErrors++; + + // Handle user input errors + if (numErrors < 3) { + System.out.println("SORRY, BUT I CAN'T DO THAT JOB FOR YOU."); + } + + } + else { + break; // Leave the while loop + } + } + + // Too many user input errors + if (numErrors > 2) { + System.out.println("ALL RIGHT, WISE GUY, IF YOU CAN'T PLAY THE GAME RIGHT, I'LL"); + System.out.println("JUST TAKE MY PUZZLE AND GO HOME. SO LONG."); + return; + } + + // Display detailed instructions + System.out.println("IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE."); + System.out.println("3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,"); + System.out.println("7 THE NEXT, AND SO ON, UP TO 15. IF YOU DO THE PUZZLE WITH"); + System.out.println("2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15. WITH 3 DISKS"); + System.out.println("THE CODE NAMES WOULD BE 11, 13 AND 15, ETC. THE NEEDLES"); + System.out.println("ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3. WE WILL"); + System.out.println("START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM"); + System.out.println("TO NEEDLE 3.\n"); + System.out.println("GOOD LUCK!\n"); + + disk = MAX_DISK_SIZE; + + // Set disk starting positions + for (row = MAX_NUM_ROWS; row > (MAX_NUM_ROWS - numDisks); row--) { + positions[row][1] = disk; + disk = disk - 2; + } + + printPositions(); + + nextStep = Step.SELECT_DISK_MOVE; + break; + + + case SELECT_DISK_MOVE: + + System.out.print("WHICH DISK WOULD YOU LIKE TO MOVE? "); + + numErrors = 0; + + while (numErrors < 2) { + disk = scan.nextInt(); + + // Validate disk numbers + if ((disk - 3) * (disk - 5) * (disk - 7) * (disk - 9) * (disk - 11) * (disk - 13) * (disk - 15) == 0) { + + // Check if disk exists + diskPosition = getDiskPosition(disk); + + // Disk found + if ((diskPosition.row > 0) && (diskPosition.column > 0)) + { + // Disk can be moved + if (isDiskMovable(disk, diskPosition.row, diskPosition.column) == true) { + + break; + + } + // Disk cannot be moved + else { + + System.out.println("THAT DISK IS BELOW ANOTHER ONE. MAKE ANOTHER CHOICE."); + System.out.print("WHICH DISK WOULD YOU LIKE TO MOVE? "); + + } + } + // Mimic legacy handling of valid disk number but disk not found + else { + + System.out.println("THAT DISK IS BELOW ANOTHER ONE. MAKE ANOTHER CHOICE."); + System.out.print("WHICH DISK WOULD YOU LIKE TO MOVE? "); + numErrors = 0; + continue; + + } + + } + // Invalid disk number + else { + + System.out.println("ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15."); + numErrors++; + + if (numErrors > 1) { + break; + } + + System.out.print("? "); + + } + } + + if (numErrors > 1) { + + System.out.println("STOP WASTING MY TIME. GO BOTHER SOMEONE ELSE."); + return; + } + + nextStep = Step.SELECT_NEEDLE; + break; + + + case SELECT_NEEDLE: + + numErrors = 0; + + while (true) { + + System.out.print("PLACE DISK ON WHICH NEEDLE? "); + needle = scan.nextInt(); + + // Handle valid needle numbers + if ((needle - 1) * (needle - 2) * (needle - 3) == 0) { + + // Ensure needle is safe for disk move + if (isNeedleSafe(needle, disk, row) == false) { + + System.out.println("YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE,"); + System.out.println("IT MIGHT CRUSH IT!"); + System.out.print("NOW THEN, "); + + nextStep = Step.SELECT_DISK_MOVE; + break; + } + + diskPosition = getDiskPosition(disk); + + // Attempt to move the disk on a non-empty needle + diskMoved = false; + for (row = 1; row <= MAX_NUM_ROWS; row++) { + if (positions[row][needle] != 0) { + row--; + + positions[row][needle] = positions[diskPosition.row][diskPosition.column]; + positions[diskPosition.row][diskPosition.column] = 0; + + diskMoved = true; + break; + } + } + + // Needle was empty, so move disk to the bottom + if (diskMoved == false) { + positions[MAX_NUM_ROWS][needle] = positions[diskPosition.row][diskPosition.column]; + positions[diskPosition.row][diskPosition.column] = 0; + } + + nextStep = Step.CHECK_SOLUTION; + break; + + } + // Handle invalid needle numbers + else { + + numErrors++; + + if (numErrors > 1) { + System.out.println("I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN."); + System.out.println("BYE BYE, BIG SHOT."); + return; + } + else { + System.out.println("I'LL ASSUME YOU HIT THE WRONG KEY THIS TIME. BUT WATCH IT,"); + System.out.println("I ONLY ALLOW ONE MISTAKE."); + } + } + + } + + break; + + + case CHECK_SOLUTION: + + printPositions(); + + numMoves++; + + // Puzzle is solved + if (isPuzzleSolved() == true) { + + // Check for optimal solution + if (numMoves == (Math.pow(2, numDisks) - 1)) { + System.out.println(""); + System.out.println("CONGRATULATIONS!!\n"); + } + + System.out.println("YOU HAVE PERFORMED THE TASK IN " + numMoves + " MOVES.\n"); + System.out.print("TRY AGAIN (YES OR NO)? "); + + // Prompt for retries + while (true) { + userResponse = scan.next(); + + if (userResponse.toUpperCase().equals("YES")) { + nextStep = Step.INITIALIZE; + break; + } + else if (userResponse.toUpperCase().equals("NO")) { + System.out.println(""); + System.out.println("THANKS FOR THE GAME!\n"); + return; + } + else { + System.out.print("'YES' OR 'NO' PLEASE? "); + } + } + } + // Puzzle is not solved + else { + + // Exceeded maximum number of moves + if (numMoves > MAX_NUM_MOVES) { + System.out.println("SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN"); + System.out.println("128 MOVES."); + return; + } + + nextStep = Step.SELECT_DISK_MOVE; + break; + } + + break; + + default: + System.out.println("INVALID STEP"); + break; + + } + + } // End outer while loop + + } // End of method startGame + + + private boolean isPuzzleSolved() { + + int column = 0; + int row = 0; + + // Puzzle is solved if first 2 needles are empty + for (row = 1; row <= MAX_NUM_ROWS; row++) { + for (column = 1; column <= 2; column++) { + if (positions[row][column] != 0) { + return false; + } + } + } + + return true; + + } // End of method isPuzzleSolved + + + private Position getDiskPosition(int disk) { + + int column = 0; + int row = 0; + + Position pos = new Position(0, 0); + + // Begin loop through all rows + for (row = 1; row <= MAX_NUM_ROWS; row++) { + + // Begin loop through all columns + for (column = 1; column <= MAX_NUM_COLUMNS; column++) { + + // Found the disk + if (positions[row][column] == disk) { + + pos.row = row; + pos.column = column; + return pos; + + } + + } // End loop through all columns + + } // End loop through all rows + + return pos; + + } // End of method getDiskPosition + + + private boolean isDiskMovable(int disk, int row, int column) { + + int ii = 0; // Loop iterator + + // Begin loop through all rows above disk + for (ii = row; ii >= 1; ii--) { + + // Disk can be moved + if (positions[ii][column] == 0) { + continue; + } + + // Disk cannot be moved + if (positions[ii][column] < disk) { + return false; + } + + } // End loop through all rows above disk + + return true; + + } // End of method isDiskMovable + + + private boolean isNeedleSafe(int needle, int disk, int row) { + + for (row = 1; row <= MAX_NUM_ROWS; row++) { + + // Needle is not empty + if (positions[row][needle] != 0) { + + // Disk crush condition + if (disk >= positions[row][needle]) { + return false; + } + } + } + + return true; + + } // End of method isNeedleSafe + + + private void printPositions() { + + int column = 1; + int ii = 0; // Loop iterator + int numSpaces = 0; + int row = 1; + + // Begin loop through all rows + for (row = 1; row <= MAX_NUM_ROWS; row++) { + + numSpaces = 9; + + // Begin loop through all columns + for (column = 1; column <= MAX_NUM_COLUMNS; column++) { + + // No disk at the current position + if (positions[row][column] == 0) { + + System.out.print(" ".repeat(numSpaces) + "*"); + numSpaces = 20; + } + + // Draw a disk at the current position + else { + + System.out.print(" ".repeat(numSpaces - ((int) (positions[row][column] / 2)))); + + for (ii = 1; ii <= positions[row][column]; ii++) { + System.out.print("*"); + } + + numSpaces = 20 - ((int) (positions[row][column] / 2)); + } + + } // End loop through all columns + + System.out.println(""); + + } // End loop through all rows + + } // End of method printPositions + + + public static void main(String[] args) { + + Tower tower = new Tower(); + tower.play(); + + } // End of method main + +} // End of class Tower \ No newline at end of file From 297a2b5df9c61f7c0f087b89fa3d1a222c393b24 Mon Sep 17 00:00:00 2001 From: nanochess Date: Mon, 15 Mar 2021 16:38:38 -0600 Subject: [PATCH 15/19] Ported TOWER to Javascript --- 90 Tower/javascript/tower.html | 9 ++ 90 Tower/javascript/tower.js | 254 +++++++++++++++++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 90 Tower/javascript/tower.html create mode 100644 90 Tower/javascript/tower.js diff --git a/90 Tower/javascript/tower.html b/90 Tower/javascript/tower.html new file mode 100644 index 00000000..84318f33 --- /dev/null +++ b/90 Tower/javascript/tower.html @@ -0,0 +1,9 @@ + + +TOWER + + +


+
+
+
diff --git a/90 Tower/javascript/tower.js b/90 Tower/javascript/tower.js
new file mode 100644
index 00000000..06e8745c
--- /dev/null
+++ b/90 Tower/javascript/tower.js	
@@ -0,0 +1,254 @@
+// TOWER
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+var ta = [];
+
+// Print subroutine
+function show_towers()
+{
+    var z;
+    
+    for (var k = 1; k <= 7; k++) {
+        z = 10;
+        str = "";
+        for (var j = 1; j <= 3; j++) {
+            if (ta[k][j] != 0) {
+                while (str.length < z - Math.floor(ta[k][j] / 2))
+                    str += " ";
+                for (v = 1; v <= ta[k][j]; v++)
+                    str += "*";
+            } else {
+                while (str.length < z)
+                    str += " ";
+                str += "*";
+            }
+            z += 21;
+        }
+        print(str + "\n");
+    }
+}
+
+// Main control section
+async function main()
+{
+    print(tab(33) + "TOWERS\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    while (1) {
+        print("\n");
+        // Initialize
+        e = 0;
+        for (d = 1; d <= 7; d++) {
+            ta[d] = [];
+            for (n = 1; n <= 3; n++)
+                ta[d][n] = 0;
+        }
+        print("TOWERS OF HANOI PUZZLE.\n");
+        print("\n");
+        print("YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT\n");
+        print("TOWER, ONE AT A TIME, NEVER PUTTING A LARGER DISK ON A\n");
+        print("SMALLER DISK.\n");
+        print("\n");
+        while (1) {
+            print("HOW MANY DISKS DO YOU WANT TO MOVE (7 IS MAX)");
+            s = parseInt(await input());
+            print("\n");
+            m = 0;
+            if (s >= 1 && s <= 7)
+                break;
+            e++;
+            if (e < 2) {
+                print("SORRY, BUT I CAN'T DO THAT JOB FOR YOU.\n");
+                continue;
+            }
+            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");
+            return;
+        }
+        // Store disks from smallest to largest
+        print("IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.\n");
+        print("3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,\n");
+        print("7 THE NEXT, AND SO ON, UP TO 15.  IF YOU DO THE PUZZLE WITH\n");
+        print("2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15.  WITH 3 DISKS\n");
+        print("THE CODE NAMES WOULD BE 11, 13 AND 15, ETC.  THE NEEDLES\n");
+        print("ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3.  WE WILL\n");
+        print("START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM\n");
+        print("TO NEEDLE 3.\n");
+        print("\n");
+        print("GOOD LUCK!\n");
+        print("\n");
+        y = 7;
+        d = 15;
+        for (x = s; x >= 1; x--) {
+            ta[y][1] = d;
+            d -= 2;
+            y--;
+        }
+        show_towers();
+        while (1) {
+            print("WHICH DISK WOULD YOU LIKE TO MOVE");
+            e = 0;
+            while (1) {
+                d = parseInt(await input());
+                if (d % 2 == 0 || d < 3 || d > 15) {
+                    print("ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15.\n");
+                    e++;
+                    if (e <= 1)
+                        continue;
+                    print("STOP WASTING MY TIME.  GO BOTHER SOMEONE ELSE.\n");
+                    return;
+                } else {
+                    break;
+                }
+            }
+            // Check if requested disk is below another
+            for (r = 1; r <= 7; r++) {
+                for (c = 1; c <= 3; c++) {
+                    if (ta[r][c] == d)
+                        break;
+                }
+                if (c <= 3)
+                    break;
+            }
+            for (q = r; q >= 1; q--) {
+                if (ta[q][c] != 0 && ta[q][c] < d)
+                    break;
+            }
+            if (q >= 1) {
+                print("THAT DISK IS BELOW ANOTHER ONE.  MAKE ANOTHER CHOICE.\n");
+                continue;
+            }
+            e = 0;
+            while (1) {
+                print("PLACE DISK ON WHICH NEEDLE");
+                n = parseInt(await input());
+                if (n >= 1 && n <= 3)
+                    break;
+                e++;
+                if (e <= 1) {
+                    print("I'LL ASSUME YOU HIT THE WRONG KEY THI TIME.  BUT WATCH IT,\n");
+                    print("I ONLY ALLOW ONE MISTAKE.\n");
+                    continue;
+                } else {
+                    print("I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN.\n");
+                    print("BYE BYE, BIG SHOT.\n");
+                    return;
+                }
+            }
+            // Check if requested disk is below another
+            for (r = 1; r <= 7; r++) {
+                if (ta[r][n] != 0)
+                    break;
+            }
+            if (r <= 7) {
+                // Check if disk to be placed on a larger one
+                if (d >= ta[r][n]) {
+                    print("YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE,\n");
+                    print("IT MIGHT CRUSH IT!\n");
+                    print("NOW THEN, ");
+                    continue;
+                }
+            }
+            // Move relocated disk
+            for (v = 1; v <= 7; v++) {
+                for (w = 1; w <= 3; w++) {
+                    if (ta[v][w] == d)
+                        break;
+                }
+                if (w <= 3)
+                    break;
+            }
+            // Locate empty space on needle n
+            for (u = 1; u <= 7; u++) {
+                if (ta[u][n] != 0)
+                    break;
+            }
+            ta[--u][n] = ta[v][w];
+            ta[v][w] = 0;
+            // Print out current status
+            show_towers();
+            // Check if done
+            m++;
+            for (r = 1; r <= 7; r++) {
+                for (c = 1; c <= 2; c++) {
+                    if (ta[r][c] != 0)
+                        break;
+                }
+                if (c <= 2)
+                    break;
+            }
+            if (r > 7)
+                break;
+            if (m > 128) {
+                print("SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN\n");
+                print("128 MOVES.\n");
+                return;
+            }
+        }
+        if (m == Math.pow(2, s) - 1) {
+            print("\n");
+            print("CONGRATULATIONS!!\n");
+            print("\n");
+        }
+        print("YOU HAVE PERFORMED THE TASK IN " + m + " MOVES.\n");
+        print("\n");
+        print("TRY AGAIN (YES OR NO)");
+        while (1) {
+            str = await input();
+            if (str == "YES" || str == "NO")
+                break;
+            print("\n");
+            print("'YES' OR 'NO' PLEASE");
+        }
+        if (str == "NO")
+            break;
+    }
+    print("\n");
+    print("THANKS FOR THE GAME!\n");
+    print("\n");
+}
+
+main();

From 6b2952fa72066abd926a0f3827c768dd64e6386c Mon Sep 17 00:00:00 2001
From: nanochess 
Date: Mon, 15 Mar 2021 22:10:32 -0600
Subject: [PATCH 16/19] Ported 3DTICTACTOE to Javascript

---
 88 3-D Tic-Tac-Toe/javascript/qubit.html |   9 +
 88 3-D Tic-Tac-Toe/javascript/qubit.js   | 448 +++++++++++++++++++++++
 2 files changed, 457 insertions(+)
 create mode 100644 88 3-D Tic-Tac-Toe/javascript/qubit.html
 create mode 100644 88 3-D Tic-Tac-Toe/javascript/qubit.js

diff --git a/88 3-D Tic-Tac-Toe/javascript/qubit.html b/88 3-D Tic-Tac-Toe/javascript/qubit.html
new file mode 100644
index 00000000..813015bb
--- /dev/null
+++ b/88 3-D Tic-Tac-Toe/javascript/qubit.html	
@@ -0,0 +1,9 @@
+
+
+QUBIT
+
+
+

+
+
+
diff --git a/88 3-D Tic-Tac-Toe/javascript/qubit.js b/88 3-D Tic-Tac-Toe/javascript/qubit.js
new file mode 100644
index 00000000..9d73734d
--- /dev/null
+++ b/88 3-D Tic-Tac-Toe/javascript/qubit.js	
@@ -0,0 +1,448 @@
+// QUBIT
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+    var input_element;
+    var input_str;
+    
+    return new Promise(function (resolve) {
+                       input_element = document.createElement("INPUT");
+                       
+                       print("? ");
+                       input_element.setAttribute("type", "text");
+                       input_element.setAttribute("length", "50");
+                       document.getElementById("output").appendChild(input_element);
+                       input_element.focus();
+                       input_str = undefined;
+                       input_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode == 13) {
+                                                      input_str = input_element.value;
+                                                      document.getElementById("output").removeChild(input_element);
+                                                      print(input_str);
+                                                      print("\n");
+                                                      resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    var str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+var xa = [];
+var la = [];
+var ma = [[],
+          [,1,2,3,4],    // 1
+          [,5,6,7,8],    // 2
+          [,9,10,11,12], // 3
+          [,13,14,15,16],    // 4
+          [,17,18,19,20],    // 5
+          [,21,22,23,24],    // 6
+          [,25,26,27,28],    // 7
+          [,29,30,31,32],    // 8
+          [,33,34,35,36],    // 9
+          [,37,38,39,40],    // 10
+          [,41,42,43,44],    // 11
+          [,45,46,47,48],    // 12
+          [,49,50,51,52],    // 13
+          [,53,54,55,56],    // 14
+          [,57,58,59,60],    // 15
+          [,61,62,63,64],    // 16
+          [,1,17,33,49], // 17
+          [,5,21,37,53],    // 18
+          [,9,25,41,57],   // 19
+          [,13,29,45,61], // 20
+          [,2,18,34,50], // 21
+          [,6,22,38,54],    // 22
+          [,10,26,42,58],  // 23
+          [,14,30,46,62],   // 24
+          [,3,19,35,51], // 25
+          [,7,23,39,55],    // 26
+          [,11,27,43,59],  // 27
+          [,15,31,47,63], // 28
+          [,4,20,36,52], // 29
+          [,8,24,40,56], // 30
+          [,12,28,44,60],    // 31
+          [,16,32,48,64],    // 32
+          [,1,5,9,13],   // 33
+          [,17,21,25,29],    // 34
+          [,33,37,41,45],    // 35
+          [,49,53,57,61],    // 36
+          [,2,6,10,14],  // 37
+          [,18,22,26,30],    // 38
+          [,34,38,42,46],    // 39
+          [,50,54,58,62],    // 40
+          [,3,7,11,15],  // 41
+          [,19,23,27,31],    // 42
+          [,35,39,43,47],    // 43
+          [,51,55,59,63],    // 44
+          [,4,8,12,16],  // 45
+          [,20,24,28,32],    // 46
+          [,36,40,44,48],    // 47
+          [,52,56,60,64],    // 48
+          [,1,6,11,16],  // 49
+          [,17,22,27,32],    // 50
+          [,33,38,43,48],    // 51
+          [,49,54,59,64],    // 52
+          [,13,10,7,4],  // 53
+          [,29,26,23,20],    // 54
+          [,45,42,39,36],    // 55
+          [,61,58,55,52],    // 56
+          [,1,21,41,61], // 57
+          [,2,22,42,62], // 58
+          [,3,23,43,63], // 59
+          [,4,24,44,64], // 60
+          [,49,37,25,13],    // 61
+          [,50,38,26,14],    // 62
+          [,51,39,27,15],    // 63
+          [,52,40,28,16],    // 64
+          [,1,18,35,52], // 65
+          [,5,22,39,56], // 66
+          [,9,26,43,60], // 67
+          [,13,30,47,64],    // 68
+          [,49,34,19,4], // 69
+          [,53,38,23,8], // 70
+          [,57,42,27,12],    // 71
+          [,61,46,31,16],    // 72
+          [,1,22,43,64], // 73
+          [,16,27,38,49],    // 74
+          [,4,23,42,61], // 75
+          [,13,26,39,52] // 76
+          ];
+var ya = [,1,49,52,4,13,61,64,16,22,39,23,38,26,42,27,43];
+
+function show_board()
+{
+    for (xx = 1; xx <= 9; xx++)
+        print("\n");
+    for (i = 1; i <= 4; i++) {
+        for (j = 1; j <= 4; j++) {
+            str = "";
+            for (i1 = 1; i1 <= j; i1++)
+                str += "   ";
+            for (k = 1; k <= 4; k++) {
+                q = 16 * i + 4 * j + k - 20;
+                if (xa[q] == 0)
+                    str += "( )      ";
+                if (xa[q] == 5)
+                    str += "(M)      ";
+                if (xa[q] == 1)
+                    str += "(Y)      ";
+                if (xa[q] == 1 / 8)
+                    str += "( )      ";
+            }
+            print(str + "\n");
+            print("\n");
+        }
+        print("\n");
+        print("\n");
+    }
+}
+
+function process_board()
+{
+    for (i = 1; i <= 64; i++) {
+        if (xa[i] == 1 / 8)
+            xa[i] = 0;
+    }
+}
+
+function check_for_lines()
+{
+    for (s = 1; s <= 76; s++) {
+        j1 = ma[s][1];
+        j2 = ma[s][2];
+        j3 = ma[s][3];
+        j4 = ma[s][4];
+        la[s] = xa[j1] + xa[j2] + xa[j3] + xa[j4];
+    }
+}
+
+function show_square(m)
+{
+    k1 = Math.floor((m - 1) / 16) + 1;
+    j2 = m - 16 * (k1 - 1);
+    k2 = Math.floor((j2 - 1) / 4) + 1;
+    k3 = m - (k1 - 1) * 16 - (k2 - 1) * 4;
+    m = k1 * 100 + k2 * 10 + k3;
+    print(" " + m + " ");
+}
+
+function select_move() {
+    if (i % 4 <= 1) {
+        a = 1;
+    } else {
+        a = 2;
+    }
+    for (j = a; j <= 5 - a; j += 5 - 2 * a) {
+        if (xa[ma[i][j]] == s)
+            break;
+    }
+    if (j > 5 - a)
+        return false;
+    xa[ma[i][j]] = s;
+    m = ma[i][j];
+    print("MACHINE TAKES");
+    show_square(m);
+    return true;
+}
+
+// Main control section
+async function main()
+{
+    print(tab(33) + "QUBIC\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    while (1) {
+        print("DO YOU WANT INSTRUCTIONS");
+        str = await input();
+        str = str.substr(0, 1);
+        if (str == "Y" || str == "N")
+            break;
+        print("INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'");
+    }
+    if (str == "Y") {
+        print("\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");
+        print("\n");
+        print("TO PRINT THE PLAYING BOARD, TYPE 0 (ZERO) AS YOUR MOVE.\n");
+        print("THE PROGRAM WILL PRINT THE BOARD WITH YOUR MOVES INDI-\n");
+        print("CATED WITH A (Y), THE MACHINE'S MOVES WITH AN (M), AND\n");
+        print("UNUSED SQUARES WITH A ( ).  OUTPUT IS ON PAPER.\n");
+        print("\n");
+        print("TO STOP THE PROGRAM RUN, TYPE 1 AS YOUR MOVE.\n");
+        print("\n");
+        print("\n");
+    }
+    while (1) {
+        for (i = 1; i <= 64; i++)
+            xa[i] = 0;
+        z = 1;
+        print("DO YOU WANT TO MOVE FIRST");
+        while (1) {
+            str = await input();
+            str = str.substr(0, 1);
+            if (str == "Y" || str == "N")
+                break;
+            print("INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'");
+        }
+        while (1) {
+            while (1) {
+                print(" \n");
+                print("YOUR MOVE");
+                j1 = parseInt(await input());
+                if (j1 == 0) {
+                    show_board();
+                    continue;
+                }
+                if (j1 == 1)
+                    return;
+                k1 = Math.floor(j1 / 100);
+                j2 = j1 - k1 * 100;
+                k2 = Math.floor(j2 / 10);
+                k3 = j2 - k2 * 10;
+                m = 16 * k1 + 4 * k2 + k3 - 20;
+                if (k1 < 1 || k2 < 1 || k3 < 1 || k1 > 4 || k2 > 4 || k3 >> 4) {
+                    print("INCORRECT MOVE, RETYPE IT--");
+                } else {
+                    process_board();
+                    if (xa[m] != 0) {
+                        print("THAT SQUARE IS USED, TRY AGAIN.\n");
+                    } else {
+                        break;
+                    }
+                }
+            }
+            xa[m] = 1;
+            check_for_lines();
+            status = 0;
+            for (j = 1; j <= 3; j++) {
+                for (i = 1; i <= 76; i++) {
+                    if (j == 1) {
+                        if (la[i] != 4)
+                            continue;
+                        print("YOU WIN AS FOLLOWS");
+                        for (j = 1; j <= 4; j++) {
+                            m = ma[i][j];
+                            show_square(m);
+                        }
+                        status = 1;
+                        break;
+                    }
+                    if (j == 2) {
+                        if (la[i] != 15)
+                            continue;
+                        for (j = 1; j <= 4; j++) {
+                            m = ma[i][j];
+                            if (xa[m] != 0)
+                                continue;
+                            xa[m] = 5;
+                            print("MACHINE MOVES TO ");
+                            show_square(m);
+                        }
+                        print(", AND WINS AS FOLLOWS");
+                        for (j = 1; j <= 4; j++) {
+                            m = ma[i][j];
+                            show_square(m);
+                        }
+                        status = 1;
+                        break;
+                    }
+                    if (j == 3) {
+                        if (la[i] != 3)
+                            continue;
+                        print("NICE TRY, MACHINE MOVES TO");
+                        for (j = 1; j <= 4; j++) {
+                            m = ma[i][j];
+                            if (xa[m] != 0)
+                                continue;
+                            xa[m] = 5;
+                            show_square(m);
+                            status = 2;
+                        }
+                        break;
+                    }
+                }
+                if (i <= 76)
+                    break;
+            }
+            if (status == 2)
+                continue;
+            if (status == 1)
+                break;
+            // x = x; non-useful in original
+            i = 1;
+            do {
+                la[i] = xa[ma[i][1]] + xa[ma[i][2]] + xa[ma[i][3]] + xa[ma[i][4]];
+                l = la[i];
+                if (l == 10) {
+                    for (j = 1; j <= 4; j++) {
+                        if (xa[ma[i][j]] == 0)
+                            xa[ma[i][j]] = 1 / 8;
+                    }
+                }
+            } while (++i <= 76) ;
+            check_for_lines();
+            i = 1;
+            do {
+                if (la[i] == 0.5) {
+                    s = 1 / 8;
+                    select_move();
+                    break;
+                }
+                if (la[i] == 5 + 3 / 8) {
+                    s = 1 / 8;
+                    select_move();
+                    break;
+                }
+            } while (++i <= 76) ;
+            if (i <= 76)
+                continue;
+            
+            process_board();
+            
+            i = 1;
+            do {
+                la[i] = xa[ma[i][1]] + xa[ma[i][2]] + xa[ma[i][3]] + xa[ma[i][4]];
+                l = la[i];
+                if (l == 2) {
+                    for (j = 1; j <= 4; j++) {
+                        if (xa[ma[i][j]] == 0)
+                            xa[ma[i][j]] = 1 / 8;
+                    }
+                }
+            } while (++i <= 76) ;
+            check_for_lines();
+            i = 1;
+            do {
+                if (la[i] == 0.5) {
+                    s = 1 / 8;
+                    select_move();
+                    break;
+                }
+                if (la[i] == 1 + 3 / 8) {
+                    s = 1 / 8;
+                    select_move();
+                    break;
+                }
+            } while (++i <= 76) ;
+            if (i <= 76)
+                continue;
+            
+            for (k = 1; k <= 18; k++) {
+                p = 0;
+                for (i = 4 * k - 3; i <= 4 * k; i++) {
+                    for (j = 1; j <= 4; j++)
+                        p += xa[ma[i][j]];
+                }
+                if (p == 4 || p == 9) {
+                    s = 1 / 8;
+                    for (i = 4 * k - 3; i <= 4 * k; i++) {
+                        if (select_move())
+                            break;
+                    }
+                    s = 0;
+                }
+            }
+            if (k <= 18)
+                continue
+            process_board();
+            z = 1;
+            do {
+                if (xa[ya[z]] == 0)
+                    break;
+            } while (++z < 17) ;
+            if (z >= 17) {
+                for (i = 1; i <= 64; i++) {
+                    if (xa[i] == 0) {
+                        xa[i] = 5;
+                        m = i;
+                        print("MACHINE LIKES");
+                        break;
+                    }
+                }
+                if (i > 64) {
+                    print("THE GAME IS A DRAW.\n");
+                    break;
+                }
+            } else {
+                m = ya[z];
+                xa[m] = 5;
+                print("MACHINE MOVES TO");
+            }
+            show_square(m);
+        }
+        print(" \n");
+        print("DO YOU WANT TO TRY ANOTHER GAME");
+        while (1) {
+            str = await input();
+            str = str.substr(0, 1);
+            if (str == "Y" || str == "N")
+                break;
+            print("INCORRECT ANSWER. PLEASE TYPE 'YES' OR 'NO'");
+        }
+        if (str == "N")
+            break;
+    }
+}
+
+main();

From 8bea3b92f4c547f8ffc61621050a3fa8bf4f605d Mon Sep 17 00:00:00 2001
From: Todd Kaiser 
Date: Tue, 16 Mar 2021 15:29:25 -0600
Subject: [PATCH 17/19] Added major turn logic.

---
 77 Salvo/python/salvo.py | 193 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 169 insertions(+), 24 deletions(-)

diff --git a/77 Salvo/python/salvo.py b/77 Salvo/python/salvo.py
index 73ff55ec..3ebdcddc 100644
--- a/77 Salvo/python/salvo.py	
+++ b/77 Salvo/python/salvo.py	
@@ -10,10 +10,20 @@ import random
 BOARD_WIDTH = 10
 BOARD_HEIGHT = 10
 
-SHIPS = [("BATTLESHIP", 5),
-         ("CRUISER", 3),
-         ("DESTROYER
", 2), - ("DESTROYER", 2)] +# game ships +# +# data structure keeping track of information +# about the ships in the game. for each ship, +# the following information is provided: +# +# name - string representation of the ship +# length - number of "parts" on the ship that +# can be shot +# shots - number of shots the ship counts for +SHIPS = [("BATTLESHIP", 5, 3), + ("CRUISER", 3, 2), + ("DESTROYER", 2, 1), + ("DESTROYER", 2, 1)] VALID_MOVES = [[-1, 0], # North [-1, 1], # North East @@ -46,6 +56,18 @@ computer_ship_coords = [] # keep track of the turn current_turn = 0 +#################################### +# +# SHOTS +# +# The number of shots computer/player +# has is determined by the shot "worth" +# of each ship the computer/player +# possesses. As long as the ship has one +# part not hit (i.e., ship was not +# sunk), the player gets all the shots +# from that ship. + # flag indicating if computer's shots are # printed out during computer's turn print_computer_shots = False @@ -60,6 +82,17 @@ num_computer_shots = 7 # initial shots are 7 num_player_shots = 7 +# +# SHOTS +# +#################################### + +# flag indicating whose turn +# it currently is +COMPUTER = 0 +PLAYER = 1 +active_turn = COMPUTER + #################### # # game functions @@ -241,7 +274,38 @@ def generate_board(): # execute a shot. returns True if the shot # is valid, False if not def execute_shot(board, x, y): - print("execute shot:", x, y) + + global current_turn + square = board[x-1][y-1] + if square is not None: + if square >= 0 and square < len(SHIPS): + if active_turn == PLAYER: + print("YOU HIT MY", SHIPS[square][0]) + else: + print("I HIT YOUR", SHIPS[square][0]) + + board[x-1][y-1] = 10 + current_turn + + +# calculate_shots +# +# function to examine each board +# and determine how many shots remaining +def calculate_shots(board): + + ships_found = [0 for x in range(len(SHIPS))] + for x in range(BOARD_HEIGHT): + for y in range(BOARD_WIDTH): + square = board[x-1][y-1] + if square is not None: + if square >= 0 and square < len(SHIPS): + ships_found[square] = 1 + shots = 0 + for ship in range(len(ships_found)): + if ships_found[ship] == 1: + shots += SHIPS[ship][2] + + return shots # initialize @@ -309,8 +373,14 @@ def initialize_game(): global first_turn global second_turn if player_start.lower() != "yes": - first_turn = computer_turn - second_turn = player_turn + first_turn = COMPUTER + second_turn = PLAYER + + # calculate the initial number of shots for each + global num_computer_shots + global num_player_shots + num_player_shots = calculate_shots(player_board) + num_computer_shots = calculate_shots(computer_board) #################################### @@ -322,32 +392,94 @@ def initialize_game(): # functions, we can easily start the game with # either computer or player and alternate back and # forth, replicating the gotos in the original game + + +# initialize the first_turn function to the +# player's turn +first_turn = PLAYER + + +# initialize the second_turn to the computer's +# turn +second_turn = COMPUTER + + def player_turn(): - print("YOU HAVE", num_computer_shots, "SHOTS.") + print("YOU HAVE", num_player_shots, "SHOTS.") + global active_turn + active_turn = PLAYER shots = [] for shot in range(num_player_shots): valid_shot = False while not valid_shot: x, y = input_coord() - valid_shot = execute_shot(player_board, x, y) + square = computer_board[x-1][y-1] + if square is not None: + if square > 10: + if active_turn == PLAYER: + print("YOU SHOT THERE BEFORE ON TURN", square - 10) + continue shots.append((x, y)) - - print(shots) + valid_shot = True + for shot in shots: + execute_shot(computer_board, shot[0], shot[1]) -# initialize the first_turn function to the -# player's turn -first_turn = player_turn +def execute_turn(turn): + global num_computer_shots + global num_player_shots -def computer_turn(): - print("I HAVE", num_computer_shots, "SHOTS.") + # print out the number of shots the current + # player has + board = None + num_shots = 0 + if turn == COMPUTER: + print("I HAVE", num_computer_shots, "SHOTS.") + board = player_board + num_shots = num_computer_shots + else: + print("YOU HAVE", num_player_shots, "SHOTS.") + board = computer_board + num_shots = num_player_shots + shots = [] + for shot in range(num_shots): + valid_shot = False + x = -1 + y = -1 + + # loop until we have a valid shot. for the + # computer, we randomly pick a shot. for the + # player we request shots + while not valid_shot: + if turn == COMPUTER: + x, y = random_x_y() + else: + x, y = input_coord() + square = board[x-1][y-1] + if square is not None: + if square > 10: + if turn == PLAYER: + print("YOU SHOT THERE BEFORE ON TURN", square - 10) + continue + shots.append((x, y)) + valid_shot = True + + for shot in shots: + execute_shot(board, shot[0], shot[1]) + if turn == COMPUTER: + if print_computer_shots: + print(shot[0], shot[1]) + + if turn == COMPUTER: + num_player_shots = calculate_shots(board) + return num_player_shots + else: + num_computer_shots = calculate_shots(board) + return num_computer_shots -# initialize the second_turn to the computer's -# turn -second_turn = computer_turn # # Turn Control @@ -367,9 +499,22 @@ initialize_game() # execute turns until someone wins or we run # out of squares to shoot -current_turn = current_turn + 1 -print("\n") -print("TURN", current_turn) +game_over = False +while not game_over: -first_turn() -second_turn() + # increment the turn + current_turn = current_turn + 1 + + print("\n") + print("TURN", current_turn) + print("computer") + print_board(computer_board) + print("player") + print_board(player_board) + + if execute_turn(first_turn) == 0: + game_over = True + continue + if execute_turn(second_turn) == 0: + game_over = True + continue From e6e6a52646053b956cd9b157d8762ddc9c12ef17 Mon Sep 17 00:00:00 2001 From: Todd Kaiser Date: Tue, 16 Mar 2021 18:19:01 -0600 Subject: [PATCH 18/19] Cleaned up debug statements and program flow. Fixed a couple of bugs from testing --- 77 Salvo/python/salvo.py | 44 +++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/77 Salvo/python/salvo.py b/77 Salvo/python/salvo.py index 3ebdcddc..bad23352 100644 --- a/77 Salvo/python/salvo.py +++ b/77 Salvo/python/salvo.py @@ -147,8 +147,24 @@ def input_coord(): return x, y -# TODO: add an optional starting coordinate for testing -# purposes +# generate_ship_coordinates +# +# given a ship from the SHIPS array, generate +# the coordinates of the ship. the starting point +# of the ship's first coordinate is generated randomly. +# once the starting coordinates are determined, the +# possible directions of the ship, accounting for the +# edges of the board, are determined. once possible +# directions are found, a direction is randomly +# determined and the remaining coordinates are +# generated by adding or substraction from the starting +# coordinates as determined by direction. +# +# arguments: +# ship - index into the SHIPS array +# +# returns: +# array of sets of coordinates (x,y) def generate_ship_coordinates(ship): # randomly generate starting x,y coordinates start_x, start_y = random_x_y() @@ -273,16 +289,16 @@ def generate_board(): # given a board and x, y coordinates, # execute a shot. returns True if the shot # is valid, False if not -def execute_shot(board, x, y): +def execute_shot(turn, board, x, y): global current_turn square = board[x-1][y-1] if square is not None: if square >= 0 and square < len(SHIPS): - if active_turn == PLAYER: - print("YOU HIT MY", SHIPS[square][0]) - else: + if turn == COMPUTER: print("I HIT YOUR", SHIPS[square][0]) + else: + print("YOU HIT MY", SHIPS[square][0]) board[x-1][y-1] = 10 + current_turn @@ -328,7 +344,10 @@ def initialize_game(): # print out the title 'screen' print('{0:>38}'.format("SALVO")) print('{0:>57s}'.format("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")) - print('\n\n') + print('') + print('{0:>52s}'.format("ORIGINAL BY LAWRENCE SIEGEL, 1973")) + print('{0:>56s}'.format("PYTHON 3 PORT BY TODD KAISER, MARCH 2021")) + print('\n') # ask the player for ship coordinates print("ENTER COORDINATES FOR...") @@ -468,7 +487,7 @@ def execute_turn(turn): valid_shot = True for shot in shots: - execute_shot(board, shot[0], shot[1]) + execute_shot(turn, board, shot[0], shot[1]) if turn == COMPUTER: if print_computer_shots: print(shot[0], shot[1]) @@ -507,10 +526,11 @@ while not game_over: print("\n") print("TURN", current_turn) - print("computer") - print_board(computer_board) - print("player") - print_board(player_board) + + # print("computer") + # print_board(computer_board) + # print("player") + # print_board(player_board) if execute_turn(first_turn) == 0: game_over = True From 7222546bcff87248551b26c89374960bb63c63d9 Mon Sep 17 00:00:00 2001 From: Todd Kaiser Date: Tue, 16 Mar 2021 19:28:55 -0600 Subject: [PATCH 19/19] Fixed the order of printing out which ships were hit. Original game printed out ships that were hit AFTER updating the board, not during. getting close to done! --- 77 Salvo/python/salvo.py | 42 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/77 Salvo/python/salvo.py b/77 Salvo/python/salvo.py index bad23352..0dd19816 100644 --- a/77 Salvo/python/salvo.py +++ b/77 Salvo/python/salvo.py @@ -293,14 +293,12 @@ def execute_shot(turn, board, x, y): global current_turn square = board[x-1][y-1] + ship_hit = -1 if square is not None: if square >= 0 and square < len(SHIPS): - if turn == COMPUTER: - print("I HIT YOUR", SHIPS[square][0]) - else: - print("YOU HIT MY", SHIPS[square][0]) - + ship_hit = square board[x-1][y-1] = 10 + current_turn + return ship_hit # calculate_shots @@ -423,28 +421,6 @@ first_turn = PLAYER second_turn = COMPUTER -def player_turn(): - print("YOU HAVE", num_player_shots, "SHOTS.") - global active_turn - active_turn = PLAYER - - shots = [] - for shot in range(num_player_shots): - valid_shot = False - while not valid_shot: - x, y = input_coord() - square = computer_board[x-1][y-1] - if square is not None: - if square > 10: - if active_turn == PLAYER: - print("YOU SHOT THERE BEFORE ON TURN", square - 10) - continue - shots.append((x, y)) - valid_shot = True - for shot in shots: - execute_shot(computer_board, shot[0], shot[1]) - - def execute_turn(turn): global num_computer_shots @@ -486,12 +462,22 @@ def execute_turn(turn): shots.append((x, y)) valid_shot = True + hits = [] for shot in shots: - execute_shot(turn, board, shot[0], shot[1]) + hit = execute_shot(turn, board, shot[0], shot[1]) + if hit >= 0: + hits.append(hit) if turn == COMPUTER: if print_computer_shots: print(shot[0], shot[1]) + for hit in hits: + if turn == COMPUTER: + print("I HIT YOUR", SHIPS[hit][0]) + else: + print("YOU HIT MY", SHIPS[hit][0]) + + if turn == COMPUTER: num_player_shots = calculate_shots(board) return num_player_shots