diff --git a/00_Alternate_Languages/01_Acey_Ducey/README.md b/00_Alternate_Languages/01_Acey_Ducey/README.md new file mode 100644 index 00000000..07ac752b --- /dev/null +++ b/00_Alternate_Languages/01_Acey_Ducey/README.md @@ -0,0 +1,13 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. + +#### External Links + - Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp + - PowerShell: https://github.com/eweilnau/basic-computer-games-powershell/blob/main/AceyDucey.ps1 diff --git a/00_Alternate_Languages/01_Acey_Ducey/aceyducey.bas b/00_Alternate_Languages/01_Acey_Ducey/aceyducey.bas new file mode 100644 index 00000000..0b6f72db --- /dev/null +++ b/00_Alternate_Languages/01_Acey_Ducey/aceyducey.bas @@ -0,0 +1,100 @@ +10 PRINT TAB(26);"ACEY DUCEY CARD GAME" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +21 PRINT +22 PRINT +30 PRINT"ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER " +40 PRINT"THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP" +50 PRINT"YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING" +60 PRINT"ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE" +70 PRINT"A VALUE BETWEEN THE FIRST TWO." +80 PRINT"IF YOU DO NOT WANT TO BET, INPUT A 0" +100 N=100 +110 Q=100 +120 PRINT "YOU NOW HAVE ";Q;" DOLLARS." +130 PRINT +140 GOTO 260 +210 Q=Q+M +220 GOTO 120 +240 Q=Q-M +250 GOTO 120 +260 PRINT"HERE ARE YOUR NEXT TWO CARDS: " +270 A=INT(14*RND(1))+2 +280 IF A<2 THEN 270 +290 IF A>14 THEN 270 +300 B=INT(14*RND(1))+2 +310 IF B<2 THEN 300 +320 IF B>14 THEN 300 +330 IF A>=B THEN 270 +350 IF A<11 THEN 400 +360 IF A=11 THEN 420 +370 IF A=12 THEN 440 +380 IF A=13 THEN 460 +390 IF A=14 THEN 480 +400 PRINT A +410 GOTO 500 +420 PRINT"JACK" +430 GOTO 500 +440 PRINT"QUEEN" +450 GOTO 500 +460 PRINT"KING" +470 GOTO 500 +480 PRINT"ACE" +500 IF B<11 THEN 550 +510 IF B=11 THEN 570 +520 IF B=12 THEN 590 +530 IF B=13 THEN 610 +540 IF B=14 THEN 630 +550 PRINT B +560 GOTO 650 +570 PRINT"JACK" +580 GOTO 650 +590 PRINT"QUEEN" +600 GOTO 650 +610 PRINT"KING" +620 GOTO 650 +630 PRINT"ACE" +640 PRINT +650 PRINT +660 INPUT"WHAT IS YOUR BET";M +670 IF M<>0 THEN 680 +675 PRINT"CHICKEN!!" +676 PRINT +677 GOTO 260 +680 IF M<=Q THEN 730 +690 PRINT"SORRY, MY FRIEND, BUT YOU BET TOO MUCH." +700 PRINT"YOU HAVE ONLY ";Q;" DOLLARS TO BET." +710 GOTO 650 +730 C=INT(14*RND(1))+2 +740 IF C<2 THEN 730 +750 IF C>14 THEN 730 +760 IF C<11 THEN 810 +770 IF C=11 THEN 830 +780 IF C=12 THEN 850 +790 IF C=13 THEN 870 +800 IF C=14 THEN 890 +810 PRINT C +820 GOTO 910 +830 PRINT"JACK" +840 GOTO 910 +850 PRINT"QUEEN" +860 GOTO 910 +870 PRINT"KING" +880 GOTO 910 +890 PRINT "ACE" +900 PRINT +910 IF C>A THEN 930 +920 GOTO 970 +930 IF C>=B THEN 970 +950 PRINT"YOU WIN!!!" +960 GOTO 210 +970 PRINT"SORRY, YOU LOSE" +980 IF M1 AND V<>1 THEN 110 +104 PRINT "MEANINGLESS DIMENSIONS. TRY AGAIN.":GOTO 100 +110 DIM W(H,V),V(H,V) +120 PRINT +130 PRINT +140 PRINT +150 PRINT +160 Q=0:Z=0:X=INT(RND(1)*H+1) +165 FOR I=1 TO H +170 IF I=X THEN 173 +171 PRINT ".--";:GOTO 180 +173 PRINT ". "; +180 NEXT I +190 PRINT "." +195 C=1:W(X,1)=C:C=C+1 +200 R=X:S=1:GOTO 260 +210 IF R<>H THEN 240 +215 IF S<>V THEN 230 +220 R=1:S=1:GOTO 250 +230 R=1:S=S+1:GOTO 250 +240 R=R+1 +250 IF W(R,S)=0 THEN 210 +260 IF R-1=0 THEN 530 +265 IF W(R-1,S)<>0 THEN 530 +270 IF S-1=0 THEN 390 +280 IF W(R,S-1)<>0 THEN 390 +290 IF R=H THEN 330 +300 IF W(R+1,S)<>0 THEN 330 +310 X=INT(RND(1)*3+1) +320 ON X GOTO 790,820,860 +330 IF S<>V THEN 340 +334 IF Z=1 THEN 370 +338 Q=1:GOTO 350 +340 IF W(R,S+1)<>0 THEN 370 +350 X=INT(RND(1)*3+1) +360 ON X GOTO 790,820,910 +370 X=INT(RND(1)*2+1) +380 ON X GOTO 790,820 +390 IF R=H THEN 470 +400 IF W(R+1,S)<>0 THEN 470 +405 IF S<>V THEN 420 +410 IF Z=1 THEN 450 +415 Q=1:GOTO 430 +420 IF W(R,S+1)<>0 THEN 450 +430 X=INT(RND(1)*3+1) +440 ON X GOTO 790,860,910 +450 X=INT(RND(1)*2+1) +460 ON X GOTO 790,860 +470 IF S<>V THEN 490 +480 IF Z=1 THEN 520 +485 Q=1:GOTO 500 +490 IF W(R,S+1)<>0 THEN 520 +500 X=INT(RND(1)*2+1) +510 ON X GOTO 790,910 +520 GOTO 790 +530 IF S-1=0 THEN 670 +540 IF W(R,S-1)<>0 THEN 670 +545 IF R=H THEN 610 +547 IF W(R+1,S)<>0 THEN 610 +550 IF S<>V THEN 560 +552 IF Z=1 THEN 590 +554 Q=1:GOTO 570 +560 IF W(R,S+1)<>0 THEN 590 +570 X=INT(RND(1)*3+1) +580 ON X GOTO 820,860,910 +590 X=INT(RND(1)*2+1) +600 ON X GOTO 820,860 +610 IF S<>V THEN 630 +620 IF Z=1 THEN 660 +625 Q=1:GOTO 640 +630 IF W(R,S+1)<>0 THEN 660 +640 X=INT(RND(1)*2+1) +650 ON X GOTO 820,910 +660 GOTO 820 +670 IF R=H THEN 740 +680 IF W(R+1,S)<>0 THEN 740 +685 IF S<>V THEN 700 +690 IF Z=1 THEN 730 +695 Q=1:GOTO 710 +700 IF W(R,S+1)<>0 THEN 730 +710 X=INT(RND(1)*2+1) +720 ON X GOTO 860,910 +730 GOTO 860 +740 IF S<>V THEN 760 +750 IF Z=1 THEN 780 +755 Q=1:GOTO 770 +760 IF W(R,S+1)<>0 THEN 780 +770 GOTO 910 +780 GOTO 1000 +790 W(R-1,S)=C +800 C=C+1:V(R-1,S)=2:R=R-1 +810 IF C=H*V+1 THEN 1010 +815 Q=0:GOTO 260 +820 W(R,S-1)=C +830 C=C+1 +840 V(R,S-1)=1:S=S-1:IF C=H*V+1 THEN 1010 +850 Q=0:GOTO 260 +860 W(R+1,S)=C +870 C=C+1:IF V(R,S)=0 THEN 880 +875 V(R,S)=3:GOTO 890 +880 V(R,S)=2 +890 R=R+1 +900 IF C=H*V+1 THEN 1010 +905 GOTO 530 +910 IF Q=1 THEN 960 +920 W(R,S+1)=C:C=C+1:IF V(R,S)=0 THEN 940 +930 V(R,S)=3:GOTO 950 +940 V(R,S)=1 +950 S=S+1:IF C=H*V+1 THEN 1010 +955 GOTO 260 +960 Z=1 +970 IF V(R,S)=0 THEN 980 +975 V(R,S)=3:Q=0:GOTO 1000 +980 V(R,S)=1:Q=0:R=1:S=1:GOTO 250 +1000 GOTO 210 +1010 IF Z=1 THEN 1015 +1011 X=INT(RND(1)*H+1) +1012 IF V(X,V)=0 THEN 1014 +1013 V(X,V)=3: GOTO 1015 +1014 V(X,V)=1 +1015 FOR J=1 TO V +1016 PRINT "I"; +1017 FOR I=1 TO H +1018 IF V(I,J)<2 THEN 1030 +1020 PRINT " "; +1021 GOTO 1040 +1030 PRINT " I"; +1040 NEXT I +1041 PRINT +1043 FOR I=1 TO H +1045 IF V(I,J)=0 THEN 1060 +1050 IF V(I,J)=2 THEN 1060 +1051 PRINT ": "; +1052 GOTO 1070 +1060 PRINT ":--"; +1070 NEXT I +1071 PRINT "." +1072 NEXT J +1073 END diff --git a/02_Amazing/pascal/.gitattributes b/00_Alternate_Languages/02_Amazing/pascal/.gitattributes similarity index 100% rename from 02_Amazing/pascal/.gitattributes rename to 00_Alternate_Languages/02_Amazing/pascal/.gitattributes diff --git a/02_Amazing/pascal/.gitignore b/00_Alternate_Languages/02_Amazing/pascal/.gitignore similarity index 100% rename from 02_Amazing/pascal/.gitignore rename to 00_Alternate_Languages/02_Amazing/pascal/.gitignore diff --git a/02_Amazing/pascal/README.md b/00_Alternate_Languages/02_Amazing/pascal/README.md similarity index 100% rename from 02_Amazing/pascal/README.md rename to 00_Alternate_Languages/02_Amazing/pascal/README.md diff --git a/02_Amazing/pascal/object-pascal/amazing.lpi b/00_Alternate_Languages/02_Amazing/pascal/object-pascal/amazing.lpi similarity index 100% rename from 02_Amazing/pascal/object-pascal/amazing.lpi rename to 00_Alternate_Languages/02_Amazing/pascal/object-pascal/amazing.lpi diff --git a/02_Amazing/pascal/object-pascal/amazing.pas b/00_Alternate_Languages/02_Amazing/pascal/object-pascal/amazing.pas similarity index 100% rename from 02_Amazing/pascal/object-pascal/amazing.pas rename to 00_Alternate_Languages/02_Amazing/pascal/object-pascal/amazing.pas diff --git a/02_Amazing/pascal/object-pascal/amazingapplication.pas b/00_Alternate_Languages/02_Amazing/pascal/object-pascal/amazingapplication.pas similarity index 100% rename from 02_Amazing/pascal/object-pascal/amazingapplication.pas rename to 00_Alternate_Languages/02_Amazing/pascal/object-pascal/amazingapplication.pas diff --git a/02_Amazing/pascal/object-pascal/maze.pas b/00_Alternate_Languages/02_Amazing/pascal/object-pascal/maze.pas similarity index 100% rename from 02_Amazing/pascal/object-pascal/maze.pas rename to 00_Alternate_Languages/02_Amazing/pascal/object-pascal/maze.pas diff --git a/02_Amazing/pascal/object-pascal/room.pas b/00_Alternate_Languages/02_Amazing/pascal/object-pascal/room.pas similarity index 100% rename from 02_Amazing/pascal/object-pascal/room.pas rename to 00_Alternate_Languages/02_Amazing/pascal/object-pascal/room.pas diff --git a/02_Amazing/pascal/simple/amazing.lpi b/00_Alternate_Languages/02_Amazing/pascal/simple/amazing.lpi similarity index 100% rename from 02_Amazing/pascal/simple/amazing.lpi rename to 00_Alternate_Languages/02_Amazing/pascal/simple/amazing.lpi diff --git a/02_Amazing/pascal/simple/amazing.pas b/00_Alternate_Languages/02_Amazing/pascal/simple/amazing.pas similarity index 100% rename from 02_Amazing/pascal/simple/amazing.pas rename to 00_Alternate_Languages/02_Amazing/pascal/simple/amazing.pas diff --git a/00_Alternate_Languages/03_Animal/README.md b/00_Alternate_Languages/03_Animal/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/03_Animal/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/03_Animal/animal.bas b/00_Alternate_Languages/03_Animal/animal.bas new file mode 100644 index 00000000..271eb0d0 --- /dev/null +++ b/00_Alternate_Languages/03_Animal/animal.bas @@ -0,0 +1,71 @@ +10 PRINT TAB(32);"ANIMAL" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT: PRINT: PRINT +40 PRINT "PLAY 'GUESS THE ANIMAL'" +45 PRINT +50 PRINT "THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT." +60 PRINT +70 DIM A$(200) +80 FOR I=0 TO 3 +90 READ A$(I) +100 NEXT I +110 N=VAL(A$(0)) +120 REM MAIN CONTROL SECTION +130 INPUT "ARE YOU THINKING OF AN ANIMAL";A$ +140 IF A$="LIST" THEN 600 +150 IF LEFT$(A$,1)<>"Y" THEN 120 +160 K=1 +170 GOSUB 390 +180 IF LEN(A$(K))=0 THEN 999 +190 IF LEFT$(A$(K),2)="\Q" THEN 170 +200 PRINT "IS IT A ";RIGHT$(A$(K),LEN(A$(K))-2); +210 INPUT A$ +220 A$=LEFT$(A$,1) +230 IF LEFT$(A$,1)="Y" THEN PRINT "WHY NOT TRY ANOTHER ANIMAL?": GOTO 120 +240 INPUT "THE ANIMAL YOU WERE THINKING OF WAS A ";V$ +250 PRINT "PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A" +260 PRINT V$;" FROM A ";RIGHT$(A$(K),LEN(A$(K))-2) +270 INPUT X$ +280 PRINT "FOR A ";V$;" THE ANSWER WOULD BE "; +290 INPUT A$ +300 A$=LEFT$(A$,1): IF A$<>"Y" AND A$<>"N" THEN 280 +310 IF A$="Y" THEN B$="N" +320 IF A$="N" THEN B$="Y" +330 Z1=VAL(A$(0)) +340 A$(0)=STR$(Z1+2) +350 A$(Z1)=A$(K) +360 A$(Z1+1)="\A"+V$ +370 A$(K)="\Q"+X$+"\"+A$+STR$(Z1+1)+"\"+B$+STR$(Z1)+"\" +380 GOTO 120 +390 REM SUBROUTINE TO PRINT QUESTIONS +400 Q$=A$(K) +410 FOR Z=3 TO LEN(Q$) +415 IF MID$(Q$,Z,1)<>"\" THEN PRINT MID$(Q$,Z,1);: NEXT Z +420 INPUT C$ +430 C$=LEFT$(C$,1) +440 IF C$<>"Y" AND C$<>"N" THEN 410 +450 T$="\"+C$ +455 FOR X=3 TO LEN(Q$)-1 +460 IF MID$(Q$,X,2)=T$ THEN 480 +470 NEXT X +475 STOP +480 FOR Y=X+1 TO LEN(Q$) +490 IF MID$(Q$,Y,1)="\" THEN 510 +500 NEXT Y +505 STOP +510 K=VAL(MID$(Q$,X+2,Y-X-2)) +520 RETURN +530 DATA "4","\QDOES IT SWIM\Y2\N3\","\AFISH","\ABIRD" +600 PRINT:PRINT "ANIMALS I ALREADY KNOW ARE:" +605 X=0 +610 FOR I=1 TO 200 +620 IF LEFT$(A$(I),2)<>"\A" THEN 650 +624 PRINT TAB(15*X); +630 FOR Z=3 TO LEN(A$(I)) +640 IF MID$(A$(I),Z,1)<>"\" THEN PRINT MID$(A$(I),Z,1);: NEXT Z +645 X=X+1: IF X=4 THEN X=0: PRINT +650 NEXT I +660 PRINT +670 PRINT +680 GOTO 120 +999 END diff --git a/00_Alternate_Languages/04_Awari/README.md b/00_Alternate_Languages/04_Awari/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/04_Awari/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/04_Awari/awari.bas b/00_Alternate_Languages/04_Awari/awari.bas new file mode 100644 index 00000000..78c204e3 --- /dev/null +++ b/00_Alternate_Languages/04_Awari/awari.bas @@ -0,0 +1,70 @@ +5 PRINT TAB(34);"AWARI" +7 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +10 DATA 0 +15 DIM B(13),G(13),F(50):READ N +20 PRINT:PRINT:E=0 +25 FOR I=0 TO 12:B(I)=3:NEXT I +30 C=0:F(N)=0:B(13)=0:B(6)=0 +35 GOSUB 500 +40 PRINT "YOUR MOVE";:GOSUB 110 +45 IF E=0 THEN 80 +50 IF M=H THEN GOSUB 100 +55 IF E=0 THEN 80 +60 PRINT "MY MOVE IS ";:GOSUB 800 +65 IF E=0 THEN 80 +70 IF M=H THEN PRINT ",";:GOSUB 800 +75 IF E>0 THEN 35 +80 PRINT:PRINT"GAME OVER" +85 D=B(6)-B(13):IF D<0 THEN PRINT "I WIN BY";-D;"POINTS":GOTO 20 +90 N=N+1:IF D=0 THEN PRINT "DRAWN GAME":GOTO 20 +95 PRINT "YOU WIN BY";D;"POINTS":GOTO 20 +100 PRINT "AGAIN"; +110 INPUT M:IF M<7 THEN IF M>0 THEN M=M-1:GOTO 130 +120 PRINT "ILLEGAL MOVE":GOTO 100 +130 IF B(M)=0 THEN 120 +140 H=6:GOSUB 200 +150 GOTO 500 +200 K=M:GOSUB 600 +205 E=0:IF K>6 THEN K=K-7 +210 C=C+1:IF C<9 THEN F(N)=F(N)*6+K +215 FOR I=0 TO 5:IF B(I)<>0 THEN 230 +220 NEXT I +225 RETURN +230 FOR I=7 TO 12:IF B(I)<>0 THEN E=1:RETURN +235 GOTO 220 +500 PRINT:PRINT" "; +505 FOR I=12 TO 7 STEP -1:GOSUB 580 +510 NEXT I +515 PRINT:I=13:GOSUB 580 +520 PRINT " ";:PRINT B(6):PRINT " "; +525 FOR I=0 TO 5:GOSUB 580 +530 NEXT I +535 PRINT:PRINT:RETURN +580 IF B(I)<10 THEN PRINT " "; +585 PRINT B(I);:RETURN +600 P=B(M):B(M)=0 +605 FOR P=P TO 1 STEP -1:M=M+1:IF M>13 THEN M=M-14 +610 B(M)=B(M)+1:NEXT P +615 IF B(M)=1 THEN IF M<>6 THEN IF M<>13 THEN IF B(12-M)<>0 THEN 625 +620 RETURN +625 B(H)=B(H)+B(12-M)+1:B(M)=0:B(12-M)=0:RETURN +800 D=-99:H=13 +805 FOR I=0 TO 13:G(I)=B(I):NEXT I +810 FOR J=7 TO 12:IF B(J)=0 THEN 885 +815 Q=0:M=J:GOSUB 600 +820 FOR I=0 TO 5:IF B(I)=0 THEN 845 +825 L=B(I)+I:R=0 +830 IF L>13 THEN L=L-14:R=1:GOTO 830 +835 IF B(L)=0 THEN IF L<>6 THEN IF L<>13 THEN R=B(12-L)+R +840 IF R>Q THEN Q=R +845 NEXT I +850 Q=B(13)-B(6)-Q:IF C>8 THEN 875 +855 K=J:IF K>6 THEN K=K-7 +860 FOR I=0 TO N-1:IF F(N)*6+K=INT(F(I)/6^(7-C)+.1) THEN Q=Q-2 +870 NEXT I +875 FOR I=0 TO 13:B(I)=G(I):NEXT I +880 IF Q>=D THEN A=J:D=Q +885 NEXT J +890 M=A:PRINT CHR$(42+M);:GOTO 200 +900 FOR I=0 TO N-1:PRINT B(I):NEXT I +999 END diff --git a/00_Alternate_Languages/05_Bagels/README.md b/00_Alternate_Languages/05_Bagels/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/05_Bagels/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/05_Bagels/bagels.bas b/00_Alternate_Languages/05_Bagels/bagels.bas new file mode 100644 index 00000000..d16c20c3 --- /dev/null +++ b/00_Alternate_Languages/05_Bagels/bagels.bas @@ -0,0 +1,81 @@ +5 PRINT TAB(33);"BAGELS" +10 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY":PRINT:PRINT +15 REM *** BAGLES NUMBER GUESSING GAME +20 REM *** ORIGINAL SOURCE UNKNOWN BUT SUSPECTED TO BE +25 REM *** LAWRENCE HALL OF SCIENCE, U.C. BERKELY +30 DIM A1(3),A(3),B(3) +40 Y=0:T=255 +50 PRINT:PRINT:PRINT +70 INPUT "WOULD YOU LIKE THE RULES (YES OR NO)";A$ +90 IF LEFT$(A$,1)="N" THEN 150 +100 PRINT:PRINT "I AM THINKING OF A THREE-DIGIT NUMBER. TRY TO GUESS" +110 PRINT "MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:" +120 PRINT " PICO - ONE DIGIT CORRECT BUT IN THE WRONG POSITION" +130 PRINT " FERMI - ONE DIGIT CORRECT AND IN THE RIGHT POSITION" +140 PRINT " BAGELS - NO DIGITS CORRECT" +150 FOR I=1 TO 3 +160 A(I)=INT(10*RND(1)) +165 IF I-1=0 THEN 200 +170 FOR J=1 TO I-1 +180 IF A(I)=A(J) THEN 160 +190 NEXT J +200 NEXT I +210 PRINT:PRINT "O.K. I HAVE A NUMBER IN MIND." +220 FOR I=1 TO 20 +230 PRINT "GUESS #";I, +240 INPUT A$ +245 IF LEN(A$)<>3 THEN 630 +250 FOR Z=1 TO 3:A1(Z)=ASC(MID$(A$,Z,1)):NEXT Z +260 FOR J=1 TO 3 +270 IF A1(J)<48 THEN 300 +280 IF A1(J)>57 THEN 300 +285 B(J)=A1(J)-48 +290 NEXT J +295 GOTO 320 +300 PRINT "WHAT?" +310 GOTO 230 +320 IF B(1)=B(2) THEN 650 +330 IF B(2)=B(3) THEN 650 +340 IF B(3)=B(1) THEN 650 +350 C=0:D=0 +360 FOR J=1 TO 2 +370 IF A(J)<>B(J+1) THEN 390 +380 C=C+1 +390 IF A(J+1)<>B(J) THEN 410 +400 C=C+1 +410 NEXT J +420 IF A(1)<>B(3) THEN 440 +430 C=C+1 +440 IF A(3)<>B(1) THEN 460 +450 C=C+1 +460 FOR J=1 TO 3 +470 IF A(J)<>B(J) THEN 490 +480 D=D+1 +490 NEXT J +500 IF D=3 THEN 680 +505 IF C=0 THEN 545 +520 FOR J=1 TO C +530 PRINT "PICO "; +540 NEXT J +545 IF D=0 THEN 580 +550 FOR J=1 TO D +560 PRINT "FERMI "; +570 NEXT J +580 IF C+D<>0 THEN 600 +590 PRINT "BAGELS"; +600 PRINT +605 NEXT I +610 PRINT "OH WELL." +615 PRINT "THAT'S TWENTY GUESSES. MY NUMBER WAS";100*A(1)+10*A(2)+A(3) +620 GOTO 700 +630 PRINT "TRY GUESSING A THREE-DIGIT NUMBER.":GOTO 230 +650 PRINT "OH, I FORGOT TO TELL YOU THAT THE NUMBER I HAVE IN MIND" +660 PRINT "HAS NO TWO DIGITS THE SAME.":GOTO 230 +680 PRINT "YOU GOT IT!!!":PRINT +690 Y=Y+1 +700 INPUT "PLAY AGAIN (YES OR NO)";A$ +720 IF LEFT$(A$,1)="Y" THEN 150 +730 IF Y=0 THEN 750 +740 PRINT:PRINT "A";Y;"POINT BAGELS BUFF!!" +750 PRINT "HOPE YOU HAD FUN. BYE." +999 END diff --git a/00_Alternate_Languages/06_Banner/README.md b/00_Alternate_Languages/06_Banner/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/06_Banner/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/06_Banner/banner.bas b/00_Alternate_Languages/06_Banner/banner.bas new file mode 100644 index 00000000..3eb50c45 --- /dev/null +++ b/00_Alternate_Languages/06_Banner/banner.bas @@ -0,0 +1,94 @@ +10 INPUT "HORIZONTAL";X +20 INPUT "VERTICAL";Y +21 INPUT "CENTERED";L$ +22 G1=0:IF L$>"P" THEN G1=1 +23 INPUT "CHARACTER (TYPE 'ALL' IF YOU WANT CHARACTER BEING PRINTED)";M$ +29 PRINT "STATEMENT"; +30 INPUT A$ +35 INPUT "SET PAGE";O$ +40 A=ASC(LEFT$(A$,1)) +50 REM +60 REM +70 FOR T=1 TO LEN(A$) +80 P$=MID$(A$,T,1) +90 FOR O=1 TO 50 +95 READ S$,S(1),S(2),S(3),S(4),S(5),S(6),S(7) +96 IF P$=" " THEN 812 +100 IF P$=S$ THEN 200 +120 NEXT O +200 RESTORE +201 X$=M$ +202 IF M$="ALL" THEN X$=S$ +205 FOR U=1 TO 7 +210 FOR K=8 TO 0 STEP -1 +230 IF 2^K 3/5 THEN 420 +400 PRINT O$;" CONTROLS THE TAP." +410 GOTO 3000 +420 PRINT "DARTMOUTH CONTROLS THE TAP." +425 PRINT +430 INPUT "YOUR SHOT";Z +440 P=0 +445 IF Z<>INT(Z) THEN 455 +446 IF Z<0 OR Z>4 THEN 455 +447 GOTO 460 +455 PRINT "INCORRECT ANSWER. RETYPE IT. ";:GOTO 430 +460 IF RND(1)<.5 THEN 1000 +480 IF T<100 THEN 1000 +490 PRINT +491 IF S(1)<>S(0) THEN 510 +492 PRINT:PRINT " ***** END OF SECOND HALF *****":PRINT +493 PRINT "SCORE AT END OF REGULATION TIME:" +494 PRINT " DARTMOUTH:";S(1);" ";O$;":";S(0) +495 PRINT +496 PRINT "BEGIN TWO MINUTE OVERTIME PERIOD" +499 T=93 +500 GOTO 370 +510 PRINT " ***** END OF GAME *****" +515 PRINT "FINAL SCORE: DARTMOUTH:";S(1);" ";O$;":";S(0) +520 STOP +600 PRINT +610 PRINT " *** TWO MINUTES LEFT IN THE GAME ***" +620 PRINT +630 RETURN +1000 ON Z GOTO 1040,1040 +1030 GOTO 1300 +1040 T=T+1 +1041 IF T=50 THEN 8000 +1042 IF T=92 THEN 1046 +1043 GOTO 1050 +1046 GOSUB 600 +1050 PRINT "JUMP SHOT" +1060 IF RND(1)>.341*D/8 THEN 1090 +1070 PRINT "SHOT IS GOOD." +1075 GOSUB 7000 +1085 GOTO 3000 +1090 IF RND(1)>.682*D/8 THEN 1200 +1100 PRINT "SHOT IS OFF TARGET." +1105 IF D/6*RND(1)>.45 THEN 1130 +1110 PRINT "DARTMOUTH CONTROLS THE REBOUND." +1120 GOTO 1145 +1130 PRINT "REBOUND TO ";O$ +1140 GOTO 3000 +1145 IF RND(1)>.4 THEN 1158 +1150 GOTO 1300 +1158 IF D=6 THEN 5100 +1160 PRINT "BALL PASSED BACK TO YOU. "; +1170 GOTO 430 +1180 IF RND(1)>.9 THEN 1190 +1185 PRINT "PLAYER FOULED, TWO SHOTS." +1187 GOSUB 4000 +1188 GOTO 3000 +1190 PRINT "BALL STOLEN. ";O$;"'S BALL." +1195 GOTO 3000 +1200 IF RND(1)>.782*D/8 THEN 1250 +1210 PRINT "SHOT IS BLOCKED. BALL CONTROLLED BY "; +1230 IF RND(1)>.5 THEN 1242 +1235 PRINT "DARTMOUTH." +1240 GOTO 430 +1242 PRINT O$;"." +1245 GOTO 3000 +1250 IF RND(1)>.843*D/8 THEN 1270 +1255 PRINT "SHOOTER IS FOULED. TWO SHOTS." +1260 GOSUB 4000 +1265 GOTO 3000 +1270 PRINT "CHARGING FOUL. DARTMOUTH LOSES BALL." +1280 GOTO 3000 +1300 T=T+1 +1301 IF T=50 THEN 8000 +1302 IF T=92 THEN 1304 +1303 GOTO 1305 +1304 GOSUB 600 +1305 IF Z=0 THEN 2010 +1310 IF Z>3 THEN 1700 +1320 PRINT "LAY UP." +1330 IF 7/D*RND(1)>.4 THEN 1360 +1340 PRINT "SHOT IS GOOD. TWO POINTS." +1345 GOSUB 7000 +1355 GOTO 3000 +1360 IF 7/D*RND(1)>.7 THEN 1500 +1370 PRINT "SHOT IS OFF THE RIM." +1380 IF RND(1)>2/3 THEN 1415 +1390 PRINT O$;" CONTROLS THE REBOUND." +1400 GOTO 3000 +1415 PRINT "DARTMOUTH CONTROLS THE REBOUND." +1420 IF RND(1)>.4 THEN 1440 +1430 GOTO 1300 +1440 PRINT "BALL PASSED BACK TO YOU."; +1450 GOTO 430 +1500 IF 7/D*RND(1)>.875 THEN 1600 +1510 PRINT "SHOOTER FOULED. TWO SHOTS." +1520 GOSUB 4000 +1530 GOTO 3000 +1600 IF 7/D*RND(1)>.925 THEN 1630 +1610 PRINT "SHOT BLOCKED. ";O$;"'S BALL." +1620 GOTO 3000 +1630 PRINT "CHARGING FOUL. DARTMOUTH LOSES THE BALL." +1640 GOTO 3000 +1700 PRINT "SET SHOT." +1710 GOTO 1330 +2010 INPUT "YOUR NEW DEFENSIVE ALLIGNMENT IS";D +2030 IF D<6 THEN 2010 +2040 GOTO 425 +3000 P=1 +3005 T=T+1 +3008 IF T=50 THEN 8000 +3012 GOTO 3018 +3015 GOSUB 600 +3018 PRINT +3020 Z1=10/4*RND(1)+1 +3030 IF Z1>2 THEN 3500 +3040 PRINT "JUMP SHOT." +3050 IF 8/D*RND(1)>.35 THEN 3100 +3060 PRINT "SHOT IS GOOD." +3080 GOSUB 6000 +3090 GOTO 425 +3100 IF 8/D*RND(1)>.75 THEN 3200 +3105 PRINT "SHOT IS OFF RIM." +3110 IF D/6*RND(1)>.5 THEN 3150 +3120 PRINT "DARTMOUTH CONTROLS THE REBOUND." +3130 GOTO 425 +3150 PRINT O$;" CONTROLS THE REBOUND." +3160 IF D=6 THEN 5000 +3165 IF RND(1)>.5 THEN 3175 +3168 PRINT "PASS BACK TO ";O$;" GUARD." +3170 GOTO 3000 +3175 GOTO 3500 +3200 IF 8/D*RND(1)>.9 THEN 3310 +3210 PRINT "PLAYER FOULED. TWO SHOTS." +3220 GOSUB 4000 +3230 GOTO 425 +3310 PRINT "OFFENSIVE FOUL. DARTMOUTH'S BALL." +3320 GOTO 425 +3500 IF Z1>3 THEN 3800 +3510 PRINT "LAY UP." +3520 IF 7/D*RND(1)>.413 THEN 3600 +3530 PRINT "SHOT IS GOOD." +3540 GOSUB 6000 +3550 GOTO 425 +3600 PRINT "SHOT IS MISSED." +3610 GOTO 3110 +3800 PRINT "SET SHOT." +3810 GOTO 3520 +4000 REM FOUL SHOOTING +4010 IF RND(1)>.49 THEN 4050 +4020 PRINT "SHOOTER MAKES BOTH SHOTS." +4030 S(1-P)=S(1-P)+2 +4040 GOSUB 6010 +4041 RETURN +4050 IF RND(1)>.75 THEN 4100 +4060 PRINT "SHOOTER MAKES ONE SHOT AND MISSES ONE." +4070 S(1-P)=S(1-P)+1 +4080 GOTO 4040 +4100 PRINT "BOTH SHOTS MISSED." +4110 GOTO 4040 +5000 IF RND(1)>.75 THEN 5010 +5005 GOTO 3165 +5010 PRINT "BALL STOLEN. EASY LAY UP FOR DARTMOUTH." +5015 GOSUB 7000 +5030 GOTO 3000 +5100 IF RND(1)>.6 THEN 5120 +5110 GOTO 1160 +5120 PRINT "PASS STOLEN BY ";O$;" EASY LAYUP." +5130 GOSUB 6000 +5140 GOTO 425 +6000 S(0)=S(0)+2 +6010 PRINT "SCORE: ";S(1);"TO";S(0) +6020 RETURN +7000 S(1)=S(1)+2 +7010 GOSUB 6010 +7020 RETURN +8000 PRINT:PRINT " ***** END OF FIRST HALF *****":PRINT +8010 PRINT "SCORE: DARTMOUTH:";S(1);" ";O$;":";S(0) +8015 PRINT +8016 PRINT +8020 GOTO 370 +9999 END diff --git a/00_Alternate_Languages/08_Batnum/README.md b/00_Alternate_Languages/08_Batnum/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/08_Batnum/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/08_Batnum/batnum.bas b/00_Alternate_Languages/08_Batnum/batnum.bas new file mode 100644 index 00000000..40ec8616 --- /dev/null +++ b/00_Alternate_Languages/08_Batnum/batnum.bas @@ -0,0 +1,90 @@ +10 PRINT TAB(33);"BATNUM" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT:PRINT:PRINT +110 PRINT "THIS PROGRAM IS A 'BATTLE OF NUMBERS' GAME, WHERE THE" +120 PRINT "COMPUTER IS YOUR OPPONENT." +130 PRINT +140 PRINT "THE GAME STARTS WITH AN ASSUMED PILE OF OBJECTS. YOU" +150 PRINT "AND YOUR OPPONENT ALTERNATELY REMOVE OBJECTS FROM THE PILE." +160 PRINT "WINNING IS DEFINED IN ADVANCE AS TAKING THE LAST OBJECT OR" +170 PRINT "NOT. YOU CAN ALSO SPECIFY SOME OTHER BEGINNING CONDITIONS." +180 PRINT "DON'T USE ZERO, HOWEVER, IN PLAYING THE GAME." +190 PRINT "ENTER A NEGATIVE NUMBER FOR NEW PILE SIZE TO STOP PLAYING." +200 PRINT +210 GOTO 330 +220 FOR I=1 TO 10 +230 PRINT +240 NEXT I +330 INPUT "ENTER PILE SIZE";N +350 IF N>=1 THEN 370 +360 GOTO 330 +370 IF N<>INT(N) THEN 220 +380 IF N<1 THEN 220 +390 INPUT "ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST: ";M +410 IF M=1 THEN 430 +420 IF M<>2 THEN 390 +430 INPUT "ENTER MIN AND MAX ";A,B +450 IF A>B THEN 430 +460 IF A<1 THEN 430 +470 IF A<>INT(A) THEN 430 +480 IF B<>INT(B) THEN 430 +490 INPUT "ENTER START OPTION - 1 COMPUTER FIRST, 2 YOU FIRST ";S +500 PRINT:PRINT +510 IF S=1 THEN 530 +520 IF S<>2 THEN 490 +530 C=A+B +540 IF S=2 THEN 570 +550 GOSUB 600 +560 IF W=1 THEN 220 +570 GOSUB 810 +580 IF W=1 THEN 220 +590 GOTO 550 +600 Q=N +610 IF M=1 THEN 630 +620 Q=Q-1 +630 IF M=1 THEN 680 +640 IF N>A THEN 720 +650 W=1 +660 PRINT "COMPUTER TAKES";N;"AND LOSES." +670 RETURN +680 IF N>B THEN 720 +690 W=1 +700 PRINT "COMPUTER TAKES";N;"AND WINS." +710 RETURN +720 P=Q-C*INT(Q/C) +730 IF P>=A THEN 750 +740 P=A +750 IF P<=B THEN 770 +760 P=B +770 N=N-P +780 PRINT "COMPUTER TAKES";P;"AND LEAVES";N +790 W=0 +800 RETURN +810 PRINT:PRINT "YOUR MOVE "; +820 INPUT P +830 IF P<>0 THEN 870 +840 PRINT "I TOLD YOU NOT TO USE ZERO! COMPUTER WINS BY FORFEIT." +850 W=1 +860 RETURN +870 IF P<>INT(P) THEN 920 +880 IF P>=A THEN 910 +890 IF P=N THEN 960 +900 GOTO 920 +910 IF P<=B THEN 940 +920 PRINT "ILLEGAL MOVE, REENTER IT "; +930 GOTO 820 +940 N=N-P +950 IF N<>0 THEN 1030 +960 IF M=1 THEN 1000 +970 PRINT "TOUGH LUCK, YOU LOSE." +980 W=1 +990 RETURN +1000 PRINT "CONGRATULATIONS, YOU WIN." +1010 W=1 +1020 RETURN +1030 IF N>=0 THEN 1060 +1040 N=N+P +1050 GOTO 920 +1060 W=0 +1070 RETURN +1080 END diff --git a/00_Alternate_Languages/09_Battle/README.md b/00_Alternate_Languages/09_Battle/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/09_Battle/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/09_Battle/battle.bas b/00_Alternate_Languages/09_Battle/battle.bas new file mode 100644 index 00000000..6f85f567 --- /dev/null +++ b/00_Alternate_Languages/09_Battle/battle.bas @@ -0,0 +1,196 @@ +5 PRINT TAB(33);"BATTLE" +7 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +10 REM -- BATTLE WRITTEN BY RAY WESTERGARD 10/70 +20 REM COPYRIGHT 1971 BY THE REGENTS OF THE UNIV. OF CALIF. +30 REM PRODUCED AT THE LAWRENCE HALL OF SCIENCE, BERKELEY +40 DIM F(6,6),H(6,6),A(4),B(4),C(6),L(3) +50 FOR X=1 TO 6 +51 FOR Y=1 TO 6 +52 F(X,Y)=0 +53 NEXT Y +54 NEXT X +60 FOR I=1 TO 3 +70 N=4-I +80 FOR J=1 TO 2 +90 A=INT(6*RND(1)+1) +100 B=INT(6*RND(1)+1) +110 D=INT(4*RND(1)+1) +120 IF F(A,B)>0 THEN 90 +130 M=0 +140 ON D GOTO 150,340,550,740 +150 B(1)=B +160 B(2)=7:B(3)=7 +170 FOR K=1 TO N +180 IF M>1 THEN 240 +190 IF B(K)=6 THEN 230 +200 IF F(A,B(K)+1)>0 THEN 230 +210 B(K+1)=B(K)+1 +220 GOTO 280 +230 M=2 +240 IF B(1)0 THEN 90 +270 B(K+1)=Z-1 +280 NEXT K +290 F(A,B)=9-2*I-J +300 FOR K=1 TO N +310 F(A,B(K+1))=F(A,B) +320 NEXT K +330 GOTO 990 +340 A(1)=A +350 B(1)=B +360 A(2)=0:A(3)=0:B(2)=0:B(3)=0 +370 FOR K=1 TO N +380 IF M>1 THEN 460 +390 IF A(K)=1 OR B(K)=1 THEN 450 +400 IF F(A(K)-1,B(K)-1)>0 THEN 450 +410 IF F(A(K)-1,B(K))>0 AND F(A(K)-1,B(K))=F(A(K),B(K)-1) THEN 450 +420 A(K+1)=A(K)-1 +430 B(K+1)=B(K)-1 +440 GOTO 530 +450 M=2 +460 IF A(1)>A(2) AND A(1)>A(3) THEN Z1=A(1) +462 IF A(2)>A(1) AND A(2)>A(3) THEN Z1=A(2) +464 IF A(3)>A(1) AND A(3)>A(2) THEN Z1=A(3) +470 IF B(1)>B(2) AND B(1)>B(3) THEN Z2=B(1) +474 IF B(2)>B(1) AND B(2)>B(3) THEN Z2=B(2) +476 IF B(3)>B(1) AND B(3)>B(2) THEN Z2=B(3) +480 IF Z1=6 OR Z2=6 THEN 90 +490 IF F(Z1+1,Z2+1)>0 THEN 90 +500 IF F(Z1,Z2+1)>0 AND F(Z1,Z2+1)=F(Z1+1,Z2) THEN 90 +510 A(K+1)=Z1+1 +520 B(K+1)=Z2+1 +530 NEXT K +540 GOTO 950 +550 A(1)=A +560 A(2)=7:A(3)=7 +570 FOR K=1 TO N +580 IF M>1 THEN 640 +590 IF A(K)=6 THEN 630 +600 IF F(A(K)+1,B)>0 THEN 630 +610 A(K+1)=A(K)+1 +620 GOTO 680 +630 M=2 +640 IF A(1)0 THEN 90 +670 A(K+1)=Z-1 +680 NEXT K +690 F(A,B)=9-2*I-J +700 FOR K=1 TO N +710 F(A(K+1),B)=F(A,B) +720 NEXT K +730 GOTO 990 +740 A(1)=A +750 B(1)=B +760 A(2)=7:A(3)=7 +770 B(2)=0:B(3)=0 +780 FOR K=1 TO N +790 IF M>1 THEN 870 +800 IF A(K)=6 OR B(K)=1 THEN 860 +810 IF F(A(K)+1,B(K)-1)>0 THEN 860 +820 IF F(A(K)+1,B(K))>0 AND F(A(K)+1,B(K))=F(A(K),B(K)-1) THEN 860 +830 A(K+1)=A(K)+1 +840 B(K+1)=B(K)-1 +850 GOTO 940 +860 M=2 +870 IF A(1)B(2) AND B(1)>B(3) THEN Z2=B(1) +882 IF B(2)>B(1) AND B(2)>B(3) THEN Z2=B(2) +884 IF B(3)>B(1) AND B(3)>B(2) THEN Z2=B(3) +890 IF Z1=1 OR Z2=6 THEN 90 +900 IF F(Z1-1,Z2+1)>0 THEN 90 +910 IF F(Z1,Z2+1)>0 AND F(Z1,Z2+1)=F(Z1-1,Z2) THEN 90 +920 A(K+1)=Z1-1 +930 B(K+1)=Z2+1 +940 NEXT K +950 F(A,B)=9-2*I-J +960 FOR K=1 TO N +970 F(A(K+1),B(K+1))=F(A,B) +980 NEXT K +990 NEXT J +1000 NEXT I +1010 PRINT +1020 PRINT "THE FOLLOWING CODE OF THE BAD GUYS' FLEET DISPOSITION" +1030 PRINT "HAS BEEN CAPTURED BUT NOT DECODED:" +1040 PRINT +1050 FOR I=1 TO 6 +1051 FOR J=1 TO 6 +1052 H(I,J)=F(J,I) +1053 NEXT J +1054 NEXT I +1060 FOR I=1 TO 6 +1061 FOR J=1 TO 6 +1062 PRINT H(I,J); +1063 NEXT J +1064 PRINT +1065 NEXT I +1070 PRINT +1080 PRINT "DE-CODE IT AND USE IT IF YOU CAN" +1090 PRINT "BUT KEEP THE DE-CODING METHOD A SECRET." +1100 PRINT +1110 FOR I=1 TO 6 +1111 FOR J=1 TO 6 +1112 H(I,J)=0 +1113 NEXT J +1114 NEXT I +1120 FOR I=1 TO 3 +1121 L(I)=0 +1122 NEXT I +1130 C(1)=2:C(2)=2 +1140 C(3)=1:C(4)=1 +1150 C(5)=0:C(6)=0 +1160 S=0:H=0 +1170 PRINT "START GAME" +1180 INPUT X,Y +1190 IF X<1 OR X>6 OR INT(X)<>ABS(X) THEN 1210 +1200 IF Y>0 AND Y<7 AND INT(Y)=ABS(Y) THEN 1230 +1210 PRINT "INVALID INPUT. TRY AGAIN." +1220 GOTO 1180 +1230 R=7-Y +1240 C=X +1250 IF F(R,C)>0 THEN 1290 +1260 S=S+1 +1270 PRINT "SPLASH! TRY AGAIN." +1280 GOTO 1180 +1290 IF C(F(R,C))<4 THEN 1340 +1300 PRINT "THERE USED TO BE A SHIP AT THAT POINT, BUT YOU SUNK IT." +1310 PRINT "SPLASH! TRY AGAIN." +1320 S=S+1 +1330 GOTO 1180 +1340 IF H(R,C)>0 THEN 1420 +1350 H=H+1 +1360 H(R,C)=F(R,C) +1370 PRINT "A DIRECT HIT ON SHIP NUMBER";F(R,C) +1380 C(F(R,C))=C(F(R,C))+1 +1390 IF C(F(R,C))>=4 THEN 1470 +1400 PRINT "TRY AGAIN." +1410 GOTO 1180 +1420 PRINT "YOU ALREADY PUT A HOLE IN SHIP NUMBER";F(R,C); +1430 PRINT "AT THAT POINT." +1440 PRINT "SPLASH! TRY AGAIN." +1450 S=S+1 +1460 GOTO 1180 +1470 L((INT(F(R,C)-1)/2)+1)=L((INT(F(R,C)-1)/2)+1)+1 +1480 PRINT "AND YOU SUNK IT. HURRAH FOR THE GOOD GUYS." +1490 PRINT "SO FAR, THE BAD GUYS HAVE LOST" +1500 PRINT L(1);"DESTROYER(S),";L(2);"CRUISER(S), AND"; +1510 PRINT L(3);"AIRCRAFT CARRIER(S)." +1520 PRINT "YOUR CURRENT SPLASH/HIT RATIO IS";S/H +1530 IF (L(1)+L(2)+L(3))<6 THEN 1180 +1540 PRINT +1550 PRINT "YOU HAVE TOTALLY WIPED OUT THE BAD GUYS' FLEET" +1560 PRINT "WITH A FINAL SPLASH/HIT RATIO OF";S/H +1570 IF S/H>0 THEN 1590 +1580 PRINT "CONGRATULATIONS -- A DIRECT HIT EVERY TIME." +1590 PRINT +1600 PRINT "****************************" +1610 PRINT +1620 GOTO 50 +1630 END diff --git a/00_Alternate_Languages/10_Blackjack/README.md b/00_Alternate_Languages/10_Blackjack/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/10_Blackjack/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/10_Blackjack/blackjack.bas b/00_Alternate_Languages/10_Blackjack/blackjack.bas new file mode 100644 index 00000000..121c6502 --- /dev/null +++ b/00_Alternate_Languages/10_Blackjack/blackjack.bas @@ -0,0 +1,321 @@ +2 PRINT TAB(31);"BLACK JACK" +4 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +6 PRINT:PRINT:PRINT +10 DEF FNA(Q)=Q+11*(Q>=22) +20 DIM P(15,12),Q(15),C(52),D(52),T(8),S(7),B(15) +30 DIM R(15) +40 REM--P(I,J) IS THE JTH CARD IN HAND I, Q(I) IS TOTAL OF HAND I +50 REM--C IS THE DECK BEING DEALT FROM, D IS THE DISCARD PILE, +60 REM--T(I) IS THE TOTAL FOR PLAYER I, S(I) IS THE TOTAL THIS HAND FOR +70 REM--PLAYER I, B(I) IS TH BET FOR HAND I +80 REM--R(I) IS THE LENGTH OF P(I,*) +90 GOTO 1500 +100 REM--SUBROUTINE TO GET A CARD. RESULT IS PUT IN X. +110 IF C<51 THEN 230 +120 PRINT "RESHUFFLING" +130 FOR D=D TO 1 STEP -1 +140 C=C-1 +150 C(C)=D(D) +160 NEXT D +170 FOR C1=52 TO C STEP -1 +180 C2=INT(RND(1)*(C1-C+1))+C +190 C3=C(C2) +200 C(C2)=C(C1) +210 C(C1)=C3 +220 NEXT C1 +230 X=C(C) +240 C=C+1 +250 RETURN +300 REM--SUBROUTINE TO EVALUATE HAND I. TOTAL IS PUT INTO +310 REM--Q(I). TOTALS HAVE THE FOLLOWING MEANING: +320 REM-- 2-10...HARD 2-10 +330 REM-- 11-21...SOFT 11-21 +340 REM-- 22-32...HARD 11-21 +350 REM-- 33+....BUSTED +360 Q=0 +370 FOR Q2=1 TO R(I) +380 X=P(I,Q2) +390 GOSUB 500 +400 NEXT Q2 +410 Q(I)=Q +420 RETURN +500 REM--SUBROUTINE TO ADD CARD X TO TOTAL Q. +510 X1=X: IF X1>10 THEN X1=10: REM SAME AS X1=10 MIN X +520 Q1=Q+X1 +530 IF Q>=11 THEN 590 +540 IF X>1 THEN 570 +550 Q=Q+11 +560 RETURN +570 Q=Q1-11*(Q1>=11) +580 RETURN +590 Q=Q1-(Q<=21 AND Q1>21) +600 IF Q<33 THEN 620 +610 Q=-1 +620 RETURN +700 REM--CARD PRINTING SUBROUTINE +710 REM D$ DEFINED ELSEWHERE +720 PRINT MID$(D$,3*X-2,3); +730 PRINT " "; +740 RETURN +750 REM--ALTERNATIVE PRINTING ROUTINE +760 PRINT " ";MID$(D$,3*X-1,2); +770 PRINT " "; +780 RETURN +800 REM--SUBROUTINE TO PLAY OUT A HAND. +810 REM--NO SPLITTING OR BLACKJACKS ALLOWED +820 H1=5 +830 GOSUB 1410 +840 H1=3 +850 ON H GOTO 950,930 +860 GOSUB 100 +870 B(I)=B(I)*2 +880 PRINT "RECEIVED A"; +890 GOSUB 700 +900 GOSUB 1100 +910 IF Q>0 THEN GOSUB 1300 +920 RETURN +930 GOSUB 1320 +940 RETURN +950 GOSUB 100 +960 PRINT "RECEIVED A"; +970 GOSUB 700 +980 GOSUB 1100 +990 IF Q<0 THEN 940 +1000 PRINT "HIT"; +1010 GOTO 830 +1100 REM--SUBROUTINE TO ADD A CARD TO ROW I +1110 R(I)=R(I)+1 +1120 P(I,R(I))=X +1130 Q=Q(I) +1140 GOSUB 500 +1150 Q(I)=Q +1160 IF Q>=0 THEN 1190 +1170 PRINT "...BUSTED" +1180 GOSUB 1200 +1190 RETURN +1200 REM--SUBROUTINE TO DISCARD ROW I +1210 IF R(I)<>0 THEN 1230 +1220 RETURN +1230 D=D+1 +1240 D(D)=P(I,R(I)) +1250 R(I)=R(I)-1 +1260 GOTO 1210 +1300 REM--PRINTS TOTAL OF HAND I +1310 PRINT +1320 AA=Q(I): GOSUB 3400 +1325 PRINT "TOTAL IS";AA +1330 RETURN +1400 REM--SUBROUTINE TO READ REPLY +1410 REM I$ DEFINED ELSEWHERE +1420 INPUT H$: H$=LEFT$(H$,1) +1430 FOR H=1 TO H1 STEP 2 +1440 IF H$=MID$(I$,H,1) THEN 1480 +1450 NEXT H +1460 PRINT "TYPE ";MID$(I$,1,H1-1);" OR ";MID$(I$,H1,2);" PLEASE"; +1470 GOTO 1420 +1480 H=(H+1)/2 +1490 RETURN +1500 REM--PROGRAM STARTS HERE +1510 REM--INITIALIZE +1520 D$="N A 2 3 4 5 6 7N 8 9 10 J Q K" +1530 I$="H,S,D,/," +1540 FOR I=1 TO 13 +1550 FOR J=4*I-3 TO 4*I +1560 D(J)=I +1570 NEXT J +1580 NEXT I +1590 D=52 +1600 C=53 +1610 PRINT "DO YOU WANT INSTRUCTIONS"; +1620 INPUT H$ +1630 IF LEFT$(H$,1)="N" OR LEFT$(H$,1)="n" THEN 1760 +1640 PRINT "THIS IS THE GAME OF 21. AS MANY AS 7 PLAYERS MAY PLAY THE" +1650 PRINT "GAME. ON EACH DEAL, BETS WILL BE ASKED FOR, AND THE" +1660 PRINT "PLAYERS' BETS SHOULD BE TYPED IN. THE CARDS WILL THEN BE" +1670 PRINT "DEALT, AND EACH PLAYER IN TURN PLAYS HIS HAND. THE" +1680 PRINT "FIRST RESPONSE SHOULD BE EITHER 'D', INDICATING THAT THE" +1690 PRINT "PLAYER IS DOUBLING DOWN, 'S', INDICATING THAT HE IS" +1700 PRINT "STANDING, 'H', INDICATING HE WANTS ANOTHER CARD, OR '/'," +1710 PRINT "INDICATING THAT HE WANTS TO SPLIT HIS CARDS. AFTER THE" +1720 PRINT "INITIAL RESPONSE, ALL FURTHER RESPONSES SHOULD BE 'S' OR" +1730 PRINT "'H', UNLESS THE CARDS WERE SPLIT, IN WHICH CASE DOUBLING" +1740 PRINT "DOWN IS AGAIN PERMITTED. IN ORDER TO COLLECT FOR" +1750 PRINT "BLACKJACK, THE INITIAL RESPONSE SHOULD BE 'S'." +1760 PRINT "NUMBER OF PLAYERS"; +1770 INPUT N +1775 PRINT +1780 IF N<1 OR N>7 OR N>INT(N) THEN 1760 +1790 FOR I=1 TO 8: T(I)=0: NEXT I +1800 D1=N+1 +1810 IF 2*D1+C>=52 THEN GOSUB 120 +1820 IF C=2 THEN C=C-1 +1830 FOR I=1 TO N: Z(I)=0: NEXT I +1840 FOR I=1 TO 15: B(I)=0: NEXT I +1850 FOR I=1 TO 15: Q(I)=0: NEXT I +1860 FOR I=1 TO 7: S(I)=0: NEXT I +1870 FOR I=1 TO 15: R(I)=0: NEXT I +1880 PRINT "BETS:" +1890 FOR I=1 TO N: PRINT "#";I;: INPUT Z(I): NEXT I +1900 FOR I=1 TO N +1910 IF Z(I)<=0 OR Z(I)>500 THEN 1880 +1920 B(I)=Z(I) +1930 NEXT I +1940 PRINT "PLAYER"; +1950 FOR I=1 TO N +1960 PRINT I;" "; +1970 NEXT I +1980 PRINT "DEALER" +1990 FOR J=1 TO 2 +2000 PRINT TAB(5); +2010 FOR I=1 TO D1 +2020 GOSUB 100 +2030 P(I,J)=X +2040 IF J=1 OR I<=N THEN GOSUB 750 +2050 NEXT I +2060 PRINT +2070 NEXT J +2080 FOR I=1 TO D1 +2090 R(I)=2 +2100 NEXT I +2110 REM--TEST FOR INSURANCE +2120 IF P(D1,1)>1 THEN 2240 +2130 PRINT "ANY INSURANCE"; +2140 INPUT H$ +2150 IF LEFT$(H$,1)<>"Y" THEN 2240 +2160 PRINT "INSURANCE BETS" +2170 FOR I=1 TO N: PRINT "#";I;: INPUT Z(I): NEXT I +2180 FOR I=1 TO N +2190 IF Z(I)<0 OR Z(I)>B(I)/2 THEN 2160 +2200 NEXT I +2210 FOR I=1 TO N +2220 S(I)=Z(I)*(3*(-(P(D1,2)>=10))-1) +2230 NEXT I +2240 REM--TEST FOR DEALER BLACKJACK +2250 L1=1: L2=1 +2252 IF P(D1,1)=1 AND P(D1,2)>9 THEN L1=0: L2=0 +2253 IF P(D1,2)=1 AND P(D1,1)>9 THEN L1=0: L2=0 +2254 IF L1<>0 OR L2<>0 THEN 2320 +2260 PRINT:PRINT "DEALER HAS A";MID$(D$,3*P(D1,2)-2,3);" IN THE HOLE "; +2270 PRINT "FOR BLACKJACK" +2280 FOR I=1 TO D1 +2290 GOSUB 300 +2300 NEXT I +2310 GOTO 3140 +2320 REM--NO DEALER BLACKJACK +2330 IF P(D1,1)>1 AND P(D1,1)<10 THEN 2350 +2340 PRINT:PRINT "NO DEALER BLACKJACK." +2350 REM--NOW PLAY THE HANDS +2360 FOR I=1 TO N +2370 PRINT "PLAYER";I; +2380 H1=7 +2390 GOSUB 1410 +2400 ON H GOTO 2550,2410,2510,2600 +2410 REM--PLAYER WANTS TO STAND +2420 GOSUB 300 +2430 IF Q(I)<>21 THEN 2490 +2440 PRINT "BLACKJACK" +2450 S(I)=S(I)+1.5*B(I) +2460 B(I)=0 +2470 GOSUB 1200 +2480 GOTO 2900 +2490 GOSUB 1320 +2500 GOTO 2900 +2510 REM--PLAYER WANTS TO DOUBLE DOWN +2520 GOSUB 300 +2530 GOSUB 860 +2540 GOTO 2900 +2550 REM--PLAYER WANTS TO BE HIT +2560 GOSUB 300 +2570 H1=3 +2580 GOSUB 950 +2590 GOTO 2900 +2600 REM--PLAYER WANTS TO SPLIT +2610 L1=P(I,1): IF P(I,1)>10 THEN L1=10 +2612 L2=P(I,2): IF P(I,2)>10 THEN L2=10 +2614 IF L1=L2 THEN 2640 +2620 PRINT "SPLITTING NOT ALLOWED." +2630 GOTO 2370 +2640 REM--PLAY OUT SPLIT +2650 I1=I+D1 +2660 R(I1)=2 +2670 P(I1,1)=P(I,2) +2680 B(I+D1)=B(I) +2690 GOSUB 100 +2700 PRINT "FIRST HAND RECEIVES A"; +2710 GOSUB 700 +2720 P(I,2)=X +2730 GOSUB 300 +2740 PRINT +2750 GOSUB 100 +2760 PRINT "SECOND HAND RECEIVES A"; +2770 I=I1 +2780 GOSUB 700 +2790 P(I,2)=X +2800 GOSUB 300 +2810 PRINT +2820 I=I1-D1 +2830 IF P(I,1)=1 THEN 2900 +2840 REM--NOW PLAY THE TWO HANDS +2850 PRINT "HAND";1-(I>D1); +2860 GOSUB 800 +2870 I=I+D1 +2880 IF I=I1 THEN 2850 +2890 I=I1-D1 +2900 NEXT I +2910 GOSUB 300 +2920 REM--TEST FOR PLAYING DEALER'S HAND +2930 FOR I=1 TO N +2940 IF R(I)>0 OR R(I+D1)>0 THEN 3010 +2950 NEXT I +2960 PRINT "DEALER HAD A"; +2970 X=P(D1,2) +2980 GOSUB 700 +2990 PRINT " CONCEALED." +3000 GOTO 3140 +3010 PRINT "DEALER HAS A";MID$(D$,3*P(D1,2)-2,3);" CONCEALED "; +3020 I=D1 +3030 AA=Q(I): GOSUB 3400 +3035 PRINT "FOR A TOTAL OF";AA +3040 IF AA>16 THEN 3130 +3050 PRINT "DRAWS"; +3060 GOSUB 100 +3070 GOSUB 750 +3080 GOSUB 1100 +3090 AA=Q: GOSUB 3400 +3095 IF Q>0 AND AA<17 THEN 3060 +3100 Q(I)=Q-(Q<0)/2 +3110 IF Q<0 THEN 3140 +3120 AA=Q: GOSUB 3400 +3125 PRINT "---TOTAL IS";AA +3130 PRINT +3140 REM--TALLY THE RESULT +3150 REM +3160 Z$="LOSES PUSHES WINS " +3165 PRINT +3170 FOR I=1 TO N +3180 AA=Q(I): GOSUB 3400 +3182 AB=Q(I+D1): GOSUB 3410 +3184 AC=Q(D1): GOSUB 3420 +3186 S(I)=S(I)+B(I)*SGN(AA-AC)+B(I+D1)*SGN(AB-AC) +3188 B(I+D1)=0 +3200 PRINT "PLAYER";I; +3210 PRINT MID$(Z$,SGN(S(I))*6+7,6);" "; +3220 IF S(I)<>0 THEN 3250 +3230 PRINT " "; +3240 GOTO 3260 +3250 PRINT ABS(S(I)); +3260 T(I)=T(I)+S(I) +3270 PRINT "TOTAL=";T(I) +3280 GOSUB 1200 +3290 T(D1)=T(D1)-S(I) +3300 I=I+D1 +3310 GOSUB 1200 +3320 I=I-D1 +3330 NEXT I +3340 PRINT "DEALER'S TOTAL=";T(D1) +3345 PRINT +3350 GOSUB 1200 +3360 GOTO 1810 +3400 AA=AA+11*(AA>=22): RETURN +3410 AB=AB+11*(AB>=22): RETURN +3420 AC=AC+11*(AC>=22): RETURN diff --git a/03_Animal/pascal/README.md b/00_Alternate_Languages/10_Blackjack/pascal/README.md similarity index 100% rename from 03_Animal/pascal/README.md rename to 00_Alternate_Languages/10_Blackjack/pascal/README.md diff --git a/00_Alternate_Languages/11_Bombardment/README.md b/00_Alternate_Languages/11_Bombardment/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/11_Bombardment/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/11_Bombardment/bombardment.bas b/00_Alternate_Languages/11_Bombardment/bombardment.bas new file mode 100644 index 00000000..0c2950ce --- /dev/null +++ b/00_Alternate_Languages/11_Bombardment/bombardment.bas @@ -0,0 +1,93 @@ +10 PRINT TAB(33);"BOMBARDMENT" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT:PRINT:PRINT +100 PRINT "YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU" +110 PRINT "HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED." +120 PRINT "YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST." +130 PRINT "THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS." +135 PRINT +140 PRINT "THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE" +150 PRINT "OUTPOSTS OF THE COMPUTER. IT WILL DO THE SAME TO YOU." +160 PRINT "THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS" +170 PRINT "FIRST IS THE WINNER." +180 PRINT +190 PRINT "GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!" +200 PRINT +210 PRINT "TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS." +220 FOR R=1 TO 5: PRINT: NEXT R +260 DIM M(100) +270 FOR R=1 TO 5 +280 I=(R-1)*5+1 +290 PRINT I,I+1,I+2,I+3,I+4 +300 NEXT R +350 FOR R=1 TO 10: PRINT: NEXT R +380 C=INT(RND(1)*25)+1 +390 D=INT(RND(1)*25)+1 +400 E=INT(RND(1)*25)+1 +410 F=INT(RND(1)*25)+1 +420 IF C=D THEN 390 +430 IF C=E THEN 400 +440 IF C=F THEN 410 +450 IF D=E THEN 400 +460 IF D=F THEN 410 +470 IF E=F THEN 410 +480 PRINT "WHAT ARE YOUR FOUR POSITIONS"; +490 INPUT G,H,K,L +495 PRINT +500 PRINT "WHERE DO YOU WISH TO FIRE YOUR MISSLE"; +510 INPUT Y +520 IF Y=C THEN 710 +530 IF Y=D THEN 710 +540 IF Y=E THEN 710 +550 IF Y=F THEN 710 +560 GOTO 630 +570 M=INT(RND(1)*25)+1 +575 GOTO 1160 +580 IF X=G THEN 920 +590 IF X=H THEN 920 +600 IF X=L THEN 920 +610 IF X=K THEN 920 +620 GOTO 670 +630 PRINT "HA, HA YOU MISSED. MY TURN NOW:" +640 PRINT: PRINT: GOTO 570 +670 PRINT "I MISSED YOU, YOU DIRTY RAT. I PICKED";M". YOUR TURN:" +680 PRINT: PRINT: GOTO 500 +710 Q=Q+1 +720 IF Q=4 THEN 890 +730 PRINT "YOU GOT ONE OF MY OUTPOSTS!" +740 IF Q=1 THEN 770 +750 IF Q=2 THEN 810 +760 IF Q=3 THEN 850 +770 PRINT "ONE DOWN, THREE TO GO." +780 PRINT: PRINT: GOTO 570 +810 PRINT "TWO DOWN, TWO TO GO." +820 PRINT: PRINT: GOTO 570 +850 PRINT "THREE DOWN, ONE TO GO." +860 PRINT: PRINT: GOTO 570 +890 PRINT "YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN" +900 PRINT "MY TRANSISTO&S RECUP%RA*E!" +910 GOTO 1235 +920 Z=Z+1 +930 IF Z=4 THEN 1110 +940 PRINT "I GOT YOU. IT WON'T BE LONG NOW. POST";X;"WAS HIT." +950 IF Z=1 THEN 990 +960 IF Z=2 THEN 1030 +970 IF Z=3 THEN 1070 +990 PRINT "YOU HAVE ONLY THREE OUTPOSTS LEFT." +1000 PRINT: PRINT: GOTO 500 +1030 PRINT "YOU HAVE ONLY TWO OUTPOSTS LEFT." +1040 PRINT: PRINT: GOTO 500 +1070 PRINT "YOU HAVE ONLY ONE OUTPOST LEFT." +1080 PRINT: PRINT: GOTO 500 +1110 PRINT "YOU'RE DEAD. YOUR LAST OUTPOST WAS AT";X;". HA, HA, HA." +1120 PRINT "BETTER LUCK NEXT TIME." +1150 GOTO 1235 +1160 P=P+1 +1170 N=P-1 +1180 FOR T=1 TO N +1190 IF M=M(T) THEN 570 +1200 NEXT T +1210 X=M +1220 M(P)=M +1230 GOTO 580 +1235 END diff --git a/00_Alternate_Languages/12_Bombs_Away/README.md b/00_Alternate_Languages/12_Bombs_Away/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/12_Bombs_Away/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/12_Bombs_Away/bombsaway.bas b/00_Alternate_Languages/12_Bombs_Away/bombsaway.bas new file mode 100644 index 00000000..bbf61c8a --- /dev/null +++ b/00_Alternate_Languages/12_Bombs_Away/bombsaway.bas @@ -0,0 +1,65 @@ +8 PRINT "YOU ARE A PILOT IN A WORLD WAR II BOMBER." +10 INPUT "WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)";A +20 IF A>0 AND A<5 THEN 25 +22 PRINT "TRY AGAIN..." : GOTO 10 +25 ON A GOTO 30, 110, 200, 220 +30 INPUT "YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)";B +40 IF B>0 AND B<4 THEN 45 +42 PRINT "TRY AGAIN..." : GOTO 30 +45 PRINT : ON B GOTO 50, 80,90 +50 PRINT "SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE." +60 GOTO 280 +80 PRINT "BE CAREFUL!!!" : GOTO 280 +90 PRINT "YOU'RE GOING FOR THE OIL, EH?" : GOTO 280 +110 INPUT "AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)";G +120 IF G>0 AND G<5 THEN 125 +122 PRINT "TRY AGAIN..." : GOTO 110 +125 PRINT : ON G GOTO 130, 150, 170, 190 +130 PRINT "YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI." : GOTO 280 +150 PRINT "YOU'RE DUMPING THE A-BOMB ON HIROSHIMA." : GOTO 280 +170 PRINT "YOU'RE CHASING THE BISMARK IN THE NORTH SEA." : GOTO 280 +190 PRINT "YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR." +195 GOTO 280 +200 PRINT "YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON." +205 INPUT "YOUR FIRST KAMIKAZE MISSION(Y OR N)";F$ +207 IF F$="N" THEN S=0 : GOTO 358 +210 PRINT : IF RND(1)>.65 THEN 325 +215 GOTO 380 +220 PRINT "A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1)," +230 INPUT "ENGLAND(2), OR FRANCE(3)";M : IF M>0 AND M<4 THEN 235 +232 PRINT "TRY AGAIN..." : GOTO 220 +235 PRINT : ON M GOTO 250, 260, 270 +250 PRINT "YOU'RE NEARING STALINGRAD." : GOTO 280 +260 PRINT "NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR." : GOTO 280 +270 PRINT "NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS." +280 PRINT +285 INPUT "HOW MANY MISSIONS HAVE YOU FLOWN";D +290 IF D<160 THEN 300 +292 PRINT "MISSIONS, NOT MILES..." +295 PRINT "150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS." +297 PRINT "NOW THEN, "; : GOTO 285 +300 PRINT:IF D<100 THEN 310 +305 PRINT "THAT'S PUSHING THE ODDS!" : GOTO 320 +310 IF D<25 THEN PRINT "FRESH OUT OF TRAINING, EH?" +320 PRINT : IF D<160*RND(1) THEN 330 +325 PRINT "DIRECT HIT!!!! "INT(100*RND(1))"KILLED." +327 PRINT "MISSION SUCCESSFUL." : GOTO 390 +330 PRINT "MISSED TARGET BY"INT(2+30*RND(1))"MILES!" +335 PRINT "NOW YOU'RE REALLY IN FOR IT !!" : PRINT +340 INPUT "DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)";R +345 IF R>0 AND R<4 THEN 350 +347 PRINT "TRY AGAIN..." : GOTO 340 +350 PRINT : T=0 : IF R=2 THEN 360 +355 INPUT "WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)";S +357 IF S<10 THEN PRINT "YOU LIE, BUT YOU'LL PAY...": GOTO 380 +358 PRINT +360 PRINT : IF R>1 THEN T=35 +365 IF S+T>100*RND(1) THEN 380 +370 PRINT "YOU MADE IT THROUGH TREMENDOUS FLAK!!" : GOTO 390 +380 PRINT "* * * * BOOM * * * *" +384 PRINT "YOU HAVE BEEN SHOT DOWN....." +386 PRINT "DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR" +387 PRINT "LAST TRIBUTE..." +390 PRINT:PRINT:PRINT:INPUT "ANOTHER MISSION (Y OR N)";U$ +395 IF U$="Y" THEN 8 +400 PRINT "CHICKEN !!!" : PRINT : END diff --git a/00_Alternate_Languages/13_Bounce/README.md b/00_Alternate_Languages/13_Bounce/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/13_Bounce/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/13_Bounce/bounce.bas b/00_Alternate_Languages/13_Bounce/bounce.bas new file mode 100644 index 00000000..7dd04509 --- /dev/null +++ b/00_Alternate_Languages/13_Bounce/bounce.bas @@ -0,0 +1,53 @@ +10 PRINT TAB(33);"BOUNCE" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT:PRINT:PRINT +90 DIM T(20) +100 PRINT "THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY" +110 PRINT "OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF" +120 PRINT "ELASTICITY OF THE BALL. PLEASE USE A DECIMAL FRACTION" +130 PRINT "COEFFICIENCY (LESS THAN 1)." +131 PRINT +132 PRINT "YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN" +133 PRINT "'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY)." +134 PRINT +135 INPUT "TIME INCREMENT (SEC)";S2 +140 PRINT +150 INPUT "VELOCITY (FPS)";V +160 PRINT +170 INPUT "COEFFICIENT";C +180 PRINT +182 PRINT "FEET" +184 PRINT +186 S1=INT(70/(V/(16*S2))) +190 FOR I=1 TO S1 +200 T(I)=V*C^(I-1)/16 +210 NEXT I +220 FOR H=INT(-16*(V/32)^2+V^2/32+.5) TO 0 STEP -.5 +221 IF INT(H)<>H THEN 225 +222 PRINT H; +225 L=0 +230 FOR I=1 TO S1 +240 FOR T=0 TO T(I) STEP S2 +245 L=L+S2 +250 IF ABS(H-(.5*(-32)*T^2+V*C^(I-1)*T))>.25 THEN 270 +260 PRINT TAB(L/S2);"0"; +270 NEXT T +275 T=T(I+1)/2 +276 IF -16*T^2+V*C^(I-1)*T 0 THEN 5220 +5130 PRINT "GUTTER!!" +5220 IF B<>1 OR D<>10 THEN 5490 +5310 PRINT "STRIKE!!!!!" +5400 Q=3 +5490 IF B<>2 OR D<>10 THEN 5760 +5580 PRINT "SPARE!!!!" +5670 Q=2 +5760 IF B<>2 OR D>=10 THEN 6030 +5850 PRINT "ERROR!!!" +5940 Q=1 +6030 IF B<>1 OR D>=10 THEN 6210 +6120 PRINT "ROLL YOUR 2ND BALL" +6210 REM ARK STORAGE OF THE SCORES +6300 PRINT +6390 A(F*P,B)=D +6480 IF B=2 THEN 7020 +6570 B=2 +6660 M=D +6750 IF Q=3 THEN 6210 +6840 A(F*P,B)=D-M +6930 IF Q=0 THEN 2520 +7020 A(F*P,3)=Q +7110 NEXT P +7200 F=F+1 +7290 IF F<11 THEN 2070 +7295 PRINT "FRAMES" +7380 FOR I=1 TO 10 +7470 PRINT I; +7560 NEXT I +7650 PRINT +7740 FOR P=1 TO R +7830 FOR I=1 TO 3 +7920 FOR J=1 TO 10 +8010 PRINT A(J*P,I); +8100 NEXT J +8105 PRINT +8190 NEXT I +8280 PRINT +8370 NEXT P +8460 PRINT "DO YOU WANT ANOTHER GAME" +8550 INPUT A$ +8640 IF LEFT$(A$,1)="Y" THEN 2610 +8730 END diff --git a/00_Alternate_Languages/15_Boxing/README.md b/00_Alternate_Languages/15_Boxing/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/15_Boxing/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/15_Boxing/boxing.bas b/00_Alternate_Languages/15_Boxing/boxing.bas new file mode 100644 index 00000000..f6d0d727 --- /dev/null +++ b/00_Alternate_Languages/15_Boxing/boxing.bas @@ -0,0 +1,142 @@ +1 PRINT TAB(33);"BOXING" +2 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +3 PRINT:PRINT:PRINT +4 PRINT "BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)" +5 J=0 +6 L=0 +8 PRINT +10 PRINT "WHAT IS YOUR OPPONENT'S NAME"; +20 INPUT J$ +30 PRINT "INPUT YOUR MAN'S NAME"; +40 INPUT L$ +50 PRINT "DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB." +60 PRINT "WHAT IS YOUR MANS BEST"; +64 INPUT B +70 PRINT "WHAT IS HIS VULNERABILITY"; +80 INPUT D +90 B1=INT(4*RND(1)+1) +100 D1=INT(4*RND(1)+1) +110 IF B1=D1 THEN 90 +120 PRINT J$;"'S ADVANTAGE IS";B1;"AND VULNERABILITY IS SECRET.":PRINT +130 FOR R=1 TO 3 +140 IF J>= 2 THEN 1040 +150 IF L>=2 THEN 1060 +160 X=0 +170 Y=0 +180 PRINT "ROUND";R;"BEGINS..." +185 FOR R1= 1 TO 7 +190 I=INT(10*RND(1)+1) +200 IF I>5 THEN 600 +210 PRINT L$;"'S PUNCH"; +220 INPUT P +221 IF P=B THEN 225 +222 GOTO 230 +225 X=X+2 +230 IF P=1 THEN 340 +240 IF P=2 THEN 450 +250 IF P=3 THEN 520 +270 PRINT L$;" JABS AT ";J$"'S HEAD "; +271 IF D1=4 THEN 290 +275 C=INT(8*RND(1)+1) +280 IF C<4 THEN 310 +290 X=X+3 +300 GOTO 950 +310 PRINT "IT'S BLOCKED." +330 GOTO 950 +340 PRINT L$ " SWINGS AND "; +341 IF D1=4 THEN 410 +345 X3=INT(30*RND(1)+1) +350 IF X3<10 THEN 410 +360 PRINT "HE MISSES "; +370 PRINT +375 IF X=1 THEN 950 +380 PRINT +390 PRINT +400 GOTO 300 +410 PRINT "HE CONNECTS!" +420 IF X>35 THEN 980 +425 X=X+15 +440 GOTO 300 +450 PRINT L$;" GIVES THE HOOK... "; +455 IF D1=2 THEN 480 +460 H1=INT(2*RND(1)+1) +470 IF H1=1 THEN 500 +475 PRINT "CONNECTS..." +480 X=X+7 +490 GOTO 300 +500 PRINT "BUT IT'S BLOCKED!!!!!!!!!!!!!" +510 GOTO 300 +520 PRINT L$ " TRIES AN UPPERCUT "; +530 IF D1=3 THEN 570 +540 D5=INT(100*RND(1)+1) +550 IF D5<51 THEN 570 +560 PRINT "AND IT'S BLOCKED (LUCKY BLOCK!)" +565 GOTO 300 +570 PRINT "AND HE CONNECTS!" +580 X=X+4 +590 GOTO 300 +600 J7=INT(4*RND(1)+1) +601 IF J7 =B1 THEN 605 +602 GOTO 610 +605 Y=Y+2 +610 IF J7=1 THEN 720 +620 IF J7=2 THEN 810 +630 IF J7 =3 THEN 860 +640 PRINT J$;" JABS AND "; +645 IF D=4 THEN 700 +650 Z4=INT(7*RND(1)+1) +655 IF Z4>4 THEN 690 +660 PRINT "IT'S BLOCKED!" +670 GOTO 300 +690 PRINT " BLOOD SPILLS !!!" +700 Y=Y+5 +710 GOTO 300 +720 PRINT J$" TAKES A FULL SWING AND"; +730 IF D=1 THEN 770 +740 R6=INT(60*RND(1)+1) +745 IF R6 <30 THEN 770 +750 PRINT " IT'S BLOCKED!" +760 GOTO 300 +770 PRINT " POW!!!!! HE HITS HIM RIGHT IN THE FACE!" +780 IF Y>35 THEN 1010 +790 Y=Y+15 +800 GOTO 300 +810 PRINT J$;" GETS ";L$;" IN THE JAW (OUCH!)" +820 Y=Y+7 +830 PRINT "....AND AGAIN!" +835 Y=Y+5 +840 IF Y>35 THEN 1010 +850 PRINT +860 PRINT L$;" IS ATTACKED BY AN UPPERCUT (OH,OH)..." +865 IF D=3 THEN 890 +870 Q4=INT(200*RND(1)+1) +880 IF Q4>75 THEN 920 +890 PRINT "AND ";J$;" CONNECTS..." +900 Y=Y+8 +910 GOTO 300 +920 PRINT " BLOCKS AND HITS ";J$;" WITH A HOOK." +930 X=X+5 +940 GOTO 300 +950 NEXT R1 +951 IF X>Y THEN 955 +952 PRINT:PRINT J$" WINS ROUND" R +953 J=J+1 +954 GOTO 960 +955 PRINT:PRINT L$" WINS ROUND"R +956 L=L+1 +960 NEXT R +961 IF J>= 2 THEN 1040 +962 IF L>=2 THEN 1060 +980 PRINT J$ " IS KNOCKED COLD AND " L$" IS THE WINNER AND CHAMP!"; +1000 GOTO 1080 +1010 PRINT L$ " IS KNOCKED COLD AND " J$" IS THE WINNER AND CHAMP!"; +1030 GOTO 1000 +1040 PRINT J$ " WINS (NICE GOING," J$;")." +1050 GOTO 1000 +1060 PRINT L$ " AMAZINGLY WINS!!" +1070 GOTO 1000 +1080 PRINT +1085 PRINT +1090 PRINT "AND NOW GOODBYE FROM THE OLYMPIC ARENA." +1100 PRINT +1110 END diff --git a/00_Alternate_Languages/16_Bug/README.md b/00_Alternate_Languages/16_Bug/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/16_Bug/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/16_Bug/bug.bas b/00_Alternate_Languages/16_Bug/bug.bas new file mode 100644 index 00000000..ec129998 --- /dev/null +++ b/00_Alternate_Languages/16_Bug/bug.bas @@ -0,0 +1,256 @@ +10 PRINT TAB(34);"BUG" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT:PRINT:PRINT +40 REM +50 A=0: B=0: H=0: L=0: N=0: P=0: Q=0: R=0: S=0: T=0: U=0: V=0: Y=0 +60 PRINT "THE GAME BUG" +70 PRINT "I HOPE YOU ENJOY THIS GAME." +80 PRINT +90 PRINT "DO YOU WANT INSTRUCTIONS"; +100 INPUT Z$ +110 IF Z$="NO" THEN 300 +120 PRINT "THE OBJECT OF BUG IS TO FINISH YOUR BUG BEFORE I FINISH" +130 PRINT "MINE. EACH NUMBER STANDS FOR A PART OF THE BUG BODY." +140 PRINT "I WILL ROLL THE DIE FOR YOU, TELL YOU WHAT I ROLLED FOR YOU" +150 PRINT "WHAT THE NUMBER STANDS FOR, AND IF YOU CAN GET THE PART." +160 PRINT "IF YOU CAN GET THE PART I WILL GIVE IT TO YOU." +170 PRINT "THE SAME WILL HAPPEN ON MY TURN." +180 PRINT "IF THERE IS A CHANGE IN EITHER BUG I WILL GIVE YOU THE" +190 PRINT "OPTION OF SEEING THE PICTURES OF THE BUGS." +200 PRINT "THE NUMBERS STAND FOR PARTS AS FOLLOWS:" +210 PRINT "NUMBER","PART","NUMBER OF PART NEEDED" +220 PRINT "1","BODY","1" +230 PRINT "2","NECK","1" +240 PRINT "3","HEAD","1" +250 PRINT "4","FEELERS","2" +260 PRINT "5","TAIL","1" +270 PRINT "6","LEGS","6" +280 PRINT +290 PRINT +300 IF Y>0 THEN 2480 +310 Z=INT(6*RND(1)+1) +320 C=1 +330 PRINT "YOU ROLLED A";Z +340 ON Z GOTO 350,430,540,650,760,870 +350 PRINT "1=BODY" +360 IF B=1 THEN 410 +370 PRINT "YOU NOW HAVE A BODY." +380 B=1 +390 C=0 +400 GOTO 970 +410 PRINT "YOU DO NOT NEED A BODY." +420 GOTO 970 +430 PRINT "2=NECK" +440 IF N=1 THEN 500 +450 IF B=0 THEN 520 +460 PRINT "YOU NOW HAVE A NECK." +470 N=1 +480 C=0 +490 GOTO 970 +500 PRINT "YOU DO NOT NEED A NECK." +510 GOTO 970 +520 PRINT "YOU DO NOT HAVE A BODY." +530 GOTO 970 +540 PRINT "3=HEAD" +550 IF N=0 THEN 610 +560 IF H=1 THEN 630 +570 PRINT "YOU NEEDED A HEAD." +580 H=1 +590 C=0 +600 GOTO 970 +610 PRINT "YOU DO NOT HAVE A NECK." +620 GOTO 970 +630 PRINT "YOU HAVE A HEAD." +640 GOTO 970 +650 PRINT "4=FEELERS" +660 IF H=0 THEN 740 +670 IF A=2 THEN 720 +680 PRINT "I NOW GIVE YOU A FEELER." +690 A=A+1 +700 C=0 +710 GOTO 970 +720 PRINT "YOU HAVE TWO FEELERS ALREADY." +730 GOTO 970 +740 PRINT "YOU DO NOT HAVE A HEAD." +750 GOTO 970 +760 PRINT "5=TAIL" +770 IF B=0 THEN 830 +780 IF T=1 THEN 850 +790 PRINT "I NOW GIVE YOU A TAIL." +800 T=T+1 +810 C=0 +820 GOTO 970 +830 PRINT "YOU DO NOT HAVE A BODY." +840 GOTO 970 +850 PRINT "YOU ALREADY HAVE A TAIL." +860 GOTO 970 +870 PRINT "6=LEG" +880 IF L=6 THEN 940 +890 IF B=0 THEN 960 +900 L=L+1 +910 C=0 +920 PRINT "YOU NOW HAVE";L;"LEGS." +930 GOTO 970 +940 PRINT "YOU HAVE 6 FEET ALREADY." +950 GOTO 970 +960 PRINT "YOU DO NOT HAVE A BODY." +970 X=INT(6*RND(1)+1) +971 PRINT +975 FOR DELAY=1 TO 2000:NEXT DELAY +980 PRINT "I ROLLED A";X +990 ON X GOTO 1000,1080,1190,1300,1410,1520 +1000 PRINT "1=BODY" +1010 IF P=1 THEN 1060 +1020 PRINT "I NOW HAVE A BODY." +1030 C=0 +1040 P=1 +1050 GOTO 1630 +1060 PRINT "I DO NOT NEED A BODY." +1070 GOTO 1630 +1080 PRINT "2=NECK" +1090 IF Q=1 THEN 1150 +1100 IF P=0 THEN 1170 +1110 PRINT "I NOW HAVE A NECK." +1120 Q=1 +1130 C=0 +1140 GOTO 1630 +1150 PRINT "I DO NOT NEED A NECK." +1160 GOTO 1630 +1170 PRINT "I DO NOT HAVE A BODY." +1180 GOTO 1630 +1190 PRINT "3=HEAD" +1200 IF Q=0 THEN 1260 +1210 IF R=1 THEN 1280 +1220 PRINT "I NEEDED A HEAD." +1230 R=1 +1240 C=0 +1250 GOTO 1630 +1260 PRINT "I DO NOT HAVE A NECK." +1270 GOTO 1630 +1280 PRINT "I DO NOT NEED A HEAD." +1290 GOTO 1630 +1300 PRINT "4=FEELERS" +1310 IF R=0 THEN 1390 +1320 IF S=2 THEN 1370 +1330 PRINT "I GET A FEELER." +1340 S=S+1 +1350 C=0 +1360 GOTO 1630 +1370 PRINT "I HAVE 2 FEELERS ALREADY." +1380 GOTO 1630 +1390 PRINT "I DO NOT HAVE A HEAD." +1400 GOTO 1630 +1410 PRINT "5=TAIL" +1420 IF P=0 THEN 1480 +1430 IF U=1 THEN 1500 +1440 PRINT "I NOW HAVE A TAIL." +1450 U=1 +1460 C=0 +1470 GOTO 1630 +1480 PRINT "I DO NOT HAVE A BODY." +1490 GOTO 1630 +1500 PRINT "I DO NOT NEED A TAIL." +1510 GOTO 1630 +1520 PRINT "6=LEGS" +1530 IF V=6 THEN 1590 +1540 IF P=0 THEN 1610 +1550 V=V+1 +1560 C=0 +1570 PRINT "I NOW HAVE";V;"LEGS." +1580 GOTO 1630 +1590 PRINT,"I HAVE 6 FEET." +1600 GOTO 1630 +1610 PRINT "I DO NOT HAVE A BODY." +1620 GOTO 1630 +1630 IF A=2 AND T=1 AND L=6 THEN 1650 +1640 GOTO 1670 +1650 PRINT "YOUR BUG IS FINISHED." +1660 Y=Y+1 +1670 IF S=2 AND P=1 AND V=6 THEN 1690 +1680 GOTO 1710 +1690 PRINT "MY BUG IS FINISHED." +1700 Y=Y+2 +1710 IF C=1 THEN 300 +1720 PRINT "DO YOU WANT THE PICTURES"; +1730 INPUT Z$ +1740 IF Z$="NO" THEN 300 +1750 PRINT "*****YOUR BUG*****" +1760 PRINT +1770 PRINT +1780 IF A=0 THEN 1860 +1790 FOR Z=1 TO 4 +1800 FOR X=1 TO A +1810 PRINT TAB(10); +1820 PRINT "A "; +1830 NEXT X +1840 PRINT +1850 NEXT Z +1860 IF H=0 THEN 1880 +1870 GOSUB 2470 +1880 IF N=0 THEN 1920 +1890 FOR Z=1 TO 2 +1900 PRINT " N N" +1910 NEXT Z +1920 IF B=0 THEN 2000 +1930 PRINT " BBBBBBBBBBBB" +1940 FOR Z=1 TO 2 +1950 PRINT " B B" +1960 NEXT Z +1970 IF T<>1 THEN 1990 +1980 PRINT "TTTTTB B" +1990 PRINT " BBBBBBBBBBBB" +2000 IF L=0 THEN 2080 +2010 FOR Z=1 TO 2 +2020 PRINT TAB(5); +2030 FOR X=1 TO L +2040 PRINT " L"; +2050 NEXT X +2060 PRINT +2070 NEXT Z +2080 FOR Z=1 TO 4 +2090 PRINT +2100 NEXT Z +2110 PRINT "*****MY BUG*****" +2120 PRINT +2130 PRINT +2140 PRINT +2150 IF S=0 THEN 2230 +2160 FOR Z=1 TO 4 +2170 PRINT TAB(10); +2180 FOR X=1 TO S +2190 PRINT "F "; +2200 NEXT X +2210 PRINT +2220 NEXT Z +2230 IF R<>1 THEN 2250 +2240 GOSUB 2470 +2250 IF Q=0 THEN 2280 +2260 PRINT " N N" +2270 PRINT " N N" +2280 IF P=0 THEN 2360 +2290 PRINT " BBBBBBBBBBBB" +2300 FOR Z=1 TO 2 +2310 PRINT " B B" +2320 NEXT Z +2330 IF U<>1 THEN 2350 +2340 PRINT "TTTTTB B" +2350 PRINT " BBBBBBBBBBBB" +2360 IF V=0 THEN 2450 +2370 FOR Z=1 TO 2 +2380 PRINT TAB(5); +2390 FOR X=1 TO V +2400 PRINT " L"; +2410 NEXT X +2420 PRINT +2430 NEXT Z +2450 IF Y<>0 THEN 2540 +2460 GOTO 300 +2470 PRINT " HHHHHHH" +2480 PRINT " H H" +2490 PRINT " H O O H" +2500 PRINT " H H" +2510 PRINT " H V H" +2520 PRINT " HHHHHHH" +2530 RETURN +2540 PRINT "I HOPE YOU ENJOYED THE GAME, PLAY IT AGAIN SOON!!" +2550 END diff --git a/00_Alternate_Languages/17_Bullfight/README.md b/00_Alternate_Languages/17_Bullfight/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/17_Bullfight/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/17_Bullfight/bullfight.bas b/00_Alternate_Languages/17_Bullfight/bullfight.bas new file mode 100644 index 00000000..32b04b89 --- /dev/null +++ b/00_Alternate_Languages/17_Bullfight/bullfight.bas @@ -0,0 +1,193 @@ +10 PRINT TAB(34);"BULL" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 DEF FNA(K)=INT(RND(1)*2+1) +200 PRINT:PRINT:PRINT +202 L=1 +205 PRINT "DO YOU WANT INSTRUCTIONS"; +206 INPUT Z$ +207 IF Z$="NO" THEN 400 +210 PRINT "HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS." +220 PRINT "HERE IS YOUR BIG CHANCE TO KILL A BULL." +230 PRINT +240 PRINT "ON EACH PASS OF THE BULL, YOU MAY TRY" +250 PRINT "0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)" +260 PRINT "1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE" +270 PRINT "2 - ORDINARY SWIRL OF THE CAPE." +280 PRINT +290 PRINT "INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL" +300 PRINT "ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST)." +310 PRINT "BUT IF I WERE YOU," +320 PRINT "I WOULDN'T TRY IT BEFORE THE SEVENTH PASS." +330 PRINT +340 PRINT "THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE" +350 PRINT "(POSTHUMOUSLY IF NECESSARY)." +360 PRINT "THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE." +370 PRINT +380 PRINT "THE BETTER THE JOB THE PICADORES AND TOREADORES DO," +390 PRINT "THE BETTER YOUR CHANCES ARE." +400 PRINT +410 PRINT +420 D(5)=1 +430 D(4)=1 +450 DIM L$(5) +455 A=INT(RND(1)*5+1) +460 FOR I=1 TO 5 +463 READ L$(I) +467 NEXT I +470 DATA "SUPERB","GOOD","FAIR","POOR","AWFUL" +490 PRINT "YOU HAVE DRAWN A ";L$(A);" BULL." +500 IF A>4 THEN 530 +510 IF A<2 THEN 550 +520 GOTO 570 +530 PRINT "YOU'RE LUCKY." +540 GOTO 570 +550 PRINT "GOOD LUCK. YOU'LL NEED IT." +560 PRINT +570 PRINT +590 A$="PICADO" +595 B$="RES" +600 GOSUB 1610 +610 D(1)=C +630 A$="TOREAD" +635 B$="ORES" +640 GOSUB 1610 +650 D(2)=C +660 PRINT +670 PRINT +680 IF Z=1 THEN 1310 +690 D(3)=D(3)+1 +700 PRINT "PASS NUMBER";D(3) +710 IF D(3)<3 THEN 760 +720 PRINT "HERE COMES THE BULL. TRY FOR A KILL"; +730 GOSUB 1930 +735 IF Z1=1 THEN 1130 +740 PRINT "CAPE MOVE"; +750 GOTO 800 +760 PRINT "THE BULL IS CHARGING AT YOU! YOU ARE THE MATADOR--" +770 PRINT "DO YOU WANT TO KILL THE BULL"; +780 GOSUB 1930 +785 IF Z1=1 THEN 1130 +790 PRINT "WHAT MOVE DO YOU MAKE WITH THE CAPE"; +800 INPUT E +810 IF E<>INT(ABS(E)) THEN 830 +820 IF E<3 THEN 850 +830 PRINT "DON'T PANIC, YOU IDIOT! PUT DOWN A CORRECT NUMBER" +840 GOTO 800 +850 REM +860 IF E=0 THEN 920 +870 IF E=1 THEN 900 +880 M=.5 +890 GOTO 930 +900 M=2 +910 GOTO 930 +920 M=3 +930 L=L+M +940 F=(6-A+M/10)*RND(1)/((D(1)+D(2)+D(3)/10)*5) +950 IF F<.51 THEN 660 +960 PRINT "THE BULL HAS GORED YOU!" +970 ON FNA(0) GOTO 980,1010 +980 PRINT "YOU ARE DEAD." +990 D(4)=1.5 +1000 GOTO 1310 +1010 PRINT "YOU ARE STILL ALIVE.":PRINT +1020 PRINT "DO YOU RUN FROM THE RING"; +1030 GOSUB 1930 +1035 IF Z1=2 THEN 1070 +1040 PRINT "COWARD" +1050 D(4)=0 +1060 GOTO 1310 +1070 PRINT "YOU ARE BRAVE. STUPID, BUT BRAVE." +1080 ON FNA(0) GOTO 1090,1110 +1090 D(4)=2 +1100 GOTO 660 +1110 PRINT "YOU ARE GORED AGAIN!" +1120 GOTO 970 +1130 REM +1140 Z=1 +1150 PRINT:PRINT "IT IS THE MOMENT OF TRUTH.":PRINT +1155 PRINT "HOW DO YOU TRY TO KILL THE BULL"; +1160 INPUT H +1170 IF H=4 THEN 1230 +1180 IF H=5 THEN 1230 +1190 PRINT "YOU PANICKED. THE BULL GORED YOU." +1220 GOTO 970 +1230 K=(6-A)*10*RND(1)/((D(1)+D(2))*5*D(3)) +1240 IF H=4 THEN 1290 +1250 IF K>.2 THEN 960 +1260 PRINT "YOU KILLED THE BULL!" +1270 D(5)=2 +1280 GOTO 1320 +1290 IF K>.8 THEN 960 +1300 GOTO 1260 +1310 PRINT +1320 PRINT +1330 PRINT +1340 IF D(4)<>0 THEN 1390 +1350 PRINT "THE CROWD BOOS FOR TEN MINUTES. IF YOU EVER DARE TO SHOW" +1360 PRINT "YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--" +1370 PRINT "UNLESS THE BULL DOES FIRST." +1380 GOTO 1580 +1390 DEF FNC(Q)=FND(Q)*RND(1) +1395 DEF FND(Q)=(4.5+L/6-(D(1)+D(2))*2.5+4*D(4)+2*D(5)-D(3)^2/120-A) +1400 IF D(4)<>2 THEN 1430 +1410 PRINT "THE CROWD CHEERS WILDLY!" +1420 GOTO 1450 +1430 IF D(5)<>2 THEN 1450 +1440 PRINT "THE CROWD CHEERS!":PRINT +1450 PRINT "THE CROWD AWARDS YOU" +1460 IF FNC(Q)<2.4 THEN 1570 +1470 IF FNC(Q)<4.9 THEN 1550 +1480 IF FNC(Q)<7.4 THEN 1520 +1500 PRINT "OLE! YOU ARE 'MUY HOMBRE'!! OLE! OLE!" +1510 GOTO 1580 +1520 PRINT "BOTH EARS OF THE BULL!" +1530 PRINT "OLE!" +1540 GOTO 1580 +1550 PRINT "ONE EAR OF THE BULL." +1560 GOTO 1580 +1570 PRINT "NOTHING AT ALL." +1580 PRINT +1590 PRINT "ADIOS":PRINT:PRINT:PRINT +1600 GOTO 2030 +1610 B=3/A*RND(1) +1620 IF B<.37 THEN 1740 +1630 IF B<.5 THEN 1720 +1640 IF B<.63 THEN 1700 +1650 IF B<.87 THEN 1680 +1660 C=.1 +1670 GOTO 1750 +1680 C=.2 +1690 GOTO 1750 +1700 C=.3 +1710 GOTO 1750 +1720 C=.4 +1730 GOTO 1750 +1740 C=.5 +1750 T=INT(10*C+.2) +1760 PRINT "THE ";A$;B$;" DID A ";L$(T);" JOB." +1770 IF 4>T THEN 1900 +1780 IF 5=T THEN 1870 +1790 ON FNA(K) GOTO 1830,1850 +1800 IF A$="TOREAD" THEN 1820 +1810 PRINT "ONE OF THE HORSES OF THE ";A$;B$;" WAS KILLED." +1820 ON FNA(K) GOTO 1830,1850 +1830 PRINT "ONE OF THE ";A$;B$;" WAS KILLED." +1840 GOTO 1900 +1850 PRINT "NO ";A$;B$;" WERE KILLED." +1860 GOTO 1900 +1870 IF A$="TOREAD" THEN 1890 +1880 PRINT FNA(K);"OF THE HORSES OF THE ";A$;B$;" KILLED." +1890 PRINT FNA(K);"OF THE ";A$;B$;" KILLED." +1900 PRINT +1910 RETURN +1920 REM +1930 INPUT A$ +1940 IF A$="YES" THEN 1990 +1950 IF A$="NO" THEN 2010 +1970 PRINT "INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'." +1980 GOTO 1930 +1990 Z1=1 +2000 GOTO 2020 +2010 Z1=2 +2020 RETURN +2030 END diff --git a/00_Alternate_Languages/18_Bullseye/README.md b/00_Alternate_Languages/18_Bullseye/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/18_Bullseye/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/18_Bullseye/bullseye.bas b/00_Alternate_Languages/18_Bullseye/bullseye.bas new file mode 100644 index 00000000..eec7cf06 --- /dev/null +++ b/00_Alternate_Languages/18_Bullseye/bullseye.bas @@ -0,0 +1,37 @@ +5 PRINT TAB(32);"BULLSEYE" +10 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +20 PRINT:PRINT:PRINT +30 PRINT "IN THIS GAME, UP TO 20 PLAYERS THROW DARTS AT A TARGET" +40 PRINT "WITH 10, 20, 30, AND 40 POINT ZONES. THE OBJECTIVE IS" +50 PRINT "TO GET 200 POINTS.": PRINT +60 PRINT "THROW",TAB(20);"DESCRIPTION";TAB(45);"PROBABLE SCORE" +70 PRINT" 1";TAB(20);"FAST OVERARM";TAB(45);"BULLSEYE OR COMPLETE MISS" +80 PRINT" 2";TAB(20);"CONTROLLED OVERARM";TAB(45);"10, 20 OR 30 POINTS" +90 PRINT" 3";TAB(20);"UNDERARM";TAB(45);"ANYTHING":PRINT +100 DIM A$(20),S(20),W(10): M=0: R=0: FOR I=1 TO 20: S(I)=0: NEXT I +110 INPUT "HOW MANY PLAYERS";N: PRINT +120 FOR I=1 TO N +130 PRINT "NAME OF PLAYER #";I;:INPUT A$(I) +140 NEXT I +150 R=R+1: PRINT: PRINT "ROUND";R:PRINT "---------" +160 FOR I=1 TO N +170 PRINT: PRINT A$(I)"'S THROW";: INPUT T +180 IF T<1 OR T>3 THEN PRINT "INPUT 1, 2, OR 3!": GOTO 170 +190 ON T GOTO 200, 210, 200 +200 P1=.65: P2=.55: P3=.5: P4=.5: GOTO 230 +210 P1=.99: P2=.77: P3=.43: P4=.01: GOTO 230 +220 P1=.95: P2=.75: P3=.45: P4=.05 +230 U=RND(1) +240 IF U>=P1 THEN PRINT "BULLSEYE!! 40 POINTS!":B=40: GOTO 290 +250 IF U>=P2 THEN PRINT "30-POINT ZONE!":B=30: GOTO 290 +260 IF U>=P3 THEN PRINT "20-POINT ZONE":B=20: GOTO 290 +270 IF U>=P4 THEN PRINT "WHEW! 10 POINTS.":B=10: GOTO 290 +280 PRINT "MISSED THE TARGET! TOO BAD.": B=0 +290 S(I)=S(I)+B: PRINT "TOTAL SCORE =";S(I): NEXT I +300 FOR I=1 TO N +310 IF S(I)>=200 THEN M=M+1: W(M)=I +320 NEXT I +330 IF M=0 THEN 150 +340 PRINT: PRINT "WE HAVE A WINNER!!": PRINT +350 FOR I=1 TO M: PRINT A$(W(I));" SCORED";S(W(I));"POINTS.": NEXT I +360 PRINT: PRINT "THANKS FOR THE GAME.": END diff --git a/00_Alternate_Languages/19_Bunny/README.md b/00_Alternate_Languages/19_Bunny/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/19_Bunny/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/19_Bunny/bunny.bas b/00_Alternate_Languages/19_Bunny/bunny.bas new file mode 100644 index 00000000..1d37fb4a --- /dev/null +++ b/00_Alternate_Languages/19_Bunny/bunny.bas @@ -0,0 +1,40 @@ +10 PRINT TAB(33);"BUNNY" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT: PRINT: PRINT +100 REM "BUNNY" FROM AHL'S 'BASIC COMPUTER GAMES' +110 REM +120 FOR I=0 TO 4: READ B(I): NEXT I +130 GOSUB 260 +140 L=64: REM ASCII LETTER CODE... +150 REM +160 PRINT +170 READ X: IF X<0 THEN 160 +175 IF X>128 THEN 240 +180 PRINT TAB(X);: READ Y +190 FOR I=X TO Y: J=I-5*INT(I/5) +200 PRINT CHR$(L+B(J)); +210 NEXT I +220 GOTO 170 +230 REM +240 GOSUB 260: GOTO 450 +250 REM +260 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I +270 RETURN +280 REM +290 DATA 2,21,14,14,25 +300 DATA 1,2,-1,0,2,45,50,-1,0,5,43,52,-1,0,7,41,52,-1 +310 DATA 1,9,37,50,-1,2,11,36,50,-1,3,13,34,49,-1,4,14,32,48,-1 +320 DATA 5,15,31,47,-1,6,16,30,45,-1,7,17,29,44,-1,8,19,28,43,-1 +330 DATA 9,20,27,41,-1,10,21,26,40,-1,11,22,25,38,-1,12,22,24,36,-1 +340 DATA 13,34,-1,14,33,-1,15,31,-1,17,29,-1,18,27,-1 +350 DATA 19,26,-1,16,28,-1,13,30,-1,11,31,-1,10,32,-1 +360 DATA 8,33,-1,7,34,-1,6,13,16,34,-1,5,12,16,35,-1 +370 DATA 4,12,16,35,-1,3,12,15,35,-1,2,35,-1,1,35,-1 +380 DATA 2,34,-1,3,34,-1,4,33,-1,6,33,-1,10,32,34,34,-1 +390 DATA 14,17,19,25,28,31,35,35,-1,15,19,23,30,36,36,-1 +400 DATA 14,18,21,21,24,30,37,37,-1,13,18,23,29,33,38,-1 +410 DATA 12,29,31,33,-1,11,13,17,17,19,19,22,22,24,31,-1 +420 DATA 10,11,17,18,22,22,24,24,29,29,-1 +430 DATA 22,23,26,29,-1,27,29,-1,28,29,-1,4096 +440 REM +450 END diff --git a/00_Alternate_Languages/20_Buzzword/README.md b/00_Alternate_Languages/20_Buzzword/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/20_Buzzword/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/20_Buzzword/buzzword.bas b/00_Alternate_Languages/20_Buzzword/buzzword.bas new file mode 100644 index 00000000..7c751a70 --- /dev/null +++ b/00_Alternate_Languages/20_Buzzword/buzzword.bas @@ -0,0 +1,26 @@ +10 PRINT TAB(26);"BUZZWORD GENERATOR" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT:PRINT:PRINT +40 PRINT "THIS PROGRAM PRINTS HIGHLY ACCEPTABLE PHRASES IN" +50 PRINT "'EDUCATOR-SPEAK' THAT YOU CAN WORK INTO REPORTS" +60 PRINT "AND SPEECHES. WHENEVER A QUESTION MARK IS PRINTED," +70 PRINT "TYPE A 'Y' FOR ANOTHER PHRASE OR 'N' TO QUIT." +80 PRINT:PRINT:PRINT "HERE'S THE FIRST PHRASE:" +90 DIM A$(40) +100 FOR I=1 TO 39 : READ A$(I) : NEXT I +110 PRINT A$(INT(13*RND(1)+1));" "; +120 PRINT A$(INT(13*RND(1)+14));" "; +130 PRINT A$(INT(13*RND(1)+27)) : PRINT +150 INPUT Y$ : IF Y$="Y" THEN 110 +160 GOTO 999 +200 DATA "ABILITY","BASAL","BEHAVIORAL","CHILD-CENTERED" +210 DATA "DIFFERENTIATED","DISCOVERY","FLEXIBLE","HETEROGENEOUS" +220 DATA "HOMOGENEOUS","MANIPULATIVE","MODULAR","TAVISTOCK" +230 DATA "INDIVIDUALIZED","LEARNING","EVALUATIVE","OBJECTIVE" +240 DATA "COGNITIVE","ENRICHMENT","SCHEDULING","HUMANISTIC" +250 DATA "INTEGRATED","NON-GRADED","TRAINING","VERTICAL AGE" +260 DATA "MOTIVATIONAL","CREATIVE","GROUPING","MODIFICATION" +270 DATA "ACCOUNTABILITY","PROCESS","CORE CURRICULUM","ALGORITHM" +280 DATA "PERFORMANCE","REINFORCEMENT","OPEN CLASSROOM","RESOURCE" +290 DATA "STRUCTURE","FACILITY","ENVIRONMENT" +999 PRINT "COME BACK WHEN YOU NEED HELP WITH ANOTHER REPORT!":END diff --git a/00_Alternate_Languages/21_Calendar/README.md b/00_Alternate_Languages/21_Calendar/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/21_Calendar/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/21_Calendar/calendar.bas b/00_Alternate_Languages/21_Calendar/calendar.bas new file mode 100644 index 00000000..8a7703f9 --- /dev/null +++ b/00_Alternate_Languages/21_Calendar/calendar.bas @@ -0,0 +1,58 @@ +10 PRINT TAB(32);"CALENDAR" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT:PRINT:PRINT +100 REM VALUES FOR 1979 - SEE NOTES +110 DIM M(12) +120 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I +130 D=-1: REM 1979 STARTS ON MONDAY (0=SUN, -1=MON, -2=TUES...) +140 S=0 +150 REM READ DAYS OF EACH MONTH +160 FOR N=0 TO 12: READ M(N): NEXT N +170 REM +180 FOR N=1 TO 12 +190 PRINT: PRINT: S=S+M(N-1) +200 PRINT "**";S;TAB(7); +210 FOR I=1 TO 18: PRINT "*";: NEXT I +220 ON N GOTO 230,240,250,260,270,280,290,300,310,320,330,340 +230 PRINT " JANUARY ";: GOTO 350 +240 PRINT " FEBRUARY";: GOTO 350 +250 PRINT " MARCH ";: GOTO 350 +260 PRINT " APRIL ";: GOTO 350 +270 PRINT " MAY ";: GOTO 350 +280 PRINT " JUNE ";: GOTO 350 +290 PRINT " JULY ";: GOTO 350 +300 PRINT " AUGUST ";: GOTO 350 +310 PRINT "SEPTEMBER";: GOTO 350 +320 PRINT " OCTOBER ";: GOTO 350 +330 PRINT " NOVEMBER";: GOTO 350 +340 PRINT " DECEMBER"; +350 FOR I=1 TO 18: PRINT "*";: NEXT I +360 PRINT 365-S;"**"; +370 REM 366-S; ON LEAP YEARS +380 PRINT CHR$(10): PRINT " S M T W"; +390 PRINT " T F S" +400 PRINT +410 FOR I=1 TO 59: PRINT "*";: NEXT I +420 REM +430 FOR W=1 TO 6 +440 PRINT CHR$(10) +450 PRINT TAB(4) +460 REM +470 FOR G=1 TO 7 +480 D=D+1 +490 D2=D-S +500 IF D2>M(N) THEN 580 +510 IF D2>0 THEN PRINT D2; +520 PRINT TAB(4+8*G); +530 NEXT G +540 REM +550 IF D2=M(N) THEN 590 +560 NEXT W +570 REM +580 D=D-G +590 NEXT N +600 REM +610 FOR I=1 TO 6: PRINT CHR$(10);: NEXT I +620 DATA 0,31,28,31,30,31,30,31,31,30,31,30,31 +630 REM 0,31,29, ..., ON LEAP YEARS +640 END diff --git a/00_Alternate_Languages/22_Change/README.md b/00_Alternate_Languages/22_Change/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/22_Change/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/22_Change/change.bas b/00_Alternate_Languages/22_Change/change.bas new file mode 100644 index 00000000..ac84db06 --- /dev/null +++ b/00_Alternate_Languages/22_Change/change.bas @@ -0,0 +1,51 @@ +2 PRINT TAB(33);"CHANGE" +4 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +5 PRINT:PRINT:PRINT +6 PRINT "I, YOUR FRIENDLY MICROCOMPUTER, WILL DETERMINE" +8 PRINT "THE CORRECT CHANGE FOR ITEMS COSTING UP TO $100." +9 PRINT:PRINT +10 PRINT "COST OF ITEM";:INPUT A:PRINT "AMOUNT OF PAYMENT";:INPUT P +20 C=P-A:M=C:IF C<>0 THEN 90 +25 PRINT "CORRECT AMOUNT, THANK YOU." +30 GOTO 400 +90 IF C>0 THEN 120 +95 PRINT "SORRY, YOU HAVE SHORT-CHANGED ME $";A-P +100 GOTO 10 +120 PRINT "YOUR CHANGE, $";C +130 D=INT(C/10) +140 IF D=0 THEN 155 +150 PRINT D;"TEN DOLLAR BILL(S)" +155 C=M-(D*10) +160 E=INT(C/5) +170 IF E=0 THEN 185 +180 PRINT E;"FIVE DOLLARS BILL(S)" +185 C=M-(D*10+E*5) +190 F=INT(C) +200 IF F=0 THEN 215 +210 PRINT F;"ONE DOLLAR BILL(S)" +215 C=M-(D*10+E*5+F) +220 C=C*100 +225 N=C +230 G=INT(C/50) +240 IF G=0 THEN 255 +250 PRINT G;"ONE HALF DOLLAR(S)" +255 C=N-(G*50) +260 H=INT(C/25) +270 IF H=0 THEN 285 +280 PRINT H;"QUARTER(S)" +285 C=N-(G*50+H*25) +290 I=INT(C/10) +300 IF I=0 THEN 315 +310 PRINT I;"DIME(S)" +315 C=N-(G*50+H*25+I*10) +320 J=INT(C/5) +330 IF J=0 THEN 345 +340 PRINT J;"NICKEL(S)" +345 C=N-(G*50+H*25+I*10+J*5) +350 K=INT(C+.5) +360 IF K=0 THEN 380 +370 PRINT K;"PENNY(S)" +380 PRINT "THANK YOU, COME AGAIN." +390 PRINT:PRINT +400 GOTO 10 +410 END diff --git a/00_Alternate_Languages/23_Checkers/README.md b/00_Alternate_Languages/23_Checkers/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/23_Checkers/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/23_Checkers/checkers.annotated.bas b/00_Alternate_Languages/23_Checkers/checkers.annotated.bas new file mode 100644 index 00000000..78e2e2d9 --- /dev/null +++ b/00_Alternate_Languages/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/00_Alternate_Languages/23_Checkers/checkers.bas b/00_Alternate_Languages/23_Checkers/checkers.bas new file mode 100644 index 00000000..634c2486 --- /dev/null +++ b/00_Alternate_Languages/23_Checkers/checkers.bas @@ -0,0 +1,82 @@ +5 PRINT TAB(32);"CHECKERS" +10 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +15 PRINT:PRINT:PRINT +20 PRINT "THIS IS THE GAME OF CHECKERS. THE COMPUTER IS X," +25 PRINT "AND YOU ARE O. THE COMPUTER WILL MOVE FIRST." +30 PRINT "SQUARES ARE REFERRED TO BY A COORDINATE SYSTEM." +35 PRINT "(0,0) IS THE LOWER LEFT CORNER" +40 PRINT "(0,7) IS THE UPPER LEFT CORNER" +45 PRINT "(7,0) IS THE LOWER RIGHT CORNER" +50 PRINT "(7,7) IS THE UPPER RIGHT CORNER" +55 PRINT "THE COMPUTER WILL TYPE '+TO' WHEN YOU HAVE ANOTHER" +60 PRINT "JUMP. TYPE TWO NEGATIVE NUMBERS IF YOU CANNOT JUMP." +65 PRINT:PRINT:PRINT +80 DIM R(4),S(7,7):G=-1:R(0)=-99 +90 DATA 1,0,1,0,0,0,-1,0,0,1,0,0,0,-1,0,-1,15 +120 FOR X=0 TO 7:FOR Y=0 TO 7:READ J:IF J=15 THEN 180 +160 S(X,Y)=J:GOTO 200 +180 RESTORE:READ S(X,Y) +200 NEXT Y,X +230 FOR X=0 TO 7:FOR Y=0 TO 7:IF S(X,Y)>-1 THEN 350 +310 IF S(X,Y)=-1 THEN FOR A=-1 TO 1 STEP 2:B=G:GOSUB 650:NEXT A +330 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 +350 NEXT Y,X:GOTO 1140 +650 U=X+A:V=Y+B:IF U<0 OR U>7 OR V<0 OR V>7 THEN 870 +740 IF S(U,V)=0 THEN GOSUB 910:GOTO 870 +770 IF S(U,V)<0 THEN 870 +790 U=U+A:V=V+B:IF U<0 OR V<0 OR U>7 OR V>7 THEN 870 +850 IF S(U,V)=0 THEN GOSUB 910 +870 RETURN +910 IF V=0 AND S(X,Y)=-1 THEN Q=Q+2 +920 IF ABS(Y-V)=2 THEN Q=Q+5 +960 IF Y=7 THEN Q=Q-2 +980 IF U=0 OR U=7 THEN Q=Q+1 +1030 FOR C=-1 TO 1 STEP 2:IF U+C<0 OR U+C>7 OR V+G<0 THEN 1080 +1035 IF S(U+C,V+G)<0 THEN Q=Q+1:GOTO 1080 +1040 IF U-C<0 OR U-C>7 OR V-G>7 THEN 1080 +1045 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:IF Q>R(0)THEN R(0)=Q:R(1)=X:R(2)=Y:R(3)=U:R(4)=V +1100 Q=0:RETURN +1140 IF R(0)=-99 THEN 1880 +1230 PRINT CHR$(30)"FROM"R(1);R(2)"TO"R(3);R(4);:R(0)=-99 +1240 IF R(4)=0 THEN S(R(3),R(4))=-2:GOTO 1420 +1250 S(R(3),R(4))=S(R(1),R(2)) +1310 S(R(1),R(2))=0:IF ABS(R(1)-R(3))<>2 THEN 1420 +1330 S((R(1)+R(3))/2,(R(2)+R(4))/2)=0 +1340 X=R(3):Y=R(4):IF S(X,Y)=-1 THEN B=-2:FOR A=-2 TO 2 STEP 4:GOSUB 1370 +1350 IF S(X,Y)=-2 THEN FOR A=-2 TO 2 STEP 4:FOR B=-2 TO 2 STEP 4:GOSUB 1370:NEXT B +1360 NEXT A:IF R(0)<>-99 THEN PRINT"TO"R(3);R(4);:R(0)=-99:GOTO 1240 +1365 GOTO 1420 +1370 U=X+A:V=Y+B:IF U<0 OR U>7 OR V<0 OR V>7 THEN 1400 +1380 IF S(U,V)=0 AND S(X+A/2,Y+B/2)>0 THEN GOSUB 910 +1400 RETURN +1420 PRINT:PRINT:PRINT:FOR Y=7 TO 0 STEP-1:FOR X=0 TO 7:I=5*X:PRINT TAB(I); +1430 IF S(X,Y)=0 THEN PRINT"."; +1470 IF S(X,Y)=1 THEN PRINT"O"; +1490 IF S(X,Y)=-1 THEN PRINT"X"; +1510 IF S(X,Y)=-2 THEN PRINT"X*"; +1530 IF S(X,Y)=2 THEN PRINT"O*"; +1550 NEXT X:PRINT" ":PRINT:NEXT Y:PRINT +1552 FOR L=0 TO 7 +1554 FOR M=0 TO 7 +1556 IF S(L,M)=1 OR S(L,M)=2 THEN Z=1 +1558 IF S(L,M)=-1 OR S(L,M)=-2 THEN T=1 +1560 NEXT M +1562 NEXT L +1564 IF Z<>1 THEN 1885 +1566 IF T<>1 THEN 1880 +1570 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 +1680 IF S(X,Y)=0 AND ABS(A-E)<=2 AND ABS(A-E)=ABS(B-H)THEN 1700 +1690 PRINT CHR$(7)CHR$(11);:GOTO 1670 +1700 I=46 +1750 S(A,B)=S(E,H):S(E,H)=0:IF ABS(E-A)<>2 THEN 1810 +1800 S((E+A)/2,(H+B)/2)=0 +1802 INPUT "+TO";A1,B1:IF A1<0 THEN 1810 +1804 IF S(A1,B1)<>0 OR ABS(A1-A)<>2 OR ABS(B1-B)<>2 THEN 1802 +1806 E=A:H=B:A=A1:B=B1:I=I+15:GOTO 1750 +1810 IF B=7 THEN S(A,B)=2 +1830 GOTO 230 +1880 PRINT: PRINT "YOU WIN.": END +1885 PRINT: PRINT "I WIN.": END diff --git a/00_Alternate_Languages/24_Chemist/README.md b/00_Alternate_Languages/24_Chemist/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/24_Chemist/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/24_Chemist/chemist.bas b/00_Alternate_Languages/24_Chemist/chemist.bas new file mode 100644 index 00000000..8b673c27 --- /dev/null +++ b/00_Alternate_Languages/24_Chemist/chemist.bas @@ -0,0 +1,27 @@ +3 PRINT TAB(33);"CHEMIST" +6 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +8 PRINT:PRINT:PRINT +10 PRINT "THE FICTITIOUS CHEMICAL KRYPTOCYANIC ACID CAN ONLY BE" +20 PRINT "DILUTED BY THE RATIO OF 7 PARTS WATER TO 3 PARTS ACID." +30 PRINT "IF ANY OTHER RATIO IS ATTEMPTED, THE ACID BECOMES UNSTABLE" +40 PRINT "AND SOON EXPLODES. GIVEN THE AMOUNT OF ACID, YOU MUST" +50 PRINT "DECIDE WHO MUCH WATER TO ADD FOR DILUTION. IF YOU MISS" +60 PRINT "YOU FACE THE CONSEQUENCES." +100 A=INT(RND(1)*50) +110 W=7*A/3 +120 PRINT A;"LITERS OF KRYPTOCYANIC ACID. HOW MUCH WATER"; +130 INPUT R +140 D=ABS(W-R) +150 IF D>W/20 THEN 200 +160 PRINT " GOOD JOB! YOU MAY BREATHE NOW, BUT DON'T INHALE THE FUMES!" +170 PRINT +180 GOTO 100 +200 PRINT " SIZZLE! YOU HAVE JUST BEEN DESALINATED INTO A BLOB" +210 PRINT " OF QUIVERING PROTOPLASM!" +220 T=T+1 +230 IF T=9 THEN 260 +240 PRINT " HOWEVER, YOU MAY TRY AGAIN WITH ANOTHER LIFE." +250 GOTO 100 +260 PRINT " YOUR 9 LIVES ARE USED, BUT YOU WILL BE LONG REMEMBERED FOR" +270 PRINT " YOUR CONTRIBUTIONS TO THE FIELD OF COMIC BOOK CHEMISTRY." +280 END diff --git a/00_Alternate_Languages/25_Chief/README.md b/00_Alternate_Languages/25_Chief/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/25_Chief/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/25_Chief/chief.bas b/00_Alternate_Languages/25_Chief/chief.bas new file mode 100644 index 00000000..d3157e73 --- /dev/null +++ b/00_Alternate_Languages/25_Chief/chief.bas @@ -0,0 +1,51 @@ +2 PRINT TAB(30) "CHIEF" +4 PRINT TAB(15) "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +6 PRINT:PRINT:PRINT +10 PRINT "I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD." +20 PRINT "ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR"; +30 INPUT A$ +40 IF A$="YES" THEN 60 +50 PRINT "SHUT UP, PALE FACE WITH WISE TONGUE." +60 PRINT " TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND" +70 PRINT "MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1." +80 PRINT " WHAT DO YOU HAVE"; +90 INPUT B +100 LET C = (B+1-5)*5/8*5-3 +110 PRINT "I BET YOUR NUMBER WAS" C". AM I RIGHT"; +120 INPUT D$ +130 IF D$="YES" THEN 500 +140 PRINT "WHAT WAS YOUR ORIGINAL NUMBER"; +150 INPUT K +155 LET F=K+3 +160 LET G=F/5 +170 LET H=G*8 +180 LET I=H/5+5 +190 LET J=I-1 +200 PRINT "SO YOU THINK YOU'RE SO SMART, EH?" +210 PRINT "NOW WATCH." +230 PRINT K"PLUS 3 EQUALS"F". THIS DIVIDED BY 5 EQUALS"G";" +240 PRINT "THIS TIMES 8 EQUALS"H". IF WE DIVIDE BY 5 AND ADD 5," +250 PRINT "WE GET"I", WHICH, MINUS 1, EQUALS"J"." +260 PRINT "NOW DO YOU BELIEVE ME"; +270 INPUT Z$ +290 IF Z$="YES" THEN 500 +295 PRINT "YOU HAVE MADE ME MAD!!!" +300 PRINT "THERE MUST BE A GREAT LIGHTNING BOLT!" +310 PRINT:PRINT +330 FOR X=30 TO 22 STEP -1 +340 PRINT TAB(X) "X X" +350 NEXT X +360 PRINT TAB(21) "X XXX" +370 PRINT TAB(20) "X X" +380 PRINT TAB(19) "XX X" +390 FOR Y=20 TO 13 STEP -1 +400 PRINT TAB(Y) "X X" +410 NEXT Y +420 PRINT TAB(12) "XX" +430 PRINT TAB(11) "X" +440 PRINT TAB(10) "*" +450 PRINT:PRINT"#########################":PRINT +470 PRINT "I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!" +480 GOTO 520 +500 PRINT "BYE!!!" +520 END diff --git a/00_Alternate_Languages/26_Chomp/README.md b/00_Alternate_Languages/26_Chomp/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/26_Chomp/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/26_Chomp/chomp.bas b/00_Alternate_Languages/26_Chomp/chomp.bas new file mode 100644 index 00000000..2ca7a51f --- /dev/null +++ b/00_Alternate_Languages/26_Chomp/chomp.bas @@ -0,0 +1,104 @@ +10 PRINT TAB(33);"CHOMP" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT:PRINT:PRINT +40 DIM A(10,10) +100 REM *** THE GAME OF CHOMP *** COPYRIGHT PCC 1973 *** +110 PRINT +120 PRINT "THIS IS THE GAME OF CHOMP (SCIENTIFIC AMERICAN, JAN 1973)" +130 PRINT "DO YOU WANT THE RULES (1=YES, 0=NO!)"; +140 INPUT R +150 IF R=0 THEN 340 +160 F=1 +170 R=5 +180 C=7 +190 PRINT "CHOMP IS FOR 1 OR MORE PLAYERS (HUMANS ONLY)." +200 PRINT +210 PRINT "HERE'S HOW A BOARD LOOKS (THIS ONE IS 5 BY 7):" +220 GOSUB 540 +230 PRINT +240 PRINT "THE BOARD IS A BIG COOKIE - R ROWS HIGH AND C COLUMNS" +250 PRINT "WIDE. YOU INPUT R AND C AT THE START. IN THE UPPER LEFT" +260 PRINT "CORNER OF THE COOKIE IS A POISON SQUARE (P). THE ONE WHO" +270 PRINT "CHOMPS THE POISON SQUARE LOSES. TO TAKE A CHOMP, TYPE THE" +280 PRINT "ROW AND COLUMN OF ONE OF THE SQUARES ON THE COOKIE." +290 PRINT "ALL OF THE SQUARES BELOW AND TO THE RIGHT OF THAT SQUARE" +300 PRINT "(INCLUDING THAT SQUARE, TOO) DISAPPEAR -- CHOMP!!" +310 PRINT "NO FAIR CHOMPING SQUARES THAT HAVE ALREADY BEEN CHOMPED," +320 PRINT "OR THAT ARE OUTSIDE THE ORIGINAL DIMENSIONS OF THE COOKIE." +330 PRINT +340 PRINT "HERE WE GO..." +350 REM +360 F=0 +370 FOR I=1 TO 10 +372 FOR J=1 TO 10 +375 A(I,J)=0 +377 NEXT J +379 NEXT I +380 PRINT +390 PRINT "HOW MANY PLAYERS"; +400 INPUT P +410 I1=0 +420 PRINT "HOW MANY ROWS"; +430 INPUT R +440 IF R <= 9 THEN 470 +450 PRINT "TOO MANY ROWS (9 IS MAXIMUM). NOW, "; +460 GOTO 420 +470 PRINT "HOW MANY COLUMNS"; +480 INPUT C +490 IF C <= 9 THEN 530 +500 PRINT "TOO MANY COLUMNS (9 IS MAXIMUM). NOW, "; +510 GOTO 470 +530 PRINT +540 FOR I=1 TO R +550 FOR J=1 TO C +560 A(I,J)=1 +570 NEXT J +580 NEXT I +590 A(1,1)=-1 +600 REM PRINT THE BOARD +610 PRINT +620 PRINT TAB(7);"1 2 3 4 5 6 7 8 9" +630 FOR I=1 TO R +640 PRINT I;TAB(7); +650 FOR J=1 TO C +660 IF A(I,J)=-1 THEN 700 +670 IF A(I,J)=0 THEN 720 +680 PRINT "* "; +690 GOTO 710 +700 PRINT "P "; +710 NEXT J +720 PRINT +730 NEXT I +740 PRINT +750 IF F=0 THEN 770 +760 RETURN +770 REM GET CHOMPS FOR EACH PLAYER IN TURN +780 LET I1=I1+1 +790 LET P1=I1-INT(I1/P)*P +800 IF P1 <> 0 THEN 820 +810 P1=P +820 PRINT "PLAYER";P1 +830 PRINT "COORDINATES OF CHOMP (ROW,COLUMN)"; +840 INPUT R1,C1 +850 IF R1<1 THEN 920 +860 IF R1>R THEN 920 +870 IF C1<1 THEN 920 +880 IF C1>C THEN 920 +890 IF A(R1,C1)=0 THEN 920 +900 IF A(R1,C1)=-1 THEN 1010 +910 GOTO 940 +920 PRINT "NO FAIR. YOU'RE TRYING TO CHOMP ON EMPTY SPACE!" +930 GOTO 820 +940 FOR I=R1 TO R +950 FOR J=C1 TO C +960 A(I,J)=0 +970 NEXT J +980 NEXT I +990 GOTO 610 +1000 REM END OF GAME DETECTED IN LINE 900 +1010 PRINT "YOU LOSE, PLAYER";P1 +1020 PRINT +1030 PRINT "AGAIN (1=YES, 0=NO!)"; +1040 INPUT R +1050 IF R=1 THEN 340 +1060 END diff --git a/00_Alternate_Languages/27_Civil_War/README.md b/00_Alternate_Languages/27_Civil_War/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/27_Civil_War/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/27_Civil_War/civilwar.bas b/00_Alternate_Languages/27_Civil_War/civilwar.bas new file mode 100644 index 00000000..f8fe9701 --- /dev/null +++ b/00_Alternate_Languages/27_Civil_War/civilwar.bas @@ -0,0 +1,395 @@ +2 PRINT TAB(26) "CIVIL WAR" +4 PRINT TAB(15) "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +6 PRINT : PRINT : PRINT +20 REM ORIGINAL GAME DESIGN: CRAM, GOODIE, HIBBARD LEXINGTON H.S. +30 REM MODIFICATIONS: G. PAUL, R. HESS (TIES), 1973 +50 DIM S(4),C$(14),M1(14),M2(14),C1(14),C2(14),M(14) +60 REM UNION INFO ON LIKELY CONFEDERATE STRATEGY +70 S(1)=25 : S(2)=25 : S(3)=25 : S(4)=25 +82 REM READ HISTORICAL DATA. +84 FOR D=1 TO 14 +86 READ C$(D),M1(D),M2(D),C1(D),C2(D),M(D) +88 NEXT D +89 LET D=RND(-1) +90 PRINT +100 PRINT "DO YOU WANT INSTRUCTIONS"; +110 INPUT X$ +120 IF X$="YES" THEN 160 +130 IF X$="NO" THEN 370 +140 PRINT "YES OR NO -- "; +150 GOTO 110 +160 PRINT : PRINT : PRINT : PRINT +170 PRINT "THIS IS A CIVIL WAR SIMULATION." +180 PRINT "TO PLAY TYPE A RESPONSE WHEN THE COMPUTER ASKS." +190 PRINT "REMEMBER THAT ALL FACTORS ARE INTERRELATED AND THAT YOUR" +200 PRINT "RESPONSES COULD CHANGE HISTORY. FACTS AND FIGURES USED ARE" +210 PRINT "BASED ON THE ACTUAL OCCURRENCE. MOST BATTLES TEND TO RESULT" +220 PRINT "AS THEY DID IN THE CIVIL WAR, BUT IT ALL DEPENDS ON YOU!!" +230 PRINT +240 PRINT "THE OBJECT OF THE GAME IS TO WIN AS MANY BATTLES AS "; +245 PRINT "POSSIBLE." +250 PRINT +260 PRINT "YOUR CHOICES FOR DEFENSIVE STRATEGY ARE:" +270 PRINT " (1) ARTILLERY ATTACK" +280 PRINT " (2) FORTIFICATION AGAINST FRONTAL ATTACK" +290 PRINT " (3) FORTIFICATION AGAINST FLANKING MANEUVERS" +300 PRINT " (4) FALLING BACK" +310 PRINT " YOUR CHOICES FOR OFFENSIVE STRATEGY ARE:" +320 PRINT " (1) ARTILLERY ATTACK" +330 PRINT " (2) FRONTAL ATTACK" +340 PRINT " (3) FLANKING MANEUVERS" +350 PRINT " (4) ENCIRCLEMENT" +360 PRINT "YOU MAY SURRENDER BY TYPING A '5' FOR YOUR STRATEGY." +370 PRINT : PRINT : PRINT : PRINT "ARE THERE TWO GENERALS PRESENT "; +380 PRINT "(ANSWER YES OR NO)"; +390 INPUT B$ +400 IF B$="YES" THEN 430 +410 IF B$ <> "NO" THEN 380 +420 PRINT : PRINT "YOU ARE THE CONFEDERACY. GOOD LUCK!" +425 PRINT +430 LET D=1 +440 IF B$ <> "YES" THEN 460 +450 LET D=2 +460 PRINT "SELECT A BATTLE BY TYPING A NUMBER FROM 1 TO 14 ON" +470 PRINT "REQUEST. TYPE ANY OTHER NUMBER TO END THE SIMULATION." +480 PRINT "BUT '0' BRINGS BACK EXACT PREVIOUS BATTLE SITUATION" +490 PRINT "ALLOWING YOU TO REPLAY IT" +500 PRINT +510 PRINT "NOTE: A NEGATIVE FOOD$ ENTRY CAUSES THE PROGRAM TO " +520 PRINT "USE THE ENTRIES FROM THE PREVIOUS BATTLE" +530 PRINT +540 PRINT "AFTER REQUESTING A BATTLE, DO YOU WISH "; +550 PRINT "BATTLE DESCRIPTIONS "; +560 PRINT "(ANSWER YES OR NO)"; +570 INPUT X$ +580 IF X$="YES" THEN 600 +590 IF X$ <> "NO" THEN 560 +600 L=0:W=0:R1=0:Q1=0:M3=0:M4=0:P1=0:P2=0:T1=0:T2=0 +610 F(2)=0:H(2)=0:B(2)=0:R2=0:Q2=0:C6=0:F=0:W0=0:Y=0:Y2=0:U=0:U2=0 +620 PRINT : PRINT : PRINT +630 PRINT "WHICH BATTLE DO YOU WISH TO SIMULATE"; +640 INPUT A +650 IF A <> 0 THEN 660 +655 IF R <> 0 THEN 1140 +660 IF A <=0 THEN 2860 +665 IF A >= 15 THEN 2860 +670 LET C$=C$(A) +680 LET M1=M1(A) +690 LET M2=M2(A) +700 LET C1=C1(A) +710 LET C2=C2(A) +720 LET M=M(A) +960 LET U=0 +970 REM INFLATION CALC +980 LET I1=10+(L-W)*2 +990 LET I2=10+(W-L)*2 +1000 REM - MONEY AVAILABLE +1010 LET D(1)=100*INT((M1*(100-I1)/2000)*(1+(R1-Q1)/(R1+1))+.5) +1020 LET D(2)=100*INT(M2*(100-I2)/2000+.5) +1030 IF B$ <> "YES" THEN 1050 +1040 LET D(2)=100*INT((M2*(100-I2)/2000)*(1+(R2-Q2)/(R2+1))+.5) +1050 REM - MEN AVAILABLE +1060 LET M5=INT(M1*(1+(P1-T1)/(M3+1))) +1070 LET M6=INT(M2*(1+(P2-T2)/(M4+1))) +1080 LET F1=5*M1/6 +1090 PRINT : PRINT : PRINT : PRINT : PRINT +1100 PRINT "THIS IS THE BATTLE OF ";C$ +1110 IF X$="NO" THEN 1150 +1120 IF A>11 THEN 1130 +1125 ON A GOTO 3580,3620,3650,3690,3720,3750,3780,3800,3830,3860,3890 +1130 ON A-11 GOTO 3920,3950,3980 +1140 PRINT C$" INSTANT REPLAY" +1150 PRINT +1160 PRINT " ","CONFEDERACY"," UNION" +1170 PRINT "MEN"," "M5," "M6 +1180 PRINT "MONEY","$";D(1),"$";D(2) +1190 PRINT "INFLATION"," ";I1+15;"%"," ";I2;"%" +1195 PRINT +1200 REM - ONLY IN PRINTOUT IS CONFED INFLATION = I1+15% +1210 REM - IF TWO GENERALS, INPUT CONFED. FIRST +1220 FOR I=1 TO D +1230 IF B$ <> "YES" THEN 1260 +1240 IF I=2 THEN 1260 +1250 PRINT "CONFEDERATE GENERAL---"; +1260 PRINT "HOW MUCH DO YOU WISH TO SPEND FOR" +1270 PRINT " - FOOD......"; +1280 INPUT F +1290 IF F >= 0 THEN 1360 +1300 IF R1 <> 0 THEN 1330 +1310 PRINT "NO PREVIOUS ENTRIES" +1320 GOTO 1270 +1330 PRINT "ASSUME YOU WANT TO KEEP SAME ALLOCATIONS" +1340 PRINT +1350 GOTO 1510 +1360 LET F(I)=F +1370 PRINT " - SALARIES.."; +1380 INPUT H(I) +1390 LET N=1 +1400 IF H(I)<0 THEN 1490 +1410 PRINT " - AMMUNITION"; +1420 INPUT B(I) +1430 LET N=2 +1440 IF B(I)<0 THEN 1490 +1450 PRINT +1460 IF F(I)+H(I)+B(I) <= D(I) THEN 1510 +1470 PRINT "THINK AGAIN! YOU HAVE ONLY $"D(I) +1480 GOTO 1270 +1490 PRINT "NEGATIVE VALUES NOT ALLOWED." +1500 ON N GOTO 1370,1410 +1510 IF B$ <> "YES" THEN 1550 +1520 IF I=2 THEN 1550 +1530 PRINT "UNION GENERAL---"; +1540 NEXT I +1550 FOR Z=1 TO D +1560 IF B$ <> "YES" THEN 1620 +1570 ON Z GOTO 1580,1600 +1580 PRINT "CONFEDERATE "; +1590 GOTO 1620 +1600 PRINT " UNION "; +1610 REM - FIND MORALE +1620 LET O=((2*F(Z)^2+H(Z)^2)/F1^2+1) +1630 IF O<10 THEN 1660 +1640 PRINT "MORALE IS HIGH" +1650 GOTO 1700 +1660 IF O<5 THEN 1690 +1670 PRINT "MORALE IS FAIR" +1680 GOTO 1700 +1690 PRINT "MORALE IS POOR" +1700 IF B$ <> "YES" THEN 1760 +1710 LET O(Z)=O +1720 NEXT Z +1730 LET O2=O(2) +1740 LET O=O(1) +1750 PRINT "CONFEDERATE GENERAL---"; +1760 REM - ACTUAL OFF/DEF BATTLE SITUATION +1770 IF M <> 3 THEN 1800 +1780 PRINT "YOU ARE ON THE OFFENSIVE" +1790 GOTO 1840 +1800 IF M <> 1 THEN 1830 +1810 PRINT "YOU ARE ON THE DEFENSIVE" +1820 GOTO 1840 +1830 PRINT "BOTH SIDES ARE ON THE OFFENSIVE " +1840 PRINT +1850 REM - CHOOSE STRATEGIES +1860 IF B$ <> "YES" THEN 1910 +1870 FOR I=1 TO 2 +1880 ON I GOTO 1890,1920 +1890 PRINT "CONFEDERATE STRATEGY "; +1900 GOTO 1920 +1910 PRINT "YOUR STRATEGY "; +1920 INPUT Y +1930 IF ABS(Y-3)<3 THEN 1960 +1940 PRINT "STRATEGY";Y;"NOT ALLOWED." +1950 GOTO 1910 +1960 IF B$="YES" THEN 2000 +1970 IF Y=5 THEN 2830 +1980 GOSUB 3110 +1990 GOTO 2170 +2000 IF I=2 THEN 2040 +2010 LET Y1=Y +2020 PRINT "UNION STRATEGY "; +2030 NEXT I +2040 LET Y2=Y +2050 LET Y=Y1 +2060 IF Y2=5 THEN 2020 +2070 REM : SIMULATED LOSSES-NORTH +2080 LET C6=(2*C2/5)*(1+1/(2*(ABS(Y2-Y)+1))) +2090 LET C6=C6*(1.28+(5*M2/6)/(B(2)+1)) +2100 LET C6=INT(C6*(1+1/O2)+.5) +2110 REM - IF LOSS > MEN PRESENT, RESCALE LOSSES +2120 LET E2=100/O2 +2130 IF INT(C6+E2) "YES" THEN 2530 +2320 PRINT "COMPARED TO THE ACTUAL CASUALTIES AT "C$ +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 WON +2370 IF U <> 1 THEN 2380 +2375 IF U2=1 THEN 2460 +2380 IF U=1 THEN 2420 +2390 IF U2=1 THEN 2440 +2400 IF C5+E=C6+E2 THEN 2460 +2410 IF C5+E 0 THEN 3180 +3140 INPUT Y2 +3150 IF Y2 <=0 THEN 3160 +3155 IF Y2<5 THEN 3290 +3160 PRINT "ENTER 1 , 2 ,3 , OR 4 (USUALLY PREVIOUS UNION STRATEGY)" +3170 GOTO 3140 +3180 LET S0=0 +3190 LET R=100*RND(0) +3200 FOR I=1 TO 4 +3210 LET S0=S0+S(I) +3220 REM - IF ACTUAL STRATEGY INFO IS IN PROGRAM DATA STATEMENTS +3230 REM THEN R-100 IS EXTRA WEIGHT GIVEN TO THAT STATEGY. +3240 IF R72000 THEN 5 +14 D=30000 +15 E=20000 +16 F=22000 +17 PRINT "YOU ATTACK FIRST. TYPE (1) FOR ARMY; (2) FOR NAVY;" +18 PRINT "AND (3) FOR AIR FORCE." +19 INPUT Y +20 PRINT "HOW MANY MEN" +21 INPUT X +22 IF X<0 THEN 20 +23 ON Y GOTO 100,200,300 +100 IF X>A THEN 20 +105 IF XB THEN 20 +210 IF XC THEN 20 +310 IF XA THEN 1030 +1610 IF TB THEN 1030 +1710 IF TC THEN 1030 +1810 IF T>F/2 THEN 1830 +1820 GOTO 1850 +1830 PRINT "MY NAVY AND AIR FORCE IN A COMBINED ATTACK LEFT" +1831 PRINT "YOUR COUNTRY IN SHAMBLES." +1835 A=A/3 +1837 B=B/3 +1840 C=C/3 +1845 GOTO 2000 +1850 PRINT "ONE OF YOUR PLANES CRASHED INTO MY HOUSE. I AM DEAD." +1851 PRINT "MY COUNTRY FELL APART." +1860 GOTO 2010 +2000 PRINT +2001 PRINT "FROM THE RESULTS OF BOTH OF YOUR ATTACKS," +2002 IF A+B+C>3/2*(D+E+F) THEN 2010 +2005 IF A+B+C<2/3*(D+E+F) THEN 2015 +2006 PRINT "THE TREATY OF PARIS CONCLUDED THAT WE TAKE OUR" +2007 PRINT "RESPECTIVE COUNTRIES AND LIVE IN PEACE." +2008 GOTO 2020 +2010 PRINT "YOU WON, OH! SHUCKS!!!!" +2012 GOTO 2020 +2015 PRINT "YOU LOST-I CONQUERED YOUR COUNTRY. IT SERVES YOU" +2016 PRINT "RIGHT FOR PLAYING THIS STUPID GAME!!!" +2020 END diff --git a/00_Alternate_Languages/29_Craps/README.md b/00_Alternate_Languages/29_Craps/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/29_Craps/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/29_Craps/craps.bas b/00_Alternate_Languages/29_Craps/craps.bas new file mode 100644 index 00000000..3a387059 --- /dev/null +++ b/00_Alternate_Languages/29_Craps/craps.bas @@ -0,0 +1,82 @@ +5 PRINT TAB(33);"CRAPS" +10 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +12 PRINT:PRINT:PRINT +15 LET R=0 +20 PRINT"2,3,12 ARE LOSERS; 4,5,6,8,9,10 ARE POINTS; 7,11 ARE NATURAL WINNERS." +21 LET T=1 +22 PRINT "PICK A NUMBER AND INPUT TO ROLL DICE"; +23 INPUT Z +24 LET X=(RND(0)) +25 LET T =T+1 +26 IF T<=Z THEN 24 +27 PRINT"INPUT THE AMOUNT OF YOUR WAGER."; +28 INPUT F +30 PRINT "I WILL NOW THROW THE DICE" +40 LET E=INT(7*RND(1)) +41 LET S=INT(7*RND(1)) +42 LET X=E+S +50 IF X=7 THEN 180 +55 IF X=11 THEN 180 +60 IF X=1 THEN 40 +62 IF X=2 THEN 195 +65 IF X=0 THEN 40 +70 IF X=2 THEN 200 +80 IF X=3 THEN 200 +90 IF X=12 THEN 200 +125 IF X=5 THEN 220 +130 IF X =6 THEN 220 +140 IF X=8 THEN 220 +150 IF X=9 THEN 220 +160 IF X =10 THEN 220 +170 IF X=4 THEN 220 +180 PRINT X "- NATURAL....A WINNER!!!!" +185 PRINT X"PAYS EVEN MONEY, YOU WIN"F"DOLLARS" +190 GOTO 210 +195 PRINT X"- SNAKE EYES....YOU LOSE." +196 PRINT "YOU LOSE"F "DOLLARS." +197 LET F=0-F +198 GOTO 210 +200 PRINT X " - CRAPS...YOU LOSE." +205 PRINT "YOU LOSE"F"DOLLARS." +206 LET F=0-F +210 LET R= R+F +211 GOTO 320 +220 PRINT X "IS THE POINT. I WILL ROLL AGAIN" +230 LET H=INT(7*RND(1)) +231 LET Q=INT(7*RND(1)) +232 LET O=H+Q +240 IF O=1 THEN 230 +250 IF O=7 THEN 290 +255 IF O=0 THEN 230 +260 IF O=X THEN 310 +270 PRINT O " - NO POINT. I WILL ROLL AGAIN" +280 GOTO 230 +290 PRINT O "- CRAPS. YOU LOSE." +291 PRINT "YOU LOSE $"F +292 F=0-F +293 GOTO 210 +300 GOTO 320 +310 PRINT X"- A WINNER.........CONGRATS!!!!!!!!" +311 PRINT X "AT 2 TO 1 ODDS PAYS YOU...LET ME SEE..."2*F"DOLLARS" +312 LET F=2*F +313 GOTO 210 +320 PRINT " IF YOU WANT TO PLAY AGAIN PRINT 5 IF NOT PRINT 2"; +330 INPUT M +331 IF R<0 THEN 334 +332 IF R>0 THEN 336 +333 IF R=0 THEN 338 +334 PRINT "YOU ARE NOW UNDER $";-R +335 GOTO 340 +336 PRINT "YOU ARE NOW AHEAD $";R +337 GOTO 340 +338 PRINT "YOU ARE NOW EVEN AT 0" +340 IF M=5 THEN 27 +341 IF R<0 THEN 350 +342 IF R>0 THEN 353 +343 IF R=0 THEN 355 +350 PRINT"TOO BAD, YOU ARE IN THE HOLE. COME AGAIN." +351 GOTO 360 +353 PRINT"CONGRATULATIONS---YOU CAME OUT A WINNER. COME AGAIN!" +354 GOTO 360 +355 PRINT"CONGRATULATIONS---YOU CAME OUT EVEN, NOT BAD FOR AN AMATEUR" +360 END diff --git a/00_Alternate_Languages/29_Craps/distributions.bas b/00_Alternate_Languages/29_Craps/distributions.bas new file mode 100644 index 00000000..a963b228 --- /dev/null +++ b/00_Alternate_Languages/29_Craps/distributions.bas @@ -0,0 +1,24 @@ +10 PRINT "DISTRIBUTION OF DICE ROLLS WITH INT(7*RND(1)) VS INT(6*RND(1)+1)" +20 DIM A(12) +30 DIM B(12) +100 FOR X = 1 TO 100000 : REM CHOOSE A LARGE NUMBER TO GET A FINER GRAINED HISTOGRAM +140 REM GET A NUMBER FROM 0 TO 6 INCLUSIVE WITH THE INTENT TO THROW AWAY ZEROES. +150 LET D1 = INT(7*RND(1)) +155 LET D2 = INT(7*RND(1)) +160 LET S1 = D1+D2 +165 REM IF THIS SUM IS LESS THAN TWO THEN TRY AGAIN. +170 IF S1<2 THEN 150 +199 REM GET A NUMBER FROM 0 TO 5 THEN ADD 1 TO IT TO MAKE IT 1 TO 6 +200 LET D3 = INT(6*RND(1))+1 +210 LET D4 = INT(6*RND(1))+1 +220 LET S2 = D3+D4 +245 REM USE OUR ARRAY AS A HISTOGRAM, COUNTING EACH OCCURRENCE OF DICE ROLL +250 A(S1) = A(S1) + 1 +260 B(S2) = B(S2) + 1 +290 NEXT X +300 PRINT "THE INT(7*RND(1)) DISTRIBUTION:" +310 FOR I = 2 TO 12 :PRINT I,:NEXT:PRINT +320 FOR I = 2 TO 12 :PRINT A(I),:NEXT:PRINT +325 PRINT "THE INT(6*RND(1)+1) DISTRIBUTION" +330 FOR I = 2 TO 12 :PRINT I,:NEXT:PRINT +340 FOR I = 2 TO 12 :PRINT B(I),:NEXT:PRINT diff --git a/00_Alternate_Languages/30_Cube/README.md b/00_Alternate_Languages/30_Cube/README.md new file mode 100644 index 00000000..d9f03b9d --- /dev/null +++ b/00_Alternate_Languages/30_Cube/README.md @@ -0,0 +1,3 @@ +#### External Links + - Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp + - PowerShell: https://github.com/eweilnau/basic-computer-games-powershell/blob/main/AceyDucey.ps1 diff --git a/00_Alternate_Languages/30_Cube/cube.bas b/00_Alternate_Languages/30_Cube/cube.bas new file mode 100644 index 00000000..b2019839 --- /dev/null +++ b/00_Alternate_Languages/30_Cube/cube.bas @@ -0,0 +1,161 @@ +10 PRINT TAB(34);"CUBE" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT : PRINT : PRINT +100 PRINT "DO YOU WANT TO SEE THE INSTRUCTIONS? (YES--1,NO--0)" +110 INPUT B7 +120 IF B7=0 THEN 370 +130 PRINT"THIS IS A GAME IN WHICH YOU WILL BE PLAYING AGAINST THE" +140 PRINT"RANDOM DECISION OF THE COMPUTER. THE FIELD OF PLAY IS A" +150 PRINT"CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED" +160 PRINT"BY INPUTING THREE NUMBERS SUCH AS 2,3,1. AT THE START," +170 PRINT"YOU ARE AUTOMATICALLY AT LOCATION 1,1,1. THE OBJECT OF" +180 PRINT"THE GAME IS TO GET TO LOCATION 3,3,3. ONE MINOR DETAIL:" +190 PRINT"THE COMPUTER WILL PICK, AT RANDOM, 5 LOCATIONS AT WHICH" +200 PRINT"IT WILL PLANT LAND MINES. IF YOU HIT ONE OF THESE LOCATIONS" +210 PRINT"YOU LOSE. ONE OTHER DETAIL: YOU MAY MOVE ONLY ONE SPACE " +220 PRINT"IN ONE DIRECTION EACH MOVE. FOR EXAMPLE: FROM 1,1,2 YOU" +230 PRINT"MAY MOVE TO 2,1,2 OR 1,1,3. YOU MAY NOT CHANGE" +240 PRINT"TWO OF THE NUMBERS ON THE SAME MOVE. IF YOU MAKE AN ILLEGAL" +250 PRINT"MOVE, YOU LOSE AND THE COMPUTER TAKES THE MONEY YOU MAY" +260 PRINT"HAVE BET ON THAT ROUND." +270 PRINT +280 PRINT +290 PRINT"ALL YES OR NO QUESTIONS WILL BE ANSWERED BY A 1 FOR YES" +300 PRINT"OR A 0 (ZERO) FOR NO." +310 PRINT +320 PRINT"WHEN STATING THE AMOUNT OF A WAGER, PRINT ONLY THE NUMBER" +330 PRINT"OF DOLLARS (EXAMPLE: 250) YOU ARE AUTOMATICALLY STARTED WITH" +340 PRINT"500 DOLLARS IN YOUR ACCOUNT." +350 PRINT +360 PRINT "GOOD LUCK!" +370 LET A1=500 +380 LET A=INT(3*(RND(X))) +390 IF A<>0 THEN 410 +400 LET A=3 +410 LET B=INT(3*(RND(X))) +420 IF B<>0 THEN 440 +430 LET B=2 +440 LET C=INT(3*(RND(X))) +450 IF C<>0 THEN 470 +460 LET C=3 +470 LET D=INT(3*(RND(X))) +480 IF D<>0 THEN 500 +490 LET D=1 +500 LET E=INT(3*(RND(X))) +510 IF E<>0 THEN 530 +520 LET E=3 +530 LET F=INT(3*(RND(X))) +540 IF F<>0 THEN 560 +550 LET F=3 +560 LET G=INT(3*(RND(X))) +570 IF G<>0 THEN 590 +580 LET G=3 +590 LET H=INT(3*(RND(X))) +600 IF H<>0 THEN 620 +610 LET H=3 +620 LET I=INT(3*(RND(X))) +630 IF I<>0 THEN 650 +640 LET I=2 +650 LET J=INT(3*(RND(X))) +660 IF J<>0 THEN 680 +670 LET J=3 +680 LET K=INT(3*(RND(X))) +690 IF K<>0 THEN 710 +700 LET K=2 +710 LET L=INT(3*(RND(X))) +720 IF L<>0 THEN 740 +730 LET L=3 +740 LET M=INT(3*(RND(X))) +750 IF M<>0 THEN 770 +760 LET M=3 +770 LET N=INT(3*(RND(X))) +780 IF N<>0 THEN 800 +790 LET N=1 +800 LET O=INT (3*(RND(X))) +810 IF O <>0 THEN 830 +820 LET O=3 +830 PRINT "WANT TO MAKE A WAGER?" +840 INPUT Z +850 IF Z=0 THEN 880 +860 PRINT "HOW MUCH "; +870 INPUT Z1 +876 IF A1W+1 THEN 1030 +950 IF P=W+1 THEN 1000 +960 IF Q>X+1 THEN 1030 +970 IF Q=(X+1) THEN 1010 +980 IF R >(Y+1) THEN 1030 +990 GOTO 1050 +1000 IF Q>= X+1 THEN 1030 +1010 IF R>=Y+1 THEN 1030 +1020 GOTO 1050 +1030 PRINT:PRINT "ILLEGAL MOVE. YOU LOSE." +1040 GOTO 1440 +1050 LET W=P +1060 LET X=Q +1070 LET Y=R +1080 IF P=3 THEN 1100 +1090 GOTO 1130 +1100 IF Q=3 THEN 1120 +1110 GOTO 1130 +1120 IF R=3 THEN 1530 +1130 IF P=A THEN 1150 +1140 GOTO 1180 +1150 IF Q=B THEN 1170 +1160 GOTO 1180 +1170 IF R=C THEN 1400 +1180 IF P=D THEN 1200 +1190 GOTO 1230 +1200 IF Q=E THEN 1220 +1210 GOTO 1230 +1220 IF R=F THEN 1400 +1230 IF P=G THEN 1250 +1240 GOTO 1280 +1250 IF Q=H THEN 1270 +1260 GOTO 1280 +1270 IF R=I THEN 1400 +1280 IF P=J THEN 1300 +1290 GOTO 1330 +1300 IF Q=K THEN 1320 +1310 GOTO 1330 +1320 IF R=L THEN 1400 +1330 IF P=M THEN 1350 +1340 GOTO 1380 +1350 IF Q=N THEN 1370 +1360 GOTO 1380 +1370 IF R=O THEN 1400 +1380 PRINT "NEXT MOVE: "; +1390 GOTO 930 +1400 PRINT"******BANG******" +1410 PRINT "YOU LOSE!" +1420 PRINT +1430 PRINT +1440 IF Z=0 THEN 1580 +1450 PRINT +1460 LET Z2=A1-Z1 +1470 IF Z2>0 THEN 1500 +1480 PRINT "YOU BUST." +1490 GOTO 1610 +1500 PRINT " YOU NOW HAVE"; Z2; "DOLLARS." +1510 LET A1=Z2 +1520 GOTO 1580 +1522 PRINT"TRIED TO FOOL ME; BET AGAIN"; +1525 GOTO 870 +1530 PRINT"CONGRATULATIONS!" +1540 IF Z=0 THEN 1580 +1550 LET Z2=A1+Z1 +1560 PRINT "YOU NOW HAVE"; Z2;"DOLLARS." +1570 LET A1=Z2 +1580 PRINT"DO YOU WANT TO TRY AGAIN "; +1590 INPUT S +1600 IF S=1 THEN 380 +1610 PRINT "TOUGH LUCK!" +1620 PRINT +1630 PRINT "GOODBYE." +1640 END diff --git a/00_Alternate_Languages/31_Depth_Charge/README.md b/00_Alternate_Languages/31_Depth_Charge/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/31_Depth_Charge/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/31_Depth_Charge/depthcharge.bas b/00_Alternate_Languages/31_Depth_Charge/depthcharge.bas new file mode 100644 index 00000000..0b58467d --- /dev/null +++ b/00_Alternate_Languages/31_Depth_Charge/depthcharge.bas @@ -0,0 +1,33 @@ +2 PRINT TAB(30);"DEPTH CHARGE" +4 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +6 PRINT: PRINT: PRINT +20 INPUT "DIMENSION OF SEARCH AREA";G: PRINT +30 N=INT(LOG(G)/LOG(2))+1 +40 PRINT "YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER" +50 PRINT "AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR" +60 PRINT "MISSION IS TO DESTROY IT. YOU HAVE";N;"SHOTS." +70 PRINT "SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A" +80 PRINT "TRIO OF NUMBERS -- THE FIRST TWO ARE THE" +90 PRINT "SURFACE COORDINATES; THE THIRD IS THE DEPTH." +100 PRINT : PRINT "GOOD LUCK !": PRINT +110 A=INT(G*RND(1)) : B=INT(G*RND(1)) : C=INT(G*RND(1)) +120 FOR D=1 TO N : PRINT : PRINT "TRIAL #";D; : INPUT X,Y,Z +130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300 +140 GOSUB 500 : PRINT : NEXT D +200 PRINT : PRINT "YOU HAVE BEEN TORPEDOED! ABANDON SHIP!" +210 PRINT "THE SUBMARINE WAS AT";A;",";B;",";C : GOTO 400 +300 PRINT : PRINT "B O O M ! ! YOU FOUND IT IN";D;"TRIES!" +400 PRINT : PRINT: INPUT "ANOTHER GAME (Y OR N)";A$ +410 IF A$="Y" THEN 100 +420 PRINT "OK. HOPE YOU ENJOYED YOURSELF." : GOTO 600 +500 PRINT "SONAR REPORTS SHOT WAS "; +510 IF Y>B THEN PRINT "NORTH"; +520 IF YA THEN PRINT "EAST"; +540 IF XB OR X<>A THEN PRINT " AND"; +560 IF Z>C THEN PRINT " TOO LOW." +570 IF Z + + Exe + net6.0 + 10 + enable + enable + + diff --git a/00_Alternate_Languages/32_Diamond/csharp/Diamond.sln b/00_Alternate_Languages/32_Diamond/csharp/Diamond.sln new file mode 100644 index 00000000..2af37dbd --- /dev/null +++ b/00_Alternate_Languages/32_Diamond/csharp/Diamond.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Diamond", "Diamond.csproj", "{44B406C8-70F0-4183-B19A-5B045A1AEBA4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {44B406C8-70F0-4183-B19A-5B045A1AEBA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44B406C8-70F0-4183-B19A-5B045A1AEBA4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44B406C8-70F0-4183-B19A-5B045A1AEBA4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44B406C8-70F0-4183-B19A-5B045A1AEBA4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/74_Rock_Scissors_Paper/pascal/README.md b/00_Alternate_Languages/32_Diamond/csharp/README.md similarity index 51% rename from 74_Rock_Scissors_Paper/pascal/README.md rename to 00_Alternate_Languages/32_Diamond/csharp/README.md index aa1b3ae5..4daabb5c 100644 --- a/74_Rock_Scissors_Paper/pascal/README.md +++ b/00_Alternate_Languages/32_Diamond/csharp/README.md @@ -1,3 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language)) +Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) diff --git a/00_Alternate_Languages/32_Diamond/diamond.bas b/00_Alternate_Languages/32_Diamond/diamond.bas new file mode 100644 index 00000000..5c940580 --- /dev/null +++ b/00_Alternate_Languages/32_Diamond/diamond.bas @@ -0,0 +1,27 @@ +1 PRINT TAB(33);"DIAMOND" +2 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +3 PRINT:PRINT:PRINT +4 PRINT "FOR A PRETTY DIAMOND PATTERN," +5 INPUT "TYPE IN AN ODD NUMBER BETWEEN 5 AND 21";R:PRINT +6 Q=INT(60/R):A$="CC" +8 FOR L=1 TO Q +10 X=1:Y=R:Z=2 +20 FOR N=X TO Y STEP Z +25 PRINT TAB((R-N)/2); +28 FOR M=1 TO Q +29 C=1 +30 FOR A=1 TO N +32 IF C>LEN(A$) THEN PRINT "!";:GOTO 50 +34 PRINT MID$(A$,C,1); +36 C=C+1 +50 NEXT A +53 IF M=Q THEN 60 +55 PRINT TAB(R*M+(R-N)/2); +56 NEXT M +60 PRINT +70 NEXT N +83 IF X<>1 THEN 95 +85 X=R-2:Y=1:Z=-2 +90 GOTO 20 +95 NEXT L +99 END diff --git a/00_Alternate_Languages/32_Diamond/java/Diamond.java b/00_Alternate_Languages/32_Diamond/java/Diamond.java new file mode 100644 index 00000000..2989ce2d --- /dev/null +++ b/00_Alternate_Languages/32_Diamond/java/Diamond.java @@ -0,0 +1,163 @@ +import java.util.Scanner; + +/** + * Game of Diamond + *

+ * Based on the BASIC game of Diamond here + * https://github.com/coding-horror/basic-computer-games/blob/main/32%20Diamond/diamond.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 Diamond { + + private static final int LINE_WIDTH = 60; + + private static final String PREFIX = "CC"; + + private static final char SYMBOL = '!'; + + private final Scanner scan; // For user input + + + public Diamond() { + + scan = new Scanner(System.in); + + } // End of constructor Diamond + + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + + private void showIntro() { + + System.out.println(" ".repeat(32) + "DIAMOND"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + } // End of method showIntro + + + private void startGame() { + + int body = 0; + int column = 0; + int end = 0; + int fill = 0; + int increment = 2; + int numPerSide = 0; + int prefixIndex = 0; + int row = 0; + int start = 1; + int userNum = 0; + + String lineContent = ""; + + // Get user input + System.out.println("FOR A PRETTY DIAMOND PATTERN,"); + System.out.print("TYPE IN AN ODD NUMBER BETWEEN 5 AND 21? "); + userNum = scan.nextInt(); + System.out.println(""); + + // Calcuate number of diamonds to be drawn on each side of screen + numPerSide = (int) (LINE_WIDTH / userNum); + + end = userNum; + + // Begin loop through each row of diamonds + for (row = 1; row <= numPerSide; row++) { + + // Begin loop through top and bottom halves of each diamond + for (body = start; increment < 0 ? body >= end : body <= end; body += increment) { + + lineContent = ""; + + // Add whitespace + while (lineContent.length() < ((userNum - body) / 2)) { + lineContent += " "; + } + + // Begin loop through each column of diamonds + for (column = 1; column <= numPerSide; column++) { + + prefixIndex = 1; + + // Begin loop that fills each diamond with characters + for (fill = 1; fill <= body; fill++) { + + // Right side of diamond + if (prefixIndex > PREFIX.length()) { + + lineContent += SYMBOL; + + } + // Left side of diamond + else { + + lineContent += PREFIX.charAt(prefixIndex - 1); + prefixIndex++; + + } + + } // End loop that fills each diamond with characters + + // Column finished + if (column == numPerSide) { + + break; + + } + // Column not finishd + else { + + // Add whitespace + while (lineContent.length() < (userNum * column + (userNum - body) / 2)) { + lineContent += " "; + } + + } + + } // End loop through each column of diamonds + + System.out.println(lineContent); + + } // End loop through top and bottom half of each diamond + + if (start != 1) { + + start = 1; + end = userNum; + increment = 2; + + } + else { + + start = userNum - 2; + end = 1; + increment = -2; + row--; + + } + + } // End loop through each row of diamonds + + } // End of method startGame + + + public static void main(String[] args) { + + Diamond diamond = new Diamond(); + diamond.play(); + + } // End of method main + +} // End of class Diamond diff --git a/75_Roulette/pascal/README.md b/00_Alternate_Languages/32_Diamond/java/README.md similarity index 51% rename from 75_Roulette/pascal/README.md rename to 00_Alternate_Languages/32_Diamond/java/README.md index aa1b3ae5..51edd8d4 100644 --- a/75_Roulette/pascal/README.md +++ b/00_Alternate_Languages/32_Diamond/java/README.md @@ -1,3 +1,3 @@ Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) -Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language)) +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/32_Diamond/javascript/README.md b/00_Alternate_Languages/32_Diamond/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/32_Diamond/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/32_Diamond/javascript/diamond.html b/00_Alternate_Languages/32_Diamond/javascript/diamond.html new file mode 100644 index 00000000..9756b2ab --- /dev/null +++ b/00_Alternate_Languages/32_Diamond/javascript/diamond.html @@ -0,0 +1,9 @@ + + +DIAMOND + + +


+
+
+
diff --git a/00_Alternate_Languages/32_Diamond/javascript/diamond.js b/00_Alternate_Languages/32_Diamond/javascript/diamond.js
new file mode 100644
index 00000000..e454a2d5
--- /dev/null
+++ b/00_Alternate_Languages/32_Diamond/javascript/diamond.js
@@ -0,0 +1,94 @@
+// DIAMOND
+//
+// 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(33) + "DIAMOND\n");
+    print(tab(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");
+    r = parseInt(await input());
+    q = Math.floor(60 / r);
+    as = "CC"
+    x = 1;
+    y = r;
+    z = 2;
+    for (l = 1; l <= q; l++) {
+        for (n = x; z < 0 ? n >= y : n <= y; n += z) {
+            str = "";
+            while (str.length < (r - n) / 2)
+                str += " ";
+            for (m = 1; m <= q; m++) {
+                c = 1;
+                for (a = 1; a <= n; a++) {
+                    if (c > as.length)
+                        str += "!";
+                    else
+                        str += as[c++ - 1];
+                }
+                if (m == q)
+                    break;
+                while (str.length < r * m + (r - n) / 2)
+                    str += " ";
+            }
+            print(str + "\n");
+        }
+        if (x != 1) {
+            x = 1;
+            y = r;
+            z = 2;
+        } else {
+            x = r - 2;
+            y = 1;
+            z = -2;
+            l--;
+        }
+    }
+}
+
+main();
diff --git a/04_Awari/pascal/README.md b/00_Alternate_Languages/32_Diamond/pascal/README.md
similarity index 100%
rename from 04_Awari/pascal/README.md
rename to 00_Alternate_Languages/32_Diamond/pascal/README.md
diff --git a/76_Russian_Roulette/pascal/README.md b/00_Alternate_Languages/32_Diamond/perl/README.md
similarity index 51%
rename from 76_Russian_Roulette/pascal/README.md
rename to 00_Alternate_Languages/32_Diamond/perl/README.md
index aa1b3ae5..e69c8b81 100644
--- a/76_Russian_Roulette/pascal/README.md
+++ b/00_Alternate_Languages/32_Diamond/perl/README.md
@@ -1,3 +1,3 @@
 Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
 
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/32_Diamond/perl/diamond.pl b/00_Alternate_Languages/32_Diamond/perl/diamond.pl
new file mode 100644
index 00000000..fcd4dc40
--- /dev/null
+++ b/00_Alternate_Languages/32_Diamond/perl/diamond.pl
@@ -0,0 +1,35 @@
+#!/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;
diff --git a/77_Salvo/pascal/README.md b/00_Alternate_Languages/32_Diamond/python/README.md
similarity index 51%
rename from 77_Salvo/pascal/README.md
rename to 00_Alternate_Languages/32_Diamond/python/README.md
index aa1b3ae5..781945ec 100644
--- a/77_Salvo/pascal/README.md
+++ b/00_Alternate_Languages/32_Diamond/python/README.md
@@ -1,3 +1,3 @@
 Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
 
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/32_Diamond/python/diamond.py b/00_Alternate_Languages/32_Diamond/python/diamond.py
new file mode 100644
index 00000000..a622eb58
--- /dev/null
+++ b/00_Alternate_Languages/32_Diamond/python/diamond.py
@@ -0,0 +1,64 @@
+"""
+DIAMOND
+
+Prints pretty diamond patterns to the screen.
+
+Ported by Dave LeCompte
+"""
+
+
+def print_with_tab(space_count, msg):
+    if space_count > 0:
+        spaces = " " * space_count
+    else:
+        spaces = ""
+    print(spaces + msg)
+
+
+def print_diamond(begin_width, end_width, step, width, count):
+    edgeString = "CC"
+    fill = "!"
+
+    n = begin_width
+    while True:
+        line_buffer = " " * ((width - n) // 2)
+        for across in range(count):
+            for a in range(n):
+                if a >= len(edgeString):
+                    line_buffer += fill
+                else:
+                    line_buffer += edgeString[a]
+            line_buffer += " " * (
+                (width * (across + 1) + (width - n) // 2) - len(line_buffer)
+            )
+        print(line_buffer)
+        if n == end_width:
+            return
+        n += step
+
+
+def main():
+    print_with_tab(33, "DIAMOND")
+    print_with_tab(15, "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+    print("FOR A PRETTY DIAMOND PATTERN,")
+    print("TYPE IN AN ODD NUMBER BETWEEN 5 AND 21")
+    width = int(input())
+    print()
+
+    PAGE_WIDTH = 60
+
+    count = int(PAGE_WIDTH / width)
+
+    for down in range(count):
+        print_diamond(1, width, 2, width, count)
+        print_diamond(width - 2, 1, -2, width, count)
+
+    print()
+    print()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/32_Diamond/ruby/README.md b/00_Alternate_Languages/32_Diamond/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/32_Diamond/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/32_Diamond/ruby/diamond.rb b/00_Alternate_Languages/32_Diamond/ruby/diamond.rb
new file mode 100644
index 00000000..a28f4e55
--- /dev/null
+++ b/00_Alternate_Languages/32_Diamond/ruby/diamond.rb
@@ -0,0 +1,45 @@
+def intro
+  print "                                 DIAMOND
+               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+
+
+
+FOR A PRETTY DIAMOND PATTERN,
+TYPE IN AN ODD NUMBER BETWEEN 5 AND 21? "
+end
+
+def get_facets
+  while true
+    number = gets.chomp
+    return number.to_i if /^\d+$/.match(number)
+    puts "!NUMBER EXPECTED - RETRY INPUT LINE"
+    print "? "
+  end
+end
+
+def get_diamond_lines(facets)
+  spacers = (facets - 1) / 2
+  lines = [' ' * spacers + 'C' + ' ' * spacers]
+  lines += (1...facets).step(2).to_a.map { |v|
+    spacers -= 1
+    ' ' * spacers + 'CC' + '!' * v + ' ' * spacers
+  }
+  lines + lines[0..-2].reverse
+end
+
+def draw_diamonds(lines)
+  repeat = 60 / lines[0].length
+  (0...repeat).each { lines.map { |l| l * repeat }.each { |l| puts l } }
+end
+
+def main
+  intro
+  facets = get_facets
+  puts
+  lines = get_diamond_lines(facets)
+  draw_diamonds(lines)
+end
+
+trap "SIGINT" do puts; exit 130 end
+
+main
diff --git a/00_Alternate_Languages/32_Diamond/vbnet/Diamond.sln b/00_Alternate_Languages/32_Diamond/vbnet/Diamond.sln
new file mode 100644
index 00000000..3f05715d
--- /dev/null
+++ b/00_Alternate_Languages/32_Diamond/vbnet/Diamond.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Diamond", "Diamond.vbproj", "{87084ED3-F01C-4D7E-8BE7-10C2F3FA148F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{87084ED3-F01C-4D7E-8BE7-10C2F3FA148F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{87084ED3-F01C-4D7E-8BE7-10C2F3FA148F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{87084ED3-F01C-4D7E-8BE7-10C2F3FA148F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{87084ED3-F01C-4D7E-8BE7-10C2F3FA148F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/32_Diamond/vbnet/Diamond.vbproj b/00_Alternate_Languages/32_Diamond/vbnet/Diamond.vbproj
new file mode 100644
index 00000000..069fe872
--- /dev/null
+++ b/00_Alternate_Languages/32_Diamond/vbnet/Diamond.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Diamond
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/32_Diamond/vbnet/README.md b/00_Alternate_Languages/32_Diamond/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/32_Diamond/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/33_Dice/README.md b/00_Alternate_Languages/33_Dice/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/33_Dice/csharp/Dice.csproj b/00_Alternate_Languages/33_Dice/csharp/Dice.csproj
new file mode 100644
index 00000000..54cdbe42
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/csharp/Dice.csproj
@@ -0,0 +1,12 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+  
+    
+  
+
+
diff --git a/00_Alternate_Languages/33_Dice/csharp/Dice.sln b/00_Alternate_Languages/33_Dice/csharp/Dice.sln
new file mode 100644
index 00000000..738a8c1c
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/csharp/Dice.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dice", "Dice.csproj", "{D136AC51-DDC0-471A-8EAC-D3C772FA7D51}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D136AC51-DDC0-471A-8EAC-D3C772FA7D51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D136AC51-DDC0-471A-8EAC-D3C772FA7D51}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D136AC51-DDC0-471A-8EAC-D3C772FA7D51}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D136AC51-DDC0-471A-8EAC-D3C772FA7D51}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/33_Dice/csharp/Game.cs b/00_Alternate_Languages/33_Dice/csharp/Game.cs
new file mode 100644
index 00000000..0a21da35
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/csharp/Game.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Linq;
+
+namespace BasicComputerGames.Dice
+{
+	public class Game
+	{
+		private readonly RollGenerator _roller = new RollGenerator();
+
+		public void GameLoop()
+		{
+			DisplayIntroText();
+
+			// RollGenerator.ReseedRNG(1234);		// hard-code seed for repeatabilty during testing
+
+			do
+			{
+				int numRolls = GetInput();
+				var counter = CountRolls(numRolls);
+				DisplayCounts(counter);
+			} while (TryAgain());
+		}
+
+		private void DisplayIntroText()
+		{
+			Console.ForegroundColor = ConsoleColor.Yellow;
+			Console.WriteLine("Dice");
+			Console.WriteLine("Creating Computing, Morristown, New Jersey."); Console.WriteLine();
+
+			Console.ForegroundColor = ConsoleColor.DarkGreen;
+			Console.WriteLine("Original code by Danny Freidus.");
+			Console.WriteLine("Originally published in 1978 in the book 'Basic Computer Games' by David Ahl.");
+			Console.WriteLine("Modernized and converted to C# in 2021 by James Curran (noveltheory.com).");
+			Console.WriteLine();
+
+			Console.ForegroundColor = ConsoleColor.Gray;
+			Console.WriteLine("This program simulates the rolling of a pair of dice.");
+			Console.WriteLine("You enter the number of times you want the computer to");
+			Console.WriteLine("'roll' the dice. Watch out, very large numbers take");
+			Console.WriteLine("a long time. In particular, numbers over 10 million.");
+			Console.WriteLine();
+
+			Console.ForegroundColor = ConsoleColor.Yellow;
+			Console.WriteLine("Press any key start the game.");
+			Console.ReadKey(true);
+		}
+
+		private int GetInput()
+		{
+			int num = -1;
+			Console.WriteLine();
+			do
+			{
+				Console.WriteLine();
+				Console.Write("How many rolls? ");
+			} while (!Int32.TryParse(Console.ReadLine(), out num));
+
+			return num;
+		}
+
+		private  void DisplayCounts(int[] counter)
+		{
+			Console.WriteLine();
+			Console.WriteLine($"\tTotal\tTotal Number");
+			Console.WriteLine($"\tSpots\tof Times");
+			Console.WriteLine($"\t===\t=========");
+			for (var n = 1; n < counter.Length; ++n)
+			{
+				Console.WriteLine($"\t{n + 1,2}\t{counter[n],9:#,0}");
+			}
+			Console.WriteLine();
+		}
+
+		private  int[] CountRolls(int x)
+		{
+			var counter = _roller.Rolls().Take(x).Aggregate(new int[12], (cntr, r) =>
+			{
+				cntr[r.die1 + r.die2 - 1]++;
+				return cntr;
+			});
+			return counter;
+		}
+		/// 
+		/// Prompt the player to try again, and wait for them to press Y or N.
+		/// 
+		/// Returns true if the player wants to try again, false if they have finished playing.
+		private bool TryAgain()
+		{
+			Console.ForegroundColor = ConsoleColor.White;
+			Console.WriteLine("Would you like to try again? (Press 'Y' for yes or 'N' for no)");
+
+			Console.ForegroundColor = ConsoleColor.Yellow;
+			Console.Write("> ");
+
+			char pressedKey;
+			// Keep looping until we get a recognised input
+			do
+			{
+				// Read a key, don't display it on screen
+				ConsoleKeyInfo key = Console.ReadKey(true);
+				// Convert to upper-case so we don't need to care about capitalisation
+				pressedKey = Char.ToUpper(key.KeyChar);
+				// Is this a key we recognise? If not, keep looping
+			} while (pressedKey != 'Y' && pressedKey != 'N');
+			// Display the result on the screen
+			Console.WriteLine(pressedKey);
+
+			// Return true if the player pressed 'Y', false for anything else.
+			return (pressedKey == 'Y');
+		}
+	}
+}
diff --git a/00_Alternate_Languages/33_Dice/csharp/Program.cs b/00_Alternate_Languages/33_Dice/csharp/Program.cs
new file mode 100644
index 00000000..959587cc
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/csharp/Program.cs
@@ -0,0 +1,14 @@
+namespace BasicComputerGames.Dice
+{
+	public class Program
+	{
+		public static void Main(string[] args)
+		{
+			// Create an instance of our main Game class
+			Game game = new Game();
+
+			// Call its GameLoop function. This will play the game endlessly in a loop until the player chooses to quit.
+			game.GameLoop();
+		}
+	}
+}
diff --git a/00_Alternate_Languages/33_Dice/csharp/README.md b/00_Alternate_Languages/33_Dice/csharp/README.md
new file mode 100644
index 00000000..3dba781c
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) by James Curran (http://www.noveltheory.com)
diff --git a/00_Alternate_Languages/33_Dice/csharp/RollGenerator.cs b/00_Alternate_Languages/33_Dice/csharp/RollGenerator.cs
new file mode 100644
index 00000000..e707d45f
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/csharp/RollGenerator.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+
+namespace BasicComputerGames.Dice
+{
+	public class RollGenerator
+	{
+		static Random _rnd = new Random();
+
+		public static void ReseedRNG(int seed) => _rnd = new Random(seed);
+
+		public IEnumerable<(int die1, int die2)> Rolls()
+		{
+			while (true)
+			{
+				yield return (_rnd.Next(1, 7), _rnd.Next(1, 7));
+			}
+		}
+	}
+}
diff --git a/00_Alternate_Languages/33_Dice/dice.bas b/00_Alternate_Languages/33_Dice/dice.bas
new file mode 100644
index 00000000..b74bf724
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/dice.bas
@@ -0,0 +1,31 @@
+2 PRINT TAB(34);"DICE"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT:PRINT:PRINT
+10 DIM F(12)
+20 REM  DANNY FREIDUS
+30 PRINT "THIS PROGRAM SIMULATES THE ROLLING OF A"
+40 PRINT "PAIR OF DICE."
+50 PRINT "YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO"
+60 PRINT "'ROLL' THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE"
+70 PRINT "A LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000."
+80 FOR Q=1 TO 12
+90 F(Q)=0
+100 NEXT Q
+110 PRINT:PRINT "HOW MANY ROLLS";
+120 INPUT X
+130 FOR S=1 TO X
+140 A=INT(6*RND(1)+1)
+150 B=INT(6*RND(1)+1)
+160 R=A+B
+170 F(R)=F(R)+1
+180 NEXT S
+185 PRINT
+190 PRINT "TOTAL SPOTS","NUMBER OF TIMES"
+200 FOR V=2 TO 12
+210 PRINT V,F(V)
+220 NEXT V
+221 PRINT
+222 PRINT:PRINT "TRY AGAIN";
+223 INPUT Z$
+224 IF Z$="YES" THEN 80
+240 END
diff --git a/00_Alternate_Languages/33_Dice/java/README.md b/00_Alternate_Languages/33_Dice/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/33_Dice/java/src/Dice.java b/00_Alternate_Languages/33_Dice/java/src/Dice.java
new file mode 100644
index 00000000..739b2084
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/java/src/Dice.java
@@ -0,0 +1,146 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Dice
+ * 

+ * Based on the Basic game of Dice here + * https://github.com/coding-horror/basic-computer-games/blob/main/33%20Dice/dice.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. + */ +public class Dice { + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + START_GAME, + INPUT_AND_CALCULATE, + RESULTS, + GAME_OVER + } + + // Current game state + private GAME_STATE gameState; + + private int[] spots; + + public Dice() { + kbScanner = new Scanner(System.in); + + gameState = GAME_STATE.START_GAME; + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + case START_GAME: + intro(); + spots = new int[12]; + gameState = GAME_STATE.INPUT_AND_CALCULATE; + break; + + case INPUT_AND_CALCULATE: + + int howManyRolls = displayTextAndGetNumber("HOW MANY ROLLS? "); + for (int i = 0; i < howManyRolls; i++) { + int diceRoll = (int) (Math.random() * 6 + 1) + (int) (Math.random() * 6 + 1); + // save dice roll in zero based array + spots[diceRoll - 1]++; + } + gameState = GAME_STATE.RESULTS; + break; + + case RESULTS: + System.out.println("TOTAL SPOTS" + simulateTabs(8) + "NUMBER OF TIMES"); + for (int i = 1; i < 12; i++) { + // show output using zero based array + System.out.println(simulateTabs(5) + (i + 1) + simulateTabs(20) + spots[i]); + } + System.out.println(); + if (yesEntered(displayTextAndGetInput("TRY AGAIN? "))) { + gameState = GAME_STATE.START_GAME; + } else { + gameState = GAME_STATE.GAME_OVER; + } + break; + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + private void intro() { + System.out.println(simulateTabs(34) + "DICE"); + System.out.println(simulateTabs(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("THIS PROGRAM SIMULATES THE ROLLING OF A"); + System.out.println("PAIR OF DICE."); + System.out.println("YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO"); + System.out.println("'ROLL' THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE"); + System.out.println("A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000."); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to an Integer + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private int displayTextAndGetNumber(String text) { + return Integer.parseInt(displayTextAndGetInput(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + + /** + * Checks whether player entered Y or YES to a question. + * + * @param text player string from kb + * @return true of Y or YES was entered, otherwise false + */ + private boolean yesEntered(String text) { + return stringIsAnyValue(text, "Y", "YES"); + } + + /** + * Check whether a string equals one of a variable number of values + * Useful to check for Y or YES for example + * Comparison is case insensitive. + * + * @param text source string + * @param values a range of values to compare against the source string + * @return true if a comparison was found in one of the variable number of strings passed + */ + private boolean stringIsAnyValue(String text, String... values) { + + return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text)); + } + + /** + * Simulate the old basic tab(xx) command which indented text by xx spaces. + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String simulateTabs(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } +} diff --git a/00_Alternate_Languages/33_Dice/java/src/DiceGame.java b/00_Alternate_Languages/33_Dice/java/src/DiceGame.java new file mode 100644 index 00000000..97f24e61 --- /dev/null +++ b/00_Alternate_Languages/33_Dice/java/src/DiceGame.java @@ -0,0 +1,6 @@ +public class DiceGame { + public static void main(String[] args) { + Dice dice = new Dice(); + dice.play(); + } +} diff --git a/00_Alternate_Languages/33_Dice/javascript/README.md b/00_Alternate_Languages/33_Dice/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/33_Dice/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/33_Dice/javascript/dice.html b/00_Alternate_Languages/33_Dice/javascript/dice.html new file mode 100644 index 00000000..420dbc5d --- /dev/null +++ b/00_Alternate_Languages/33_Dice/javascript/dice.html @@ -0,0 +1,9 @@ + + +DICE + + +


+
+
+
diff --git a/00_Alternate_Languages/33_Dice/javascript/dice.js b/00_Alternate_Languages/33_Dice/javascript/dice.js
new file mode 100644
index 00000000..d570ea8a
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/javascript/dice.js
@@ -0,0 +1,84 @@
+// DICE
+//
+// 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) + "DICE\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    f = [];
+    // Danny Freidus
+    print("THIS PROGRAM SIMULATES THE ROLLING OF A\n");
+    print("PAIR OF DICE.\n");
+    print("YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\n");
+    print("'ROLL' THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE\n");
+    print("A LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000.\n");
+    do {
+        for (q = 1; q <= 12; q++)
+            f[q] = 0;
+        print("\n");
+        print("HOW MANY ROLLS");
+        x = parseInt(await input());
+        for (s = 1; s <= x; s++) {
+            a = Math.floor(Math.random() * 6 + 1);
+            b = Math.floor(Math.random() * 6 + 1);
+            r = a + b;
+            f[r]++;
+        }
+        print("\n");
+        print("TOTAL SPOTS\tNUMBER OF TIMES\n");
+        for (v = 2; v <= 12; v++) {
+            print("\t" + v + "\t" + f[v] + "\n");
+        }
+        print("\n");
+        print("\n");
+        print("TRY AGAIN");
+        str = await input();
+    } while (str.substr(0, 1) == "Y") ;
+}
+
+main();
diff --git a/05_Bagels/pascal/README.md b/00_Alternate_Languages/33_Dice/pascal/README.md
similarity index 100%
rename from 05_Bagels/pascal/README.md
rename to 00_Alternate_Languages/33_Dice/pascal/README.md
diff --git a/00_Alternate_Languages/33_Dice/perl/README.md b/00_Alternate_Languages/33_Dice/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/33_Dice/perl/dice.pl b/00_Alternate_Languages/33_Dice/perl/dice.pl
new file mode 100644
index 00000000..2683b7a3
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/perl/dice.pl
@@ -0,0 +1,40 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 34 . "DICE\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+my @F;
+
+#REM DANNY FREIDUS;
+print "THIS PROGRAM SIMULATES THE ROLLING OF A\n";
+print "PAIR OF DICE.\n";
+print "YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\n";
+print "'ROLL' THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE\n";
+print "A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000.\n";
+
+my $X;
+my $Z;
+do {
+	for (my $Q=1; $Q<=12; $Q++) {
+		$F[$Q]=0;
+		}
+	print "\n"; print "HOW MANY ROLLS";
+	print "? "; chomp($X = );
+	for (my $S=1; $S<=$X; $S++) {
+		my $A=int(6*rand(1)+1);
+		my $B=int(6*rand(1)+1);
+		my $R=$A+$B;
+		$F[$R]=$F[$R]+1;
+		}
+	print "\n";
+	print "TOTAL SPOTS\tNUMBER OF TIMES\n";
+	for (my $V=2; $V<=12; $V++) {
+		print "$V\t\t$F[$V]\n";
+		}
+	print "\n";
+	print "\n"; print "TRY AGAIN";
+	print "? "; chomp($Z = );
+	} until (uc($Z) ne "YES");
+exit;
diff --git a/00_Alternate_Languages/33_Dice/python/README.md b/00_Alternate_Languages/33_Dice/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/33_Dice/python/dice.py b/00_Alternate_Languages/33_Dice/python/dice.py
new file mode 100644
index 00000000..1818bb54
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/python/dice.py
@@ -0,0 +1,113 @@
+########################################################
+#
+# Dice
+#
+# From: BASIC Computer Games (1978)
+#       Edited by David H. Ahl
+#
+# "Not exactly a game, this program simulates rolling
+#  a pair of dice a large number of times and prints out
+#  the frequency distribution.  You simply input the
+#  number of rolls.  It is interesting to see how many
+#  rolls are necessary to approach the theoretical
+#  distribution:
+#
+#  2  1/36  2.7777...%
+#  3  2/36  5.5555...%
+#  4  3/36  8.3333...%
+#    etc.
+#
+# "Daniel Freidus wrote this program while in the
+#  seventh grade at Harrison Jr-Sr High School,
+#  Harrison, New York."
+#
+# Python port by Jeff Jetton, 2019
+#
+########################################################
+
+
+import random
+
+# We'll track counts of roll outcomes in a 13-element list.
+# The first two indices (0 & 1) are ignored, leaving just
+# the indices that match the roll values (2 through 12).
+freq = [0] * 13
+
+
+# Display intro text
+print("\n                   Dice")
+print("Creative Computing  Morristown, New Jersey")
+print("\n\n")
+# "Danny Freidus"
+print("This program simulates the rolling of a")
+print("pair of dice.")
+print("You enter the number of times you want the computer to")
+print("'roll' the dice.   Watch out, very large numbers take")
+print("a long time.  In particular, numbers over 5000.")
+
+still_playing = True
+while still_playing:
+    print("")
+    n = int(input("How many rolls? "))
+
+    # Roll the dice n times
+    for i in range(n):
+        die1 = random.randint(1, 6)
+        die2 = random.randint(1, 6)
+        roll_total = die1 + die2
+        freq[roll_total] += 1
+
+    # Display final results
+    print("\nTotal Spots   Number of Times")
+    for i in range(2, 13):
+        print(" %-14d%d" % (i, freq[i]))
+
+    # Keep playing?
+    print("")
+    response = input("Try again? ")
+    if len(response) > 0 and response.upper()[0] == "Y":
+        # Clear out the frequency list
+        freq = [0] * 13
+    else:
+        # Exit the game loop
+        still_playing = False
+
+
+########################################################
+#
+# Porting Notes
+#
+#   A fairly straightforward port.  The only change is
+#   in the handling of the user's "try again" response.
+#   The original program only continued if the user
+#   entered "YES", whereas this version will continue
+#   if any word starting with "Y" or "y" is given.
+#
+#   The instruction text--which, like all these ports,
+#   was taken verbatim from the original listing--is
+#   charmingly quaint in its dire warning against
+#   setting the number of rolls too high.  At the time
+#   of this writing, on a fairly slow computer, a
+#   5000-roll run typically clocks in at well under
+#   1/10 of a second!
+#
+#
+# Ideas for Modifications
+#
+#   Have the results include a third column showing
+#   the percent of rolls each count represents.  Or
+#   (better yet) print a low-fi bar graph using
+#   rows of asterisks to represent relative values,
+#   with each asterisk representing one percent,
+#   for example.
+#
+#   Add a column showing the theoretically expected
+#   percentage, for comparison.
+#
+#   Keep track of how much time the series of rolls
+#   takes and add that info to the final report.
+#
+#   What if three (or four, or five...) dice were
+#   rolled each time?
+#
+########################################################
diff --git a/00_Alternate_Languages/33_Dice/ruby/README.md b/00_Alternate_Languages/33_Dice/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/33_Dice/ruby/dice.rb b/00_Alternate_Languages/33_Dice/ruby/dice.rb
new file mode 100644
index 00000000..ea1911e7
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/ruby/dice.rb
@@ -0,0 +1,51 @@
+def intro
+  puts "                                  DICE
+               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+
+
+
+THIS PROGRAM SIMULATES THE ROLLING OF A
+PAIR OF DICE.
+YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO
+'ROLL' THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE
+A LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000.
+
+"
+end
+
+def get_rolls
+  while true
+    number = gets.chomp
+    return number.to_i if /^\d+$/.match(number)
+    puts "!NUMBER EXPECTED - RETRY INPUT LINE"
+    print "? "
+  end
+end
+
+def dice_roll = rand(6) + 1 # ruby 3, woot!
+
+def print_rolls(rolls)
+  values = Array.new(11, 0)
+  (1..rolls).each { values[dice_roll + dice_roll - 2] += 1 }
+  puts "\nTOTAL SPOTS   NUMBER OF TIMES"
+  (0..10).each { |k| puts " %-2d            %-2d" % [k + 2, values[k]] }
+end
+
+def main
+  intro
+  loop do
+    print "HOW MANY ROLLS? "
+    rolls = get_rolls
+
+    print_rolls(rolls)
+
+    print "\n\nTRY AGAIN? "
+    option = (gets || '').chomp.upcase
+    break unless option == 'YES'
+    puts
+  end
+end
+
+trap "SIGINT" do puts; exit 130 end
+
+main
diff --git a/00_Alternate_Languages/33_Dice/vbnet/Dice.sln b/00_Alternate_Languages/33_Dice/vbnet/Dice.sln
new file mode 100644
index 00000000..afb7b912
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/vbnet/Dice.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Dice", "Dice.vbproj", "{6410CCD0-0D78-49C9-9B15-70F901A1EB19}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6410CCD0-0D78-49C9-9B15-70F901A1EB19}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6410CCD0-0D78-49C9-9B15-70F901A1EB19}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6410CCD0-0D78-49C9-9B15-70F901A1EB19}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6410CCD0-0D78-49C9-9B15-70F901A1EB19}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/33_Dice/vbnet/Dice.vbproj b/00_Alternate_Languages/33_Dice/vbnet/Dice.vbproj
new file mode 100644
index 00000000..16929f96
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/vbnet/Dice.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Dice
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/33_Dice/vbnet/README.md b/00_Alternate_Languages/33_Dice/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/33_Dice/vbnet/program.vb b/00_Alternate_Languages/33_Dice/vbnet/program.vb
new file mode 100644
index 00000000..977a5344
--- /dev/null
+++ b/00_Alternate_Languages/33_Dice/vbnet/program.vb
@@ -0,0 +1,38 @@
+Imports System
+
+Module Program
+    Sub Main(args As String())
+        Const header As String =
+"                   DICE
+CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+
+
+
+THIS PROGRAM SIMULATES THE ROLLING OF A
+PAIR OF DICE.
+YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO
+/ROLL/ THE DICE.  WATCH OUT, VERY LARGE NUMBERS TAKE
+A LONG TIME.  IN PARTICULAR, NUMBERS OVER 5000."
+
+        Console.WriteLine(header)
+
+        Dim D6 As New Random()
+        Dim continuePrompt As String = "YES"
+        While continuePrompt = "YES"
+            Console.Write($"{vbCrLf}HOW MANY ROLLS? ")
+            Dim x As Integer = Convert.ToInt32(Console.ReadLine())
+            Dim F = Enumerable.Repeat(0, 11).ToList()
+            For s As Integer = 0 To x - 1
+                F(D6.Next(6) + D6.Next(6)) += 1
+            Next
+
+            Console.WriteLine($"{vbCrLf}TOTAL SPOTS   NUMBER OF TIMES")
+            For V As Integer = 0 To 10
+                Console.WriteLine($" {V + 2}{vbTab,-8}{F(V)}")
+            Next
+
+            Console.Write($"{vbCrLf}TRY AGAIN ")
+            continuePrompt = Console.ReadLine().ToUpper()
+        End While
+    End Sub
+End Module
diff --git a/00_Alternate_Languages/34_Digits/README.md b/00_Alternate_Languages/34_Digits/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/34_Digits/csharp/Digits.csproj b/00_Alternate_Languages/34_Digits/csharp/Digits.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/csharp/Digits.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/34_Digits/csharp/Digits.sln b/00_Alternate_Languages/34_Digits/csharp/Digits.sln
new file mode 100644
index 00000000..04b94496
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/csharp/Digits.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Digits", "Digits.csproj", "{BB89211D-85FB-4FC0-AF62-715459227D7E}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BB89211D-85FB-4FC0-AF62-715459227D7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BB89211D-85FB-4FC0-AF62-715459227D7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BB89211D-85FB-4FC0-AF62-715459227D7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BB89211D-85FB-4FC0-AF62-715459227D7E}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/34_Digits/csharp/README.md b/00_Alternate_Languages/34_Digits/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/34_Digits/digits.bas b/00_Alternate_Languages/34_Digits/digits.bas
new file mode 100644
index 00000000..76fbbaff
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/digits.bas
@@ -0,0 +1,78 @@
+10 PRINT TAB(33);"DIGITS"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+210 PRINT "THIS IS A GAME OF GUESSING."
+220 PRINT "FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0'";
+230 INPUT E
+240 IF E=0 THEN 360
+250 PRINT
+260 PRINT "PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN"
+270 PRINT "THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM."
+280 PRINT "ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH."
+290 PRINT "I WILL ASK FOR THEN TEN AT A TIME."
+300 PRINT "I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR"
+310 PRINT "NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,"
+320 PRINT "I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER"
+330 PRINT "THAN THAT *****"
+340 PRINT:PRINT
+360 READ A,B,C
+370 DATA 0,1,3
+380 DIM M(26,2),K(2,2),L(8,2)
+400 FOR I=0 TO 26: FOR J=0 TO 2: M(I,J)=1: NEXT J: NEXT I
+410 FOR I=0 TO 2: FOR J=0 TO 2: K(I,J)=9: NEXT J: NEXT I
+420 FOR I=0 TO 8: FOR J=0 TO 2: L(I,J)=3: NEXT J: NEXT I
+450 L(0,0)=2: L(4,1)=2: L(8,2)=2
+480 Z=26: Z1=8: Z2=2
+510 X=0
+520 FOR T=1 TO 3
+530 PRINT
+540 PRINT "TEN NUMBERS, PLEASE";
+550 INPUT N(1),N(2),N(3),N(4),N(5),N(6),N(7),N(8),N(9),N(10)
+560 FOR I=1 TO 10
+570 W=N(I)-1
+580 IF W=SGN(W) THEN 620
+590 PRINT "ONLY USE THE DIGITS '0', '1', OR '2'."
+600 PRINT "LET'S TRY AGAIN.":GOTO 530
+620 NEXT I
+630 PRINT: PRINT "MY GUESS","YOUR NO.","RESULT","NO. RIGHT":PRINT
+660 FOR U=1 TO 10
+670 N=N(U): S=0
+690 FOR J=0 TO 2
+700 S1=A*K(Z2,J)+B*L(Z1,J)+C*M(Z,J)
+710 IF S>S1 THEN 760
+720 IF S10 THEN 980
+940 IF X<10 THEN 1010
+950 PRINT "I GUESSED EXACTLY 1/3 OF YOUR NUMBERS."
+960 PRINT "IT'S A TIE GAME."
+970 GOTO 1030
+980 PRINT "I GUESSED MORE THAN 1/3 OF YOUR NUMBERS."
+990 PRINT "I WIN.": FOR Q=1 TO 10: PRINT CHR$(7);: NEXT Q
+1000 GOTO 1030
+1010 PRINT "I GUESSED LESS THAN 1/3 OF YOUR NUMBERS."
+1020 PRINT "YOU BEAT ME.  CONGRATULATIONS *****"
+1030 PRINT
+1040 PRINT "DO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO)";
+1060 INPUT X
+1070 IF X=1 THEN 400
+1080 PRINT:PRINT "THANKS FOR THE GAME."
+1090 END
diff --git a/00_Alternate_Languages/34_Digits/java/Digits.java b/00_Alternate_Languages/34_Digits/java/Digits.java
new file mode 100644
index 00000000..71c39d95
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/java/Digits.java
@@ -0,0 +1,185 @@
+import java.util.Arrays;
+import java.util.InputMismatchException;
+import java.util.Scanner;
+
+/**
+ * DIGITS
+ * 

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + */ +public class Digits { + + public static void main(String[] args) { + printIntro(); + Scanner scan = new Scanner(System.in); + + boolean showInstructions = readInstructionChoice(scan); + if (showInstructions) { + printInstructions(); + } + + int a = 0, b = 1, c = 3; + int[][] m = new int[27][3]; + int[][] k = new int[3][3]; + int[][] l = new int[9][3]; + + boolean continueGame = true; + while (continueGame) { + for (int[] ints : m) { + Arrays.fill(ints, 1); + } + for (int[] ints : k) { + Arrays.fill(ints, 9); + } + for (int[] ints : l) { + Arrays.fill(ints, 3); + } + + l[0][0] = 2; + l[4][1] = 2; + l[8][2] = 2; + + int z = 26, z1 = 8, z2 = 2, runningCorrect = 0; + + for (int t = 1; t <= 3; t++) { + boolean validNumbers = false; + int[] numbers = new int[0]; + while (!validNumbers) { + System.out.println(); + numbers = read10Numbers(scan); + validNumbers = true; + for (int number : numbers) { + if (number < 0 || number > 2) { + System.out.println("ONLY USE THE DIGITS '0', '1', OR '2'."); + System.out.println("LET'S TRY AGAIN."); + validNumbers = false; + break; + } + } + } + + System.out.printf("\n%-14s%-14s%-14s%-14s", "MY GUESS", "YOUR NO.", "RESULT", "NO. RIGHT"); + for (int number : numbers) { + int s = 0; + int myGuess = 0; + for (int j = 0; j <= 2; j++) { + //What did the original author have in mind ? The first expression always results in 0 because a is always 0 + int s1 = a * k[z2][j] + b * l[z1][j] + c * m[z][j]; + if (s < s1) { + s = s1; + myGuess = j; + } else if (s1 == s) { + if (Math.random() >= 0.5) { + myGuess = j; + } + } + } + + String result; + if (myGuess != number) { + result = "WRONG"; + } else { + runningCorrect++; + result = "RIGHT"; + m[z][number] = m[z][number] + 1; + l[z1][number] = l[z1][number] + 1; + k[z2][number] = k[z2][number] + 1; + z = z - (z / 9) * 9; + z = 3 * z + number; + } + System.out.printf("\n%-14d%-14d%-14s%-14d", myGuess, number, result, runningCorrect); + + z1 = z - (z / 9) * 9; + z2 = number; + } + } + + //print summary report + System.out.println(); + if (runningCorrect > 10) { + System.out.println(); + System.out.println("I GUESSED MORE THAN 1/3 OF YOUR NUMBERS."); + System.out.println("I WIN.\u0007"); + } else if (runningCorrect < 10) { + System.out.println("I GUESSED LESS THAN 1/3 OF YOUR NUMBERS."); + System.out.println("YOU BEAT ME. CONGRATULATIONS *****"); + } else { + System.out.println("I GUESSED EXACTLY 1/3 OF YOUR NUMBERS."); + System.out.println("IT'S A TIE GAME."); + } + + continueGame = readContinueChoice(scan); + } + + System.out.println("\nTHANKS FOR THE GAME."); + } + + private static boolean readContinueChoice(Scanner scan) { + System.out.print("\nDO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO) ? "); + int choice; + try { + choice = scan.nextInt(); + return choice == 1; + } catch (InputMismatchException ex) { + return false; + } finally { + scan.nextLine(); + } + } + + private static int[] read10Numbers(Scanner scan) { + System.out.print("TEN NUMBERS, PLEASE ? "); + int[] numbers = new int[10]; + + for (int i = 0; i < numbers.length; i++) { + boolean validInput = false; + while (!validInput) { + try { + int n = scan.nextInt(); + validInput = true; + numbers[i] = n; + } catch (InputMismatchException ex) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE"); + } finally { + scan.nextLine(); + } + } + } + + return numbers; + } + + private static void printInstructions() { + System.out.println("\n"); + System.out.println("PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN"); + System.out.println("THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM."); + System.out.println("ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH."); + System.out.println("I WILL ASK FOR THEN TEN AT A TIME."); + System.out.println("I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR"); + System.out.println("NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,"); + System.out.println("I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER"); + System.out.println("THAN THAT *****"); + System.out.println(); + } + + private static boolean readInstructionChoice(Scanner scan) { + System.out.print("FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0' ? "); + int choice; + try { + choice = scan.nextInt(); + return choice == 1; + } catch (InputMismatchException ex) { + return false; + } finally { + scan.nextLine(); + } + } + + private static void printIntro() { + System.out.println(" DIGITS"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + System.out.println("THIS IS A GAME OF GUESSING."); + } + +} diff --git a/00_Alternate_Languages/34_Digits/java/README.md b/00_Alternate_Languages/34_Digits/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/34_Digits/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/34_Digits/javascript/README.md b/00_Alternate_Languages/34_Digits/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/34_Digits/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/34_Digits/javascript/digits.html b/00_Alternate_Languages/34_Digits/javascript/digits.html new file mode 100644 index 00000000..c6db808f --- /dev/null +++ b/00_Alternate_Languages/34_Digits/javascript/digits.html @@ -0,0 +1,9 @@ + + +DIGITS + + +


+
+
+
diff --git a/00_Alternate_Languages/34_Digits/javascript/digits.js b/00_Alternate_Languages/34_Digits/javascript/digits.js
new file mode 100644
index 00000000..31fd1e2c
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/javascript/digits.js
@@ -0,0 +1,175 @@
+// DIGITS
+//
+// 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(33) + "DIGITS\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("THIS IS A GAME OF GUESSING.\n");
+    print("FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0'");
+    e = parseInt(await input());
+    if (e != 0) {
+        print("\n");
+        print("PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN\n");
+        print("THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.\n");
+        print("ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.\n");
+        print("I WILL ASK FOR THEN TEN AT A TIME.\n");
+        print("I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR\n");
+        print("NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,\n");
+        print("I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER\n");
+        print("THAN THAT *****\n");
+        print("\n");
+        print("\n");
+    }
+    a = 0;
+    b = 1;
+    c = 3;
+    m = [];
+    k = [];
+    l = [];
+    n = [];
+    while (1) {
+        for (i = 0; i <= 26; i++) {
+            m[i] = [];
+            for (j = 0; j <= 2; j++) {
+                m[i][j] = 1;
+            }
+        }
+        for (i = 0; i <= 2; i++) {
+            k[i] = [];
+            for (j = 0; j <= 2; j++) {
+                k[i][j] = 9;
+            }
+        }
+        for (i = 0; i <= 8; i++) {
+            l[i] = [];
+            for (j = 0; j <= 2; j++) {
+                l[i][j] = 3;
+            }
+        }
+        l[0][0] = 2;
+        l[4][1] = 2;
+        l[8][2] = 2;
+        z = 26;
+        z1 = 8;
+        z2 = 2;
+        x = 0;
+        for (t = 1; t <= 3; t++) {
+            while (1) {
+                print("\n");
+                print("TEN NUMBERS, PLEASE");
+                str = await input();
+                for (i = 1; i <= 10; i++) {
+                    n[i] = parseInt(str);
+                    j = str.indexOf(",");
+                    if (j >= 0) {
+                        str = str.substr(j + 1);
+                    }
+                    if (n[i] < 0 || n[i] > 2)
+                        break;
+                }
+                if (i <= 10) {
+                    print("ONLY USE THE DIGITS '0', '1', OR '2'.\n");
+                    print("LET'S TRY AGAIN.\n");
+                } else {
+                    break;
+                }
+            }
+            print("\n");
+            print("MY GUESS\tYOUR NO.\tRESULT\tNO. RIGHT\n");
+            print("\n");
+            for (u = 1; u <= 10; u++) {
+                n2 = n[u];
+                s = 0;
+                for (j = 0; j <= 2; j++) {
+                    s1 = a * k[z2][j] + b * l[z1][j] + c * m[z][j];
+                    if (s > s1)
+                        continue;
+                    if (s < s1 || Math.random() >= 0.5) {
+                        s = s1;
+                        g = j;
+                    }
+                }
+                print("  " + g + "\t\t   " + n[u] + "\t\t");
+                if (g == n[u]) {
+                    x++;
+                    print(" RIGHT\t " + x + "\n");
+                    m[z][n2]++;
+                    l[z1][n2]++;
+                    k[z2][n2]++;
+                    z = z % 9;
+                    z = 3 * z + n[u];
+                } else {
+                    print(" WRONG\t " + x + "\n");
+                }
+                z1 = z % 9;
+                z2 = n[u];
+            }
+        }
+        print("\n");
+        if (x > 10) {
+            print("I GUESSED MORE THAN 1/3 OF YOUR NUMBERS.\n");
+            print("I WIN.\n");
+        } else if (x == 10) {
+            print("I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.\n");
+            print("IT'S A TIE GAME.\n");
+        } else {
+            print("I GUESSED LESS THAN 1/3 OF YOUR NUMBERS.\n");
+            print("YOU BEAT ME.  CONGRATULATIONS *****\n");
+        }
+        print("\n");
+        print("DO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO)");
+        x = parseInt(await input());
+        if (x != 1)
+            break;
+    }
+    print("\n");
+    print("THANKS FOR THE GAME.\n");
+}
+
+main();
diff --git a/10_Blackjack/pascal/README.md b/00_Alternate_Languages/34_Digits/pascal/README.md
similarity index 100%
rename from 10_Blackjack/pascal/README.md
rename to 00_Alternate_Languages/34_Digits/pascal/README.md
diff --git a/00_Alternate_Languages/34_Digits/perl/README.md b/00_Alternate_Languages/34_Digits/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/34_Digits/python/Digits.py b/00_Alternate_Languages/34_Digits/python/Digits.py
new file mode 100644
index 00000000..bda172a9
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/python/Digits.py
@@ -0,0 +1,156 @@
+import random
+
+
+def print_intro():
+    print("                                DIGITS")
+    print("              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print("\n\n")
+    print("THIS IS A GAME OF GUESSING.")
+
+
+def read_instruction_choice():
+    print("FOR INSTRUCTIONS, TYPE '1', ELSE TYPE '0' ? ")
+    try:
+        choice = int(input())
+        return choice == 1
+    except (ValueError, TypeError):
+        return False
+
+
+def print_instructions():
+    print("\n")
+    print("PLEASE TAKE A PIECE OF PAPER AND WRITE DOWN")
+    print("THE DIGITS '0', '1', OR '2' THIRTY TIMES AT RANDOM.")
+    print("ARRANGE THEM IN THREE LINES OF TEN DIGITS EACH.")
+    print("I WILL ASK FOR THEN TEN AT A TIME.")
+    print("I WILL ALWAYS GUESS THEM FIRST AND THEN LOOK AT YOUR")
+    print("NEXT NUMBER TO SEE IF I WAS RIGHT. BY PURE LUCK,")
+    print("I OUGHT TO BE RIGHT TEN TIMES. BUT I HOPE TO DO BETTER")
+    print("THAN THAT *****")
+    print()
+
+
+def read_10_numbers():
+    print("TEN NUMBERS, PLEASE ? ")
+    numbers = []
+
+    for _ in range(10):
+        valid_input = False
+        while not valid_input:
+            try:
+                n = int(input())
+                valid_input = True
+                numbers.append(n)
+            except (TypeError, ValueError):
+                print("!NUMBER EXPECTED - RETRY INPUT LINE")
+
+    return numbers
+
+
+def read_continue_choice():
+    print("\nDO YOU WANT TO TRY AGAIN (1 FOR YES, 0 FOR NO) ? ")
+    try:
+        choice = int(input())
+        return choice == 1
+    except (ValueError, TypeError):
+        return False
+
+
+def print_summary_report(running_correct: int):
+    print()
+    if running_correct > 10:
+        print()
+        print("I GUESSED MORE THAN 1/3 OF YOUR NUMBERS.")
+        print("I WIN.\u0007")
+    elif running_correct < 10:
+        print("I GUESSED LESS THAN 1/3 OF YOUR NUMBERS.")
+        print("YOU BEAT ME.  CONGRATULATIONS *****")
+    else:
+        print("I GUESSED EXACTLY 1/3 OF YOUR NUMBERS.")
+        print("IT'S A TIE GAME.")
+
+
+def main():
+    print_intro()
+    if read_instruction_choice():
+        print_instructions()
+
+    a = 0
+    b = 1
+    c = 3
+
+    m = [[1] * 3 for _ in range(27)]
+    k = [[9] * 3 for _ in range(3)]
+    l = [[3] * 3 for _ in range(9)]  # noqa: E741
+
+    continue_game = True
+    while continue_game:
+        l[0][0] = 2
+        l[4][1] = 2
+        l[8][2] = 2
+        z = 26
+        z1 = 8
+        z2 = 2
+        running_correct = 0
+
+        for round in range(1, 4):
+            valid_numbers = False
+            numbers = []
+            while not valid_numbers:
+                print()
+                numbers = read_10_numbers()
+                valid_numbers = True
+                for number in numbers:
+                    if number < 0 or number > 2:
+                        print("ONLY USE THE DIGITS '0', '1', OR '2'.")
+                        print("LET'S TRY AGAIN.")
+                        valid_numbers = False
+                        break
+
+            print(
+                "\n%-14s%-14s%-14s%-14s"
+                % ("MY GUESS", "YOUR NO.", "RESULT", "NO. RIGHT")
+            )
+
+            for number in numbers:
+                s = 0
+                my_guess = 0
+                for j in range(0, 3):
+                    # What did the original author have in mind ?
+                    # The first expression always results in 0 because a is always 0
+                    s1 = a * k[z2][j] + b * l[int(z1)][j] + c * m[int(z)][j]
+                    if s < s1:
+                        s = s1
+                        my_guess = j
+                    elif s1 == s:
+                        if random.random() >= 0.5:
+                            my_guess = j
+
+                result = ""
+
+                if my_guess != number:
+                    result = "WRONG"
+                else:
+                    running_correct += 1
+                    result = "RIGHT"
+                    m[int(z)][number] = m[int(z)][number] + 1
+                    l[int(z1)][number] = l[int(z1)][number] + 1
+                    k[int(z2)][number] = k[int(z2)][number] + 1
+                    z = z - (z / 9) * 9
+                    z = 3 * z + number
+                print(
+                    "\n%-14d%-14d%-14s%-14d"
+                    % (my_guess, number, result, running_correct)
+                )
+
+                z1 = z - (z / 9) * 9
+                z2 = number
+
+        print_summary_report(running_correct)
+        continue_game = read_continue_choice()
+
+    print("\nTHANKS FOR THE GAME.")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/34_Digits/python/README.md b/00_Alternate_Languages/34_Digits/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/34_Digits/ruby/README.md b/00_Alternate_Languages/34_Digits/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/34_Digits/vbnet/Digits.sln b/00_Alternate_Languages/34_Digits/vbnet/Digits.sln
new file mode 100644
index 00000000..2d5733a9
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/vbnet/Digits.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Digits", "Digits.vbproj", "{837EB2E4-3EE6-447A-8AF7-91CA08841B93}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{837EB2E4-3EE6-447A-8AF7-91CA08841B93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{837EB2E4-3EE6-447A-8AF7-91CA08841B93}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{837EB2E4-3EE6-447A-8AF7-91CA08841B93}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{837EB2E4-3EE6-447A-8AF7-91CA08841B93}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/34_Digits/vbnet/Digits.vbproj b/00_Alternate_Languages/34_Digits/vbnet/Digits.vbproj
new file mode 100644
index 00000000..d8f673e1
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/vbnet/Digits.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Digits
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/34_Digits/vbnet/README.md b/00_Alternate_Languages/34_Digits/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/34_Digits/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/35_Even_Wins/README.md b/00_Alternate_Languages/35_Even_Wins/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/35_Even_Wins/csharp/EvenWins.csproj b/00_Alternate_Languages/35_Even_Wins/csharp/EvenWins.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/csharp/EvenWins.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/35_Even_Wins/csharp/EvenWins.sln b/00_Alternate_Languages/35_Even_Wins/csharp/EvenWins.sln
new file mode 100644
index 00000000..b384c20c
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/csharp/EvenWins.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EvenWins", "EvenWins.csproj", "{84209510-4089-4147-B220-E41E534A228B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{84209510-4089-4147-B220-E41E534A228B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{84209510-4089-4147-B220-E41E534A228B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{84209510-4089-4147-B220-E41E534A228B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{84209510-4089-4147-B220-E41E534A228B}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/35_Even_Wins/csharp/README.md b/00_Alternate_Languages/35_Even_Wins/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/35_Even_Wins/evenwins.bas b/00_Alternate_Languages/35_Even_Wins/evenwins.bas
new file mode 100644
index 00000000..4e663c68
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/evenwins.bas
@@ -0,0 +1,128 @@
+1 PRINT TAB(31);"EVEN WINS"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT
+4 Y1=0
+10 M1=0
+20 DIM M(20),Y(20)
+30 PRINT "     THIS IS A TWO PERSON GAME CALLED 'EVEN WINS.'"
+40 PRINT "TO PLAY THE GAME, THE PLAYERS NEED 27 MARBLES OR"
+50 PRINT "OTHER OBJECTS ON A TABLE."
+60 PRINT
+70 PRINT
+80 PRINT "     THE 2 PLAYERS ALTERNATE TURNS, WITH EACH PLAYER"
+90 PRINT "REMOVING FROM 1 TO 4 MARBLES ON EACH MOVE.  THE GAME"
+100 PRINT "ENDS WHEN THERE ARE NO MARBLES LEFT, AND THE WINNER"
+110 PRINT "IS THE ONE WITH AN EVEN NUMBER OF MARBLES."
+120 PRINT
+130 PRINT
+140 PRINT "     THE ONLY RULES ARE THAT (1) YOU MUST ALTERNATE TURNS,"
+150 PRINT "(2) YOU MUST TAKE BETWEEN 1 AND 4 MARBLES EACH TURN,"
+160 PRINT "AND (3) YOU CANNOT SKIP A TURN."
+170 PRINT
+180 PRINT
+190 PRINT
+200 PRINT "     TYPE A '1' IF YOU WANT TO GO FIRST, AND TYPE"
+210 PRINT "A '0' IF YOU WANT ME TO GO FIRST."
+220 INPUT C
+225 PRINT
+230 IF C=0 THEN 250
+240 GOTO 1060
+250 T=27
+260 M=2
+270 PRINT:PRINT "TOTAL=";T:PRINT
+280 M1=M1+M
+290 T=T-M
+300 PRINT "I PICK UP";M;"MARBLES."
+310 IF T=0 THEN 880
+320 PRINT:PRINT "TOTAL=";T
+330 PRINT
+340 PRINT "     AND WHAT IS YOUR NEXT MOVE, MY TOTAL IS";M1
+350 INPUT Y
+360 PRINT
+370 IF Y<1 THEN 1160
+380 IF Y>4 THEN 1160
+390 IF Y<=T THEN 430
+400 PRINT "     YOU HAVE TRIED TO TAKE MORE MARBLES THAN THERE ARE"
+410 PRINT "LEFT.  TRY AGAIN."
+420 GOTO 350
+430 Y1=Y1+Y
+440 T=T-Y
+450 IF T=0 THEN 880
+460 PRINT "TOTAL=";T
+470 PRINT
+480 PRINT "YOUR TOTAL IS";Y1
+490 IF T<.5 THEN 880
+500 R=T-6*INT(T/6)
+510 IF INT(Y1/2)=Y1/2 THEN 700
+520 IF T<4.2 THEN 580
+530 IF R>3.4 THEN 620
+540 M=R+1
+550 M1=M1+M
+560 T=T-M
+570 GOTO 300
+580 M=T
+590 T=T-M
+600 GOTO 830
+610 REM     250 IS WHERE I WIN.
+620 IF R<4.7 THEN 660
+630 IF R>3.5 THEN 660
+640 M=1
+650 GOTO 670
+660 M=4
+670 T=T-M
+680 M1=M1+M
+690 GOTO 300
+700 REM     I AM READY TO ENCODE THE STRAT FOR WHEN OPP TOT IS EVEN
+710 IF R<1.5 THEN 1020
+720 IF R>5.3 THEN 1020
+730 M=R-1
+740 M1=M1+M
+750 T=T-M
+760 IF T<.2 THEN 790
+770 REM     IS # ZERO HERE
+780 GOTO 300
+790 REM     IS = ZERO HERE
+800 PRINT "I PICK UP";M;"MARBLES."
+810 PRINT
+820 GOTO 880
+830 REM    THIS IS WHERE I WIN
+840 PRINT "I PICK UP";M;"MARBLES."
+850 PRINT
+860 PRINT "TOTAL = 0"
+870 M1=M1+M
+880 PRINT "THAT IS ALL OF THE MARBLES."
+890 PRINT
+900 PRINT " MY TOTAL IS";M1;", YOUR TOTAL IS";Y1
+910 PRINT
+920 IF INT(M1/2)=M1/2 THEN 950
+930 PRINT "     YOU WON.  DO YOU WANT TO PLAY"
+940 GOTO 960
+950 PRINT "     I WON.  DO YOU WANT TO PLAY"
+960 PRINT "AGAIN?  TYPE 1 FOR YES AND 0 FOR NO."
+970 INPUT A1
+980 IF A1=0 THEN 1030
+990 M1=0
+1000 Y1=0
+1010 GOTO 200
+1020 GOTO 640
+1030 PRINT
+1040 PRINT "OK.  SEE YOU LATER."
+1050 GOTO 1230
+1060 T=27
+1070 PRINT
+1080 PRINT
+1090 PRINT
+1100 PRINT "TOTAL=";T
+1110 PRINT
+1120 PRINT
+1130 PRINT "WHAT IS YOUR FIRST MOVE";
+1140 INPUT Y
+1150 GOTO 360
+1160 PRINT
+1170 PRINT "THE NUMBER OF MARBLES YOU TAKE MUST BE A POSITIVE"
+1180 PRINT "INTEGER BETWEEN 1 AND 4."
+1190 PRINT
+1200 PRINT "     WHAT IS YOUR NEXT MOVE?"
+1210 PRINT
+1220 GOTO 350
+1230 END
diff --git a/00_Alternate_Languages/35_Even_Wins/gameofevenwins.bas b/00_Alternate_Languages/35_Even_Wins/gameofevenwins.bas
new file mode 100644
index 00000000..673dcc90
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/gameofevenwins.bas
@@ -0,0 +1,70 @@
+1 PRINT TAB(28);"GAME OF EVEN WINS"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT
+4 INPUT "DO YOU WANT INSTRUCTIONS (YES OR NO)";A$:PRINT
+5 IF A$="NO" THEN 20
+6 PRINT "THE GAME IS PLAYED AS FOLLOWS:":PRINT
+7 PRINT "AT THE BEGINNING OF THE GAME, A RANDOM NUMBER OF CHIPS ARE"
+8 PRINT "PLACED ON THE BOARD.  THE NUMBER OF CHIPS ALWAYS STARTS"
+9 PRINT "AS AN ODD NUMBER.  ON EACH TURN, A PLAYER MUST TAKE ONE,"
+10 PRINT "TWO, THREE, OR FOUR CHIPS.  THE WINNER IS THE PLAYER WHO"
+11 PRINT "FINISHES WITH A TOTAL NUMBER OF CHIPS THAT IS EVEN."
+12 PRINT "THE COMPUTER STARTS OUT KNOWING ONLY THE RULES OF THE"
+13 PRINT "GAME.  IT GRADUALLY LEARNS TO PLAY WELL.  IT SHOULD BE"
+14 PRINT "DIFFICULT TO BEAT THE COMPUTER AFTER TWENTY GAMES IN A ROW."
+15 PRINT "TRY IT!!!!": PRINT
+16 PRINT "TO QUIT AT ANY TIME, TYPE A '0' AS YOUR MOVE.": PRINT
+20 DIM R(1,5)
+25 L=0: B=0
+30 FOR I=0 TO 5
+40 R(1,I)=4
+50 R(0,I)=4
+60 NEXT I
+70 A=0: B=0
+90 P=INT((13*RND(1)+9)/2)*2+1
+100 IF P=1 THEN 530
+110 PRINT "THERE ARE";P;"CHIPS ON THE BOARD."
+120 E1=E
+130 L1=L
+140 E=(A/2-INT(A/2))*2
+150 L=INT((P/6-INT(P/6))*6+.5)
+160 IF R(E,L)>=P THEN 320
+170 M=R(E,L)
+180 IF M<=0 THEN 370
+190 P=P-M
+200 IF M=1 THEN 510
+210 PRINT "COMPUTER TAKES";M;"CHIPS LEAVING";P;"... YOUR MOVE";
+220 B=B+M
+230 INPUT M
+240 M=INT(M)
+250 IF M<1 THEN 450
+260 IF M>4 THEN 460
+270 IF M>P THEN 460
+280 IF M=P THEN 360
+290 P=P-M
+300 A=A+M
+310 GOTO 100
+320 IF P=1 THEN 550
+330 PRINT "COMPUTER TAKES";P;"CHIPS."
+340 R(E,L)=P
+350 B=B+P
+360 IF B/2=INT(B/2) THEN 420
+370 PRINT "GAME OVER ... YOU WIN!!!": PRINT
+390 IF R(E,L)=1 THEN 480
+400 R(E,L)=R(E,L)-1
+410 GOTO 70
+420 PRINT "GAME OVER ... I WIN!!!": PRINT
+430 GOTO 70
+450 IF M=0 THEN 570
+460 PRINT M;"IS AN ILLEGAL MOVE ... YOUR MOVE";
+470 GOTO 230
+480 IF R(E1,L1)=1 THEN 70
+490 R(E1,L1)=R(E1,L1)-1
+500 GOTO 70
+510 PRINT "COMPUTER TAKES 1 CHIP LEAVING";P;"... YOUR MOVE";
+520 GOTO 220
+530 PRINT "THERE IS 1 CHIP ON THE BOARD."
+540 GOTO 120
+550 PRINT "COMPUTER TAKES 1 CHIP."
+560 GOTO 340
+570 END
diff --git a/00_Alternate_Languages/35_Even_Wins/java/README.md b/00_Alternate_Languages/35_Even_Wins/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/35_Even_Wins/javascript/README.md b/00_Alternate_Languages/35_Even_Wins/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/35_Even_Wins/javascript/evenwins.html b/00_Alternate_Languages/35_Even_Wins/javascript/evenwins.html
new file mode 100644
index 00000000..c39d09ba
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/javascript/evenwins.html
@@ -0,0 +1,9 @@
+
+
+EVEN WINS
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/35_Even_Wins/javascript/evenwins.js b/00_Alternate_Languages/35_Even_Wins/javascript/evenwins.js
new file mode 100644
index 00000000..3ccaa9ad
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/javascript/evenwins.js
@@ -0,0 +1,197 @@
+// EVEN WINS
+//
+// 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 ma = [];
+var ya = [];
+
+// Main program
+async function main()
+{
+    print(tab(31) + "EVEN WINS\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    y1 = 0;
+    m1 = 0;
+    print("     THIS IS A TWO PERSON GAME CALLED 'EVEN WINS.'\n");
+    print("TO PLAY THE GAME, THE PLAYERS NEED 27 MARBLES OR\n");
+    print("OTHER OBJECTS ON A TABLE.\n");
+    print("\n");
+    print("\n");
+    print("     THE 2 PLAYERS ALTERNATE TURNS, WITH EACH PLAYER\n");
+    print("REMOVING FROM 1 TO 4 MARBLES ON EACH MOVE.  THE GAME\n");
+    print("ENDS WHEN THERE ARE NO MARBLES LEFT, AND THE WINNER\n");
+    print("IS THE ONE WITH AN EVEN NUMBER OF MARBLES.\n");
+    print("\n");
+    print("\n");
+    print("     THE ONLY RULES ARE THAT (1) YOU MUST ALTERNATE TURNS,\n");
+    print("(2) YOU MUST TAKE BETWEEN 1 AND 4 MARBLES EACH TURN,\n");
+    print("AND (3) YOU CANNOT SKIP A TURN.\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    while (1) {
+        print("     TYPE A '1' IF YOU WANT TO GO FIRST, AND TYPE\n");
+        print("A '0' IF YOU WANT ME TO GO FIRST.\n");
+        c = parseInt(await input());
+        print("\n");
+        if (c != 0) {
+            t = 27;
+            print("\n");
+            print("\n");
+            print("\n");
+            print("TOTAL= " + t + "\n");
+            print("\n");
+            print("\n");
+            print("WHAT IS YOUR FIRST MOVE");
+            m = 0;
+        } else {
+            t = 27;
+            m = 2;
+            print("\n");
+            print("TOTAL= " + t + "\n");
+            print("\n");
+            m1 += m;
+            t -= m;
+        }
+        while (1) {
+            if (m) {
+                print("I PICK UP " + m + " MARBLES.\n");
+                if (t == 0)
+                    break;
+                print("\n");
+                print("TOTAL= " + t + "\n");
+                print("\n");
+                print("     AND WHAT IS YOUR NEXT MOVE, MY TOTAL IS " + m1 + "\n");
+            }
+            while (1) {
+                y = parseInt(await input());
+                print("\n");
+                if (y < 1 || y > 4) {
+                    print("\n");
+                    print("THE NUMBER OF MARBLES YOU MUST TAKE BE A POSITIVE\n");
+                    print("INTEGER BETWEEN 1 AND 4.\n");
+                    print("\n");
+                    print("     WHAT IS YOUR NEXT MOVE?\n");
+                    print("\n");
+                } else if (y > t) {
+                    print("     YOU HAVE TRIED TO TAKE MORE MARBLES THAN THERE ARE\n");
+                    print("LEFT.  TRY AGAIN.\n");
+                } else {
+                    break;
+                }
+            }
+
+            y1 += y;
+            t -= y;
+            if (t == 0)
+                break;
+            print("TOTAL= " + t + "\n");
+            print("\n");
+            print("YOUR TOTAL IS " + y1 + "\n");
+            if (t < 0.5)
+                break;
+            r = t % 6;
+            if (y1 % 2 != 0) {
+                if (t >= 4.2) {
+                    if (r <= 3.4) {
+                        m = r + 1;
+                        m1 += m;
+                        t -= m;
+                    } else if (r < 4.7 || r > 3.5) {
+                        m = 4;
+                        m1 += m;
+                        t -= m;
+                    } else {
+                        m = 1;
+                        m1 += m;
+                        t -= m;
+                    }
+                } else {
+                    m = t;
+                    t -= m;
+                    print("I PICK UP " + m + " MARBLES.\n");
+                    print("\n");
+                    print("TOTAL = 0\n");
+                    m1 += m;
+                    break;
+                }
+            } else {
+                if (r < 1.5 || r > 5.3) {
+                    m = 1;
+                    m1 += m;
+                    t -= m;
+                } else {
+                    m = r - 1;
+                    m1 += m;
+                    t -= m;
+                    if (t < 0.2) {
+                        print("I PICK UP " + m + " MARBLES.\n");
+                        print("\n");
+                        break;
+                    }
+                }
+            }
+        }
+        print("THAT IS ALL OF THE MARBLES.\n");
+        print("\n");
+        print(" MY TOTAL IS " + m1 + ", YOUR TOTAL IS " + y1 +"\n");
+        print("\n");
+        if (m1 % 2 != 0) {
+            print("     YOU WON.  DO YOU WANT TO PLAY\n");
+        } else {
+            print("     I WON.  DO YOU WANT TO PLAY\n");
+        }
+        print("AGAIN?  TYPE 1 FOR YES AND 0 FOR NO.\n");
+        a1 = parseInt(await input());
+        if (a1 == 0)
+            break;
+        m1 = 0;
+        y1 = 0;
+    }
+    print("\n");
+    print("OK.  SEE YOU LATER\n");
+}
+
+main();
diff --git a/00_Alternate_Languages/35_Even_Wins/javascript/gameofevenwins.html b/00_Alternate_Languages/35_Even_Wins/javascript/gameofevenwins.html
new file mode 100644
index 00000000..9359f077
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/javascript/gameofevenwins.html
@@ -0,0 +1,9 @@
+
+
+GAME OF EVEN WINS
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/35_Even_Wins/javascript/gameofevenwins.js b/00_Alternate_Languages/35_Even_Wins/javascript/gameofevenwins.js
new file mode 100644
index 00000000..b807a260
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/javascript/gameofevenwins.js
@@ -0,0 +1,152 @@
+// GAME OF EVEN WINS
+//
+// 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 r = [[], []];
+
+// Main program
+async function main()
+{
+    print(tab(28) + "GAME OF EVEN WINS\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("DO YOU WANT INSTRUCTIONS (YES OR NO)");
+    str = await input();
+    print("\n");
+    if (str != "NO") {
+        print("THE GAME IS PLAYED AS FOLLOWS:\n");
+        print("\n");
+        print("AT THE BEGINNING OF THE GAME, A RANDOM NUMBER OF CHIPS ARE\n");
+        print("PLACED ON THE BOARD.  THE NUMBER OF CHIPS ALWAYS STARTS\n");
+        print("AS AN ODD NUMBER.  ON EACH TURN, A PLAYER MUST TAKE ONE,\n");
+        print("TWO, THREE, OR FOUR CHIPS.  THE WINNER IS THE PLAYER WHO\n");
+        print("FINISHES WITH A TOTAL NUMBER OF CHIPS THAT IS EVEN.\n");
+        print("THE COMPUTER STARTS OUT KNOWING ONLY THE RULES OF THE\n");
+        print("GAME.  IT GRADUALLY LEARNS TO PLAY WELL.  IT SHOULD BE\n");
+        print("DIFFICULT TO BEAT THE COMPUTER AFTER TWENTY GAMES IN A ROW.\n");
+        print("TRY IT!!!!\n");
+        print("\n");
+        print("TO QUIT AT ANY TIME, TYPE A '0' AS YOUR MOVE.\n");
+        print("\n");
+    }
+    l = 0;
+    b = 0;
+    for (i = 0; i <= 5; i++) {
+        r[1][i] = 4;
+        r[0][i] = 4;
+    }
+    while (1) {
+        a = 0;
+        b = 0;
+        e = 0;
+        l = 0;
+        p = Math.floor((13 * Math.random() + 9) / 2) * 2 + 1;
+        while (1) {
+            if (p == 1) {
+                print("THERE IS 1 CHIP ON THE BOARD.\n");
+            } else {
+                print("THERE ARE " + p + " CHIPS ON THE BOARD.\n");
+            }
+            e1 = e;
+            l1 = l;
+            e = a % 2;
+            l = p % 6;
+            if (r[e][l] < p) {
+                m = r[e][l];
+                if (m <= 0) {
+                    m = 1;
+                    b = 1;
+                    break;
+                }
+                p -= m;
+                if (m == 1)
+                    print("COMPUTER TAKES 1 CHIP LEAVING " + p + "... YOUR MOVE");
+                else
+                    print("COMPUTER TAKES " + m + " CHIPS LEAVING " + p + "... YOUR MOVE");
+                b += m;
+                while (1) {
+                    m = parseInt(await input());
+                    if (m == 0)
+                        break;
+                    if (m < 1 || m > 4 || m > p) {
+                        print(m + " IS AN ILLEGAL MOVE ... YOUR MOVE");
+                    } else {
+                        break;
+                    }
+                }
+                if (m == 0)
+                    break;
+                if (m == p)
+                    break;
+                p -= m;
+                a += m;
+            } else {
+                if (p == 1) {
+                    print("COMPUTER TAKES 1 CHIP.\n");
+                } else {
+                    print("COMPUTER TAKES " + p + " CHIPS.\n");
+                }
+                r[e][l] = p;
+                b += p;
+                break;
+            }
+        }
+        if (m == 0)
+            break;
+        if (b % 2 != 0) {
+            print("GAME OVER ... YOU WIN!!!\n");
+            print("\n");
+            if (r[e][l] != 1) {
+                r[e][l]--;
+            } else if (r[e1][l1] != 1) {
+                r[e1][l1]--;
+            }
+        } else {
+            print("GAME OVER ... I WIN!!!\n");
+            print("\n");
+        }
+    }
+}
+
+main();
diff --git a/11_Bombardment/pascal/README.md b/00_Alternate_Languages/35_Even_Wins/pascal/README.md
similarity index 100%
rename from 11_Bombardment/pascal/README.md
rename to 00_Alternate_Languages/35_Even_Wins/pascal/README.md
diff --git a/00_Alternate_Languages/35_Even_Wins/perl/README.md b/00_Alternate_Languages/35_Even_Wins/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/35_Even_Wins/perl/evenwins.pl b/00_Alternate_Languages/35_Even_Wins/perl/evenwins.pl
new file mode 100644
index 00000000..0eb37bdb
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/perl/evenwins.pl
@@ -0,0 +1,179 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+&main;
+
+sub main {
+	&print_intro;
+	&game_play;
+}
+
+sub game_play {
+	my $marbles = 27;
+	my $turn = 0;
+	my $player_total = 0;
+	my $computer_total = 0;
+	print "TYPE A '1' IF YOU WANT TO GO FIRST AND TYPE A '0' IF YOU WANT ME TO GO FIRST\n";
+	my $choice = ;
+	chomp($choice);
+	if ($choice == 0) {
+		until ($marbles == 0) {
+
+			my $computer_choice = &computer_select($marbles,$turn,$player_total);
+			$marbles = $marbles - $computer_choice;
+			$computer_total = $computer_total + $computer_choice;
+			print "MY TOTAL IS $computer_total\n";
+
+			print "TOTAL= $marbles\n";
+
+			if ($marbles == 0) {&determine_winner($computer_total,$player_total)};
+
+			my $player_choice = &player_select($marbles,$turn);
+			$marbles = $marbles - $player_choice;
+			$player_total = $player_total + $player_choice;
+			print "YOUR TOTAL IS $player_total\n";
+			$turn++;
+			print "TOTAL= $marbles\n";
+			if ($marbles == 0) {&determine_winner($computer_total,$player_total)};
+		}
+	}
+	elsif ($choice == 1) {
+		until ($marbles == 0) {
+
+			my $player_choice = &player_select($marbles,$turn);
+			$marbles = $marbles - $player_choice;
+			$player_total = $player_total + $player_choice;
+			$turn++;
+			print "YOUR TOTAL IS $player_total\n";
+
+			print "TOTAL= $marbles\n";
+
+			if ($marbles == 0) {&determine_winner($computer_total,$player_total)};
+
+			my $computer_choice = &computer_select($marbles,$turn,$player_total);
+			$marbles = $marbles - $computer_choice;
+			$computer_total = $computer_total + $computer_choice;
+			print "MY TOTAL IS $computer_total\n";
+
+			print "TOTAL= $marbles\n";
+
+			if ($marbles == 0) {&determine_winner($computer_total,$player_total)};
+
+		}
+	}
+}
+
+sub determine_winner {
+	my $computer = shift;
+	my $player = shift;
+	print "THAT IS ALL OF THE MARBLES.\n\n";
+	print "MY TOTAL IS $computer, YOUR TOTAL IS $player\n";
+	if ($player % 2 == 0) {
+		print "     YOU WON.\n";
+	}
+	if ($computer % 2 == 0) {
+		print "     I WON.\n";
+	}
+	my $answer = -1;
+	until ($answer == 1 || $answer == 0) {
+		print "DO YOU WANT TO PLAY AGAIN? TYPE 1 FOR YES AND 0 FOR NO.\n";
+		$answer=;
+		chomp($answer);
+	}
+	if ($answer == 1) {
+		&game_play;
+	}
+	else {
+		print "OK. SEE YOU LATER.\n";
+		exit;
+	}
+}
+
+sub player_select {
+	my $marbles = shift;
+	my $turn = shift;
+	my $validity="invalid";
+	if ($turn == 0) {
+		print "WHAT IS YOUR FIRST MOVE\n";
+	}
+	else {
+		print "WHAT IS YOUR NEXT MOVE\n";
+	}
+	until ($validity eq "valid") {
+		my $num = ;
+		chomp($num);
+		my $validity=&validity_check($marbles,$num);
+		if ($validity eq "valid") {
+			return $num;
+		}
+	}
+}
+
+sub computer_select {
+	my $marbles = shift;
+	my $turn = shift;
+	my $player_total = shift;
+	my $num = 2;
+	my $validity = "invalid";
+	if ($turn == 0) {
+		print "I PICK UP $num MARBLES.\n\n";
+	}
+	else {
+		until ($validity eq "valid") {
+			my $R=$marbles-6*int(($marbles/6));
+
+			if (int($player_total/2) == $player_total/2) {
+				if ($R < 1.5 || $R > 5.3) {
+					$num = 1;
+				}
+				else {
+					$num = $R - 1;
+				}
+			}
+
+			elsif ($marbles < 4.2) {
+				$num = $marbles;
+			}
+			elsif ($R > 3.4) {
+				if ($R < 4.7 || $R > 3.5) {
+					$num = 4;
+				}
+			else {
+					$num = 1;
+				}
+			}
+			$validity=&validity_check($marbles,$num);
+		}
+		print "\nI PICK UP $num MARBLES.\n\n";
+	}
+	return $num;
+}
+
+sub validity_check {
+	my $marbles = shift;
+	my $num = shift;
+	if ($num > $marbles) {
+		print "YOU HAVE TRIED TO TAKE MORE MARBLES THAN THERE ARE LEFT. TRY AGAIN. THERE ARE $marbles MARBLES LEFT\n";
+		return "invalid";
+	}
+	if ($num > 0 && $num <= 4) {
+		return "valid";
+	}
+	if ($num < 1 || $num > 4) {
+		print "THE NUMBER OF MARBLES YOU TAKE MUST BE A POSITIVE INTEGER BETWEEN 1 AND 4\nWHAT IS YOUR NEXT MOVE?\n";
+		return "invalid";
+	}
+	else {
+		return "invalid";
+	}
+}
+
+sub print_intro {
+	print ' ' x 31 . "EVEN WINS\n";
+	print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n";
+	print "THIS IS A 2 PERSON GAME CALLED 'EVEN WINS'. TO PLAY THE GAME, THE PLAYERS NEED 27 MARBLES OR OTHER OBJECTS ON THE TABLE\n\n";
+	print "THE 2 PLAYERS ALTERNATE TURNS, WITH EACH PLAYER REMOVING FROM 1 TO 4 MARBLES ON EACH MOVE. THE GAME ENDS WHEN THERE ARE NO MARBLES LEFT, AND THE WINNER IS THE ONE WITH AN EVEN NUMBER OF MARBLES\n";
+	print "THE ONLY RULES ARE THAT (1) YOU MUST ALTERNATE TURNS, (2) YOU MUST TAKE BETWEEN 1 AND 4 MARBLES EACH TURN, AND (3) YOU CANNOT SKIP A TURN.\n\n";
+}
diff --git a/00_Alternate_Languages/35_Even_Wins/python/README.md b/00_Alternate_Languages/35_Even_Wins/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/35_Even_Wins/python/evenwins.py b/00_Alternate_Languages/35_Even_Wins/python/evenwins.py
new file mode 100644
index 00000000..526e31bf
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/python/evenwins.py
@@ -0,0 +1,235 @@
+# evenwins.py
+
+#
+# This version of evenwins.bas based on game decscription and does *not*
+# follow the source. The computer chooses marbles at random.
+#
+# For simplicity, global variables are used to store the game state.
+# A good exercise would be to replace this with a class.
+#
+# The code is not short, but hopefully it is easy for beginners to understand
+# and modify.
+#
+# Infinite loops of the style "while True:" are used to simplify some of the
+# code. The "continue" keyword is used in a few places to jump back to the top
+# of the loop. The "return" keyword is also used to break out of functions.
+# This is generally considered poor style, but in this case it simplifies the
+# code and makes it easier to read (at least in my opinion). A good exercise
+# would be to remove these infinite loops, and uses of continue, to follow a
+# more structured style.
+#
+
+# global variables
+marbles_in_middle = -1
+human_marbles = -1
+computer_marbles = -1
+whose_turn = ""
+
+
+def serious_error(msg):
+    """
+    Only call this function during development for serious errors that are due
+    to mistakes in the program. Should never be called during a regular game.
+    """
+    print("serious_error: " + msg)
+    exit(1)
+
+
+def welcome_screen():
+    print("Welcome to Even Wins!")
+    print("Based on evenwins.bas from Creative Computing")
+    print()
+    print("Even Wins is a two-person game. You start with")
+    print("27 marbles in the middle of the table.")
+    print()
+    print("Players alternate taking marbles from the middle.")
+    print("A player can take 1 to 4 marbles on their turn, and")
+    print("turns cannot be skipped. The game ends when there are")
+    print("no marbles left, and the winner is the one with an even")
+    print("number of marbles.")
+    print()
+
+
+def marbles_str(n):
+    if n == 1:
+        return "1 marble"
+    return f"{n} marbles"
+
+
+def choose_first_player():
+    global whose_turn
+    while True:
+        ans = input("Do you want to play first? (y/n) --> ")
+        if ans == "y":
+            whose_turn = "human"
+            return
+        elif ans == "n":
+            whose_turn = "computer"
+            return
+        else:
+            print()
+            print('Please enter "y" if you want to play first,')
+            print('or "n" if you want to play second.')
+            print()
+
+
+def next_player():
+    global whose_turn
+    if whose_turn == "human":
+        whose_turn = "computer"
+    elif whose_turn == "computer":
+        whose_turn = "human"
+    else:
+        serious_error(f"play_game: unknown player {whose_turn}")
+
+
+# Converts a string s to an int, if possible.
+def to_int(s):
+    try:
+        n = int(s)
+        return True, n
+    except Exception:
+        return False, 0
+
+
+def print_board():
+    global marbles_in_middle
+    global human_marbles
+    global computer_marbles
+    print()
+    print(f" marbles in the middle: {marbles_in_middle} " + marbles_in_middle * "*")
+    print(f"    # marbles you have: {human_marbles}")
+    print(f"# marbles computer has: {computer_marbles}")
+    print()
+
+
+def human_turn():
+    global marbles_in_middle
+    global human_marbles
+
+    # get number in range 1 to min(4, marbles_in_middle)
+    max_choice = min(4, marbles_in_middle)
+    print("It's your turn!")
+    while True:
+        s = input(f"Marbles to take? (1 - {max_choice}) --> ")
+        ok, n = to_int(s)
+        if not ok:
+            print()
+            print(f"  Please enter a whole number from 1 to {max_choice}")
+            print()
+            continue
+        if n < 1:
+            print()
+            print("  You must take at least 1 marble!")
+            print()
+            continue
+        if n > max_choice:
+            print()
+            print(f"  You can take at most {marbles_str(max_choice)}")
+            print()
+            continue
+        print()
+        print(f"Okay, taking {marbles_str(n)} ...")
+        marbles_in_middle -= n
+        human_marbles += n
+        return
+
+
+def game_over():
+    global marbles_in_middle
+    global human_marbles
+    global computer_marbles
+    print()
+    print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
+    print("!! All the marbles are taken: Game Over!")
+    print("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
+    print()
+    print_board()
+    if human_marbles % 2 == 0:
+        print("You are the winner! Congratulations!")
+    else:
+        print("The computer wins: all hail mighty silicon!")
+    print("")
+
+
+def computer_turn():
+    global marbles_in_middle
+    global computer_marbles
+    global human_marbles
+
+    marbles_to_take = 0
+
+    print("It's the computer's turn ...")
+    r = marbles_in_middle - 6 * int(marbles_in_middle / 6)  # line 500
+
+    if int(human_marbles / 2) == human_marbles / 2:  # line 510
+        if r < 1.5 or r > 5.3:  # lines 710 and 720
+            marbles_to_take = 1
+        else:
+            marbles_to_take = r - 1
+
+    elif marbles_in_middle < 4.2:  # line 580
+        marbles_to_take = marbles_in_middle
+    elif r > 3.4:  # line 530
+        if r < 4.7 or r > 3.5:
+            marbles_to_take = 4
+    else:
+        marbles_to_take = r + 1
+
+    print(f"Computer takes {marbles_str(marbles_to_take)} ...")
+    marbles_in_middle -= marbles_to_take
+    computer_marbles += marbles_to_take
+
+
+def play_game():
+    global marbles_in_middle
+    global human_marbles
+    global computer_marbles
+
+    # initialize the game state
+    marbles_in_middle = 27
+    human_marbles = 0
+    computer_marbles = 0
+    print_board()
+
+    while True:
+        if marbles_in_middle == 0:
+            game_over()
+            return
+        elif whose_turn == "human":
+            human_turn()
+            print_board()
+            next_player()
+        elif whose_turn == "computer":
+            computer_turn()
+            print_board()
+            next_player()
+        else:
+            serious_error(f"play_game: unknown player {whose_turn}")
+
+
+def main():
+    global whose_turn
+
+    welcome_screen()
+
+    while True:
+        choose_first_player()
+        play_game()
+
+        # ask if the user if they want to play again
+        print()
+        again = input("Would you like to play again? (y/n) --> ")
+        if again == "y":
+            print()
+            print("Ok, let's play again ...")
+            print()
+        else:
+            print()
+            print("Ok, thanks for playing ... goodbye!")
+            print()
+            return
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/35_Even_Wins/ruby/README.md b/00_Alternate_Languages/35_Even_Wins/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/35_Even_Wins/vbnet/EvenWins.sln b/00_Alternate_Languages/35_Even_Wins/vbnet/EvenWins.sln
new file mode 100644
index 00000000..0714f204
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/vbnet/EvenWins.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "EvenWins", "EvenWins.vbproj", "{16D44A7A-9C05-4845-8289-3A65A4D978D0}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{16D44A7A-9C05-4845-8289-3A65A4D978D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{16D44A7A-9C05-4845-8289-3A65A4D978D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{16D44A7A-9C05-4845-8289-3A65A4D978D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{16D44A7A-9C05-4845-8289-3A65A4D978D0}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/35_Even_Wins/vbnet/EvenWins.vbproj b/00_Alternate_Languages/35_Even_Wins/vbnet/EvenWins.vbproj
new file mode 100644
index 00000000..7ca1146f
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/vbnet/EvenWins.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    EvenWins
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/35_Even_Wins/vbnet/README.md b/00_Alternate_Languages/35_Even_Wins/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/35_Even_Wins/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/36_Flip_Flop/README.md b/00_Alternate_Languages/36_Flip_Flop/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/36_Flip_Flop/csharp/FlipFlop.cs b/00_Alternate_Languages/36_Flip_Flop/csharp/FlipFlop.cs
new file mode 100644
index 00000000..a6cc5bb1
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/csharp/FlipFlop.cs
@@ -0,0 +1,197 @@
+// Flip Flop Game
+
+PrintGameInfo();
+
+bool startNewGame = true;
+
+string[] board = new string[] { "X", "X", "X", "X", "X", "X", "X", "X", "X", "X" };
+
+do
+{
+    int stepsCount = 0;
+    int lastMove = -1;
+    int moveIndex;
+    int gameSum;
+    double gameEntropyRate = Rnd();
+    bool toPlay = false;
+    bool setNewBoard = true;
+
+    Print();
+    Print("HERE IS THE STARTING LINE OF X'S.");
+    Print();
+
+    do
+    {
+        bool illegalEntry;
+        bool equalToLastMove;
+
+        if (setNewBoard)
+        {
+            PrintNewBoard();
+            board = new string[] { "X", "X", "X", "X", "X", "X", "X", "X", "X", "X" };
+            setNewBoard = false;
+            toPlay = true;
+        }
+
+        stepsCount++;
+        gameSum = 0;
+
+        // Read User's move
+        do
+        {
+            Write("INPUT THE NUMBER? ");
+            var input = Console.ReadLine();
+            illegalEntry = !int.TryParse(input, out moveIndex);
+
+            if (illegalEntry || moveIndex > 11)
+            {
+                illegalEntry = true;
+                Print("ILLEGAL ENTRY--TRY AGAIN.");
+            }
+        }
+        while (illegalEntry);
+
+        if (moveIndex == 11)
+        {
+            // Run new game, To start a new game at any point
+            toPlay = false;
+            stepsCount = 12;
+            startNewGame = true;
+        }
+
+
+        if (moveIndex == 0)
+        {
+            // To reset the line to all X, same game
+            setNewBoard = true;
+            toPlay = false;
+        }
+
+        if (toPlay)
+        {
+            board[moveIndex - 1] = board[moveIndex - 1] == "O" ? "X" : "O";
+
+            if (lastMove == moveIndex)
+            {
+                equalToLastMove = true;
+            }
+            else
+            {
+                equalToLastMove = false;
+                lastMove = moveIndex;
+            }
+
+            do
+            {
+                moveIndex = equalToLastMove
+                    ? GetMoveIndexWhenEqualeLastMove(moveIndex, gameEntropyRate)
+                    : GetMoveIndex(moveIndex, gameEntropyRate);
+
+                board[moveIndex] = board[moveIndex] == "O" ? "X" : "O";
+            }
+            while (lastMove == moveIndex && board[moveIndex] == "X");
+
+            PrintGameBoard(board);
+
+            foreach (var item in board)
+            {
+                if (item == "O")
+                {
+                    gameSum++;
+                }
+            }
+        }
+    }
+    while (stepsCount < 12 && gameSum < 10);
+
+    if (toPlay)
+    {
+        PrintGameResult(gameSum, stepsCount);
+
+        Write("DO YOU WANT TO TRY ANOTHER PUZZLE ");
+
+        var toContinue = Console.ReadLine();
+
+        if (!string.IsNullOrEmpty(toContinue) && toContinue?.ToUpper()[0] == 'N')
+        {
+            startNewGame = false;
+        }
+
+        Print();
+    }
+}
+while (startNewGame);
+
+void Print(string str = "") => Console.WriteLine(str);
+
+void Write(string value) => Console.Write(value);
+
+string Tab(int pos) => new(' ', pos);
+
+double Rnd() => new Random().NextDouble();
+
+int GetMoveIndex(int moveIndex, double gameEntropyRate)
+{
+    double rate = Math.Tan(gameEntropyRate + moveIndex / gameEntropyRate - moveIndex) - Math.Sin(gameEntropyRate / moveIndex) + 336 * Math.Sin(8 * moveIndex);
+    return Convert.ToInt32(Math.Floor(10 * (rate - Math.Floor(rate))));
+}
+
+int GetMoveIndexWhenEqualeLastMove(int moveIndex, double gameEntropyRate)
+{
+    double rate = 0.592 * (1 / Math.Tan(gameEntropyRate / moveIndex + gameEntropyRate)) / Math.Sin(moveIndex * 2 + gameEntropyRate) - Math.Cos(moveIndex);
+    return Convert.ToInt32(Math.Floor(10 * (rate - Math.Floor(rate))));
+}
+
+void PrintNewBoard()
+{
+    Print("1 2 3 4 5 6 7 8 9 10");
+    Print("X X X X X X X X X X");
+    Print();
+}
+
+void PrintGameBoard(string[] board)
+{
+    Print("1 2 3 4 5 6 7 8 9 10");
+
+    foreach (var item in board)
+    {
+        Write($"{item} ");
+    }
+
+    Print();
+    Print();
+}
+
+void PrintGameResult(int gameSum, int stepsCount)
+{
+    if (gameSum == 10)
+    {
+        Print($"VERY GOOD.  YOU GUESSED IT IN ONLY {stepsCount} GUESSES.");
+    }
+    else
+    {
+        Print($"TRY HARDER NEXT TIME.  IT TOOK YOU {stepsCount} GUESSES.");
+    }
+}
+
+void PrintGameInfo()
+{
+    Print(Tab(32) + "FLIPFLOP");
+    Print(Tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+    Print();
+    Print("THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:");
+    Print();
+
+    Print("X X X X X X X X X X");
+    Print();
+    Print("TO THIS:");
+    Print();
+    Print("O O O O O O O O O O");
+    Print();
+
+    Print("BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE");
+    Print("LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON");
+    Print("OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0");
+    Print("(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE ");
+    Print("11 (ELEVEN).");
+}
diff --git a/00_Alternate_Languages/36_Flip_Flop/csharp/FlipFlop.csproj b/00_Alternate_Languages/36_Flip_Flop/csharp/FlipFlop.csproj
new file mode 100644
index 00000000..74abf5c9
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/csharp/FlipFlop.csproj
@@ -0,0 +1,10 @@
+
+
+  
+    Exe
+    net6.0
+    enable
+    enable
+  
+
+
diff --git a/00_Alternate_Languages/36_Flip_Flop/csharp/FlipFlop.sln b/00_Alternate_Languages/36_Flip_Flop/csharp/FlipFlop.sln
new file mode 100644
index 00000000..a26f312e
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/csharp/FlipFlop.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlipFlop", "FlipFlop.csproj", "{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{192EDAD4-5EF5-4B11-9EB3-B17FFAD0861F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {108E5099-D7AA-4260-B587-1B1FE1AF6B54}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/36_Flip_Flop/csharp/README.md b/00_Alternate_Languages/36_Flip_Flop/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/36_Flip_Flop/flipflop.bas b/00_Alternate_Languages/36_Flip_Flop/flipflop.bas
new file mode 100644
index 00000000..38d59879
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/flipflop.bas
@@ -0,0 +1,79 @@
+2 PRINT TAB(32);"FLIPFLOP"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT
+10 REM *** CREATED BY MICHAEL CASS
+15 DIM A$(20)
+20 PRINT "THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:"
+30 PRINT
+40 PRINT "X X X X X X X X X X"
+50 PRINT
+60 PRINT "TO THIS:"
+70 PRINT
+80 PRINT "O O O O O O O O O O"
+90 PRINT
+100 PRINT "BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE"
+110 PRINT "LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON"
+120 PRINT "OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0"
+130 PRINT "(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE "
+140 PRINT "11 (ELEVEN)."
+170 PRINT
+180 REM
+190 Q=RND(1)
+200 PRINT "HERE IS THE STARTING LINE OF X'S."
+210 PRINT
+220 C=0
+230 PRINT "1 2 3 4 5 6 7 8 9 10"
+240 PRINT "X X X X X X X X X X"
+250 PRINT
+260 REM
+270 FOR X=1 TO 10
+280 A$(X)="X"
+290 NEXT X
+300 GOTO 320
+310 PRINT "ILLEGAL ENTRY--TRY AGAIN."
+320 PRINT "INPUT THE NUMBER";
+330 INPUT N
+340 IF N<>INT(N) THEN 310
+350 IF N=11 THEN 180
+360 IF N>11 THEN 310
+370 IF N=0 THEN 230
+380 IF M=N THEN 510
+390 M=N
+400 IF A$(N)="O" THEN 480
+410 A$(N)="O"
+420 R=TAN(Q+N/Q-N)-SIN(Q/N)+336*SIN(8*N)
+430 N=R-INT(R)
+440 N=INT(10*N)
+450 IF A$(N)="O" THEN 480
+460 A$(N)="O"
+470 GOTO 610
+480 A$(N)="X"
+490 IF M=N THEN 420
+500 GOTO 610
+510 IF A$(N)="O" THEN 590
+520 A$(N)="O"
+530 R=.592*(1/TAN(Q/N+Q))/SIN(N*2+Q)-COS(N)
+540 N=R-INT(R)
+550 N=INT(10*N)
+560 IF A$(N)="O" THEN 590
+570 A$(N)="O"
+580 GOTO 610
+590 A$(N)="X"
+600 IF M=N THEN 530
+610 PRINT "1 2 3 4 5 6 7 8 9 10"
+620 FOR Z=1 TO 10: PRINT A$(Z);" ";: NEXT Z
+630 C=C+1
+640 PRINT
+650 FOR Z=1 TO 10
+660 IF A$(Z)<>"O" THEN 320
+670 NEXT Z
+680 IF C>12 THEN 710
+690 PRINT "VERY GOOD.  YOU GUESSED IT IN ONLY";C;"GUESSES."
+700 GOTO 720
+710 PRINT "TRY HARDER NEXT TIME.  IT TOOK YOU";C;"GUESSES."
+720 PRINT "DO YOU WANT TO TRY ANOTHER PUZZLE";
+730 INPUT X$
+740 IF LEFT$(X$,1)="N" THEN 780
+760 PRINT
+770 GOTO 180
+780 END
diff --git a/00_Alternate_Languages/36_Flip_Flop/java/FlipFlop.java b/00_Alternate_Languages/36_Flip_Flop/java/FlipFlop.java
new file mode 100644
index 00000000..fe8309d5
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/java/FlipFlop.java
@@ -0,0 +1,287 @@
+import java.util.Scanner;
+import java.lang.Math;
+
+/**
+ * Game of FlipFlop
+ * 

+ * Based on the BASIC game of FlipFlop here + * https://github.com/coding-horror/basic-computer-games/blob/main/36%20Flip%20Flop/flipflop.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 FlipFlop { + + private final Scanner scan; // For user input + + private enum Step { + RANDOMIZE, INIT_BOARD, GET_NUMBER, ILLEGAL_ENTRY, FLIP_POSITION, SET_X_FIRST, SET_X_SECOND, + GENERATE_R_FIRST, GENERATE_R_SECOND, PRINT_BOARD, QUERY_RETRY + } + + public FlipFlop() { + + scan = new Scanner(System.in); + + } // End of constructor FlipFlop + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private static void showIntro() { + + System.out.println(" ".repeat(31) + "FLIPFLOP"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(""); + + } // End of method showIntro + + private void startGame() { + + double mathVal = 0; + double randVal = 0; + double tmpVal = 0; + + int index = 0; + int match = 0; + int numFlip = 0; + int numGuesses = 0; + + Step nextStep = Step.RANDOMIZE; + + String userResponse = ""; + + String[] board = new String[21]; + + System.out.println("THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:"); + System.out.println(""); + System.out.println("X X X X X X X X X X"); + System.out.println(""); + System.out.println("TO THIS:"); + System.out.println(""); + System.out.println("O O O O O O O O O O"); + System.out.println(""); + System.out.println("BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE"); + System.out.println("LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON"); + System.out.println("OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0"); + System.out.println("(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE "); + System.out.println("11 (ELEVEN)."); + System.out.println(""); + + // Begin outer while loop + while (true) { + + // Begin switch + switch (nextStep) { + + case RANDOMIZE: + + randVal = Math.random(); + + System.out.println("HERE IS THE STARTING LINE OF X'S."); + System.out.println(""); + + numGuesses = 0; + nextStep = Step.INIT_BOARD; + break; + + case INIT_BOARD: + + System.out.println("1 2 3 4 5 6 7 8 9 10"); + System.out.println("X X X X X X X X X X"); + System.out.println(""); + + // Avoid out of bounds error by starting at zero + for (index = 0; index <= 10; index++) { + board[index] = "X"; + } + + nextStep = Step.GET_NUMBER; + break; + + case GET_NUMBER: + + System.out.print("INPUT THE NUMBER? "); + userResponse = scan.nextLine(); + + try { + numFlip = Integer.parseInt(userResponse); + } + catch (NumberFormatException ex) { + nextStep = Step.ILLEGAL_ENTRY; + break; + } + + // Command to start a new game + if (numFlip == 11) { + nextStep = Step.RANDOMIZE; + break; + } + + if (numFlip > 11) { + nextStep = Step.ILLEGAL_ENTRY; + break; + } + + // Command to reset the board + if (numFlip == 0) { + nextStep = Step.INIT_BOARD; + break; + } + + if (match == numFlip) { + nextStep = Step.FLIP_POSITION; + break; + } + + match = numFlip; + + if (board[numFlip].equals("O")) { + nextStep = Step.SET_X_FIRST; + break; + } + + board[numFlip] = "O"; + nextStep = Step.GENERATE_R_FIRST; + break; + + case ILLEGAL_ENTRY: + System.out.println("ILLEGAL ENTRY--TRY AGAIN."); + nextStep = Step.GET_NUMBER; + break; + + case GENERATE_R_FIRST: + + mathVal = Math.tan(randVal + numFlip / randVal - numFlip) - Math.sin(randVal / numFlip) + 336 + * Math.sin(8 * numFlip); + + tmpVal = mathVal - (int)Math.floor(mathVal); + + numFlip = (int)(10 * tmpVal); + + if (board[numFlip].equals("O")) { + nextStep = Step.SET_X_FIRST; + break; + } + + board[numFlip] = "O"; + nextStep = Step.PRINT_BOARD; + break; + + case SET_X_FIRST: + board[numFlip] = "X"; + + if (match == numFlip) { + nextStep = Step.GENERATE_R_FIRST; + } else { + nextStep = Step.PRINT_BOARD; + } + break; + + case FLIP_POSITION: + + if (board[numFlip].equals("O")) { + nextStep = Step.SET_X_SECOND; + break; + } + + board[numFlip] = "O"; + nextStep = Step.GENERATE_R_SECOND; + break; + + case GENERATE_R_SECOND: + + mathVal = 0.592 * (1 / Math.tan(randVal / numFlip + randVal)) / Math.sin(numFlip * 2 + randVal) + - Math.cos(numFlip); + + tmpVal = mathVal - (int)mathVal; + numFlip = (int)(10 * tmpVal); + + if (board[numFlip].equals("O")) { + nextStep = Step.SET_X_SECOND; + break; + } + + board[numFlip] = "O"; + nextStep = Step.PRINT_BOARD; + break; + + case SET_X_SECOND: + + board[numFlip] = "X"; + if (match == numFlip) { + nextStep = Step.GENERATE_R_SECOND; + break; + } + + nextStep = Step.PRINT_BOARD; + break; + + case PRINT_BOARD: + System.out.println("1 2 3 4 5 6 7 8 9 10"); + + for (index = 1; index <= 10; index++) { + System.out.print(board[index] + " "); + } + + numGuesses++; + + System.out.println(""); + + for (index = 1; index <= 10; index++) { + if (!board[index].equals("O")) { + nextStep = Step.GET_NUMBER; + break; + } + } + + if (nextStep == Step.GET_NUMBER) { + break; + } + + if (numGuesses > 12) { + System.out.println("TRY HARDER NEXT TIME. IT TOOK YOU " + numGuesses + " GUESSES."); + } else { + System.out.println("VERY GOOD. YOU GUESSED IT IN ONLY " + numGuesses + " GUESSES."); + } + nextStep = Step.QUERY_RETRY; + break; + + case QUERY_RETRY: + + System.out.print("DO YOU WANT TO TRY ANOTHER PUZZLE? "); + userResponse = scan.nextLine(); + + if (userResponse.toUpperCase().charAt(0) == 'N') { + return; + } + System.out.println(""); + nextStep = Step.RANDOMIZE; + break; + + default: + System.out.println("INVALID STEP"); + nextStep = Step.QUERY_RETRY; + break; + + } // End of switch + + } // End outer while loop + + } // End of method startGame + + public static void main(String[] args) { + + FlipFlop game = new FlipFlop(); + game.play(); + + } // End of method main + +} // End of class FlipFlop diff --git a/00_Alternate_Languages/36_Flip_Flop/java/README.md b/00_Alternate_Languages/36_Flip_Flop/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/36_Flip_Flop/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/36_Flip_Flop/javascript/README.md b/00_Alternate_Languages/36_Flip_Flop/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/36_Flip_Flop/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/36_Flip_Flop/javascript/flipflop.html b/00_Alternate_Languages/36_Flip_Flop/javascript/flipflop.html new file mode 100644 index 00000000..2de8e198 --- /dev/null +++ b/00_Alternate_Languages/36_Flip_Flop/javascript/flipflop.html @@ -0,0 +1,9 @@ + + +FLIPFLOP + + +


+
+
+
diff --git a/00_Alternate_Languages/36_Flip_Flop/javascript/flipflop.js b/00_Alternate_Languages/36_Flip_Flop/javascript/flipflop.js
new file mode 100644
index 00000000..c74c61ca
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/javascript/flipflop.js
@@ -0,0 +1,144 @@
+// FLIPFLOP
+//
+// 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 as = [];
+
+// Main program
+async function main()
+{
+    print(tab(32) + "FLIPFLOP\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    // *** Created by Michael Cass
+    print("THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\n");
+    print("\n");
+    print("X X X X X X X X X X\n");
+    print("\n");
+    print("TO THIS:\n");
+    print("\n");
+    print("O O O O O O O O O O\n");
+    print("\n");
+    print("BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE\n");
+    print("LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON\n");
+    print("OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0\n");
+    print("(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE \n");
+    print("11 (ELEVEN).\n");
+    print("\n");
+    while (1) {
+        start = 1;
+        do {
+            z = 1;
+            if (start == 1) {
+                m = 0;
+                q = Math.random();
+                print("HERE IS THE STARTING LINE OF X'S.\n");
+                print("\n");
+                c = 0;
+                start = 2;
+            }
+            if (start == 2) {
+                print("1 2 3 4 5 6 7 8 9 10\n");
+                print("X X X X X X X X X X\n");
+                print("\n");
+                for (x = 1; x <= 10; x++)
+                    as[x] = "X";
+                start = 0;
+            }
+            print("INPUT THE NUMBER");
+            while (1) {
+                n = parseInt(await input());
+                if (n >= 0 && n <= 11)
+                    break;
+                print("ILLEGAL ENTRY--TRY AGAIN.\n");
+            }
+            if (n == 11) {
+                start = 1;
+                continue;
+            }
+            if (n == 0) {
+                start = 2;
+                continue;
+            }
+            if (m != n) {
+                m = n;
+                as[n] = (as[n] == "O" ? "X" : "O");
+                do {
+                    r = Math.tan(q + n / q - n) - Math.sin(q / n) + 336 * Math.sin(8 * n);
+                    n = r - Math.floor(r);
+                    n = Math.floor(10 * n);
+                    as[n] = (as[n] == "O" ? "X" : "O");
+                } while (m == n) ;
+            } else {
+                as[n] = (as[n] == "O" ? "X" : "O");
+                do {
+                    r = 0.592 * (1 / Math.tan(q / n + q)) / Math.sin(n * 2 + q) - Math.cos(n);
+                    n = r - Math.floor(r);
+                    n = Math.floor(10 * n);
+                    as[n] = (as[n] == "O" ? "X" : "O");
+                } while (m == n) ;
+            }
+            print("1 2 3 4 5 6 7 8 9 10\n");
+            for (z = 1; z <= 10; z++)
+                print(as[z] + " ");
+            c++;
+            print("\n");
+            for (z = 1; z <= 10; z++) {
+                if (as[z] != "O")
+                    break;
+            }
+        } while (z <= 10) ;
+        if (c <= 12) {
+            print("VERY GOOD.  YOU GUESSED IT IN ONLY " + c + " GUESSES.\n");
+        } else {
+            print("TRY HARDER NEXT TIME.  IT TOOK YOU " + c + " GUESSES.\n");
+        }
+        print("DO YOU WANT TO TRY ANOTHER PUZZLE");
+        str = await input();
+        if (str.substr(0, 1) == "N")
+            break;
+    }
+    print("\n");
+}
+
+main();
diff --git a/12_Bombs_Away/pascal/README.md b/00_Alternate_Languages/36_Flip_Flop/pascal/README.md
similarity index 100%
rename from 12_Bombs_Away/pascal/README.md
rename to 00_Alternate_Languages/36_Flip_Flop/pascal/README.md
diff --git a/00_Alternate_Languages/36_Flip_Flop/perl/README.md b/00_Alternate_Languages/36_Flip_Flop/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/36_Flip_Flop/python/README.md b/00_Alternate_Languages/36_Flip_Flop/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/36_Flip_Flop/python/flipflop.py b/00_Alternate_Languages/36_Flip_Flop/python/flipflop.py
new file mode 100644
index 00000000..9ca5e4c1
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/python/flipflop.py
@@ -0,0 +1,129 @@
+# Flip Flop
+#
+# The object of this game is to change a row of ten X's
+# X X X X X X X X X X
+# to a row of ten O's:
+# O O O O O O O O O O
+# by typing in a number corresponding
+# to the position of an "X" in the line. On
+# some numbers one position will
+# change while on other numbers, two
+# will change. For example, inputting a 3
+# may reverse the X and O in position 3,
+# but it might possibly reverse some
+# other position too! You ought to be able
+# to change all 10 in 12 or fewer
+# moves. Can you figure out a good win-
+# ning strategy?
+# To reset the line to all X's (same
+# game), type 0 (zero). To start a new
+# game at any point, type 11.
+# The original author of this game was
+# Michael Kass of New Hyde Park, New
+# York.
+import math
+import random
+from typing import Callable, List, Tuple
+
+flip_dict = {"X": "O", "O": "X"}
+
+
+def flip_bits(
+    row: List[str], m: int, n: int, r_function: Callable[[int], float]
+) -> Tuple[List[str], int]:
+    """
+    Function that flips the positions at the computed steps
+    """
+    while m == n:
+        r = r_function(n)
+        n = r - int(math.floor(r))
+        n = int(10 * n)
+        if row[n] == "X":
+            row[n] = "O"
+            break
+        elif row[n] == "O":
+            row[n] = "X"
+    return row, n
+
+
+def print_instructions():
+    print(" " * 32 + "FLIPFLOP")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print("\n" * 2)
+    print("THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:\n")
+    print("X X X X X X X X X X\n")
+    print("TO THIS:\n")
+    print("O O O O O O O O O O\n")
+    print("BY TYPING TH NUMBER CORRESPONDING TO THE POSITION OF THE")
+    print("LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON")
+    print("OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0")
+    print("(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE ")
+    print("11 (ELEVEN).\n")
+
+
+def main():
+    q = random.random()
+
+    print("HERE IS THE STARTING LINE OF X'S.\n")
+    # We add an extra 0-th item because this sometimes is set to something
+    # but we never check what it is for completion of the puzzle
+    row = [""] + ["X"] * 10
+    counter_turns = 0
+    n = -1
+    legal_move = True
+    while row[1:] != ["O"] * 10:
+        if legal_move:
+            print(" ".join([str(i) for i in range(1, 11)]))
+            print(" ".join(row[1:]) + "\n")
+        m = input("INPUT THE NUMBER\n")
+        try:
+            m = int(m)
+            if m > 11 or m < 0:
+                raise ValueError()
+        except ValueError:
+            print("ILLEGAL ENTRY--TRY AGAIN")
+            legal_move = False
+            continue
+        legal_move = True
+        if m == 11:
+            # completely reset the puzzle
+            counter_turns = 0
+            row = [""] + ["X"] * 10
+            q = random.random()
+            continue
+        elif m == 0:
+            # reset the board, but not the counter or the random number
+            row = [""] + ["X"] * 10
+        elif m == n:
+            row[n] = flip_dict[row[n]]
+            r_function = lambda n_t: 0.592 * (1 / math.tan(q / n_t + q)) / math.sin(
+                n_t * 2 + q
+            ) - math.cos(n_t)
+            row, n = flip_bits(row, m, n, r_function)
+        else:
+            n = m
+            row[n] = flip_dict[row[n]]
+            r_function = lambda n_t: (
+                math.tan(q + n_t / q - n_t)
+                - math.sin(n_t * 2 + q)
+                + 336 * math.sin(8 * n_t)
+            )
+            row, n = flip_bits(row, m, n, r_function)
+
+        counter_turns += 1
+        print()
+
+    if counter_turns <= 12:
+        print(f"VERY GOOD. YOU GUESSED IT IN ONLY {counter_turns} GUESSES.")
+    else:
+        print(f"TRY HARDER NEXT TIME. IT TOOK YOU {counter_turns} GUESSES.")
+    return
+
+
+if __name__ == "__main__":
+    print_instructions()
+
+    another = ""
+    while another != "NO":
+        main()
+        another = input("DO YOU WANT TO TRY ANOTHER PUZZLE\n")
diff --git a/00_Alternate_Languages/36_Flip_Flop/ruby/README.md b/00_Alternate_Languages/36_Flip_Flop/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/36_Flip_Flop/ruby/flipflop.rb b/00_Alternate_Languages/36_Flip_Flop/ruby/flipflop.rb
new file mode 100644
index 00000000..74ceadee
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/ruby/flipflop.rb
@@ -0,0 +1,162 @@
+#A class representing the internal state of a single game of flip flop
+# state represents the list of X's (A in the original code)
+# guesses represents the number of guesses the user has made (C in the original code)
+# seed represents the random seed for an instance of the game (Q in the original code)
+Game = Struct.new(:state, :guesses, :seed) do
+
+  #The original BASIC program used 1 indexed arrays while Ruby has 0-indexed arrays.
+  #We can't use 0 indexed arrays for the flip functions or we'll get divide by zero errors.
+  #These convenience functions allow us to modify and access internal game state in a 1-indexed fashion
+  def flip_letter(letter_number)
+    index = letter_number -1
+    if self.state[index] == 'X'
+      self.state[index] = 'O'
+    else
+      self.state[index] = 'X'
+    end
+  end
+
+  def letter_at(letter_number)
+    self.state[letter_number - 1]
+  end
+end
+
+def print_welcome
+  puts 'FLIPFLOP'.center(72)
+  puts 'CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY'.center(72)
+  puts <<~EOS
+
+    THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:
+
+    X X X X X X X X X X
+
+    TO THIS:
+
+    O O O O O O O O O O
+
+    BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE
+    LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON
+    OTHERS, TWO WILL CHANGE.  TO RESET LINE TO ALL X'S, TYPE 0
+    (ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE
+    11 (ELEVEN).
+  EOS
+end
+
+def print_starting_message
+  puts <<~EOS
+
+  HERE IS THE STARTING LINE OF X'S.
+
+  1 2 3 4 5 6 7 8 9 10
+  X X X X X X X X X X
+
+  EOS
+end
+
+#Create a new game with [X,X,X,X,X,X,X,X,X,X] as the state
+#0 as the number of guesses and a random seed between 0 and 1
+def generate_new_game
+  Game.new(Array.new(10, 'X'), 0, rand())
+end
+
+#Given a game, an index, and a shuffle function, flip one or more letters
+def shuffle_board(game, index, shuffle_function)
+  n = method(shuffle_function).call(game, index)
+
+  if game.letter_at(n) == "O"
+    game.flip_letter(n)
+    if index == n
+      n = shuffle_board(game, index, shuffle_function)
+    end
+  else
+    game.flip_letter(n)
+  end
+  return n
+end
+
+#Shuffle logic copied from original BASIC code
+def shuffle_function1(game, index)
+  r = Math.tan(game.seed + index / game.seed - index) - Math.sin(game.seed / index) + 336 * Math.sin(8 * index)
+  n = r - r.floor
+  (10 * n).floor
+end
+
+def shuffle_function2(game, index)
+  r = 0.592 * (1/ Math.tan(game.seed / index + game.seed)) / Math.sin(index * 2 + game.seed) - Math.cos(index)
+  n = r - r.floor
+  (10 * n)
+end
+
+def play_game
+  print_starting_message
+  game = generate_new_game
+  working_index = nil
+
+  loop do
+    puts "INPUT THE NUMBER"
+    input = gets.chomp.downcase
+
+    #See if the user input a valid integer, fail otherwise
+    if numeric_input = Integer(input, exception: false)
+
+      #If 11 is entered, we're done with this version of the game
+      if numeric_input == 11
+        return :restart
+      end
+
+      if numeric_input > 11
+        puts 'ILLEGAL ENTRY--TRY AGAIN.'
+        next #illegal entries don't count towards your guesses
+      end
+
+      if working_index == numeric_input
+        game.flip_letter(numeric_input)
+        working_index = shuffle_board(game, numeric_input, :shuffle_function2)
+      #If 0 is entered, we want to reset the state, but not the random seed or number of guesses and keep playing
+      elsif numeric_input == 0
+        game.state = Array.new(10, 'X')
+      elsif game.letter_at(numeric_input) == "O"
+        game.flip_letter(numeric_input)
+        if numeric_input == working_index
+          working_index = shuffle_board(game, numeric_input, :shuffle_function1)
+        end
+      else
+        game.flip_letter(numeric_input)
+        working_index = shuffle_board(game, numeric_input, :shuffle_function1)
+      end
+    else
+      puts 'ILLEGAL ENTRY--TRY AGAIN.'
+      next #illegal entries don't count towards your guesses
+    end
+
+    game.guesses += 1
+    puts '1 2 3 4 5 6 7 8 9 10'
+    puts game.state.join(' ')
+
+    if game.state.all? { |x| x == 'O' }
+      if game.guesses > 12
+        puts "TRY HARDER NEXT TIME. IT TOOK YOU #{game.guesses} GUESSES."
+      else
+        puts "VERY GOOD.  YOU GUESSED IT IN ONLY #{game.guesses} GUESSES."
+      end
+      #game is complete
+      return
+    end
+  end
+end
+
+
+
+#Execution starts
+print_welcome
+loop do
+  result = play_game
+  if result == :restart
+    next
+  end
+
+  puts 'DO YOU WANT TO TRY ANOTHER PUZZLE'
+  if gets.chomp.downcase[0] == 'n'
+    break
+  end
+end
diff --git a/00_Alternate_Languages/36_Flip_Flop/vbnet/FlipFlop.sln b/00_Alternate_Languages/36_Flip_Flop/vbnet/FlipFlop.sln
new file mode 100644
index 00000000..8301941b
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/vbnet/FlipFlop.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "FlipFlop", "FlipFlop.vbproj", "{4A5887DD-FA0C-47EE-B3A2-E334DCE3544C}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{4A5887DD-FA0C-47EE-B3A2-E334DCE3544C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4A5887DD-FA0C-47EE-B3A2-E334DCE3544C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4A5887DD-FA0C-47EE-B3A2-E334DCE3544C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4A5887DD-FA0C-47EE-B3A2-E334DCE3544C}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/36_Flip_Flop/vbnet/FlipFlop.vbproj b/00_Alternate_Languages/36_Flip_Flop/vbnet/FlipFlop.vbproj
new file mode 100644
index 00000000..388b75c1
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/vbnet/FlipFlop.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    FlipFlop
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/36_Flip_Flop/vbnet/README.md b/00_Alternate_Languages/36_Flip_Flop/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/36_Flip_Flop/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/37_Football/README.md b/00_Alternate_Languages/37_Football/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/37_Football/csharp/Football.csproj b/00_Alternate_Languages/37_Football/csharp/Football.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/csharp/Football.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/37_Football/csharp/Football.sln b/00_Alternate_Languages/37_Football/csharp/Football.sln
new file mode 100644
index 00000000..b0d85b41
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/csharp/Football.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Football", "Football.csproj", "{092442FA-EA04-4A80-AB12-138E18CD480A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{092442FA-EA04-4A80-AB12-138E18CD480A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{092442FA-EA04-4A80-AB12-138E18CD480A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{092442FA-EA04-4A80-AB12-138E18CD480A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{092442FA-EA04-4A80-AB12-138E18CD480A}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/37_Football/csharp/README.md b/00_Alternate_Languages/37_Football/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/37_Football/football.bas b/00_Alternate_Languages/37_Football/football.bas
new file mode 100644
index 00000000..9ee2192f
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/football.bas
@@ -0,0 +1,181 @@
+1 PRINT TAB(32);"FOOTBALL"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+100 REM
+120 DIM A(20),B(20),C(40),H(2),T(2),W(2),X(2),Y(2),Z(2)
+130 DIM M$(2),D(2),P$(20)
+140 PRINT "PRESENTING N.F.U. FOOTBALL (NO FORTRAN USED)"
+145 PRINT:PRINT
+150 INPUT "DO YOU WANT INSTRUCTIONS";A$
+160 IF A$="NO" THEN 290
+165 IF A$<>"YES" THEN 150
+170 PRINT "THIS IS A FOOTBALL GAME FOR TWO TEAMS IN WHICH PLAYERS MUST"
+180 PRINT "PREPARE A TAPE WITH A DATA STATEMENT (1770 FOR TEAM 1,"
+190 PRINT "1780 FOR TEAM 2) IN WHICH EACH TEAM SCRAMBLES NOS. 1-20"
+195 PRINT "THESE NUMBERS ARE THEN ASSIGNED TO TWENTY GIVEN PLAYS."
+200 PRINT"A LIST OF NOS. AND THEIR PLAYS IS PROVIDED WITH"
+210 PRINT "BOTH TEAMS HAVING THE SAME PLAYS. THE MORE SIMILAR THE"
+220 PRINT "PLAYS THE LESS YARDAGE GAINED.  SCORES ARE GIVEN"
+223 PRINT "WHENEVER SCORES ARE MADE. SCORES MAY ALSO BE OBTAINED"
+225 PRINT "BY INPUTTING 99,99 FOR PLAY NOS. TO PUNT OR ATTEMPT A"
+227 PRINT "FIELD GOAL, INPUT 77,77 FOR PLAY NUMBERS. QUESTIONS WILL BE"
+230 PRINT "ASKED THEN. ON 4TH DOWN, YOU WILL ALSO BE ASKED WHETHER"
+240 PRINT "YOU WANT TO PUNT OR ATTEMPT A FIELD GOAL. IF THE ANSWER TO"
+250 PRINT "BOTH QUESTIONS IS NO IT WILL BE ASSUMED YOU WANT TO"
+260 PRINT "TRY AND GAIN YARDAGE. ANSWER ALL QUESTIONS YES OR NO."
+270 PRINT "THE GAME IS PLAYED UNTIL PLAYERS TERMINATE (CONTROL-C)."
+280 PRINT "PLEASE PREPARE A TAPE AND RUN.": STOP
+290 PRINT:PRINT "PLEASE INPUT SCORE LIMIT ON GAME";:INPUT E
+300 FOR I=1 TO 40: READ N: IF I>20 THEN 350
+330 A(N)=I: GOTO 360
+350 B(N)=I-20
+360 C(I)=N: NEXT I
+370 FOR I=1 TO 20: READ P$(I): NEXT I
+380 L=0: T=1
+410 PRINT "TEAM";T;"PLAY CHART"
+420 PRINT "NO.      PLAY"
+430 FOR I=1 TO 20
+440 REM
+450 PRINT C(I+L);TAB(6);P$(I)
+460 NEXT I
+630 L=L+20:T=2
+640 PRINT
+650 PRINT "TEAR OFF HERE----------------------------------------------"
+660 FOR X=1 TO 11: PRINT: NEXT X
+670 FOR Z=1 TO 3000: NEXT Z
+680 IF L=20 THEN 410
+690 D(1)=0: D(2)=3: M$(1)="--->": M$(2)="<---"
+700 H(1)=0: H(2)=0: T(1)=2: T(2)=1
+710 W(1)=-1: W(2)=1: X(1)=100: X(2)=0
+720 Y(1)=1: Y(2)=-1: Z(1)=0: Z(2)=100
+725 GOSUB 1910
+730 PRINT "TEAM 1 DEFENDS 0 YD GOAL -- TEAM 2 DEFENDS 100 YD GOAL."
+740 T=INT(2*RND(1)+1)
+760 PRINT: PRINT "THE COIN IS FLIPPED"
+765 P=X(T)-Y(T)*40
+770 GOSUB 1860: PRINT : PRINT "TEAM";T;"RECEIVES KICK-OFF"
+780 K=INT(26*RND(1)+40)
+790 P=P-Y(T)*K
+794 IF W(T)*P"NO" THEN 830
+850 IF W(T)*P1 THEN 900
+895 IF Y(T)*(P+Y(T)*10)>=X(T) THEN 898
+897 C=4: GOTO 900
+898 C=8
+900 IF C=8 THEN 904
+901 PRINT TAB(27);10-(Y(T)*P-Y(T)*S);"YARDS TO 1ST DOWN"
+902 GOTO 910
+904 PRINT TAB(27);X(T)-Y(T)*P;"YARDS"
+910 GOSUB 1900: IF D=4 THEN 1180
+920 REM
+930 U=INT(3*RND(0)-1): GOTO 940
+936 PRINT "ILLEGAL PLAY NUMBER, CHECK AND"
+940 PRINT "INPUT OFFENSIVE PLAY, DEFENSIVE PLAY";
+950 IF T=2 THEN 970
+960 INPUT P1,P2: GOTO 975
+970 INPUT P2,P1
+975 IF P1=77 THEN 1180
+980 IF P1>20 THEN 1800
+985 IF P1<1 THEN 1800
+990 IF P2>20 THEN 1800
+992 IF P2<1 THEN 1800
+995 P1=INT(P1): P2=INT(P2)
+1000 Y=INT(ABS(A(P1)-B(P2))/19*((X(T)-Y(T)*P+25)*RND(1)-15))
+1005 PRINT: IF T=2 THEN 1015
+1010 IF A(P1)<11 THEN 1048
+1012 GOTO 1020
+1015 IF B(P2)<11 THEN 1048
+1020 IF U<>0 THEN 1035
+1025 PRINT "PASS INCOMPLETE TEAM";T
+1030 Y=0: GOTO 1050
+1035 G=RND(1): IF G>.025 THEN 1040
+1037 IF Y>2 THEN 1045
+1040 PRINT "QUARTERBACK SCRAMBLED": GOTO 1050
+1045 PRINT "PASS COMPLETED": GOTO 1050
+1048 PRINT "THE BALL WAS RUN"
+1050 P=P-W(T)*Y
+1060 PRINT: PRINT "NET YARDS GAINED ON DOWN";D;"ARE ";Y
+1070 G=RND(1): IF G>.025 THEN 1110
+1080 PRINT: PRINT "** LOSS OF POSSESSION FROM TEAM";T;"TO TEAM";T(T)
+1100 GOSUB 1850: PRINT: T=T(T): GOTO 830
+1110 IF Y(T)*P>=X(T) THEN 1320
+1120 IF W(T)*P>=Z(T) THEN 1230
+1130 IF Y(T)*P-Y(T)*S>=10 THEN 880
+1140 D=D+1: IF D<>5 THEN 885
+1160 PRINT: PRINT "CONVERSION UNSUCCESSFUL TEAM";T:T=T(T)
+1170 GOSUB 1850: GOTO 880
+1180 PRINT "DOES TEAM";T;"WANT TO PUNT";: INPUT A$
+1185 IF A$="NO" THEN 1200
+1187 IF A$<>"YES" THEN 1180
+1190 PRINT:PRINT "TEAM";T;"WILL PUNT": G=RND(1): IF G<.025 THEN 1080
+1195 GOSUB 1850: K=INT(25*RND(1)+35): T=T(T): GOTO 790
+1200 PRINT "DOES TEAM";T;"WANT TO ATTEMPT A FIELD GOAL";: INPUT A$
+1210 IF A$="YES" THEN 1640
+1215 IF A$<>"NO" THEN 1200
+1217 GOTO 920
+1230 PRINT: PRINT "SAFETY AGAINST TEAM";T;"**********************OH-OH"
+1240 H(T(T))=H(T(T))+2: GOSUB 1810
+1280 PRINT"TEAM";T;"DO YOU WANT TO PUNT INSTEAD OF A KICKOFF";:INPUT A$
+1290 P=Z(T)-W(T)*20: IF A$="YES" THEN 1190
+1320 PRINT: PRINT "TOUCHDOWN BY TEAM";T;"*********************YEA TEAM"
+1340 Q=7: G=RND(1): IF G>.1 THEN 1380
+1360 Q=6: PRINT "EXTRA POINT NO GOOD": GOTO 1390
+1380 PRINT "EXTRA POINT GOOD"
+1390 H(T)=H(T)+Q: GOSUB 1810
+1420 T=T(T): GOTO 765
+1430 K=INT(9*RND(0)+1)
+1440 R=INT(((X(T)-Y(T)*P+25)*RND(1)-15)/K)
+1460 P=P-W(T)*R
+1480 PRINT:PRINT "RUNBACK TEAM";T;R;"YARDS"
+1485 G=RND(1): IF G<.025 THEN 1080
+1490 IF Y(T)*P>=X(T) THEN 1320
+1500 IF W(T)*P>=Z(T) THEN 1230
+1510 GOTO 880
+1640 PRINT: PRINT "TEAM";T;"WILL ATTEMPT A FIELD GOAL"
+1645 G=RND(1): IF G<.025 THEN 1080
+1650 F=INT(35*RND(1)+20)
+1660 PRINT: PRINT "KICK IS";F;"YARDS LONG"
+1680 P=P-W(T)*F: G=RND(1)
+1690 IF G<.35 THEN 1735
+1700 IF Y(T)*P99 THEN 936
+1810 PRINT: PRINT "TEAM 1 SCORE IS";H(1)
+1820 PRINT "TEAM 2 SCORE IS";H(2): PRINT
+1825 IF H(T)=50 THEN 700
+630 LET Y=INT(50*RND(1)^2)+(1-P)*INT(50*RND(1)^4)
+640 LET X=X+FNF(1)*Y
+650 IF ABS(X-50)>=50 THEN 655
+651 PRINT Y;L$(3);" RUNBACK"
+652 GOTO 720
+655 PRINT L$(4);
+660 GOTO 2600
+700 PRINT "TOUCHBACK FOR ";O$(P);"."
+710 LET X=20+P*60
+720 REM FIRST DOWN
+730 GOSUB 800
+740 LET X1=X
+750 LET D=1
+760 PRINT:PRINT "FIRST DOWN ";O$(P);"***"
+770 PRINT
+780 PRINT
+790 GOTO 860
+800 REM PRINT POSITION
+810 IF X>50 THEN 840
+820 PRINT L$(5);O$(0);X;L$(6)
+830 GOTO 850
+840 PRINT L$(5);O$(1);100-X;L$(6)
+850 RETURN
+860 REM NEW PLAY
+870 LET T=T+1
+880 IF T=30 THEN 1060
+890 IF T<50 THEN 940
+900 IF RND(1)>.2 THEN 940
+910 PRINT "END OF GAME  ***"
+920 PRINT "FINAL SCORE:  ";O$(0);": ";S(0);"  ";O$(1);": ";S(1)
+930 STOP
+940 IF P=1 THEN 1870
+950 PRINT "NEXT PLAY";
+960 INPUT Z
+970 IF Z<>INT(Z) THEN 990
+980 IF ABS(Z-4)<=3 THEN 1010
+990 PRINT "ILLEGAL PLAY NUMBER, RETYPE";
+1000 GOTO 960
+1010 LET F=0
+1020 PRINT L$(Z+6);".  ";
+1030 LET R=RND(1)*(.98+FNF(1)*.02)
+1040 LET R1=RND(1)
+1050 ON Z GOTO 1110,1150,1260,1480,1570,1570,1680
+1060 REM  JEAN'S SPECIAL
+1070 IF RND(1)> 1/3 THEN 940
+1080 PRINT "GAME DELAYED.  DOG ON FIELD."
+1090 PRINT
+1100 GOTO 940
+1110 REM  SIMPLE RUN
+1120 LET Y=INT(24*(R-.5)^3+3)
+1130 IF RND(1)<.05 THEN 1180
+1140 GOTO 2190
+1150 REM  TRICKY RUN
+1160 LET Y=INT(20*R-5)
+1170 IF RND(1)>.1 THEN 2190
+1180 LET F=-1
+1190 LET X3=X
+1200 LET X=X+FNF(1)*Y
+1210 IF ABS(X-50)>=50 THEN 1240
+1220 PRINT "***  FUMBLE AFTER ";
+1230 GOTO 2230
+1240 PRINT "***  FUMBLE."
+1250 GOTO 2450
+1260 REM  SHORT PASS
+1270 LET Y=INT(60*(R1-.5)^3+10)
+1280 IF R<.05 THEN 1330
+1290 IF R<.15 THEN 1390
+1300 IF R<.55 THEN 1420
+1310 PRINT "COMPLETE.  ";
+1320 GOTO 2190
+1330 IF D=4 THEN 1420
+1340 PRINT "INTERCEPTED."
+1350 LET F=-1
+1360 LET X=X+FNF(1)*Y
+1370 IF ABS(X-50)>=50 THEN 2450
+1380 GOTO 2300
+1390 PRINT "PASSER TACKLED.  ";
+1400 LET Y=-INT(10*R1)
+1410 GOTO 2190
+1420 LET Y=0
+1430 IF RND(1)<.3 THEN 1460
+1440 PRINT "INCOMPLETE.  ";
+1450 GOTO 2190
+1460 PRINT "BATTED DOWN.  ";
+1470 GOTO 2190
+1480 REM  LONG PASS
+1490 LET Y=INT(160*(R1-.5)^3+30)
+1500 IF R<.1 THEN 1330
+1510 IF R<.3 THEN 1540
+1520 IF R<.75 THEN 1420
+1530 GOTO 1310
+1540 PRINT "PASSER TACKLED.  ";
+1550 LET Y=-INT(15*R1+3)
+1560 GOTO 2190
+1570 REM  PUNT OR KICK
+1580 LET Y=INT(100*(R-.5)^3+35)
+1590 IF D=4 THEN 1610
+1600 LET Y=INT(Y*1.3)
+1610 PRINT Y;L$(3);" PUNT"
+1620 IF ABS(X+Y*FNF(1)-50)>=50 THEN 1670
+1630 IF D<4 THEN 1670
+1640 LET Y1=INT(R1^2*20)
+1650 PRINT Y1;L$(3);" RUN BACK"
+1660 LET Y=Y-Y1
+1670 GOTO 1350
+1680 REM  PLACE KICK
+1690 LET Y=INT(100*(R-.5)^3+35)
+1700 IF R1>.15 THEN 1750
+1710 PRINT "KICK IS BLOCKED  ***"
+1720 LET X=X-5*FNF(1)
+1730 LET P=1-P
+1740 GOTO 720
+1750 LET X=X+FNF(1)*Y
+1760 IF ABS(X-50)>=60 THEN 1810
+1770 PRINT "KICK IS SHORT."
+1780 IF ABS(X-50)>=50 THEN 2710
+1790 P=1-P
+1800 GOTO 630
+1810 IF R1>.5 THEN 1840
+1820 PRINT "KICK IS OFF TO THE SIDE."
+1830 GOTO 2710
+1840 PRINT "FIELD GOAL ***"
+1850 LET S(P)=S(P)+3
+1860 GOTO 2640
+1870 REM  OPPONENT'S PLAY
+1880 IF D>1 THEN 1940
+1890 IF RND(1)>1/3 THEN 1920
+1900 LET Z=3
+1910 GOTO 1010
+1920 LET Z=1
+1930 GOTO 1010
+1940 IF D=4 THEN 2090
+1950 IF 10+X-X1<5 THEN 1890
+1960 IF X<5 THEN 1890
+1970 IF X<=10 THEN 2160
+1980 IF X>X1 THEN 2020
+1990 LET A=INT(2*RND(1))
+2000 LET Z=2+A*2
+2010 GOTO 1010
+2020 IF D<3 THEN 1990
+2030 IF X<45 THEN 1990
+2040 IF RND(1)>1/4 THEN 2070
+2050 LET Z=6
+2060 GOTO 1010
+2070 LET Z=4
+2080 GOTO 1010
+2090 IF X>30 THEN 2140
+2100 IF 10+X-X1<3 THEN 1890
+2110 IF X<3 THEN 1890
+2120 LET Z=7
+2130 GOTO 1010
+2140 LET Z=5
+2150 GOTO 1010
+2160 LET A=INT(2*RND(1))
+2170 LET Z=2+A
+2180 GOTO 1010
+2190 REM GAIN OR LOSS
+2200 LET X3=X
+2210 LET X=X+FNF(1)*Y
+2220 IF ABS(X-50)>=50 THEN 2450
+2230 IF Y=0 THEN 2250
+2240 PRINT ABS(Y);L$(3);
+2250 PRINT L$(15+SGN(Y))
+2280 IF ABS(X3-50)>40 THEN 2300
+2290 IF RND(1)<.1 THEN 2860
+2300 GOSUB 800
+2310 IF F=0 THEN 2340
+2320 LET P=1-P
+2330 GOTO 740
+2340 IF FNG(1)>=10 THEN 740
+2350 IF D=4 THEN 2320
+2360 LET D=D+1
+2370 PRINT "DOWN: ";D;"     ";
+2380 IF (X1-50)*FNF(1)<40 THEN 2410
+2390 PRINT "GOAL TO GO"
+2400 GOTO 2420
+2410 PRINT "YARDS TO GO: ";10-FNG(1)
+2420 PRINT
+2430 PRINT
+2440 GOTO 860
+2450 REM BALL IN END-ZONE
+2460 IF X>=100 THEN 2490
+2470 LET E=0
+2480 GOTO 2500
+2490 LET E=1
+2500 ON 1+E-F*2+P*4 GOTO 2510,2590,2760,2710,2590,2510,2710,2760
+2510 REM SAFETY
+2520 LET S(1-P)=S(1-P)+2
+2530 PRINT L$(19)
+2540 GOSUB 2800
+2550 PRINT O$(P);" KICKS OFF FROM ITS 20 YARD LINE."
+2560 LET X=20+P*60
+2570 LET P=1-P
+2580 GOTO 590
+2590 REM OFFENSIVE TD
+2600 PRINT L$(17);"***"
+2610 IF RND(1)>.8 THEN 2680
+2620 LET S(P)=S(P)+7
+2630 PRINT "KICK IS GOOD."
+2640 GOSUB 2800
+2650 PRINT O$(P);" KICKS OFF"
+2660 LET P=1-P
+2670 GOTO 580
+2680 PRINT "KICK IS OFF TO THE SIDE"
+2690 LET S(P)=S(P)+6
+2700 GOTO 2640
+2710 REM TOUCHBACK
+2720 PRINT L$(18)
+2730 LET P=1-P
+2740 LET X=20+P*60
+2750 GOTO 720
+2760 REM DEFENSIVE TD
+2770 PRINT L$(17);"FOR ";O$(1-P);"***"
+2780 LET P=1-P
+2790 GOTO 2600
+2800 REM SCORE
+2810 PRINT
+2820 PRINT "SCORE:  ";S(0);" TO ";S(1)
+2830 PRINT
+2840 PRINT
+2850 RETURN
+2860 REM PENALTY
+2870 LET P3=INT(2*RND(1))
+2880 PRINT O$(P3);" OFFSIDES -- PENALTY OF 5 YARDS."
+2890 PRINT
+2900 PRINT
+2910 IF P3=0 THEN 2980
+2920 PRINT "DO YOU ACCEPT THE PENALTY";
+2930 INPUT A$
+2940 IF A$="NO" THEN 2300
+2950 IF A$="YES" THEN 3110
+2960 PRINT "TYPE 'YES' OR 'NO'";
+2970 GOTO 2930
+2980 REM OPPONENT'S STRATEGY ON PENALTY
+2990 IF P=1 THEN 3040
+3000 IF Y<=0 THEN 3080
+3010 IF F<0 THEN 3080
+3020 IF FNG(1)<3*D-2 THEN 3080
+3030 GOTO 3100
+3040 IF Y<=5 THEN 3100
+3050 IF F<0 THEN 3100
+3060 IF D<4 THEN 3080
+3070 IF FNG(1)<10 THEN 3100
+3080 PRINT "PENALTY REFUSED."
+3090 GOTO 2300
+3100 PRINT "PENALTY ACCEPTED."
+3110 LET F=0
+3120 LET D=D-1
+3130 IF P<>P3 THEN 3160
+3140 LET X=X3-FNF(1)*5
+3150 GOTO 2300
+3160 LET X=X3+FNF(1)*5
+3170 GOTO 2300
+3180 END
diff --git a/00_Alternate_Languages/37_Football/java/README.md b/00_Alternate_Languages/37_Football/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/37_Football/javascript/README.md b/00_Alternate_Languages/37_Football/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/37_Football/javascript/football.html b/00_Alternate_Languages/37_Football/javascript/football.html
new file mode 100644
index 00000000..10e1acc1
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/javascript/football.html
@@ -0,0 +1,9 @@
+
+
+FOOTBALL
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/37_Football/javascript/football.js b/00_Alternate_Languages/37_Football/javascript/football.js
new file mode 100644
index 00000000..4ed0ae02
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/javascript/football.js
@@ -0,0 +1,504 @@
+// FOOTBALL
+//
+// 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 player_data = [17,8,4,14,19,3,10,1,7,11,15,9,5,20,13,18,16,2,12,6,
+                   20,2,17,5,8,18,12,11,1,4,19,14,10,7,9,15,6,13,16,3];
+var aa = [];
+var ba = [];
+var ca = [];
+var ha = [];
+var ta = [];
+var wa = [];
+var xa = [];
+var ya = [];
+var za = [];
+var ms = [];
+var da = [];
+var ps = [, "PITCHOUT","TRIPLE REVERSE","DRAW","QB SNEAK","END AROUND",
+          "DOUBLE REVERSE","LEFT SWEEP","RIGHT SWEEP","OFF TACKLE",
+          "WISHBONE OPTION","FLARE PASS","SCREEN PASS",
+          "ROLL OUT OPTION","RIGHT CURL","LEFT CURL","WISHBONE OPTION",
+          "SIDELINE PASS","HALF-BACK OPTION","RAZZLE-DAZZLE","BOMB!!!!"];
+var p;
+var t;
+
+function field_headers()
+{
+    print("TEAM 1 [0   10   20   30   40   50   60   70   80   90");
+    print("   100] TEAM 2\n");
+    print("\n");
+}
+
+function separator()
+{
+    str = "";
+    for (x = 1; x <= 72; x++)
+        str += "+";
+    print(str + "\n");
+}
+
+function show_ball()
+{
+    print(tab(da[t] + 5 + p / 2) + ms[t] + "\n");
+    field_headers();
+}
+
+function show_scores()
+{
+    print("\n");
+    print("TEAM 1 SCORE IS " + ha[1] + "\n");
+    print("TEAM 2 SCORE IS " + ha[2] + "\n");
+    print("\n");
+    if (ha[t] >= e) {
+        print("TEAM " + t + " WINS*******************");
+        return true;
+    }
+    return false;
+}
+
+function loss_posession() {
+    print("\n");
+    print("** LOSS OF POSSESSION FROM TEAM " + t + " TO TEAM " + ta[t] + "\n");
+    print("\n");
+    separator();
+    print("\n");
+    t = ta[t];
+}
+
+function touchdown() {
+    print("\n");
+    print("TOUCHDOWN BY TEAM " + t + " *********************YEA TEAM\n");
+    q = 7;
+    g = Math.random();
+    if (g <= 0.1) {
+        q = 6;
+        print("EXTRA POINT NO GOOD\n");
+    } else {
+        print("EXTRA POINT GOOD\n");
+    }
+    ha[t] = ha[t] + q;
+}
+
+// Main program
+async function main()
+{
+    print(tab(32) + "FOOTBALL\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("PRESENTING N.F.U. FOOTBALL (NO FORTRAN USED)\n");
+    print("\n");
+    print("\n");
+    while (1) {
+        print("DO YOU WANT INSTRUCTIONS");
+        str = await input();
+        if (str == "YES" || str == "NO")
+            break;
+    }
+    if (str == "YES") {
+        print("THIS IS A FOOTBALL GAME FOR TWO TEAMS IN WHICH PLAYERS MUST\n");
+        print("PREPARE A TAPE WITH A DATA STATEMENT (1770 FOR TEAM 1,\n");
+        print( "1780 FOR TEAM 2) IN WHICH EACH TEAM SCRAMBLES NOS. 1-20\n");
+        print("THESE NUMBERS ARE THEN ASSIGNED TO TWENTY GIVEN PLAYS.\n");
+        print("A LIST OF NOS. AND THEIR PLAYS IS PROVIDED WITH\n");
+        print("BOTH TEAMS HAVING THE SAME PLAYS. THE MORE SIMILAR THE\n");
+        print("PLAYS THE LESS YARDAGE GAINED.  SCORES ARE GIVEN\n");
+        print("WHENEVER SCORES ARE MADE. SCORES MAY ALSO BE OBTAINED\n");
+        print("BY INPUTTING 99,99 FOR PLAY NOS. TO PUNT OR ATTEMPT A\n");
+        print("FIELD GOAL, INPUT 77,77 FOR PLAY NUMBERS. QUESTIONS WILL BE\n");
+        print("ASKED THEN. ON 4TH DOWN, YOU WILL ALSO BE ASKED WHETHER\n");
+        print("YOU WANT TO PUNT OR ATTEMPT A FIELD GOAL. IF THE ANSWER TO\n");
+        print("BOTH QUESTIONS IS NO IT WILL BE ASSUMED YOU WANT TO\n");
+        print("TRY AND GAIN YARDAGE. ANSWER ALL QUESTIONS YES OR NO.\n");
+        print("THE GAME IS PLAYED UNTIL PLAYERS TERMINATE (CONTROL-C).\n");
+        print("PLEASE PREPARE A TAPE AND RUN.\n");
+    }
+    print("\n");
+    print("PLEASE INPUT SCORE LIMIT ON GAME");
+    e = parseInt(await input());
+    for (i = 1; i <= 40; i++) {
+        if (i <= 20) {
+            aa[player_data[i - 1]] = i;
+        } else {
+            ba[player_data[i - 1]] = i - 20;
+        }
+        ca[i] = player_data[i - 1];
+    }
+    l = 0;
+    t = 1;
+    do {
+        print("TEAM " + t + " PLAY CHART\n");
+        print("NO.      PLAY\n");
+        for (i = 1; i <= 20; i++) {
+            str = "" + ca[i + l];
+            while (str.length < 6)
+                str += " ";
+            str += ps[i];
+            print(str + "\n");
+        }
+        l += 20;
+        t = 2;
+        print("\n");
+        print("TEAR OFF HERE----------------------------------------------\n");
+        for (x = 1; x <= 11; x++)
+            print("\n");
+    } while (l == 20) ;
+    da[1] = 0;
+    da[2] = 3;
+    ms[1] = "--->";
+    ms[2] = "<---";
+    ha[1] = 0;
+    ha[2] = 0;
+    ta[1] = 2;
+    ta[2] = 1;
+    wa[1] = -1;
+    wa[2] = 1;
+    xa[1] = 100;
+    xa[2] = 0;
+    ya[1] = 1;
+    ya[2] = -1;
+    za[1] = 0;
+    za[2] = 100;
+    p = 0;
+    field_headers();
+    print("TEAM 1 DEFEND 0 YD GOAL -- TEAM 2 DEFENDS 100 YD GOAL.\n");
+    t = Math.floor(2 * Math.random() + 1);
+    print("\n");
+    print("THE COIN IS FLIPPED\n");
+    routine = 1;
+    while (1) {
+        if (routine <= 1) {
+            p = xa[t] - ya[t] * 40;
+            separator();
+            print("\n");
+            print("TEAM " + t + " RECEIVES KICK-OFF\n");
+            k = Math.floor(26 * Math.random() + 40);
+        }
+        if (routine <= 2) {
+            p = p - ya[t] * k;
+        }
+        if (routine <= 3) {
+            if (wa[t] * p >= za[t] + 10) {
+                print("\n");
+                print("BALL WENT OUT OF ENDZONE --AUTOMATIC TOUCHBACK--\n");
+                p = za[t] - wa[t] * 20;
+                if (routine <= 4)
+                    routine = 5;
+            } else {
+                print("BALL WENT " + k + " YARDS.  NOW ON " + p + "\n");
+                show_ball();
+            }
+        }
+        if (routine <= 4) {
+            while (1) {
+                print("TEAM " + t + " DO YOU WANT TO RUNBACK");
+                str = await input();
+                if (str == "YES" || str == "NO")
+                    break;
+            }
+            if (str == "YES") {
+                k = Math.floor(9 * Math.random() + 1);
+                r = Math.floor(((xa[t] - ya[t] * p + 25) * Math.random() - 15) / k);
+                p = p - wa[t] * r;
+                print("\n");
+                print("RUNBACK TEAM " + t + " " + r + " YARDS\n");
+                g = Math.random();
+                if (g < 0.25) {
+                    loss_posession();
+                    routine = 4;
+                    continue;
+                } else if (ya[t] * p >= xa[t]) {
+                    touchdown();
+                    if (show_scores())
+                        return;
+                    t = ta[t];
+                    routine = 1;
+                    continue;
+                } else if (wa[t] * p >= za[t]) {
+                    print("\n");
+                    print("SAFETY AGAINST TEAM " + t + " **********************OH-OH\n");
+                    ha[ta[t]] = ha[ta[t]] + 2;
+                    if (show_scores())
+                        return;
+                    print("TEAM " + t + " DO YOU WANT TO PUNT INSTEAD OF A KICKOFF");
+                    str = await input();
+                    p = za[t] - wa[t] * 20;
+                    if (str == "YES") {
+                        print("\n");
+                        print("TEAM " + t + " WILL PUNT\n");
+                        g = Math.random();
+                        if (g < 0.25) {
+                            loss_posession();
+                            routine = 4;
+                            continue;
+                        }
+                        print("\n");
+                        separator();
+                        k = Math.floor(25 * Math.random() + 35);
+                        t = ta[t];
+                        routine = 2;
+                        continue;
+                    }
+                    touchdown();
+                    if (show_scores())
+                        return;
+                    t = ta[t];
+                    routine = 1;
+                    continue;
+                } else {
+                    routine = 5;
+                    continue;
+                }
+            } else if (str == "NO") {
+                if (wa[t] * p >= za[t])
+                    p = za[t] - wa[t] * 20;
+            }
+        }
+        if (routine <= 5) {
+            d = 1;
+            s = p;
+        }
+        if (routine <= 6) {
+            str = "";
+            for (i = 1; i <= 72; i++)
+                str += "=";
+            print(str + "\n");
+            print("TEAM " + t + " DOWN " + d + " ON " + p + "\n");
+            if (d == 1) {
+                if (ya[t] * (p + ya[t] * 10) >= xa[t])
+                    c = 8;
+                else
+                    c = 4;
+            }
+            if (c != 8) {
+                print(tab(27) + (10 - (ya[t] * p - ya[t] * s)) + " YARDS TO 1ST DOWN\n");
+            } else {
+                print(tab(27) + (xa[t] - ya[t] * p) + " YARDS\n");
+            }
+            show_ball();
+            if (d == 4)
+                routine = 8;
+        }
+        if (routine <= 7) {
+            u = Math.floor(3 * Math.random() - 1);
+            while (1) {
+                print("INPUT OFFENSIVE PLAY, DEFENSIVE PLAY");
+                str = await input();
+                if (t == 1) {
+                    p1 = parseInt(str);
+                    p2 = parseInt(str.substr(str.indexOf(",") + 1));
+                } else {
+                    p2 = parseInt(str);
+                    p1 = parseInt(str.substr(str.indexOf(",") + 1));
+                }
+                if (p1 == 99) {
+                    if (show_scores())
+                        return;
+                    if (p1 == 99)
+                        continue;
+                }
+                if (p1 < 1 || p1 > 20 || p2 < 1 || p2 > 20) {
+                    print("ILLEGAL PLAY NUMBER, CHECK AND\n");
+                    continue;
+                }
+                break;
+            }
+        }
+        if (d == 4 || p1 == 77) {
+            while (1) {
+                print("DOES TEAM " + t + " WANT TO PUNT");
+                str = await input();
+                if (str == "YES" || str == "NO")
+                    break;
+            }
+            if (str == "YES") {
+                print("\n");
+                print("TEAM " + t + " WILL PUNT\n");
+                g = Math.random();
+                if (g < 0.25) {
+                    loss_posession();
+                    routine = 4;
+                    continue;
+                }
+                print("\n");
+                separator();
+                k = Math.floor(25 * Math.random() + 35);
+                t = ta[t];
+                routine = 2;
+                continue;
+            }
+            while (1) {
+                print("DOES TEAM " + t + " WANT TO ATTEMPT A FIELD GOAL");
+                str = await input();
+                if (str == "YES" || str == "NO")
+                    break;
+            }
+            if (str == "YES") {
+                print("\n");
+                print("TEAM " + t + " WILL ATTEMPT A FIELD GOAL\n");
+                g = Math.random();
+                if (g < 0.025) {
+                    loss_posession();
+                    routine = 4;
+                    continue;
+                } else {
+                    f = Math.floor(35 * Math.random() + 20);
+                    print("\n");
+                    print("KICK IS " + f + " YARDS LONG\n");
+                    p = p - wa[t] * f;
+                    g = Math.random();
+                    if (g < 0.35) {
+                        print("BALL WENT WIDE\n");
+                    } else if (ya[t] * p >= xa[t]) {
+                        print("FIELD GOLD GOOD FOR TEAM " + t + " *********************YEA");
+                        q = 3;
+                        ha[t] = ha[t] + q;
+                        if (show_scores())
+                            return;
+                        t = ta[t];
+                        routine = 1;
+                        continue;
+                    }
+                    print("FIELD GOAL UNSUCCESFUL TEAM " + t + "-----------------TOO BAD\n");
+                    print("\n");
+                    separator();
+                    if (ya[t] * p < xa[t] + 10) {
+                        print("\n");
+                        print("BALL NOW ON " + p + "\n");
+                        t = ta[t];
+                        show_ball();
+                        routine = 4;
+                        continue;
+                    } else {
+                        t = ta[t];
+                        routine = 3;
+                        continue;
+                    }
+                }
+            } else {
+                routine = 7;
+                continue;
+            }
+        }
+        y = Math.floor(Math.abs(aa[p1] - ba[p2]) / 19 * ((xa[t] - ya[t] * p + 25) * Math.random() - 15));
+        print("\n");
+        if (t == 1 && aa[p1] < 11 || t == 2 && ba[p2] < 11) {
+            print("THE BALL WAS RUN\n");
+        } else if (u == 0) {
+            print("PASS INCOMPLETE TEAM " + t + "\n");
+            y = 0;
+        } else {
+            g = Math.random();
+            if (g <= 0.025 && y > 2) {
+                print("PASS COMPLETED\n");
+            } else {
+                print("QUARTERBACK SCRAMBLED\n");
+            }
+        }
+        p = p - wa[t] * y;
+        print("\n");
+        print("NET YARDS GAINED ON DOWN " + d + " ARE " + y + "\n");
+
+        g = Math.random();
+        if (g <= 0.025) {
+            loss_posession();
+            routine = 4;
+            continue;
+        } else if (ya[t] * p >= xa[t]) {
+            touchdown();
+            if (show_scores())
+                return;
+            t = ta[t];
+            routine = 1;
+            continue;
+        } else if (wa[t] * p >= za[t]) {
+            print("\n");
+            print("SAFETY AGAINST TEAM " + t + " **********************OH-OH\n");
+            ha[ta[t]] = ha[ta[t]] + 2;
+            if (show_scores())
+                return;
+            print("TEAM " + t + " DO YOU WANT TO PUNT INSTEAD OF A KICKOFF");
+            str = await input();
+            p = za[t] - wa[t] * 20;
+            if (str == "YES") {
+                print("\n");
+                print("TEAM " + t + " WILL PUNT\n");
+                g = Math.random();
+                if (g < 0.25) {
+                    loss_posession();
+                    routine = 4;
+                    continue;
+                }
+                print("\n");
+                separator();
+                k = Math.floor(25 * Math.random() + 35);
+                t = ta[t];
+                routine = 2;
+                continue;
+            }
+            touchdown();
+            if (show_scores())
+                return;
+            t = ta[t];
+            routine = 1;
+        } else if (ya[t] * p - ya[t] * s >= 10) {
+            routine = 5;
+        } else {
+            d++;
+            if (d != 5) {
+                routine = 6;
+            } else {
+                print("\n");
+                print("CONVERSION UNSUCCESSFUL TEAM " + t + "\n");
+                t = ta[t];
+                print("\n");
+                separator();
+                routine = 5;
+            }
+        }
+    }
+}
+
+main();
diff --git a/00_Alternate_Languages/37_Football/javascript/ftball.html b/00_Alternate_Languages/37_Football/javascript/ftball.html
new file mode 100644
index 00000000..92862bde
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/javascript/ftball.html
@@ -0,0 +1,9 @@
+
+
+FTBALL
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/37_Football/javascript/ftball.js b/00_Alternate_Languages/37_Football/javascript/ftball.js
new file mode 100644
index 00000000..256a4bfc
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/javascript/ftball.js
@@ -0,0 +1,508 @@
+// FTBALL
+//
+// 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 os = [];
+var sa = [];
+var ls = [, "KICK","RECEIVE"," YARD ","RUN BACK FOR ","BALL ON ",
+          "YARD LINE"," SIMPLE RUN"," TRICKY RUN"," SHORT PASS",
+          " LONG PASS","PUNT"," QUICK KICK "," PLACE KICK"," LOSS ",
+          " NO GAIN","GAIN "," TOUCHDOWN "," TOUCHBACK ","SAFETY***",
+          "JUNK"];
+var p;
+var x;
+var x1;
+
+function fnf(x)
+{
+    return 1 - 2 * p;
+}
+
+function fng(z)
+{
+    return p * (x1 - x) + (1 - p) * (x - x1);
+}
+
+function show_score()
+{
+    print("\n");
+    print("SCORE:  " + sa[0] + " TO " + sa[1] + "\n");
+    print("\n");
+    print("\n");
+}
+
+function show_position()
+{
+    if (x <= 50) {
+        print(ls[5] + os[0] + " " + x + " " + ls[6] + "\n");
+    } else {
+        print(ls[5] + os[1] + " " + (100 - x) + " " + ls[6] + "\n");
+    }
+}
+
+function offensive_td()
+{
+    print(ls[17] + "***\n");
+    if (Math.random() <= 0.8) {
+        sa[p] = sa[p] + 7;
+        print("KICK IS GOOD.\n");
+    } else {
+        print("KICK IS OFF TO THE SIDE\n");
+        sa[p] = sa[p] + 6;
+    }
+    show_score();
+    print(os[p] + " KICKS OFF\n");
+    p = 1 - p;
+}
+
+// Main program
+async function main()
+{
+    print(tab(33) + "FTBALL\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("THIS IS DARTMOUTH CHAMPIONSHIP FOOTBALL.\n");
+    print("\n");
+    print("YOU WILL QUARTERBACK DARTMOUTH. CALL PLAYS AS FOLLOWS:\n");
+    print("1= SIMPLE RUN; 2= TRICKY RUN; 3= SHORT PASS;\n");
+    print("4= LONG PASS; 5= PUNT; 6= QUICK KICK; 7= PLACE KICK.\n");
+    print("\n");
+    print("CHOOSE YOUR OPPONENT");
+    os[1] = await input();
+    os[0] = "DARMOUTH";
+    print("\n");
+    sa[0] = 0;
+    sa[1] = 0;
+    p = Math.floor(Math.random() * 2);
+    print(os[p] + " WON THE TOSS\n");
+    if (p != 0) {
+        print(os[1] + " ELECTS TO RECEIVE.\n");
+        print("\n");
+    } else {
+        print("DO YOU ELECT TO KICK OR RECEIVE");
+        while (1) {
+            str = await input();
+            print("\n");
+            if (str == ls[1] || str == ls[2])
+                break;
+            print("INCORRECT ANSWER.  PLEASE TYPE 'KICK' OR 'RECEIVE'");
+        }
+        e = (str == ls[1]) ? 1 : 2;
+        if (e == 1)
+            p = 1;
+    }
+    t = 0;
+    start = 1;
+    while (1) {
+        if (start <= 1) {
+            x = 40 + (1 - p) * 20;
+        }
+        if (start <= 2) {
+            y = Math.floor(200 * Math.pow((Math.random() - 0.5), 3) + 55);
+            print(" " + y + " " + ls[3] + " KICKOFF\n");
+            x = x - fnf(1) * y;
+            if (Math.abs(x - 50) >= 50) {
+                print("TOUCHBACK FOR " + os[p] + ".\n");
+                x = 20 + p * 60;
+                start = 4;
+            } else {
+                start = 3;
+            }
+        }
+        if (start <= 3) {
+            y = Math.floor(50 * Math.pow(Math.random(), 2)) + (1 - p) * Math.floor(50 * Math.pow(Math.random(), 4));
+            x = x + fnf(1) * y;
+            if (Math.abs(x - 50) < 50) {
+                print(" " + y + " " + ls[3] + " RUNBACK\n");
+            } else {
+                print(ls[4]);
+                offensive_td();
+                start = 1;
+                continue;
+            }
+        }
+        if (start <= 4) {
+            // First down
+            show_position();
+        }
+        if (start <= 5) {
+            x1 = x;
+            d = 1;
+            print("\n");
+            print("FIRST DOWN " + os[p] + "***\n");
+            print("\n");
+            print("\n");
+        }
+        // New play
+        t++;
+        if (t == 30) {
+            if (Math.random() <= 1.3) {
+                print("GAME DELAYED.  DOG ON FIELD.\n");
+                print("\n");
+            }
+        }
+        if (t >= 50 && Math.random() <= 0.2)
+            break;
+        if (p != 1) {
+            // Opponent's play
+            if (d <= 1) {
+                z = Math.random() > 1 / 3 ? 1 : 3;
+            } else if (d != 4) {
+                if (10 + x - x1 < 5 || x < 5) {
+                    z = Math.random() > 1 / 3 ? 1 : 3;
+                } else if (x <= 10) {
+                    a = Math.floor(2 * Math.random());
+                    z = 2 + a;
+                } else if (x <= x1 || d < 3 || x < 45) {
+                    a = Math.floor(2 * Math.random());
+                    z = 2 + a * 2;
+                } else {
+                    if (Math.random() > 1 / 4)
+                        z = 4;
+                    else
+                        z = 6;
+                }
+            } else {
+                if (x <= 30) {
+                    z = 5;
+                } else if (10 + x - x1 < 3 || x < 3) {
+                    z = Math.random() > 1 / 3 ? 1 : 3;
+                } else {
+                    z = 7;
+                }
+            }
+        } else {
+            print("NEXT PLAY");
+            while (1) {
+                z = parseInt(await input());
+                if (Math.abs(z - 4) <= 3)
+                    break;
+                print("ILLEGAL PLAY NUMBER, RETYPE");
+            }
+        }
+        f = 0;
+        print(ls[z + 6] + ".  ");
+        r = Math.random() * (0.98 + fnf(1) * 0.02);
+        r1 = Math.random();
+        switch (z) {
+            case 1: // Simple run
+            case 2: // Tricky run
+                if (z == 1) {
+                    y = Math.floor(24 * Math.pow(r - 0.5, 3) + 3);
+                    if (Math.random() >= 0.05) {
+                        routine = 1;
+                        break;
+                    }
+                } else {
+                    y = Math.floor(20 * r - 5);
+                    if (Math.random() > 0.1) {
+                        routine = 1;
+                        break;
+                    }
+                }
+                f = -1;
+                x3 = x;
+                x = x + fnf(1) * y;
+                if (Math.abs(x - 50) < 50) {
+                    print("***  FUMBLE AFTER ");
+                    routine = 2;
+                    break;
+                } else {
+                    print("***  FUMBLE.\n");
+                    routine = 4;
+                    break;
+                }
+            case 3: // Short pass
+            case 4: // Long pass
+                if (z == 3) {
+                    y = Math.floor(60 * Math.pow(r1 - 0.5, 3) + 10);
+                } else {
+                    y = Math.floor(160 * Math.pow((r1 - 0.5), 3) + 30);
+                }
+                if (z == 3 && r < 0.05 || z == 4 && r < 0.1) {
+                    if (d != 4) {
+                        print("INTERCEPTED.\n");
+                        f = -1;
+                        x = x + fnf(1) * y;
+                        if (Math.abs(x - 50) >= 50) {
+                            routine = 4;
+                            break;
+                        }
+                        routine = 3;
+                        break;
+                    } else {
+                        y = 0;
+                        if (Math.random() < 0.3) {
+                            print("BATTED DOWN.  ");
+                        } else {
+                            print("INCOMPLETE.  ");
+                        }
+                        routine = 1;
+                        break;
+                    }
+                } else if (z == 4 && r < 0.3) {
+                    print("PASSER TACKLED.  ");
+                    y = -Math.floor(15 * r1 + 3);
+                    routine = 1;
+                    break;
+                } else if (z == 3 && r < 0.15) {
+                    print("PASSER TACLKED.  ");
+                    y = -Math.floor(10 * r1);
+                    routine = 1;
+                    break;
+                } else if (z == 3 && r < 0.55 || z == 4 && r < 0.75) {
+                    y = 0;
+                    if (Math.random() < 0.3) {
+                        print("BATTED DOWN.  ");
+                    } else {
+                        print("INCOMPLETE.  ");
+                    }
+                    routine = 1;
+                    break;
+                } else {
+                    print("COMPLETE.  ");
+                    routine = 1;
+                    break;
+                }
+            case 5:  // Punt
+            case 6:  // Quick kick
+                y = Math.floor(100 * Math.pow((r - 0.5), 3) + 35);
+                if (d != 4)
+                    y = Math.floor(y * 1.3);
+                print(" " + y + " " + ls[3] + " PUNT\n");
+                if (Math.abs(x + y * fnf(1) - 50) < 50 && d >= 4) {
+                    y1 = Math.floor(Math.pow(r1, 2) * 20);
+                    print(" " + y1 + " " + ls[3] + " RUN BACK\n");
+                    y = y - y1;
+                }
+                f = -1;
+                x = x + fnf(1) * y;
+                if (Math.abs(x - 50) >= 50) {
+                    routine = 4;
+                    break;
+                }
+                routine = 3;
+                break;
+            case 7: // Place kick
+                y = Math.floor(100 * Math.pow((r - 0.5), 3) + 35);
+                if (r1 <= 0.15) {
+                    print("KICK IS BLOCKED  ***\n");
+                    x = x - 5 * fnf(1);
+                    p = 1 - p;
+                    start = 4;
+                    continue;
+                }
+                x = x + fnf(1) * y;
+                if (Math.abs(x - 50) >= 60) {
+                    if (r1 <= 0.5) {
+                        print("KICK IS OFF TO THE SIDE.\n");
+                        print(ls[18] + "\n");
+                        p = 1 - p;
+                        x = 20 + p * 60;
+                        start = 4;
+                        continue;
+                    } else {
+                        print("FIELD GOAL ***\n");
+                        sa[p] = sa[p] + 3;
+                        show_score();
+                        print(os[p] + " KICKS OFF\n");
+                        p = 1 - p;
+                        start = 1;
+                        continue;
+                    }
+                } else {
+                    print("KICK IS SHORT.\n");
+                    if (Math.abs(x - 50) >= 50) {
+                        // Touchback
+                        print(ls[18] + "\n");
+                        p = 1 - p;
+                        x = 20 + p * 60;
+                        start = 4;
+                        continue;
+                    }
+                    p = 1 - p;
+                    start = 3;
+                    continue;
+                }
+
+        }
+        // Gain or loss
+        if (routine <= 1) {
+            x3 = x;
+            x = x + fnf(1) * y;
+            if (Math.abs(x - 50) >= 50) {
+                routine = 4;
+            }
+        }
+        if (routine <= 2) {
+            if (y != 0) {
+                print(" " + Math.abs(y) + " " + ls[3]);
+                if (y < 0)
+                    yt = -1;
+                else if (y > 0)
+                    yt = 1;
+                else
+                    yt = 0;
+                print(ls[15 + yt]);
+                if (Math.abs(x3 - 50) <= 40 && Math.random() < 0.1) {
+                    // Penalty
+                    p3 = Math.floor(2 * Math.random());
+                    print(os[p3] + " OFFSIDES -- PENALTY OF 5 YARDS.\n");
+                    print("\n");
+                    print("\n");
+                    if (p3 != 0) {
+                        print("DO YOU ACCEPT THE PENALTY");
+                        while (1) {
+                            str = await input();
+                            if (str == "YES" || str == "NO")
+                                break;
+                            print("TYPE 'YES' OR 'NO'");
+                        }
+                        if (str == "YES") {
+                            f = 0;
+                            d = d - 1;
+                            if (p != p3)
+                                x = x3 + fnf(1) * 5;
+                            else
+                                x = x3 - fnf(1) * 5;
+                        }
+                    } else {
+                        // Opponent's strategy on penalty
+                        if ((p != 1 && (y <= 0 || f < 0 || fng(1) < 3 * d - 2))
+                            || (p == 1 && ((y > 5 && f >= 0) || d < 4 || fng(1) >= 10))) {
+                            print("PENALTY REFUSED.\n");
+                        } else {
+                            print("PENALTY ACCEPTED.\n");
+                            f = 0;
+                            d = d - 1;
+                            if (p != p3)
+                                x = x3 + fnf(1) * 5;
+                            else
+                                x = x3 - fnf(1) * 5;
+                        }
+                    }
+                    routine = 3;
+                }
+            }
+        }
+        if (routine <= 3) {
+            show_position();
+            if (f != 0) {
+                p = 1 - p;
+                start = 5;
+                continue;
+            } else if (fng(1) >= 10) {
+                start = 5;
+                continue;
+            } else if (d == 4) {
+                p = 1 - p;
+                start = 5;
+                continue;
+            } else {
+                d++;
+                print("DOWN: " + d + "     ");
+                if ((x1 - 50) * fnf(1) >= 40) {
+                    print("GOAL TO GO\n");
+                } else {
+                    print("YARDS TO GO: " + (10 - fng(1)) + "\n");
+                }
+                print("\n");
+                print("\n");
+                start = 6;
+                continue;
+            }
+        }
+        if (routine <= 4) {
+            // Ball in end-zone
+            e = (x >= 100) ? 1 : 0;
+            switch (1 + e - f * 2 + p * 4) {
+                case 1:
+                case 5:
+                    // Safety
+                    sa[1 - p] = sa[1 - p] + 2;
+                    print(ls[19] + "\n");
+                    show_score();
+                    print(os[p] + " KICKS OFF FROM ITS 20 YARD LINE.\n");
+                    x = 20 + p * 60;
+                    p = 1 - p;
+                    start = 2;
+                    continue;
+                case 3:
+                case 6:
+                    // Defensive TD
+                    print(ls[17] + "FOR " + os[1 - p] + "***\n");
+                    p = 1 - p;
+                    // Fall-thru
+                case 2:
+                case 8:
+                    // Offensive TD
+                    print(ls[17] + "***\n");
+                    if (Math.random() <= 0.8) {
+                        sa[p] = sa[p] + 7;
+                        print("KICK IS GOOD.\n");
+                    } else {
+                        print("KICK IS OFF TO THE SIDE\n");
+                        sa[p] = sa[p] + 6;
+                    }
+                    show_score();
+                    print(os[p] + " KICKS OFF\n");
+                    p = 1 - p;
+                    start = 1;
+                    continue;
+                case 4:
+                case 7:
+                    // Touchback
+                    print(ls[18] + "\n");
+                    p = 1 - p;
+                    x = 20 + p * 60;
+                    start = 4;
+                    continue;
+            }
+        }
+    }
+    print("END OF GAME  ***\n");
+    print("FINAL SCORE:  " + os[0] + ": " + sa[0] + "  " + os[1] + ": " + sa[1] + "\n");
+}
+
+main();
diff --git a/13_Bounce/pascal/README.md b/00_Alternate_Languages/37_Football/pascal/README.md
similarity index 100%
rename from 13_Bounce/pascal/README.md
rename to 00_Alternate_Languages/37_Football/pascal/README.md
diff --git a/00_Alternate_Languages/37_Football/perl/README.md b/00_Alternate_Languages/37_Football/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/37_Football/python/README.md b/00_Alternate_Languages/37_Football/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/37_Football/ruby/README.md b/00_Alternate_Languages/37_Football/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/37_Football/vbnet/Football.sln b/00_Alternate_Languages/37_Football/vbnet/Football.sln
new file mode 100644
index 00000000..2e177718
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/vbnet/Football.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Football", "Football.vbproj", "{5491221D-33D3-4ADF-9E0A-FB58D5C12EE2}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{5491221D-33D3-4ADF-9E0A-FB58D5C12EE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5491221D-33D3-4ADF-9E0A-FB58D5C12EE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5491221D-33D3-4ADF-9E0A-FB58D5C12EE2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5491221D-33D3-4ADF-9E0A-FB58D5C12EE2}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/37_Football/vbnet/Football.vbproj b/00_Alternate_Languages/37_Football/vbnet/Football.vbproj
new file mode 100644
index 00000000..ce404640
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/vbnet/Football.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Football
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/37_Football/vbnet/README.md b/00_Alternate_Languages/37_Football/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/37_Football/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/38_Fur_Trader/README.md b/00_Alternate_Languages/38_Fur_Trader/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/38_Fur_Trader/c/README.md b/00_Alternate_Languages/38_Fur_Trader/c/README.md
new file mode 100644
index 00000000..cb9833d5
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/c/README.md
@@ -0,0 +1,22 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [ANSI-C](https://en.wikipedia.org/wiki/ANSI_C)
+
+##### Translator Notes:
+I tried to preserve as much of the original layout and flow of the code
+as possible.  However I did use enumerated types for the Fort numbers
+and Fur types.  I think this was certainly a change for the better, and
+makes the code much easier to read.
+
+I also tried to minimise the use of pointers, and stuck with old-school
+C formatting, because you never know how old the compiler is.
+
+Interestingly the code seems to have a bug around the prices of Fox Furs.
+The commodity-rate for these is stored in the variable `D1`, however some
+paths through the code do not set this price.  So there was a chance of
+using this uninitialised, or whatever the previous loop set.  I don't
+think this was the original authors intent.  So I preserved the original flow
+of the code (using the previous `D1` value), but also catching the
+uninitialised path, and assigning a "best guess" value.
+
+krt@krt.com.au 2020-10-10
diff --git a/00_Alternate_Languages/38_Fur_Trader/c/furtrader.c b/00_Alternate_Languages/38_Fur_Trader/c/furtrader.c
new file mode 100644
index 00000000..8735e08f
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/c/furtrader.c
@@ -0,0 +1,474 @@
+
+/*
+ * Ported from furtrader.bas to ANSI C (C99) by krt@krt.com.au
+ *
+ * compile with:
+ *    gcc -g -Wall -Werror furtrader.c -o furtrader
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+
+/* Constants */
+#define FUR_TYPE_COUNT    4
+#define FUR_MINK          0
+#define FUR_BEAVER        1
+#define FUR_ERMINE        2
+#define FUR_FOX           3
+#define MAX_FURS        190
+const char *FUR_NAMES[FUR_TYPE_COUNT] = { "MINK", "BEAVER", "ERMINE", "FOX" };
+
+#define FORT_TYPE_COUNT 3
+#define FORT_MONTREAL   1
+#define FORT_QUEBEC     2
+#define FORT_NEWYORK    3
+const char *FORT_NAMES[FORT_TYPE_COUNT] = { "HOCHELAGA (MONTREAL)", "STADACONA (QUEBEC)", "NEW YORK" };
+
+
+
+/* Print the words at the specified column */
+void printAtColumn( int column, const char *words )
+{
+    int i;
+    for ( i=0; i> " );                                 /* prompt the user */
+        fgets( buffer, sizeof( buffer ), stdin );        /* read from the console into the buffer */
+        result = (int)strtol( buffer, &endstr, 10 );     /* only simple error checking */
+
+        if ( endstr == buffer )                          /* was the string -> integer ok? */
+            result = -1;
+    }
+
+    return result;
+}
+
+
+/*
+ * Prompt the user for YES/NO input.
+ * When input is given, try to work out if it's YES, Yes, yes, Y, etc.
+ * And convert to a single upper-case letter
+ * Returns a character of 'Y' or 'N'.
+ */
+char getYesOrNo()
+{
+    char result = '!';
+    char buffer[64];   /* somewhere to store user input */
+
+    while ( !( result == 'Y' || result == 'N' ) )       /* While the answer was not Yes or No */
+    {
+        print( "ANSWER YES OR NO" );
+        printf( ">> " );
+
+        fgets( buffer, sizeof( buffer ), stdin );            /* read from the console into the buffer */
+        if ( buffer[0] == 'Y' || buffer[0] == 'y' )
+            result = 'Y';
+        else if ( buffer[0] == 'N' || buffer[0] == 'n' )
+            result = 'N';
+    }
+
+    return result;
+}
+
+
+
+/*
+ * Show the player the choices of Fort, get their input, if the
+ * input is a valid choice (1,2,3) return it, otherwise keep
+ * prompting the user.
+ */
+int getFortChoice()
+{
+    int result = 0;
+
+    while ( result == 0 )
+    {
+        print( "" );
+        print( "YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2," );
+        print( "OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)" );
+        print( "AND IS UNDER THE PROTECTION OF THE FRENCH ARMY." );
+        print( "FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE" );
+        print( "PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST" );
+        print( "MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS." );
+        print( "FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL." );
+        print( "YOU MUST CROSS THROUGH IROQUOIS LAND." );
+        print( "ANSWER 1, 2, OR 3." );
+
+        result = getNumericInput();   /* get input from the player */
+    }
+
+    return result;
+}
+
+
+/*
+ * Print the description for the fort
+ */
+void showFortComment( int which_fort )
+{
+    print( "" );
+    if ( which_fort == FORT_MONTREAL )
+    {
+        print( "YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT" );
+        print( "IS FAR FROM ANY SEAPORT.  THE VALUE" );
+        print( "YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST" );
+        print( "OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK." );
+    }
+    else if ( which_fort == FORT_QUEBEC )
+    {
+        print( "YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION," );
+        print( "HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN" );
+        print( "THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE" );
+        print( "FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE." );
+    }
+    else if ( which_fort == FORT_NEWYORK )
+    {
+        print( "YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT" );
+        print( "FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE" );
+        print( "FOR YOUR FURS.  THE COST OF YOUR SUPPLIES" );
+        print( "WILL BE LOWER THAN AT ALL THE OTHER FORTS." );
+    }
+    else
+    {
+        printf( "Internal error #1, fort %d does not exist\n", which_fort );
+        exit( 1 );  /* you have a bug */
+    }
+    print( "" );
+}
+
+
+/*
+ * Prompt the player for how many of each fur type they want.
+ * Accept numeric inputs, re-prompting on incorrect input values
+ */
+void getFursPurchase( int *furs )
+{
+    int i;
+
+    printf( "YOUR %d FURS ARE DISTRIBUTED AMONG THE FOLLOWING\n", FUR_TYPE_COUNT );
+    print( "KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX." );
+    print( "" );
+
+    for ( i=0; i MAX_FURS )
+            {
+                print( "" );
+                print( "YOU MAY NOT HAVE THAT MANY FURS." );
+                print( "DO NOT TRY TO CHEAT.  I CAN ADD." );
+                print( "YOU MUST START AGAIN." );
+                print( "" );
+                game_state = STATE_STARTING;   /* T/N: Wow, harsh. */
+            }
+            else
+            {
+                game_state = STATE_CHOOSING_FORT;
+            }
+        }
+
+        else if ( game_state == STATE_CHOOSING_FORT )
+        {
+            which_fort = getFortChoice();
+            showFortComment( which_fort );
+            print( "DO YOU WANT TO TRADE AT ANOTHER FORT?" );
+            yes_or_no = getYesOrNo();
+            if ( yes_or_no == 'N' )
+                game_state = STATE_TRAVELLING;
+        }
+
+        else if ( game_state == STATE_TRAVELLING )
+        {
+            print( "" );
+            if ( which_fort == FORT_MONTREAL )
+            {
+                mink_price   = ( ( 0.2 * randFloat() + 0.70 ) * 100 + 0.5 ) / 100;
+                ermine_price = ( ( 0.2 * randFloat() + 0.65 ) * 100 + 0.5 ) / 100;
+                beaver_price = ( ( 0.2 * randFloat() + 0.75 ) * 100 + 0.5 ) / 100;
+                fox_price    = ( ( 0.2 * randFloat() + 0.80 ) * 100 + 0.5 ) / 100;
+
+                print( "SUPPLIES AT FORT HOCHELAGA COST $150.00." );
+                print( "YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00." );
+                player_funds -= 160;
+            }
+
+            else if ( which_fort == FORT_QUEBEC )
+            {
+                mink_price   = ( ( 0.30 * randFloat() + 0.85 ) * 100 + 0.5 ) / 100;
+                ermine_price = ( ( 0.15 * randFloat() + 0.80 ) * 100 + 0.5 ) / 100;
+                beaver_price = ( ( 0.20 * randFloat() + 0.90 ) * 100 + 0.5 ) / 100;
+                fox_price    = ( ( 0.25 * randFloat() + 1.10 ) * 100 + 0.5 ) / 100;
+                event_picker = ( 10 * randFloat() ) + 1;
+
+                if ( event_picker <= 2 )
+                {
+                    print( "YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS" );
+                    print( "THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND" );
+                    print( "THEM STOLEN WHEN YOU RETURNED." );
+                    player_furs[ FUR_BEAVER ] = 0;
+                }
+                else if ( event_picker <= 6 )
+                {
+                    print( "YOU ARRIVED SAFELY AT FORT STADACONA." );
+                }
+                else if ( event_picker <= 8 )
+                {
+                    print( "YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU" );
+                    print( "LOST ALL YOUR FURS." );
+                    zeroInventory( player_furs );
+                }
+                else if ( event_picker <= 10 )
+                {
+                    print( "YOUR FOX PELTS WERE NOT CURED PROPERLY." );
+                    print( "NO ONE WILL BUY THEM." );
+                    player_furs[ FUR_FOX ] = 0;
+                }
+                else
+                {
+                    printf( "Internal Error #3, Out-of-bounds event_picker %d\n", event_picker );
+                    exit( 1 );  /* you have a bug */
+                }
+
+                print( "" );
+                print( "SUPPLIES AT FORT STADACONA COST $125.00." );
+                print( "YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00." );
+                player_funds -= 140;
+            }
+
+            else if ( which_fort == FORT_NEWYORK )
+            {
+                mink_price   = ( ( 0.15 * randFloat() + 1.05 ) * 100 + 0.5 ) / 100;
+                ermine_price = ( ( 0.15 * randFloat() + 0.95 ) * 100 + 0.5 ) / 100;
+                beaver_price = ( ( 0.25 * randFloat() + 1.00 ) * 100 + 0.5 ) / 100;
+                if ( fox_price < 0 )
+                {
+                    /* Original Bug?  There is no Fox price generated for New York,
+                       it will use any previous "D1" price.
+                       So if there was no previous value, make one up */
+                    fox_price = ( ( 0.25 * randFloat() + 1.05 ) * 100 + 0.5 ) / 100; /* not in orginal code */
+                }
+                event_picker = ( 10 * randFloat() ) + 1;
+
+                if ( event_picker <= 2 )
+                {
+                    print( "YOU WERE ATTACKED BY A PARTY OF IROQUOIS." );
+                    print( "ALL PEOPLE IN YOUR TRADING GROUP WERE" );
+                    print( "KILLED.  THIS ENDS THE GAME." );
+                    exit( 0 );
+                }
+                else if ( event_picker <= 6 )
+                {
+                    print( "YOU WERE LUCKY.  YOU ARRIVED SAFELY" );
+                    print( "AT FORT NEW YORK." );
+                }
+                else if ( event_picker <= 8 )
+                {
+                    print( "YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY." );
+                    print( "HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND." );
+                    zeroInventory( player_furs );
+                }
+                else if ( event_picker <= 10 )
+                {
+                    mink_price /= 2;
+                    fox_price  /= 2;
+                    print( "YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP." );
+                    print( "YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS." );
+                }
+                else
+                {
+                    print( "Internal Error #4, Out-of-bounds event_picker %d\n" );
+                    exit( 1 );  /* you have a bug */
+                }
+
+                print( "" );
+                print( "SUPPLIES AT NEW YORK COST $85.00." );
+                print( "YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00." );
+                player_funds -= 105;
+            }
+
+            else
+            {
+                printf( "Internal error #2, fort %d does not exist\n", which_fort );
+                exit( 1 );  /* you have a bug */
+            }
+
+            /* Calculate sales */
+            beaver_value = beaver_price * player_furs[ FUR_BEAVER ];
+            fox_value    = fox_price    * player_furs[ FUR_FOX ];
+            ermine_value = ermine_price * player_furs[ FUR_ERMINE ];
+            mink_value   = mink_price   * player_furs[ FUR_MINK ];
+
+            print( "" );
+            printf( "YOUR BEAVER SOLD FOR $%6.2f\n", beaver_value );
+            printf( "YOUR FOX SOLD FOR    $%6.2f\n", fox_value );
+            printf( "YOUR ERMINE SOLD FOR $%6.2f\n", ermine_value );
+            printf( "YOUR MINK SOLD FOR   $%6.2f\n", mink_value );
+
+            player_funds += beaver_value + fox_value + ermine_value + mink_value;
+
+            print( "" );
+            printf( "YOU NOW HAVE $ %1.2f INCLUDING YOUR PREVIOUS SAVINGS\n", player_funds );
+
+            print( "" );
+            print( "DO YOU WANT TO TRADE FURS NEXT YEAR?" );
+            yes_or_no = getYesOrNo();
+            if ( yes_or_no == 'N' )
+                exit( 0 );             /* STOP */
+            else
+                game_state = STATE_TRADING;
+
+        }
+    }
+
+    return 0; /* exit OK */
+}
diff --git a/00_Alternate_Languages/38_Fur_Trader/csharp/FurTrader.csproj b/00_Alternate_Languages/38_Fur_Trader/csharp/FurTrader.csproj
new file mode 100644
index 00000000..c73e0d16
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/csharp/FurTrader.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    netcoreapp3.1
+  
+
+
diff --git a/00_Alternate_Languages/38_Fur_Trader/csharp/FurTrader.sln b/00_Alternate_Languages/38_Fur_Trader/csharp/FurTrader.sln
new file mode 100644
index 00000000..54a1760c
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/csharp/FurTrader.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30804.86
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FurTrader", "FurTrader.csproj", "{1FB826B9-8794-4DB7-B676-B51F177B7B87}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{1FB826B9-8794-4DB7-B676-B51F177B7B87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1FB826B9-8794-4DB7-B676-B51F177B7B87}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1FB826B9-8794-4DB7-B676-B51F177B7B87}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1FB826B9-8794-4DB7-B676-B51F177B7B87}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {DDB24448-50EB-47C6-BDB9-465896A81779}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/38_Fur_Trader/csharp/Game.cs b/00_Alternate_Languages/38_Fur_Trader/csharp/Game.cs
new file mode 100644
index 00000000..461f8b8a
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/csharp/Game.cs
@@ -0,0 +1,506 @@
+using System;
+
+namespace FurTrader
+{
+    public class Game
+    {
+        /// 
+        /// random number generator; no seed to be faithful to original implementation
+        /// 
+        private Random Rnd { get; } = new Random();
+
+        /// 
+        /// Generate a price for pelts based off a factor and baseline value
+        /// 
+        /// Multiplier for the price
+        /// The baseline price
+        /// A randomised price for pelts
+        internal double RandomPriceGenerator(double factor, double baseline)
+        {
+            var price = (Convert.ToInt32((factor * Rnd.NextDouble() + baseline) * 100d) + 5) / 100d;
+            return price;
+        }
+
+        /// 
+        /// Main game loop function. This will play the game endlessly until the player chooses to quit or a GameOver event occurs
+        /// 
+        /// 
+        /// General structure followed from Adam Dawes (@AdamDawes575) implementation of Acey Ducey.");
+        /// 
+        internal void GameLoop()
+        {
+            // display instructions to the player
+            DisplayIntroText();
+
+            var state = new GameState();
+
+            // loop for each turn until the player decides not to continue (or has a Game Over event)
+            while ((!state.GameOver) && ContinueGame())
+            {
+                // clear display at start of each turn
+                Console.Clear();
+
+                // play the next turn; pass game state for details and updates from the turn
+                PlayTurn(state);
+            }
+
+            // end screen; show some statistics to the player
+            Console.Clear();
+            Console.WriteLine("Thanks for playing!");
+            Console.WriteLine("");
+            Console.WriteLine($"Total Expeditions: {state.ExpeditionCount}");
+            Console.WriteLine($"Final Amount:      {state.Savings.ToString("c")}");
+        }
+
+        /// 
+        /// Display instructions on how to play the game and wait for the player to press a key.
+        /// 
+        private void DisplayIntroText()
+        {
+            Console.ForegroundColor = ConsoleColor.Yellow;
+            Console.WriteLine("Fur Trader.");
+            Console.WriteLine("Creating Computing, Morristown, New Jersey.");
+            Console.WriteLine("");
+
+            Console.ForegroundColor = ConsoleColor.DarkGreen;
+            Console.WriteLine("Originally published in 1978 in the book 'Basic Computer Games' by David Ahl.");
+            Console.WriteLine("");
+
+            Console.ForegroundColor = ConsoleColor.Gray;
+            Console.WriteLine("You are the leader of a French fur trading expedition in 1776 leaving the Lake Ontario area to sell furs and get supplies for the next year.");
+            Console.WriteLine("");
+            Console.WriteLine("You have a choice of three forts at which you may trade. The cost of supplies and the amount you receive for your furs will depend on the fort that you choose.");
+            Console.WriteLine("");
+
+            Console.ForegroundColor = ConsoleColor.Yellow;
+            Console.WriteLine("Press any key start the game.");
+            Console.ReadKey(true);
+
+        }
+
+        /// 
+        /// Prompt the player to try again, and wait for them to press Y or N.
+        /// 
+        /// Returns true if the player wants to try again, false if they have finished playing.
+        private bool ContinueGame()
+        {
+            Console.WriteLine("");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.WriteLine("Do you wish to trade furs? ");
+            Console.Write("Answer (Y)es or (N)o ");
+            Console.ForegroundColor = ConsoleColor.Yellow;
+            Console.Write("> ");
+
+            char pressedKey;
+            // Keep looping until we get a recognised input
+            do
+            {
+                // Read a key, don't display it on screen
+                ConsoleKeyInfo key = Console.ReadKey(true);
+                // Convert to upper-case so we don't need to care about capitalisation
+                pressedKey = Char.ToUpper(key.KeyChar);
+                // Is this a key we recognise? If not, keep looping
+            } while (pressedKey != 'Y' && pressedKey != 'N');
+
+            // Display the result on the screen
+            Console.WriteLine(pressedKey);
+
+            // Return true if the player pressed 'Y', false for anything else.
+            return (pressedKey == 'Y');
+        }
+
+        /// 
+        /// Play a turn
+        /// 
+        /// The current game state
+        private void PlayTurn(GameState state)
+        {
+            state.UnasignedFurCount = 190;      /// start with 190 furs each turn
+
+            // provide current status to user
+            Console.WriteLine(new string('_', 70));
+            Console.WriteLine("");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.WriteLine("");
+            Console.WriteLine($"You have {state.Savings.ToString("c")} savings and {state.UnasignedFurCount} furs to begin the expedition.");
+            Console.WriteLine("");
+            Console.WriteLine($"Your {state.UnasignedFurCount} furs are distributed among the following kinds of pelts: Mink, Beaver, Ermine, and Fox");
+            Console.WriteLine("");
+
+            // get input on number of pelts
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.Write("How many Mink pelts do you have? ");
+            state.MinkPelts = GetPelts(state.UnasignedFurCount);
+            state.UnasignedFurCount -= state.MinkPelts;
+            Console.WriteLine("");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.WriteLine($"You have {state.UnasignedFurCount} furs remaining for distribution");
+            Console.Write("How many Beaver pelts do you have? ");
+            state.BeaverPelts = GetPelts(state.UnasignedFurCount);
+            state.UnasignedFurCount -= state.BeaverPelts;
+            Console.WriteLine("");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.WriteLine($"You have {state.UnasignedFurCount} furs remaining for distribution");
+            Console.Write("How many Ermine pelts do you have? ");
+            state.ErminePelts = GetPelts(state.UnasignedFurCount);
+            state.UnasignedFurCount -= state.ErminePelts;
+            Console.WriteLine("");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.WriteLine($"You have {state.UnasignedFurCount} furs remaining for distribution");
+            Console.Write("How many Fox pelts do you have? ");
+            state.FoxPelts = GetPelts(state.UnasignedFurCount);
+            state.UnasignedFurCount -= state.FoxPelts;
+
+            // get input on which fort to trade with; user gets an opportunity to evaluate and re-select fort after selection until user confirms selection
+            do
+            {
+                Console.ForegroundColor = ConsoleColor.White;
+                Console.WriteLine("");
+                Console.WriteLine("Do you want to trade your furs at Fort 1, Fort 2, or Fort 3");
+                Console.WriteLine("Fort 1 is Fort Hochelaga (Montreal) and is under the protection of the French army.");
+                Console.WriteLine("Fort 2 is Fort Stadacona (Quebec) and is under the protection of the French army. However, you must make a portage and cross the Lachine rapids.");
+                Console.WriteLine("Fort 3 is Fort New York and is under Dutch control. You must cross through Iroquois land.");
+                Console.WriteLine("");
+                state.SelectedFort = GetSelectedFort();
+
+                DisplaySelectedFortInformation(state.SelectedFort);
+
+            } while (TradeAtAnotherFort());
+
+            // process the travel to the fort
+            ProcessExpeditionOutcome(state);
+
+            // display results of expedition (savings change) to the user
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.Write("You now have ");
+            Console.ForegroundColor = ConsoleColor.Yellow;
+            Console.Write($"{state.Savings.ToString("c")}");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.WriteLine(" including your previous savings.");
+
+            // update the turn count now that another turn has been played
+            state.ExpeditionCount += 1;
+        }
+
+        /// 
+        /// Method to show the expedition costs to the player with some standard formatting
+        /// 
+        /// The name of the fort traded with
+        /// The cost of the supplies at the fort
+        /// The travel expenses for the expedition
+        internal void DisplayCosts(string fortname, double supplies, double expenses)
+        {
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.Write($"Supplies at {fortname} cost".PadLeft(55));
+            Console.ForegroundColor = ConsoleColor.Red;
+            Console.WriteLine($"{supplies.ToString("c").PadLeft(10)}");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.Write($"Your travel expenses to {fortname} were".PadLeft(55));
+            Console.ForegroundColor = ConsoleColor.Red;
+            Console.WriteLine($"{expenses.ToString("c").PadLeft(10)}");
+            Console.ForegroundColor = ConsoleColor.White;
+        }
+
+        /// 
+        /// Process the results of the expedition
+        /// 
+        /// the game state
+        private void ProcessExpeditionOutcome(GameState state)
+        {
+            var beaverPrice = RandomPriceGenerator(0.25d, 1.00d);
+            var foxPrice =    RandomPriceGenerator(0.2d , 0.80d);
+            var erminePrice = RandomPriceGenerator(0.15d, 0.95d);
+            var minkPrice =   RandomPriceGenerator(0.2d , 0.70d);
+
+            var fortname = String.Empty;
+            var suppliesCost = 0.0d;
+            var travelExpenses = 0.0d;
+
+            // create a random value 1 to 10 for the different outcomes at each fort
+            var p = ((int)(10 * Rnd.NextDouble())) + 1;
+            Console.WriteLine("");
+
+            switch (state.SelectedFort)
+            {
+                case 1:     // outcome for expedition to Fort Hochelaga
+                    beaverPrice = RandomPriceGenerator(0.2d, 0.75d);
+                    foxPrice =    RandomPriceGenerator(0.2d, 0.80d);
+                    erminePrice = RandomPriceGenerator(0.2d, 0.65d);
+                    minkPrice =   RandomPriceGenerator(0.2d, 0.70d);
+                    fortname = "Fort Hochelaga";
+                    suppliesCost = 150.0d;
+                    travelExpenses = 10.0d;
+                    break;
+                case 2:     // outcome for expedition to Fort Stadacona
+                    beaverPrice = RandomPriceGenerator(0.2d , 0.90d);
+                    foxPrice =    RandomPriceGenerator(0.2d , 0.80d);
+                    erminePrice = RandomPriceGenerator(0.15d, 0.80d);
+                    minkPrice =   RandomPriceGenerator(0.3d , 0.85d);
+                    fortname = "Fort Stadacona";
+                    suppliesCost = 125.0d;
+                    travelExpenses = 15.0d;
+                    if (p <= 2)
+                    {
+                        state.BeaverPelts = 0;
+                        Console.WriteLine("Your beaver were to heavy to carry across the portage.");
+                        Console.WriteLine("You had to leave the pelts but found them stolen when you returned");
+                    }
+                    else if (p <= 6)
+                    {
+                        Console.WriteLine("You arrived safely at Fort Stadacona");
+                    }
+                    else if (p <= 8)
+                    {
+                        state.BeaverPelts = 0;
+                        state.FoxPelts = 0;
+                        state.ErminePelts = 0;
+                        state.MinkPelts = 0;
+                        Console.WriteLine("Your canoe upset in the Lachine Rapids.");
+                        Console.WriteLine("Your lost all your furs");
+                    }
+                    else if (p <= 10)
+                    {
+                        state.FoxPelts = 0;
+                        Console.WriteLine("Your fox pelts were not cured properly.");
+                        Console.WriteLine("No one will buy them.");
+                    }
+                    else
+                    {
+                        throw new Exception($"Unexpected Outcome p = {p}");
+                    }
+                    break;
+                case 3:     // outcome for expedition to Fort New York
+                    beaverPrice = RandomPriceGenerator(0.2d , 1.00d);
+                    foxPrice =    RandomPriceGenerator(0.25d, 1.10d);
+                    erminePrice = RandomPriceGenerator(0.2d , 0.95d);
+                    minkPrice =   RandomPriceGenerator(0.15d, 1.05d);
+                    fortname = "Fort New York";
+                    suppliesCost = 80.0d;
+                    travelExpenses = 25.0d;
+                    if (p <= 2)
+                    {
+                        state.BeaverPelts = 0;
+                        state.FoxPelts = 0;
+                        state.ErminePelts = 0;
+                        state.MinkPelts = 0;
+                        suppliesCost = 0.0d;
+                        travelExpenses = 0.0d;
+                        Console.WriteLine("You were attacked by a party of Iroquois.");
+                        Console.WriteLine("All people in your trading group were killed.");
+                        Console.WriteLine("This ends the game (press any key).");
+                        Console.ReadKey(true);
+                        state.GameOver = true;
+                    }
+                    else if (p <= 6)
+                    {
+                        Console.WriteLine("You were lucky. You arrived safely at Fort New York.");
+                    }
+                    else if (p <= 8)
+                    {
+                        state.BeaverPelts = 0;
+                        state.FoxPelts = 0;
+                        state.ErminePelts = 0;
+                        state.MinkPelts = 0;
+                        Console.WriteLine("You narrowly escaped an Iroquois raiding party.");
+                        Console.WriteLine("However, you had to leave all your furs behind.");
+                    }
+                    else if (p <= 10)
+                    {
+                        beaverPrice = beaverPrice / 2;
+                        minkPrice = minkPrice / 2;
+                        Console.WriteLine("Your mink and beaver were damaged on your trip.");
+                        Console.WriteLine("You receive only half the current price for these furs.");
+                    }
+                    else
+                    {
+                        throw new Exception($"Unexpected Outcome p = {p}");
+                    }
+                    break;
+                default:
+                    break;
+            }
+
+            var beaverSale = state.BeaverPelts * beaverPrice;
+            var foxSale = state.FoxPelts * foxPrice;
+            var ermineSale = state.ErminePelts * erminePrice;
+            var minkSale = state.MinkPelts * minkPrice;
+            var profit = beaverSale + foxSale + ermineSale + minkSale - suppliesCost - travelExpenses;
+            state.Savings += profit;
+
+            Console.WriteLine("");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.Write($"Your {state.BeaverPelts.ToString().PadLeft(3, ' ')} beaver pelts sold @ {beaverPrice.ToString("c")} per pelt for a total");
+            Console.ForegroundColor = ConsoleColor.Green;
+            Console.WriteLine($"{beaverSale.ToString("c").PadLeft(10)}");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.Write($"Your {state.FoxPelts.ToString().PadLeft(3, ' ')} fox    pelts sold @ {foxPrice.ToString("c")} per pelt for a total");
+            Console.ForegroundColor = ConsoleColor.Green;
+            Console.WriteLine($"{foxSale.ToString("c").PadLeft(10)}");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.Write($"Your {state.ErminePelts.ToString().PadLeft(3, ' ')} ermine pelts sold @ {erminePrice.ToString("c")} per pelt for a total");
+            Console.ForegroundColor = ConsoleColor.Green;
+            Console.WriteLine($"{ermineSale.ToString("c").PadLeft(10)}");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.Write($"Your {state.MinkPelts.ToString().PadLeft(3, ' ')} mink   pelts sold @ {minkPrice.ToString("c")} per pelt for a total");
+            Console.ForegroundColor = ConsoleColor.Green;
+            Console.WriteLine($"{minkSale.ToString("c").PadLeft(10)}");
+            Console.WriteLine("");
+            DisplayCosts(fortname, suppliesCost, travelExpenses);
+            Console.WriteLine("");
+            Console.Write($"Profit / Loss".PadLeft(55));
+            Console.ForegroundColor = profit >= 0.0d ? ConsoleColor.Green : ConsoleColor.Red;
+            Console.WriteLine($"{profit.ToString("c").PadLeft(10)}");
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.WriteLine("");
+        }
+
+        private void DisplaySelectedFortInformation(int selectedFort)
+        {
+            Console.WriteLine("");
+            Console.ForegroundColor = ConsoleColor.White;
+
+            switch (selectedFort)
+            {
+                case 1:    // selected fort details for Fort Hochelaga
+                    Console.WriteLine("You have chosen the easiest route.");
+                    Console.WriteLine("However, the fort is far from any seaport.");
+                    Console.WriteLine("The value you receive for your furs will be low.");
+                    Console.WriteLine("The cost of supplies will be higher than at Forts Stadacona or New York");
+                    break;
+                case 2:    // selected fort details for Fort Stadacona
+                    Console.WriteLine("You have chosen a hard route.");
+                    Console.WriteLine("It is, in comparsion, harder than the route to Hochelaga but easier than the route to New York.");
+                    Console.WriteLine("You will receive an average value for your furs.");
+                    Console.WriteLine("The cost of your supplies will be average.");
+                    break;
+                case 3:    // selected fort details for Fort New York
+                    Console.WriteLine("You have chosen the most difficult route.");
+                    Console.WriteLine("At Fort New York you will receive the higest value for your furs.");
+                    Console.WriteLine("The cost of your supplies will be lower than at all the other forts.");
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        private bool TradeAtAnotherFort()
+        {
+            Console.ForegroundColor = ConsoleColor.White;
+            Console.WriteLine("");
+            Console.WriteLine("Do you want to trade at another fort?");
+            Console.Write("Answer (Y)es or (N)o ");
+            Console.ForegroundColor = ConsoleColor.Yellow;
+            Console.Write("> ");
+
+            char pressedKey;
+            // Keep looping until we get a recognised input
+            do
+            {
+                // Read a key, don't display it on screen
+                ConsoleKeyInfo key = Console.ReadKey(true);
+                // Convert to upper-case so we don't need to care about capitalisation
+                pressedKey = Char.ToUpper(key.KeyChar);
+                // Is this a key we recognise? If not, keep looping
+            } while (pressedKey != 'Y' && pressedKey != 'N');
+
+            // Display the result on the screen
+            Console.WriteLine(pressedKey);
+
+            // Return true if the player pressed 'Y', false for anything else.
+            return (pressedKey == 'Y');
+        }
+
+        /// 
+        /// Get an amount of pelts from the user
+        /// 
+        /// The total pelts available
+        /// Returns the amount the player selects
+        private int GetPelts(int furCount)
+        {
+            int peltCount;
+
+            // loop until the user enters a valid value
+            do
+            {
+                Console.ForegroundColor = ConsoleColor.Yellow;
+                Console.Write("> ");
+                string input = Console.ReadLine();
+
+                // parse user information to check if it is a valid entry
+                if (!int.TryParse(input, out peltCount))
+                {
+                    // invalid entry; message back to user
+                    Console.ForegroundColor = ConsoleColor.Red;
+                    Console.WriteLine("Sorry, I didn't understand. Please enter the number of pelts.");
+
+                    // continue looping
+                    continue;
+                }
+
+                // check if plet amount is more than the available pelts
+                if (peltCount > furCount)
+                {
+                    // too many pelts selected
+                    Console.ForegroundColor = ConsoleColor.Red;
+                    Console.WriteLine($"You may not have that many furs. Do not try to cheat. I can add.");
+
+                    // continue looping
+                    continue;
+                }
+
+                // valid pelt amount entered
+                break;
+            } while (true);
+
+            // return pelt count to the user
+            return peltCount;
+        }
+
+        /// 
+        /// Prompt the user for their selected fort
+        /// 
+        /// returns the fort the user has selected
+        private int GetSelectedFort()
+        {
+            int selectedFort;
+
+            // loop until the user enters a valid value
+            do
+            {
+                Console.ForegroundColor = ConsoleColor.White;
+                Console.Write("Answer 1, 2, or 3 ");
+                Console.ForegroundColor = ConsoleColor.Yellow;
+                Console.Write("> ");
+                string input = Console.ReadLine();
+
+                // is the user entry valid
+                if (!int.TryParse(input, out selectedFort))
+                {
+                    // no, invalid data
+                    Console.ForegroundColor = ConsoleColor.Red;
+                    Console.WriteLine("Sorry, I didn't understand. Please answer 1, 2, or 3.");
+
+                    // continue looping
+                    continue;
+                }
+
+                // is the selected fort an option (one, two or three only)
+                if (selectedFort != 1 && selectedFort != 2 && selectedFort != 3)
+                {
+                    // no, invalid for selected
+                    Console.ForegroundColor = ConsoleColor.Red;
+                    Console.WriteLine($"Please answer 1, 2, or 3.");
+
+                    // continue looping
+                    continue;
+                }
+
+                // valid fort selected, stop looping
+                break;
+            } while (true);
+
+            // return the players selected fort
+            return selectedFort;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/38_Fur_Trader/csharp/GameState.cs b/00_Alternate_Languages/38_Fur_Trader/csharp/GameState.cs
new file mode 100644
index 00000000..92330ffe
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/csharp/GameState.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace FurTrader
+{
+    internal class GameState
+    {
+        internal bool GameOver { get; set; }
+
+        internal double Savings { get; set; }
+
+        internal int ExpeditionCount { get; set; }
+
+        internal int UnasignedFurCount { get; set; }
+
+        internal int[] Pelts { get; private set; }
+
+        internal int MinkPelts { get { return this.Pelts[0]; } set { this.Pelts[0] = value; } }
+        internal int BeaverPelts { get { return this.Pelts[1]; } set { this.Pelts[1] = value; } }
+        internal int ErminePelts { get { return this.Pelts[2]; } set { this.Pelts[2] = value; } }
+        internal int FoxPelts { get { return this.Pelts[3]; } set { this.Pelts[3] = value; } }
+
+        internal int SelectedFort { get; set; }
+
+        internal GameState()
+        {
+            this.Savings = 600;
+            this.ExpeditionCount = 0;
+            this.UnasignedFurCount = 190;
+            this.Pelts = new int[4];
+            this.SelectedFort = 0;
+        }
+
+        internal void StartTurn()
+        {
+            this.SelectedFort = 0;              // reset to a default value
+            this.UnasignedFurCount = 190;       // each turn starts with 190 furs
+            this.Pelts = new int[4];            // reset pelts on each turn
+        }
+    }
+}
diff --git a/00_Alternate_Languages/38_Fur_Trader/csharp/Program.cs b/00_Alternate_Languages/38_Fur_Trader/csharp/Program.cs
new file mode 100644
index 00000000..438d5c4c
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/csharp/Program.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace FurTrader
+{
+    public class Program
+    {
+        /// 
+        /// This function will be called automatically when the application begins
+        /// 
+        /// 
+        public static void Main(string[] args)
+        {
+            // Create an instance of our main Game class
+            var game = new Game();
+
+            // Call its GameLoop function. This will play the game endlessly in a loop until the player chooses to quit.
+            game.GameLoop();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/38_Fur_Trader/csharp/README.md b/00_Alternate_Languages/38_Fur_Trader/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/38_Fur_Trader/furtrader.bas b/00_Alternate_Languages/38_Fur_Trader/furtrader.bas
new file mode 100644
index 00000000..9a379b2c
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/furtrader.bas
@@ -0,0 +1,170 @@
+1 DIM F(4)
+2 PRINT TAB(31);"FUR TRADER"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT: PRINT: PRINT
+15 GOSUB 1091
+16 LET I=600
+17 PRINT "DO YOU WISH TO TRADE FURS?"
+18 GOSUB 1402
+19 IF B$="YES" THEN 100
+20 IF B$="YES " THEN 100
+21 STOP
+100 PRINT
+101 PRINT "YOU HAVE $";I " SAVINGS."
+102 PRINT "AND 190 FURS TO BEGIN THE EXPEDITION."
+261 LET E1=INT((.15*RND(1)+.95)*10^2+.5)/10^2
+262 LET B1=INT((.25*RND(1)+1.00)*10^2+.5)/10^2
+300 PRINT
+301 PRINT "YOUR 190 FURS ARE DISTRIBUTED AMONG THE FOLLOWING"
+302 PRINT "KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX."
+310 GOSUB 1430
+315 RESTORE
+330 FOR J=1 TO 4
+332 READ B$
+333 PRINT
+335 PRINT "HOW MANY ";B$;" PELTS DO YOU HAVE";
+338 INPUT F(J)
+340 LET F(0)=F(1)+F(2)+F(3)+F(4)
+342 IF F(0)=190 THEN 1100
+344 IF F(0)>190 THEN 500
+348 NEXT J
+350 GOTO 1100
+500 PRINT
+501 PRINT "YOU MAY NOT HAVE THAT MANY FURS."
+502 PRINT "DO NOT TRY TO CHEAT.  I CAN ADD."
+503 PRINT "YOU MUST START AGAIN."
+504 GOTO 15
+508 PRINT
+511 PRINT "DO YOU WANT TO TRADE FURS NEXT YEAR?"
+513 GOTO 18
+1091 PRINT "YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN "
+1092 PRINT "1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET"
+1093 PRINT "SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE"
+1094 PRINT "FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES"
+1095 PRINT "AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND"
+1096 PRINT "ON THE FORT THAT YOU CHOOSE."
+1099 RETURN
+1100 PRINT "YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,"
+1102 PRINT "OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)"
+1103 PRINT "AND IS UNDER THE PROTECTION OF THE FRENCH ARMY."
+1104 PRINT "FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE"
+1105 PRINT "PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST"
+1106 PRINT "MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS."
+1108 PRINT "FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL."
+1109 PRINT "YOU MUST CROSS THROUGH IROQUOIS LAND."
+1110 PRINT "ANSWER 1, 2, OR 3."
+1111 INPUT B
+1112 IF B=1 THEN 1120
+1113 IF B=2 THEN 1135
+1115 IF B=3 THEN 1147
+1116 GOTO 1110
+1120 PRINT "YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT"
+1121 PRINT "IS FAR FROM ANY SEAPORT.  THE VALUE"
+1122 PRINT "YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST"
+1123 PRINT "OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK."
+1125 GOSUB 1400
+1129 IF B$="YES" THEN 1110
+1130 GOTO 1160
+1135 PRINT "YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,"
+1136 PRINT "HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN"
+1137 PRINT "THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE"
+1138 PRINT "FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE."
+1141 GOSUB 1400
+1144 IF B$="YES" THEN 1110
+1145 GOTO 1198
+1147 PRINT "YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT"
+1148 PRINT "FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE"
+1149 PRINT "FOR YOUR FURS.  THE COST OF YOUR SUPPLIES"
+1150 PRINT "WILL BE LOWER THAN AT ALL THE OTHER FORTS."
+1152 GOSUB 1400
+1155 IF B$="YES" THEN 1110
+1156 GOTO 1250
+1160 LET I=I-160
+1169 PRINT
+1174 LET M1=INT((.2*RND(1)+.7)*10^2+.5)/10^2
+1175 LET E1=INT((.2*RND(1)+.65)*10^2+.5)/10^2
+1176 LET B1=INT((.2*RND(1)+.75)*10^2+.5)/10^2
+1177 LET D1=INT((.2*RND(1)+.8)*10^2+.5)/10^2
+1180 PRINT "SUPPLIES AT FORT HOCHELAGA COST $150.00."
+1181 PRINT "YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00."
+1190 GOTO 1410
+1198 LET I=I-140
+1201 PRINT
+1205 LET M1=INT((.3*RND(1)+.85)*10^2+.5)/10^2
+1206 LET E1=INT((.15*RND(1)+.8)*10^2+.5)/10^2
+1207 LET B1=INT((.2*RND(1)+.9)*10^2+.5)/10^2
+1209 LET P=INT(10*RND(1))+1
+1210 IF P<=2 THEN 1216
+1212 IF P<=6 THEN 1224
+1213 IF P<=8 THEN 1226
+1215 IF P<=10 THEN 1235
+1216 LET F(2)=0
+1218 PRINT "YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS"
+1219 PRINT "THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND"
+1220 PRINT "THEM STOLEN WHEN YOU RETURNED."
+1221 GOSUB 1244
+1222 GOTO 1414
+1224 PRINT "YOU ARRIVED SAFELY AT FORT STADACONA."
+1225 GOTO 1239
+1226 GOSUB 1430
+1230 PRINT "YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU"
+1231 PRINT "LOST ALL YOUR FURS."
+1232 GOSUB 1244
+1233 GOTO 1418
+1235 LET F(4)=0
+1237 PRINT "YOUR FOX PELTS WERE NOT CURED PROPERLY."
+1238 PRINT "NO ONE WILL BUY THEM."
+1239 GOSUB 1244
+1240 GOTO 1410
+1244 PRINT "SUPPLIES AT FORT STADACONA COST $125.00."
+1246 PRINT "YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00."
+1248 RETURN
+1250 LET I=I-105
+1254 PRINT
+1260 LET M1=INT((.15*RND(1)+1.05)*10^2+.5)/10^2
+1263 LET D1=INT((.25*RND(1)+1.1)*10^2+.5)/10^2
+1270 LET P=INT(10*RND(1))+1
+1271 IF P<=2 THEN 1281
+1272 IF P<=6 THEN 1291
+1273 IF P<=8 THEN 1295
+1274 IF P<=10 THEN 1306
+1281 PRINT "YOU WERE ATTACKED BY A PARTY OF IROQUOIS."
+1282 PRINT "ALL PEOPLE IN YOUR TRADING GROUP WERE"
+1283 PRINT "KILLED.  THIS ENDS THE GAME."
+1284 STOP
+1291 PRINT "YOU WERE LUCKY.  YOU ARRIVED SAFELY"
+1292 PRINT "AT FORT NEW YORK."
+1293 GOTO 1311
+1295 GOSUB 1430
+1300 PRINT "YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY."
+1301 PRINT "HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND."
+1303 GOSUB 1320
+1304 GOTO 1418
+1306 LET B1=B1/2
+1307 LET M1=M1/2
+1308 PRINT "YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP."
+1309 PRINT "YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS."
+1311 GOSUB 1320
+1312 GOTO 1410
+1320 PRINT "SUPPLIES AT NEW YORK COST $80.00."
+1321 PRINT "YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00."
+1322 RETURN
+1400 PRINT "DO YOU WANT TO TRADE AT ANOTHER FORT?"
+1402 PRINT "ANSWER YES OR NO",
+1403 INPUT B$
+1404 RETURN
+1410 PRINT
+1412 PRINT "YOUR BEAVER SOLD FOR $";B1*F(2);
+1414 PRINT "YOUR FOX SOLD FOR $";D1*F(4)
+1416 PRINT "YOUR ERMINE SOLD FOR $";E1*F(3);
+1417 PRINT "YOUR MINK SOLD FOR $";M1*F(1)
+1418 LET I=M1*F(1)+B1*F(2)+E1*F(3)+D1*F(4)+I
+1420 PRINT
+1422 PRINT "YOU NOW HAVE $";I;" INCLUDING YOUR PREVIOUS SAVINGS"
+1425 GOTO 508
+1430 FOR J=1 TO 4
+1432 LET F(J)=0
+1434 NEXT J
+1436 RETURN
+2000 DATA "MINK","BEAVER","ERMINE","FOX"
+2046 END
diff --git a/00_Alternate_Languages/38_Fur_Trader/java/README.md b/00_Alternate_Languages/38_Fur_Trader/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/38_Fur_Trader/java/src/FurTrader.java b/00_Alternate_Languages/38_Fur_Trader/java/src/FurTrader.java
new file mode 100644
index 00000000..789adb25
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/java/src/FurTrader.java
@@ -0,0 +1,472 @@
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Fur Trader
+ * 

+ * Based on the Basic game of Fur Trader here + * https://github.com/coding-horror/basic-computer-games/blob/main/38%20Fur%20Trader/furtrader.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. + */ +public class FurTrader { + + public static final double START_SAVINGS_AMOUNT = 600.0; + public static final int STARTING_FURS = 190; + + public static final int FORT_HOCHELAGA_MONTREAL = 1; + public static final int FORT_STADACONA_QUEBEC = 2; + public static final int FORT_NEW_YORK = 3; + + public static final String MINK = "MINK"; + public static final int MINK_ENTRY = 0; + public static final String BEAVER = "BEAVER"; + public static final int BEAVER_ENTRY = 1; + public static final String ERMINE = "ERMINE"; + public static final int ERMINE_ENTRY = 2; + public static final String FOX = "FOX"; + public static final int FOX_ENTRY = 3; + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + STARTUP, + INIT, + TRADE_AT_FORT, + TRADE_SUMMARY, + TRADE_AGAIN, + GAME_OVER + } + + // Current game state + private GAME_STATE gameState; + + private double savings; + private double minkPrice; + private double beaverPrice; + private double erminePrice; + private double foxPrice; + + private ArrayList pelts; + + private boolean playedOnce; + + public FurTrader() { + kbScanner = new Scanner(System.in); + gameState = GAME_STATE.INIT; + playedOnce = false; + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + case INIT: + savings = START_SAVINGS_AMOUNT; + + // Only display initial game heading once + if (!playedOnce) { + playedOnce = true; + gameStartupMessage(); + } + + intro(); + if (yesEntered(displayTextAndGetInput("DO YOU WISH TO TRADE FURS? "))) { + System.out.println("YOU HAVE $" + formatNumber(savings) + " SAVINGS."); + System.out.println("AND " + STARTING_FURS + " FURS TO BEGIN THE EXPEDITION."); + + // Create a new array of Pelts. + pelts = initPelts(); + gameState = GAME_STATE.STARTUP; + } else { + gameState = GAME_STATE.GAME_OVER; + } + + break; + + case STARTUP: + + // Reset count of pelts (all types) + resetPelts(); + + // This is where we will go to after processing all pelts. + gameState = GAME_STATE.TRADE_AT_FORT; + + int totalPelts = 0; + // Cycle through all types of pelts + for (int i = 0; i < pelts.size(); i++) { + Pelt pelt = pelts.get(i); + int number = getPeltCount(pelt.getName()); + totalPelts += number; + if (totalPelts > STARTING_FURS) { + System.out.println("YOU MAY NOT HAVE THAT MANY FURS."); + System.out.println("DO NOT TRY TO CHEAT. I CAN ADD."); + System.out.println("YOU MUST START AGAIN."); + System.out.println(); + // Restart the game + gameState = GAME_STATE.INIT; + break; + } else { + // update count entered by player and save back to ArrayList. + pelt.setPeltCount(number); + pelts.set(i, pelt); + // Its possible for the player to put all their pelt allocation + // into one or more different pelts. They don't have to use all four types. + // If we have an exact count of pelts matching the MAX + // don't bother continuing to ask for more. + if (totalPelts == STARTING_FURS) { + break; + } + } + } + + // Only move onto the trading part of the game if the player didn't add too many pelts + if (gameState != GAME_STATE.STARTUP) { + // Set ermine and beaver default prices here, depending on where you trade these + // defaults will either be used or overwritten with other values. + // check out the tradeAt??? methods for more info. + erminePrice = ((.15 * Math.random() + .95) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + beaverPrice = ((.25 * Math.random() + 1.00) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + System.out.println(); + } + break; + + case TRADE_AT_FORT: + + extendedTradingInfo(); + int answer = displayTextAndGetNumber("ANSWER 1, 2, OR 3. "); + + System.out.println(); + + // Now show the details of the fort they are about to trade + // and give the player the chance to NOT proceed. + // A "No" or false means they do not want to change to another fort + if (!confirmFort(answer)) { + switch (answer) { + case 1: + tradeAtFortHochelagaMontreal(); + gameState = GAME_STATE.TRADE_SUMMARY; + break; + + case 2: + tradeAtFortStadaconaQuebec(); + gameState = GAME_STATE.TRADE_SUMMARY; + break; + case 3: + // Did the player and party all die? + if (!tradeAtFortNewYork()) { + gameState = GAME_STATE.GAME_OVER; + } else { + gameState = GAME_STATE.TRADE_SUMMARY; + } + break; + } + + break; + } + + case TRADE_SUMMARY: + + System.out.println(); + double beaverTotal = beaverPrice * pelts.get(BEAVER_ENTRY).getNumber(); + System.out.print("YOUR BEAVER SOLD FOR $ " + formatNumber(beaverTotal)); + + double foxTotal = foxPrice * pelts.get(FOX_ENTRY).getNumber(); + System.out.println(simulateTabs(5) + "YOUR FOX SOLD FOR $ " + formatNumber(foxTotal)); + + double erMineTotal = erminePrice * pelts.get(ERMINE_ENTRY).getNumber(); + System.out.print("YOUR ERMINE SOLD FOR $ " + formatNumber(erMineTotal)); + + double minkTotal = minkPrice * pelts.get(MINK_ENTRY).getNumber(); + System.out.println(simulateTabs(5) + "YOUR MINK SOLD FOR $ " + formatNumber(minkTotal)); + + savings += beaverTotal + foxTotal + erMineTotal + minkTotal; + System.out.println(); + System.out.println("YOU NOW HAVE $" + formatNumber(savings) + " INCLUDING YOUR PREVIOUS SAVINGS"); + + gameState = GAME_STATE.TRADE_AGAIN; + break; + + case TRADE_AGAIN: + if (yesEntered(displayTextAndGetInput("DO YOU WANT TO TRADE FURS NEXT YEAR? "))) { + gameState = GAME_STATE.STARTUP; + } else { + gameState = GAME_STATE.GAME_OVER; + } + + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + /** + * Create all pelt types with a count of zero + * + * @return Arraylist of initialised Pelt objects. + */ + private ArrayList initPelts() { + + ArrayList tempPelts = new ArrayList<>(); + tempPelts.add(new Pelt(MINK, 0)); + tempPelts.add(new Pelt(BEAVER, 0)); + tempPelts.add(new Pelt(ERMINE, 0)); + tempPelts.add(new Pelt(FOX, 0)); + return tempPelts; + } + + /** + * Display a message about trading at each fort and confirm if the player wants to trade + * at ANOTHER fort + * + * @param fort the fort in question + * @return true if YES was typed by player + */ + private boolean confirmFort(int fort) { + switch (fort) { + case FORT_HOCHELAGA_MONTREAL: + System.out.println("YOU HAVE CHOSEN THE EASIEST ROUTE. HOWEVER, THE FORT"); + System.out.println("IS FAR FROM ANY SEAPORT. THE VALUE"); + System.out.println("YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST"); + System.out.println("OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK."); + break; + case FORT_STADACONA_QUEBEC: + System.out.println("YOU HAVE CHOSEN A HARD ROUTE. IT IS, IN COMPARSION,"); + System.out.println("HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN"); + System.out.println("THE ROUTE TO NEW YORK. YOU WILL RECEIVE AN AVERAGE VALUE"); + System.out.println("FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE."); + break; + case FORT_NEW_YORK: + System.out.println("YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE. AT"); + System.out.println("FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE"); + System.out.println("FOR YOUR FURS. THE COST OF YOUR SUPPLIES"); + System.out.println("WILL BE LOWER THAN AT ALL THE OTHER FORTS."); + break; + } + + System.out.println("DO YOU WANT TO TRADE AT ANOTHER FORT?"); + return yesEntered(displayTextAndGetInput("ANSWER YES OR NO ")); + + } + + /** + * Trade at the safest fort - Fort Hochelaga + * No chance of anything bad happening, so just calculate amount per pelt + * and return + */ + private void tradeAtFortHochelagaMontreal() { + savings -= 160.0; + System.out.println(); + System.out.println("SUPPLIES AT FORT HOCHELAGA COST $150.00."); + System.out.println("YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00."); + minkPrice = ((.2 * Math.random() + .7) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + erminePrice = ((.2 * Math.random() + .65) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + beaverPrice = ((.2 * Math.random() + .75) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + foxPrice = ((.2 * Math.random() + .8) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + } + + + private void tradeAtFortStadaconaQuebec() { + savings -= 140.0; + System.out.println(); + minkPrice = ((.2 * Math.random() + .85) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + erminePrice = ((.2 * Math.random() + .8) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + beaverPrice = ((.2 * Math.random() + .9) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + + // What happened during the trip to the fort? + int tripResult = (int) (Math.random() * 10) + 1; + if (tripResult <= 2) { + // Find the Beaver pelt in our Arraylist + Pelt beaverPelt = pelts.get(BEAVER_ENTRY); + // Pelts got stolen, so update to a count of zero + beaverPelt.lostPelts(); + // Update it back in the ArrayList + pelts.set(BEAVER_ENTRY, beaverPelt); + System.out.println("YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS"); + System.out.println("THE PORTAGE. YOU HAD TO LEAVE THE PELTS, BUT FOUND"); + System.out.println("THEM STOLEN WHEN YOU RETURNED."); + } else if (tripResult <= 6) { + System.out.println("YOU ARRIVED SAFELY AT FORT STADACONA."); + } else if (tripResult <= 8) { + System.out.println("YOUR CANOE UPSET IN THE LACHINE RAPIDS. YOU"); + System.out.println("LOST ALL YOUR FURS."); + // Clear out all pelts. + resetPelts(); + } else if (tripResult <= 10) { + // Fox pelts not cured + System.out.println("YOUR FOX PELTS WERE NOT CURED PROPERLY."); + System.out.println("NO ONE WILL BUY THEM."); + // Bug because Fox furs were not calculated above in original basic program + // Find the Beaver pelt in our Arraylist + Pelt foxPelt = pelts.get(FOX_ENTRY); + // Pelts got stolen, so update to a count of zero + foxPelt.lostPelts(); + // Update it back in the ArrayList + pelts.set(FOX_ENTRY, foxPelt); + } + + System.out.println("SUPPLIES AT FORT STADACONA COST $125.00."); + System.out.println("YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00."); + } + + private boolean tradeAtFortNewYork() { + + boolean playerAlive = true; + savings -= 105.0; + System.out.println(); + minkPrice = ((.2 * Math.random() + 1.05) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + foxPrice = ((.2 * Math.random() + 1.1) * (Math.pow(10, 2) + .5)) / Math.pow(10, 2); + + // What happened during the trip to the fort? + int tripResult = (int) (Math.random() * 10) + 1; + if (tripResult <= 2) { + System.out.println("YOU WERE ATTACKED BY A PARTY OF IROQUOIS."); + System.out.println("ALL PEOPLE IN YOUR TRADING GROUP WERE"); + System.out.println("KILLED. THIS ENDS THE GAME."); + playerAlive = false; + } else if (tripResult <= 6) { + System.out.println("YOU WERE LUCKY. YOU ARRIVED SAFELY"); + System.out.println("AT FORT NEW YORK."); + } else if (tripResult <= 8) { + System.out.println("YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY."); + System.out.println("HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND."); + // Clear out all pelts. + resetPelts(); + } else if (tripResult <= 10) { + beaverPrice /= 2; + minkPrice /= 2; + System.out.println("YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP."); + System.out.println("YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS."); + } + + if (playerAlive) { + System.out.println("SUPPLIES AT NEW YORK COST $80.00."); + System.out.println("YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00."); + } + + return playerAlive; + } + + /** + * Reset pelt count for all Pelt types to zero. + */ + private void resetPelts() { + for (int i = 0; i < pelts.size(); i++) { + Pelt pelt = pelts.get(i); + pelt.lostPelts(); + pelts.set(i, pelt); + } + } + + /** + * Return a pelt object containing the user entered number of pelts. + * + * @param peltName Name of pelt (Type) + * @return number of pelts assigned by player + */ + private int getPeltCount(String peltName) { + return displayTextAndGetNumber("HOW MANY " + peltName + " PELTS DO YOU HAVE? "); + } + + private void extendedTradingInfo() { + System.out.println("YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,"); + System.out.println("OR FORT 3. FORT 1 IS FORT HOCHELAGA (MONTREAL)"); + System.out.println("AND IS UNDER THE PROTECTION OF THE FRENCH ARMY."); + System.out.println("FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE"); + System.out.println("PROTECTION OF THE FRENCH ARMY. HOWEVER, YOU MUST"); + System.out.println("MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS."); + System.out.println("FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL."); + System.out.println("YOU MUST CROSS THROUGH IROQUOIS LAND."); + System.out.println(); + + } + + private void gameStartupMessage() { + System.out.println(simulateTabs(31) + "FUR TRADER"); + System.out.println(simulateTabs(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + } + + private void intro() { + System.out.println("YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN "); + System.out.println("1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET"); + System.out.println("SUPPLIES FOR THE NEXT YEAR. YOU HAVE A CHOICE OF THREE"); + System.out.println("FORTS AT WHICH YOU MAY TRADE. THE COST OF SUPPLIES"); + System.out.println("AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND"); + System.out.println("ON THE FORT THAT YOU CHOOSE."); + System.out.println(); + } + + /** + * Format a double number to two decimal points for output. + * + * @param number double number + * @return formatted number as a string + */ + private String formatNumber(double number) { + return String.format("%.2f", number); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to an Integer + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private int displayTextAndGetNumber(String text) { + return Integer.parseInt(displayTextAndGetInput(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + + /** + * Simulate the old basic tab(xx) command which indented text by xx spaces. + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String simulateTabs(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + + /** + * Checks whether player entered Y or YES to a question. + * + * @param text player string from kb + * @return true of Y or YES was entered, otherwise false + */ + private boolean yesEntered(String text) { + return stringIsAnyValue(text, "Y", "YES"); + } + + /** + * Check whether a string equals one of a variable number of values + * Useful to check for Y or YES for example + * Comparison is case insensitive. + * + * @param text source string + * @param values a range of values to compare against the source string + * @return true if a comparison was found in one of the variable number of strings passed + */ + private boolean stringIsAnyValue(String text, String... values) { + + return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text)); + } +} diff --git a/00_Alternate_Languages/38_Fur_Trader/java/src/FurTraderGame.java b/00_Alternate_Languages/38_Fur_Trader/java/src/FurTraderGame.java new file mode 100644 index 00000000..9c7aaa1c --- /dev/null +++ b/00_Alternate_Languages/38_Fur_Trader/java/src/FurTraderGame.java @@ -0,0 +1,7 @@ +public class FurTraderGame { + public static void main(String[] args) { + + FurTrader furTrader = new FurTrader(); + furTrader.play(); + } +} diff --git a/00_Alternate_Languages/38_Fur_Trader/java/src/Pelt.java b/00_Alternate_Languages/38_Fur_Trader/java/src/Pelt.java new file mode 100644 index 00000000..92c9629d --- /dev/null +++ b/00_Alternate_Languages/38_Fur_Trader/java/src/Pelt.java @@ -0,0 +1,29 @@ +/** + * Pelt object - tracks the name and number of pelts the player has for this pelt type + */ +public class Pelt { + + private final String name; + private int number; + + public Pelt(String name, int number) { + this.name = name; + this.number = number; + } + + public void setPeltCount(int pelts) { + this.number = pelts; + } + + public int getNumber() { + return this.number; + } + + public String getName() { + return this.name; + } + + public void lostPelts() { + this.number = 0; + } +} diff --git a/00_Alternate_Languages/38_Fur_Trader/javascript/README.md b/00_Alternate_Languages/38_Fur_Trader/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/38_Fur_Trader/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/38_Fur_Trader/javascript/furtrader.html b/00_Alternate_Languages/38_Fur_Trader/javascript/furtrader.html new file mode 100644 index 00000000..c7695a09 --- /dev/null +++ b/00_Alternate_Languages/38_Fur_Trader/javascript/furtrader.html @@ -0,0 +1,9 @@ + + +FUR TRADER + + +


+
+
+
diff --git a/00_Alternate_Languages/38_Fur_Trader/javascript/furtrader.js b/00_Alternate_Languages/38_Fur_Trader/javascript/furtrader.js
new file mode 100644
index 00000000..206facd4
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/javascript/furtrader.js
@@ -0,0 +1,227 @@
+// FUR TRADER
+//
+// 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 f = [];
+var bs = [, "MINK", "BEAVER", "ERMINE", "FOX"];
+
+function reset_stats()
+{
+    for (var j = 1; j <= 4; j++)
+        f[j] = 0;
+}
+
+// Main program
+async function main()
+{
+    print(tab(31) + "FUR TRADER\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    first_time = true;
+    while (1) {
+        if (first_time) {
+            print("YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN \n");
+            print("1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET\n");
+            print("SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE\n");
+            print("FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES\n");
+            print("AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND\n");
+            print("ON THE FORT THAT YOU CHOOSE.\n");
+            i = 600;
+            print("DO YOU WISH TO TRADE FURS?\n");
+            first_time = false;
+        }
+        print("ANSWER YES OR NO\t");
+        str = await input();
+        if (str == "NO")
+            break;
+        print("\n");
+        print("YOU HAVE $" + i + " SAVINGS.\n");
+        print("AND 190 FURS TO BEGIN THE EXPEDITION.\n");
+        e1 = Math.floor((0.15 * Math.random() + 0.95) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+        b1 = Math.floor((0.25 * Math.random() + 1.00) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+        print("\n");
+        print("YOUR 190 FURS ARE DISTRIBUTED AMONG THE FOLLOWING\n");
+        print("KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.\n");
+        reset_stats();
+        for (j = 1; j <= 4; j++) {
+            print("\n");
+            print("HOW MANY " + bs[j] + " PELTS DO YOU HAVE\n");
+            f[j] = parseInt(await input());
+            f[0] = f[1] + f[2] + f[3] + f[4];
+            if (f[0] == 190)
+                break;
+            if (f[0] > 190) {
+                print("\n");
+                print("YOU MAY NOT HAVE THAT MANY FURS.\n");
+                print("DO NOT TRY TO CHEAT.  I CAN ADD.\n");
+                print("YOU MUST START AGAIN.\n");
+                break;
+            }
+        }
+        if (f[0] > 190) {
+            first_time = true;
+            continue;
+        }
+        print("YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,\n");
+        print("OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)\n");
+        print("AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.\n");
+        print("FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE\n");
+        print("PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST\n");
+        print("MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.\n");
+        print("FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.\n");
+        print("YOU MUST CROSS THROUGH IROQUOIS LAND.\n");
+        do {
+            print("ANSWER 1, 2, OR 3.\n");
+            b = parseInt(await input());
+            if (b == 1) {
+                print("YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT\n");
+                print("IS FAR FROM ANY SEAPORT.  THE VALUE\n");
+                print("YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST\n");
+                print("OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.\n");
+            } else if (b == 2) {
+                print("YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,\n");
+                print("HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN\n");
+                print("THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE\n");
+                print("FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.\n");
+            } else {
+                print("YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT\n");
+                print("FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE\n");
+                print("FOR YOUR FURS.  THE COST OF YOUR SUPPLIES\n");
+                print("WILL BE LOWER THAN AT ALL THE OTHER FORTS.\n");
+            }
+            if (b >= 1 && b <= 3) {
+                print("DO YOU WANT TO TRADE AT ANOTHER FORT?\n");
+                print("ANSWER YES OR NO\t");
+                str = await input();
+                if (str == "YES") {
+                    b = 0;
+                }
+            }
+        } while (b < 1 || b > 3) ;
+        show_beaver = true;
+        show_all = true;
+        if (b == 1) {
+            i -= 160;
+            print("\n");
+            m1 = Math.floor((0.2 * Math.random() + 0.7) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+            e1 = Math.floor((0.2 * Math.random() + 0.65) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+            b1 = Math.floor((0.2 * Math.random() + 0.75) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+            d1 = Math.floor((0.2 * Math.random() + 0.8) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+            print("SUPPLIES AT FORT HOCHELAGA COST $150.00.\n");
+            print("YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.\n");
+        } else if (b == 2) {
+            i -= 140;
+            print("\n");
+            m1 = Math.floor((0.3 * Math.random() + 0.85) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+            e1 = Math.floor((0.15 * Math.random() + 0.8) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+            b1 = Math.floor((0.2 * Math.random() + 0.9) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+            p = Math.floor(10 * Math.random()) + 1;
+            if (p <= 2) {
+                f[2] = 0;
+                print("YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS\n");
+                print("THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND\n");
+                print("THEM STOLEN WHEN YOU RETURNED.\n");
+                show_beaver = false;
+            } else if (p <= 6) {
+                print("YOU ARRIVED SAFELY AT FORT STADACONA.\n");
+            } else if (p <= 8) {
+                reset_stats();
+                print("YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU\n");
+                print("LOST ALL YOUR FURS.\n");
+                show_all = false;
+            } else if (p <= 10) {
+                f[4] = 0;
+                print("YOUR FOX PELTS WERE NOT CURED PROPERLY.\n");
+                print("NO ONE WILL BUY THEM.\n");
+            }
+            print("SUPPLIES AT FORT STADACONA COST $125.00.\n");
+            print("YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.\n");
+
+            d1 = Math.floor((0.2 * Math.random() + 0.8) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+        } else if (b == 3) {
+            i -= 105;
+            print("\n");
+            m1 = Math.floor((0.15 * Math.random() + 1.05) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+            d1 = Math.floor((0.25 * Math.random() + 1.1) * Math.pow(10, 2) + 0.5) / Math.pow(10, 2);
+            p = Math.floor(10 * Math.random()) + 1;
+            if (p <= 2) {
+                print("YOU WERE ATTACKED BY A PARTY OF IROQUOIS.\n");
+                print("ALL PEOPLE IN YOUR TRADING GROUP WERE\n");
+                print("KILLED.  THIS ENDS THE GAME.\n");
+                break;
+            } else if (p <= 6) {
+                print("YOU WERE LUCKY.  YOU ARRIVED SAFELY\n");
+                print("AT FORT NEW YORK.\n");
+            } else if (p <= 8) {
+                reset_stats();
+                print("YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.\n");
+                print("HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.\n");
+                show_all = false;
+            } else if (p <= 10) {
+                b1 /= 2;
+                m1 /= 2;
+                print("YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.\n");
+                print("YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.\n");
+            }
+            print("SUPPLIES AT NEW YORK COST $80.00.\n");
+            print("YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.\n");
+        }
+        print("\n");
+        if (show_all) {
+            if (show_beaver)
+                print("YOUR BEAVER SOLD FOR $" + b1 * f[2] + " ");
+            print("YOUR FOX SOLD FOR $" + d1 * f[4] + "\n");
+            print("YOUR ERMINE SOLD FOR $" + e1 * f[3] + " ");
+            print("YOUR MINK SOLD FOR $" + m1 * f[1] + "\n");
+        }
+        i += m1 * f[1] + b1 * f[2] + e1 * f[3] + d1 * f[4];
+        print("\n");
+        print("YOU NOW HAVE $" + i + " INCLUDING YOUR PREVIOUS SAVINGS\n");
+        print("\n");
+        print("DO YOU WANT TO TRADE FURS NEXT YEAR?\n");
+    }
+}
+
+main();
diff --git a/14_Bowling/pascal/README.md b/00_Alternate_Languages/38_Fur_Trader/pascal/README.md
similarity index 100%
rename from 14_Bowling/pascal/README.md
rename to 00_Alternate_Languages/38_Fur_Trader/pascal/README.md
diff --git a/00_Alternate_Languages/38_Fur_Trader/perl/README.md b/00_Alternate_Languages/38_Fur_Trader/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/38_Fur_Trader/python/README.md b/00_Alternate_Languages/38_Fur_Trader/python/README.md
new file mode 100644
index 00000000..cda8ed79
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/python/README.md
@@ -0,0 +1,24 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
+
+##### Translator Notes:
+I tried to preserve as much of the original layout and flow of the code
+as possible.  However I did use quasi enumerated types for the Fort numbers
+and Fur types.  I think this was certainly a change for the better, and
+makes the code much easier to read.
+
+I program in many different languages on a daily basis.  Most languages
+require brackets around expressions, so I just cannot bring myself to
+write an expression without brackets.  IMHO it makes the code easier to study,
+but it does contravene the Python PEP-8 Style guide.
+
+Interestingly the code seems to have a bug around the prices of Fox Furs.
+The commodity-rate for these is stored in the variable `D1`, however some
+paths through the code do not set this price.  So there was a chance of
+using this uninitialised, or whatever the previous loop set.  I don't
+think this was the original authors intent.  So I preserved the original flow
+of the code (using the previous `D1` value), but also catching the
+uninitialised path, and assigning a "best guess" value.
+
+krt@krt.com.au 2020-10-10
diff --git a/00_Alternate_Languages/38_Fur_Trader/python/furtrader.py b/00_Alternate_Languages/38_Fur_Trader/python/furtrader.py
new file mode 100644
index 00000000..deeb3f67
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/python/furtrader.py
@@ -0,0 +1,318 @@
+#! /usr/bin/env python3
+
+import random  # for generating random numbers
+import sys  # for system function, like exit()
+
+# global variables for storing player's status
+player_funds = 0  # no money
+player_furs = [0, 0, 0, 0]  # no furs
+
+
+# Constants
+FUR_MINK = 0
+FUR_BEAVER = 1
+FUR_ERMINE = 2
+FUR_FOX = 3
+MAX_FURS = 190
+FUR_NAMES = ["MINK", "BEAVER", "ERMINE", "FOX"]
+
+FORT_MONTREAL = 1
+FORT_QUEBEC = 2
+FORT_NEWYORK = 3
+FORT_NAMES = ["HOCHELAGA (MONTREAL)", "STADACONA (QUEBEC)", "NEW YORK"]
+
+
+def print_at_column(column: int, words: str):
+    """Print the words at the specified column"""
+    spaces = " " * column  # make a fat string of spaces
+    print(spaces + words)
+
+
+def show_introduction():
+    """Show the player the introductory message"""
+    print("YOU ARE THE LEADER OF A FRENCH FUR TRADING EXPEDITION IN ")
+    print("1776 LEAVING THE LAKE ONTARIO AREA TO SELL FURS AND GET")
+    print("SUPPLIES FOR THE NEXT YEAR.  YOU HAVE A CHOICE OF THREE")
+    print("FORTS AT WHICH YOU MAY TRADE.  THE COST OF SUPPLIES")
+    print("AND THE AMOUNT YOU RECEIVE FOR YOUR FURS WILL DEPEND")
+    print("ON THE FORT THAT YOU CHOOSE.")
+    print("")
+
+
+def get_fort_choice():
+    """Show the player the choices of Fort, get their input, if the
+    input is a valid choice (1,2,3) return it, otherwise keep
+    prompting the user."""
+    result = 0
+    while result == 0:
+        print("")
+        print("YOU MAY TRADE YOUR FURS AT FORT 1, FORT 2,")
+        print("OR FORT 3.  FORT 1 IS FORT HOCHELAGA (MONTREAL)")
+        print("AND IS UNDER THE PROTECTION OF THE FRENCH ARMY.")
+        print("FORT 2 IS FORT STADACONA (QUEBEC) AND IS UNDER THE")
+        print("PROTECTION OF THE FRENCH ARMY.  HOWEVER, YOU MUST")
+        print("MAKE A PORTAGE AND CROSS THE LACHINE RAPIDS.")
+        print("FORT 3 IS FORT NEW YORK AND IS UNDER DUTCH CONTROL.")
+        print("YOU MUST CROSS THROUGH IROQUOIS LAND.")
+        print("ANSWER 1, 2, OR 3.")
+
+        player_choice = input(">> ")  # get input from the player
+
+        # try to convert the player's string input into an integer
+        try:
+            result = int(player_choice)  # string to integer
+        except Exception:
+            # Whatever the player typed, it could not be interpreted as a number
+            pass
+
+    return result
+
+
+def show_fort_comment(which_fort):
+    """Print the description for the fort"""
+    print("")
+    if which_fort == FORT_MONTREAL:
+        print("YOU HAVE CHOSEN THE EASIEST ROUTE.  HOWEVER, THE FORT")
+        print("IS FAR FROM ANY SEAPORT.  THE VALUE")
+        print("YOU RECEIVE FOR YOUR FURS WILL BE LOW AND THE COST")
+        print("OF SUPPLIES HIGHER THAN AT FORTS STADACONA OR NEW YORK.")
+    elif which_fort == FORT_QUEBEC:
+        print("YOU HAVE CHOSEN A HARD ROUTE.  IT IS, IN COMPARSION,")
+        print("HARDER THAN THE ROUTE TO HOCHELAGA BUT EASIER THAN")
+        print("THE ROUTE TO NEW YORK.  YOU WILL RECEIVE AN AVERAGE VALUE")
+        print("FOR YOUR FURS AND THE COST OF YOUR SUPPLIES WILL BE AVERAGE.")
+    elif which_fort == FORT_NEWYORK:
+        print("YOU HAVE CHOSEN THE MOST DIFFICULT ROUTE.  AT")
+        print("FORT NEW YORK YOU WILL RECEIVE THE HIGHEST VALUE")
+        print("FOR YOUR FURS.  THE COST OF YOUR SUPPLIES")
+        print("WILL BE LOWER THAN AT ALL THE OTHER FORTS.")
+    else:
+        print("Internal error #1, fort " + str(which_fort) + " does not exist")
+        sys.exit(1)  # you have a bug
+    print("")
+
+
+def get_yes_or_no():
+    """Prompt the player to enter 'YES' or 'NO'. Keep prompting until
+    valid input is entered.  Accept various spellings by only
+    checking the first letter of input.
+    Return a single letter 'Y' or 'N'"""
+    result = 0
+    while result not in ("Y", "N"):
+        print("ANSWER YES OR NO")
+        player_choice = input(">> ")
+        player_choice = player_choice.strip().upper()  # trim spaces, make upper-case
+        if player_choice.startswith("Y"):
+            result = "Y"
+        elif player_choice.startswith("N"):
+            result = "N"
+    return result
+
+
+def get_furs_purchase():
+    """Prompt the player for how many of each fur type they want.
+    Accept numeric inputs, re-prompting on incorrect input values"""
+    results = []
+
+    print("YOUR " + str(MAX_FURS) + " FURS ARE DISTRIBUTED AMONG THE FOLLOWING")
+    print("KINDS OF PELTS: MINK, BEAVER, ERMINE AND FOX.")
+    print("")
+
+    for i in range(len(FUR_NAMES)):
+        print("HOW MANY " + FUR_NAMES[i] + " DO YOU HAVE")
+        count_str = input(">> ")
+        try:
+            count = int(count_str)
+            results.append(count)
+        except Exception:
+            # invalid input, prompt again by re-looping
+            i -= 1
+    return results
+
+
+if __name__ == "__main__":
+
+    print_at_column(31, "FUR TRADER")
+    print_at_column(15, "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print_at_column(15, "(Ported to Python Oct 2012 krt@krt.com.au)")
+    print("\n\n\n")
+
+    game_state = "starting"
+    fox_price = None  # sometimes this takes the "last" price (probably this was a bug)
+
+    while True:
+
+        if game_state == "starting":
+            show_introduction()
+
+            player_funds = 600  # Initial player start money
+            player_furs = [0, 0, 0, 0]  # Player fur inventory
+
+            print("DO YOU WISH TO TRADE FURS?")
+            should_trade = get_yes_or_no()
+            if should_trade == "N":
+                sys.exit(0)  # STOP
+            game_state = "trading"
+
+        elif game_state == "trading":
+            print("")
+            print("YOU HAVE $ %1.2f IN SAVINGS" % (player_funds))
+            print("AND " + str(MAX_FURS) + " FURS TO BEGIN THE EXPEDITION")
+            player_furs = get_furs_purchase()
+
+            if sum(player_furs) > MAX_FURS:
+                print("")
+                print("YOU MAY NOT HAVE THAT MANY FURS.")
+                print("DO NOT TRY TO CHEAT.  I CAN ADD.")
+                print("YOU MUST START AGAIN.")
+                game_state = "starting"  # T/N: Wow, harsh.
+            else:
+                game_state = "choosing fort"
+
+        elif game_state == "choosing fort":
+            which_fort = get_fort_choice()
+            show_fort_comment(which_fort)
+            print("DO YOU WANT TO TRADE AT ANOTHER FORT?")
+            change_fort = get_yes_or_no()
+            if change_fort == "N":
+                game_state = "travelling"
+
+        elif game_state == "travelling":
+            print("")
+            if which_fort == FORT_MONTREAL:
+                mink_price = (
+                    int((0.2 * random.random() + 0.70) * 100 + 0.5) / 100
+                )  # INT((.2*RND(1)+.7)*10^2+.5)/10^2
+                ermine_price = (
+                    int((0.2 * random.random() + 0.65) * 100 + 0.5) / 100
+                )  # INT((.2*RND(1)+.65)*10^2+.5)/10^2
+                beaver_price = (
+                    int((0.2 * random.random() + 0.75) * 100 + 0.5) / 100
+                )  # INT((.2*RND(1)+.75)*10^2+.5)/10^2
+                fox_price = (
+                    int((0.2 * random.random() + 0.80) * 100 + 0.5) / 100
+                )  # INT((.2*RND(1)+.8)*10^2+.5)/10^2
+
+                print("SUPPLIES AT FORT HOCHELAGA COST $150.00.")
+                print("YOUR TRAVEL EXPENSES TO HOCHELAGA WERE $10.00.")
+                player_funds -= 160
+
+            elif which_fort == FORT_QUEBEC:
+                mink_price = (
+                    int((0.30 * random.random() + 0.85) * 100 + 0.5) / 100
+                )  # INT((.3*RND(1)+.85)*10^2+.5)/10^2
+                ermine_price = (
+                    int((0.15 * random.random() + 0.80) * 100 + 0.5) / 100
+                )  # INT((.15*RND(1)+.8)*10^2+.5)/10^2
+                beaver_price = (
+                    int((0.20 * random.random() + 0.90) * 100 + 0.5) / 100
+                )  # INT((.2*RND(1)+.9)*10^2+.5)/10^2
+                fox_price = (
+                    int((0.25 * random.random() + 1.10) * 100 + 0.5) / 100
+                )  # INT((.25*RND(1)+1.1)*10^2+.5)/10^2
+                event_picker = int(10 * random.random()) + 1
+
+                if event_picker <= 2:
+                    print("YOUR BEAVER WERE TOO HEAVY TO CARRY ACROSS")
+                    print("THE PORTAGE.  YOU HAD TO LEAVE THE PELTS, BUT FOUND")
+                    print("THEM STOLEN WHEN YOU RETURNED.")
+                    player_furs[FUR_BEAVER] = 0
+                elif event_picker <= 6:
+                    print("YOU ARRIVED SAFELY AT FORT STADACONA.")
+                elif event_picker <= 8:
+                    print("YOUR CANOE UPSET IN THE LACHINE RAPIDS.  YOU")
+                    print("LOST ALL YOUR FURS.")
+                    player_furs = [0, 0, 0, 0]
+                elif event_picker <= 10:
+                    print("YOUR FOX PELTS WERE NOT CURED PROPERLY.")
+                    print("NO ONE WILL BUY THEM.")
+                    player_furs[FUR_FOX] = 0
+                else:
+                    print(
+                        "Internal Error #3, Out-of-bounds event_picker"
+                        + str(event_picker)
+                    )
+                    sys.exit(1)  # you have a bug
+
+                print("")
+                print("SUPPLIES AT FORT STADACONA COST $125.00.")
+                print("YOUR TRAVEL EXPENSES TO STADACONA WERE $15.00.")
+                player_funds -= 140
+
+            elif which_fort == FORT_NEWYORK:
+                mink_price = (
+                    int((0.15 * random.random() + 1.05) * 100 + 0.5) / 100
+                )  # INT((.15*RND(1)+1.05)*10^2+.5)/10^2
+                ermine_price = (
+                    int((0.15 * random.random() + 0.95) * 100 + 0.5) / 100
+                )  # INT((.15*RND(1)+.95)*10^2+.5)/10^2
+                beaver_price = (
+                    int((0.25 * random.random() + 1.00) * 100 + 0.5) / 100
+                )  # INT((.25*RND(1)+1.00)*10^2+.5)/10^2
+                if fox_price is None:
+                    # Original Bug?  There is no Fox price generated for New York, it will use any previous "D1" price
+                    # So if there was no previous value, make one up
+                    fox_price = (
+                        int((0.25 * random.random() + 1.05) * 100 + 0.5) / 100
+                    )  # not in orginal code
+                event_picker = int(10 * random.random()) + 1
+
+                if event_picker <= 2:
+                    print("YOU WERE ATTACKED BY A PARTY OF IROQUOIS.")
+                    print("ALL PEOPLE IN YOUR TRADING GROUP WERE")
+                    print("KILLED.  THIS ENDS THE GAME.")
+                    sys.exit(0)
+                elif event_picker <= 6:
+                    print("YOU WERE LUCKY.  YOU ARRIVED SAFELY")
+                    print("AT FORT NEW YORK.")
+                elif event_picker <= 8:
+                    print("YOU NARROWLY ESCAPED AN IROQUOIS RAIDING PARTY.")
+                    print("HOWEVER, YOU HAD TO LEAVE ALL YOUR FURS BEHIND.")
+                    player_furs = [0, 0, 0, 0]
+                elif event_picker <= 10:
+                    mink_price /= 2
+                    fox_price /= 2
+                    print("YOUR MINK AND BEAVER WERE DAMAGED ON YOUR TRIP.")
+                    print("YOU RECEIVE ONLY HALF THE CURRENT PRICE FOR THESE FURS.")
+                else:
+                    print(
+                        "Internal Error #4, Out-of-bounds event_picker"
+                        + str(event_picker)
+                    )
+                    sys.exit(1)  # you have a bug
+
+                print("")
+                print("SUPPLIES AT NEW YORK COST $85.00.")
+                print("YOUR TRAVEL EXPENSES TO NEW YORK WERE $25.00.")
+                player_funds -= 105
+
+            else:
+                print("Internal error #2, fort " + str(which_fort) + " does not exist")
+                sys.exit(1)  # you have a bug
+
+            # Calculate sales
+            beaver_value = beaver_price * player_furs[FUR_BEAVER]
+            fox_value = fox_price * player_furs[FUR_FOX]
+            ermine_value = ermine_price * player_furs[FUR_ERMINE]
+            mink_value = mink_price * player_furs[FUR_MINK]
+
+            print("")
+            print("YOUR BEAVER SOLD FOR $%6.2f" % (beaver_value))
+            print("YOUR FOX SOLD FOR    $%6.2f" % (fox_value))
+            print("YOUR ERMINE SOLD FOR $%6.2f" % (ermine_value))
+            print("YOUR MINK SOLD FOR   $%6.2f" % (mink_value))
+
+            player_funds += beaver_value + fox_value + ermine_value + mink_value
+
+            print("")
+            print(
+                "YOU NOW HAVE $ %1.2f INCLUDING YOUR PREVIOUS SAVINGS" % (player_funds)
+            )
+
+            print("")
+            print("DO YOU WANT TO TRADE FURS NEXT YEAR?")
+            should_trade = get_yes_or_no()
+            if should_trade == "N":
+                sys.exit(0)  # STOP
+            else:
+                game_state = "trading"
diff --git a/00_Alternate_Languages/38_Fur_Trader/ruby/README.md b/00_Alternate_Languages/38_Fur_Trader/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/38_Fur_Trader/vbnet/FurTrader.sln b/00_Alternate_Languages/38_Fur_Trader/vbnet/FurTrader.sln
new file mode 100644
index 00000000..cb129718
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/vbnet/FurTrader.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "FurTrader", "FurTrader.vbproj", "{D8310FB8-132A-4D43-A654-17E5A267DDBD}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D8310FB8-132A-4D43-A654-17E5A267DDBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D8310FB8-132A-4D43-A654-17E5A267DDBD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D8310FB8-132A-4D43-A654-17E5A267DDBD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D8310FB8-132A-4D43-A654-17E5A267DDBD}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/38_Fur_Trader/vbnet/FurTrader.vbproj b/00_Alternate_Languages/38_Fur_Trader/vbnet/FurTrader.vbproj
new file mode 100644
index 00000000..61ab6d99
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/vbnet/FurTrader.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    FurTrader
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/38_Fur_Trader/vbnet/README.md b/00_Alternate_Languages/38_Fur_Trader/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/38_Fur_Trader/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/39_Golf/README.md b/00_Alternate_Languages/39_Golf/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/39_Golf/csharp/Golf.csproj b/00_Alternate_Languages/39_Golf/csharp/Golf.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/csharp/Golf.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/39_Golf/csharp/Golf.sln b/00_Alternate_Languages/39_Golf/csharp/Golf.sln
new file mode 100644
index 00000000..07c90dde
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/csharp/Golf.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Golf", "Golf.csproj", "{0D91BC87-BADF-445F-876F-38F3A66A3B83}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{0D91BC87-BADF-445F-876F-38F3A66A3B83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0D91BC87-BADF-445F-876F-38F3A66A3B83}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0D91BC87-BADF-445F-876F-38F3A66A3B83}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0D91BC87-BADF-445F-876F-38F3A66A3B83}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/39_Golf/csharp/Program.cs b/00_Alternate_Languages/39_Golf/csharp/Program.cs
new file mode 100644
index 00000000..d7c51e26
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/csharp/Program.cs
@@ -0,0 +1,1142 @@
+//
+//          8""""8 8"""88 8     8""""
+//          8    " 8    8 8     8
+//          8e     8    8 8e    8eeee
+//          88  ee 8    8 88    88
+//          88   8 8    8 88    88
+//          88eee8 8eeee8 88eee 88
+//
+// GOLF
+//
+// C#
+// .NET Core
+// TargetFramework: netcoreapp 3.1
+//
+// Run source:
+// dotnet run
+//
+// Linux compile:
+// dotnet publish --self-contained -c Release -r linux-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true
+//
+// Windows compile:
+// dotnet publish -r win-x64 -c Release /p:PublishSingleFile=true
+//
+//
+// INDEX
+// ----------------- methods
+// constructor
+// NewHole
+// TeeUp
+// Stroke
+// PlotBall
+// InterpretResults
+// ReportCurrentScore
+// FindBall
+// IsOnFairway
+// IsOnGreen
+// IsInHazard
+// IsInRough
+// IsOutOfBounds
+// ScoreCardNewHole
+// ScoreCardRecordStroke
+// ScoreCardGetPreviousStroke
+// ScoreCardGetTotal
+// Ask
+// Wait
+// ReviewBag
+// Quit
+// GameOver
+// ----------------- DATA
+// Clubs
+// CourseInfo
+// ----------------- classes
+// HoleInfo
+// CircleGameObj
+// RectGameObj
+// HoleGeometry
+// Plot
+// ----------------- helper methods
+// GetDistance
+// IsInRectangle
+// ToRadians
+// ToDegrees360
+// Odds
+//
+//  Despite being a text based game, the code uses simple geometry to simulate a course.
+//  Fairways are 40 yard wide rectangles, surrounded by 5 yards of rough around the perimeter.
+//  The green is a circle of 10 yards radius around the cup.
+//  The cup is always at point (0,0).
+//
+//  Using basic trigonometry we can plot the ball's location using the distance of the stroke and
+//  and the angle of deviation (hook/slice).
+//
+//  The stroke distances are based on real world averages of different club types.
+//  Lots of randomization, "business rules", and luck influence the game play.
+//  Probabilities are commented in the code.
+//
+//  note: 'courseInfo', 'clubs', & 'scoreCard' arrays each include an empty object so indexing
+//  can begin at 1. Like all good programmers we count from zero, but in this context,
+//  it's more natural when hole number one is at index one
+//
+//
+//     |-----------------------------|
+//     |            rough            |
+//     |   ----------------------    |
+//     |   |                     |   |
+//     | r |        =  =         | r |
+//     | o |     =        =      | o |
+//     | u |    =    .     =     | u |
+//     | g |    =   green  =     | g |
+//     | h |     =        =      | h |
+//     |   |        =  =         |   |
+//     |   |                     |   |
+//     |   |                     |   |
+//     |   |      Fairway        |   |
+//     |   |                     |   |
+//     |   |               ------    |
+//     |   |            --        -- |
+//     |   |           --  hazard  --|
+//     |   |            --        -- |
+//     |   |               ------    |
+//     |   |                     |   |
+//     |   |                     |   |   out
+//     |   |                     |   |   of
+//     |   |                     |   |   bounds
+//     |   |                     |   |
+//     |   |                     |   |
+//     |            tee              |
+//
+//
+//  Typical green size: 20-30 yards
+//  Typical golf course fairways are 35 to 45 yards wide
+//  Our fairway extends 5 yards past green
+//  Our rough is a 5 yard perimeter around fairway
+//
+//  We calculate the new position of the ball given the ball's point, the distance
+//  of the stroke, and degrees off line (hook or slice).
+//
+//  Degrees off (for a right handed golfer):
+//  Slice: positive degrees = ball goes right
+//  Hook: negative degrees = left goes left
+//
+//  The cup is always at point: 0,0.
+//  We use atan2 to compute the angle between the cup and the ball.
+//  Setting the cup's vector to 0,-1 on a 360 circle is equivalent to:
+//  0 deg = 12 o'clock;  90 deg = 3 o'clock;  180 deg = 6 o'clock;  270 = 9 o'clock
+//  The reverse angle between the cup and the ball is a difference of PI (using radians).
+//
+//  Given the angle and stroke distance (hypotenuse), we use cosine to compute
+//  the opposite and adjacent sides of the triangle, which, is the ball's new position.
+//
+//           0
+//           |
+//    270 - cup - 90
+//           |
+//          180
+//
+//
+//          cup
+//           |
+//           |
+//           | opp
+//           |-----* new position
+//           |    /
+//           |   /
+//      adj  |  /
+//           | /  hyp
+//           |/
+//          tee
+//
+//    <- hook    slice ->
+//
+//
+//  Given the large number of combinations needed to describe a particular stroke / ball location,
+//  we use the technique of "bitwise masking" to describe stroke results.
+//  With bit masking, multiple flags (bits) are combined into a single binary number that can be
+//  tested by applying a mask. A mask is another binary number that isolates a particular bit that
+//  you are interested in. You can then apply your language's bitwise opeartors to test or
+//  set a flag.
+//
+//  Game design by Jason Bonthron, 2021
+//  www.bonthron.com
+//  for my father, Raymond Bonthron, an avid golfer
+//
+//  Inspired by the 1978 "Golf" from "Basic Computer Games"
+//  by Steve North, who modified an existing golf game by an unknown author
+//
+//
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Threading;
+
+
+namespace Golf
+{
+    using Ball = Golf.CircleGameObj;
+    using Hazard = Golf.CircleGameObj;
+
+    // --------------------------------------------------------------------------- Program
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            Golf g = new Golf();
+        }
+    }
+
+
+    // --------------------------------------------------------------------------- Golf
+    public class Golf
+    {
+        Ball BALL;
+        int HOLE_NUM = 0;
+        int STROKE_NUM = 0;
+        int Handicap = 0;
+        int PlayerDifficulty = 0;
+        HoleGeometry holeGeometry;
+
+        // all fairways are 40 yards wide, extend 5 yards beyond the cup, and
+        // have 5 yards of rough around the perimeter
+        const int FairwayWidth = 40;
+        const int FairwayExtension = 5;
+        const int RoughAmt = 5;
+
+        // ScoreCard records the ball position after each stroke
+        // a new list for each hole
+        // include a blank list so index 1 == hole 1
+
+        List> ScoreCard = new List> { new List() };
+
+        static void w(string s) { Console.WriteLine(s); } // WRITE
+        Random RANDOM = new Random();
+
+
+        // --------------------------------------------------------------- constructor
+        public Golf()
+        {
+            Console.Clear();
+            w(" ");
+            w("          8\"\"\"\"8 8\"\"\"88 8     8\"\"\"\" ");
+            w("          8    \" 8    8 8     8     ");
+            w("          8e     8    8 8e    8eeee ");
+            w("          88  ee 8    8 88    88    ");
+            w("          88   8 8    8 88    88    ");
+            w("          88eee8 8eeee8 88eee 88    ");
+            w(" ");
+            w("Welcome to the Creative Computing Country Club,");
+            w("an eighteen hole championship layout located a short");
+            w("distance from scenic downtown Lambertville, New Jersey.");
+            w("The game will be explained as you play.");
+            w("Enjoy your game! See you at the 19th hole...");
+            w(" ");
+            w("Type QUIT at any time to leave the game.");
+            w("Type BAG at any time to review the clubs in your bag.");
+            w(" ");
+
+            Wait((z) =>
+            {
+                w(" ");
+                w("              YOUR BAG");
+                ReviewBag();
+                w("Type BAG at any time to review the clubs in your bag.");
+                w(" ");
+
+                Wait((zz) =>
+                {
+                    w(" ");
+
+                    Ask("PGA handicaps range from 0 to 30.\nWhat is your handicap?", 0, 30, (i) =>
+                    {
+                        Handicap = i;
+                        w(" ");
+
+                        Ask("Common difficulties at golf include:\n1=Hook, 2=Slice, 3=Poor Distance, 4=Trap Shots, 5=Putting\nWhich one is your worst?", 1, 5, (j) =>
+                        {
+                            PlayerDifficulty = j;
+                            Console.Clear();
+                            NewHole();
+                        });
+                    });
+                });
+            });
+        }
+
+
+        // --------------------------------------------------------------- NewHole
+        void NewHole()
+        {
+            HOLE_NUM++;
+            STROKE_NUM = 0;
+
+            HoleInfo info = CourseInfo[HOLE_NUM];
+
+            int yards = info.Yards;  // from tee to cup
+            int par = info.Par;
+            var cup = new CircleGameObj(0, 0, 0, GameObjType.CUP);
+            var green = new CircleGameObj(0, 0, 10, GameObjType.GREEN);
+
+            var fairway = new RectGameObj(0 - (FairwayWidth / 2),
+                                          0 - (green.Radius + FairwayExtension),
+                                          FairwayWidth,
+                                          yards + (green.Radius + FairwayExtension) + 1,
+                                          GameObjType.FAIRWAY);
+
+            var rough = new RectGameObj(fairway.X - RoughAmt,
+                                        fairway.Y - RoughAmt,
+                                        fairway.Width + (2 * RoughAmt),
+                                        fairway.Length + (2 * RoughAmt),
+                                        GameObjType.ROUGH);
+
+            BALL = new Ball(0, yards, 0, GameObjType.BALL);
+
+            ScoreCardStartNewHole();
+
+            holeGeometry = new HoleGeometry(cup, green, fairway, rough, info.Hazard);
+
+            w("                |> " + HOLE_NUM);
+            w("                |        ");
+            w("                |        ");
+            w("          ^^^^^^^^^^^^^^^");
+
+            Console.WriteLine("Hole #{0}. You are at the tee. Distance {1} yards, par {2}.", HOLE_NUM, info.Yards, info.Par);
+            w(info.Description);
+
+            TeeUp();
+        }
+
+
+        // --------------------------------------------------------------- TeeUp
+        // on the green? automatically select putter
+        // otherwise Ask club and swing strength
+
+        void TeeUp()
+        {
+            if (IsOnGreen(BALL) && !IsInHazard(BALL, GameObjType.SAND))
+            {
+                var putt = 10;
+                w("[PUTTER: average 10 yards]");
+                var msg = Odds(20) ? "Keep your head down.\n" : "";
+
+                Ask(msg + "Choose your putt potency. (1-10)", 1, 10, (strength) =>
+                {
+                    var putter = Clubs[putt];
+                    Stroke(Convert.ToDouble((double)putter.Item2 * ((double)strength / 10.0)), putt);
+                });
+            }
+            else
+            {
+                Ask("What club do you choose? (1-10)", 1, 10, (c) =>
+                {
+                    var club = Clubs[c];
+
+                    w(" ");
+                    Console.WriteLine("[{0}: average {1} yards]", club.Item1.ToUpper(), club.Item2);
+
+                    Ask("Now gauge your distance by a percentage of a full swing. (1-10)", 1, 10, (strength) =>
+                    {
+                        Stroke(Convert.ToDouble((double)club.Item2 * ((double)strength / 10.0)), c);
+                    });
+                });
+            };
+        }
+
+
+        // -------------------------------------------------------- bitwise Flags
+        int dub         = 0b00000000000001;
+        int hook        = 0b00000000000010;
+        int slice       = 0b00000000000100;
+        int passedCup   = 0b00000000001000;
+        int inCup       = 0b00000000010000;
+        int onFairway   = 0b00000000100000;
+        int onGreen     = 0b00000001000000;
+        int inRough     = 0b00000010000000;
+        int inSand      = 0b00000100000000;
+        int inTrees     = 0b00001000000000;
+        int inWater     = 0b00010000000000;
+        int outOfBounds = 0b00100000000000;
+        int luck        = 0b01000000000000;
+        int ace         = 0b10000000000000;
+
+
+        // --------------------------------------------------------------- Stroke
+        void Stroke(double clubAmt, int clubIndex)
+        {
+            STROKE_NUM++;
+
+            var flags = 0b000000000000;
+
+            // fore! only when driving
+            if ((STROKE_NUM == 1) && (clubAmt > 210) && Odds(30)) { w("\"...Fore !\""); };
+
+            // dub
+            if (Odds(5)) { flags |= dub; }; // there's always a 5% chance of dubbing it
+
+            // if you're in the rough, or sand, you really should be using a wedge
+            if ((IsInRough(BALL) || IsInHazard(BALL, GameObjType.SAND)) &&
+                !(clubIndex == 8 || clubIndex == 9))
+            {
+                if (Odds(40)) { flags |= dub; };
+            };
+
+            // trap difficulty
+            if (IsInHazard(BALL, GameObjType.SAND) && PlayerDifficulty == 4)
+            {
+                if (Odds(20)) { flags |= dub; };
+            }
+
+            // hook/slice
+            // There's 10% chance of a hook or slice
+            // if it's a known playerDifficulty then increase chance to 30%
+            // if it's a putt & putting is a playerDifficulty increase to 30%
+
+            bool randHookSlice = (PlayerDifficulty == 1 ||
+                                  PlayerDifficulty == 2 ||
+                                  (PlayerDifficulty == 5 && IsOnGreen(BALL))) ? Odds(30) : Odds(10);
+
+            if (randHookSlice)
+            {
+                if (PlayerDifficulty == 1)
+                {
+                    if (Odds(80)) { flags |= hook; } else { flags |= slice; };
+                }
+                else if (PlayerDifficulty == 2)
+                {
+                    if (Odds(80)) { flags |= slice; } else { flags |= hook; };
+                }
+                else
+                {
+                    if (Odds(50)) { flags |= hook; } else { flags |= slice; };
+                };
+            };
+
+            // beginner's luck !
+            // If handicap is greater than 15, there's a 10% chance of avoiding all errors
+            if ((Handicap > 15) && (Odds(10))) { flags |= luck; };
+
+            // ace
+            // there's a 10% chance of an Ace on a par 3
+            if (CourseInfo[HOLE_NUM].Par == 3 && Odds(10) && STROKE_NUM == 1) { flags |= ace; };
+
+            // distance:
+            // If handicap is < 15, there a 50% chance of reaching club average,
+            // a 25% of exceeding it, and a 25% of falling short
+            // If handicap is > 15, there's a 25% chance of reaching club average,
+            // and 75% chance of falling short
+            // The greater the handicap, the more the ball falls short
+            // If poor distance is a known playerDifficulty, then reduce distance by 10%
+
+            double distance;
+            int rnd = RANDOM.Next(1, 101);
+
+            if (Handicap < 15)
+            {
+                if (rnd <= 25)
+                {
+                    distance = clubAmt - (clubAmt * ((double)Handicap / 100.0));
+                }
+                else if (rnd > 25 && rnd <= 75)
+                {
+                    distance = clubAmt;
+                }
+                else
+                {
+                    distance = clubAmt + (clubAmt * 0.10);
+                };
+            }
+            else
+            {
+                if (rnd <= 75)
+                {
+                    distance = clubAmt - (clubAmt * ((double)Handicap / 100.0));
+                }
+                else
+                {
+                    distance = clubAmt;
+                };
+            };
+
+            if (PlayerDifficulty == 3)  // poor distance
+            {
+                if (Odds(80)) { distance = (distance * 0.80); };
+            };
+
+            if ((flags & luck) == luck) { distance = clubAmt; }
+
+            // angle
+            // For all strokes, there's a possible "drift" of 4 degrees
+            // a hooks or slice increases the angle between 5-10 degrees, hook uses negative degrees
+            int angle = RANDOM.Next(0, 5);
+            if ((flags & slice) == slice) { angle = RANDOM.Next(5, 11); };
+            if ((flags & hook) == hook) { angle = 0 - RANDOM.Next(5, 11); };
+            if ((flags & luck) == luck) { angle = 0; };
+
+            var plot = PlotBall(BALL, distance, Convert.ToDouble(angle));  // calculate a new location
+            if ((flags & luck) == luck) { if(plot.Y > 0){ plot.Y = 2; }; };
+
+            flags = FindBall(new Ball(plot.X, plot.Y, plot.Offline, GameObjType.BALL), flags);
+
+            InterpretResults(plot, flags);
+        }
+
+
+        // --------------------------------------------------------------- plotBall
+        Plot PlotBall(Ball ball, double strokeDistance, double degreesOff)
+        {
+            var cupVector = new Point(0, -1);
+            double radFromCup = Math.Atan2((double)ball.Y, (double)ball.X) - Math.Atan2((double)cupVector.Y, (double)cupVector.X);
+            double radFromBall = radFromCup - Math.PI;
+
+            var hypotenuse = strokeDistance;
+            var adjacent = Math.Cos(radFromBall + ToRadians(degreesOff)) * hypotenuse;
+            var opposite = Math.Sqrt(Math.Pow(hypotenuse, 2) - Math.Pow(adjacent, 2));
+
+            Point newPos;
+            if (ToDegrees360(radFromBall + ToRadians(degreesOff)) > 180)
+            {
+                newPos = new Point(Convert.ToInt32(ball.X - opposite),
+                                   Convert.ToInt32(ball.Y - adjacent));
+            }
+            else
+            {
+                newPos = new Point(Convert.ToInt32(ball.X + opposite),
+                                   Convert.ToInt32(ball.Y - adjacent));
+            }
+
+            return new Plot(newPos.X, newPos.Y, Convert.ToInt32(opposite));
+        }
+
+
+        // --------------------------------------------------------------- InterpretResults
+        void InterpretResults(Plot plot, int flags)
+        {
+            int cupDistance = Convert.ToInt32(GetDistance(new Point(plot.X, plot.Y),
+                                                          new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y)));
+            int travelDistance = Convert.ToInt32(GetDistance(new Point(plot.X, plot.Y),
+                                                             new Point(BALL.X, BALL.Y)));
+
+            w(" ");
+
+            if ((flags & ace) == ace)
+            {
+                w("Hole in One! You aced it.");
+                ScoreCardRecordStroke(new Ball(0, 0, 0, GameObjType.BALL));
+                ReportCurrentScore();
+                return;
+            };
+
+            if ((flags & inTrees) == inTrees)
+            {
+                w("Your ball is lost in the trees. Take a penalty stroke.");
+                ScoreCardRecordStroke(BALL);
+                TeeUp();
+                return;
+            };
+
+            if ((flags & inWater) == inWater)
+            {
+                var msg = Odds(50) ? "Your ball has gone to a watery grave." : "Your ball is lost in the water.";
+                w(msg + " Take a penalty stroke.");
+                ScoreCardRecordStroke(BALL);
+                TeeUp();
+                return;
+            };
+
+            if ((flags & outOfBounds) == outOfBounds)
+            {
+                w("Out of bounds. Take a penalty stroke.");
+                ScoreCardRecordStroke(BALL);
+                TeeUp();
+                return;
+            };
+
+            if ((flags & dub) == dub)
+            {
+                w("You dubbed it.");
+                ScoreCardRecordStroke(BALL);
+                TeeUp();
+                return;
+            };
+
+            if ((flags & inCup) == inCup)
+            {
+                var msg = Odds(50) ? "You holed it." : "It's in!";
+                w(msg);
+                ScoreCardRecordStroke(new Ball(plot.X, plot.Y, 0, GameObjType.BALL));
+                ReportCurrentScore();
+                return;
+            };
+
+            if (((flags & slice) == slice) &&
+                !((flags & onGreen) == onGreen))
+            {
+                var bad = ((flags & outOfBounds) == outOfBounds) ? " badly" : "";
+                Console.WriteLine("You sliced{0}: {1} yards offline.", bad, plot.Offline);
+            };
+
+            if (((flags & hook) == hook) &&
+                !((flags & onGreen) == onGreen))
+            {
+                var bad = ((flags & outOfBounds) == outOfBounds) ? " badly" : "";
+                Console.WriteLine("You hooked{0}: {1} yards offline.", bad, plot.Offline);
+            };
+
+            if (STROKE_NUM > 1)
+            {
+                var prevBall = ScoreCardGetPreviousStroke();
+                var d1 = GetDistance(new Point(prevBall.X, prevBall.Y),
+                                     new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y));
+                var d2 = cupDistance;
+                if (d2 > d1) { w("Too much club."); };
+            };
+
+            if ((flags & inRough) == inRough) { w("You're in the rough."); };
+
+            if ((flags & inSand) == inSand) { w("You're in a sand trap."); };
+
+            if ((flags & onGreen) == onGreen)
+            {
+                var pd = (cupDistance < 4) ? ((cupDistance * 3) + " feet") : (cupDistance + " yards");
+                Console.WriteLine("You're on the green. It's {0} from the pin.", pd);
+            };
+
+            if (((flags & onFairway) == onFairway) ||
+                ((flags & inRough) == inRough))
+            {
+                Console.WriteLine("Shot went {0} yards. It's {1} yards from the cup.", travelDistance, cupDistance);
+            };
+
+            ScoreCardRecordStroke(new Ball(plot.X, plot.Y, 0, GameObjType.BALL));
+
+            BALL = new Ball(plot.X, plot.Y, 0, GameObjType.BALL);
+
+            TeeUp();
+        }
+
+
+        // --------------------------------------------------------------- ReportCurrentScore
+        void ReportCurrentScore()
+        {
+            var par = CourseInfo[HOLE_NUM].Par;
+            if (ScoreCard[HOLE_NUM].Count == par + 1) { w("A bogey. One above par."); };
+            if (ScoreCard[HOLE_NUM].Count == par) { w("Par. Nice."); };
+            if (ScoreCard[HOLE_NUM].Count == (par - 1)) { w("A birdie! One below par."); };
+            if (ScoreCard[HOLE_NUM].Count == (par - 2)) { w("An Eagle! Two below par."); };
+            if (ScoreCard[HOLE_NUM].Count == (par - 3)) { w("Double Eagle! Unbelievable."); };
+
+            int totalPar = 0;
+            for (var i = 1; i <= HOLE_NUM; i++) { totalPar += CourseInfo[i].Par; };
+
+            w(" ");
+            w("-----------------------------------------------------");
+            Console.WriteLine(" Total par for {0} hole{1} is: {2}. Your total is: {3}.",
+                              HOLE_NUM,
+                              ((HOLE_NUM > 1) ? "s" : ""), //plural
+                              totalPar,
+                              ScoreCardGetTotal());
+            w("-----------------------------------------------------");
+            w(" ");
+
+            if (HOLE_NUM == 18)
+            {
+                GameOver();
+            }
+            else
+            {
+                Thread.Sleep(2000);
+                NewHole();
+            };
+        }
+
+
+        // --------------------------------------------------------------- FindBall
+        int FindBall(Ball ball, int flags)
+        {
+            if (IsOnFairway(ball) && !IsOnGreen(ball)) { flags |= onFairway; }
+            if (IsOnGreen(ball)) { flags |= onGreen; }
+            if (IsInRough(ball)) { flags |= inRough; }
+            if (IsOutOfBounds(ball)) { flags |= outOfBounds; }
+            if (IsInHazard(ball, GameObjType.WATER)) { flags |= inWater; }
+            if (IsInHazard(ball, GameObjType.TREES)) { flags |= inTrees; }
+            if (IsInHazard(ball, GameObjType.SAND))  { flags |= inSand;  }
+
+            if (ball.Y < 0) { flags |= passedCup; }
+
+            // less than 2, it's in the cup
+            var d = GetDistance(new Point(ball.X, ball.Y),
+                                new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y));
+            if (d < 2) { flags |= inCup; };
+
+            return flags;
+        }
+
+
+        // --------------------------------------------------------------- IsOnFairway
+        bool IsOnFairway(Ball ball)
+        {
+            return IsInRectangle(ball, holeGeometry.Fairway);
+        }
+
+
+        // --------------------------------------------------------------- IsOngreen
+        bool IsOnGreen(Ball ball)
+        {
+            var d = GetDistance(new Point(ball.X, ball.Y),
+                                new Point(holeGeometry.Cup.X, holeGeometry.Cup.Y));
+            return d < holeGeometry.Green.Radius;
+        }
+
+
+        // --------------------------------------------------------------- IsInHazard
+        bool IsInHazard(Ball ball, GameObjType hazard)
+        {
+            bool result = false;
+            Array.ForEach(holeGeometry.Hazards, (Hazard h) =>
+            {
+                var d = GetDistance(new Point(ball.X, ball.Y), new Point(h.X, h.Y));
+                if ((d < h.Radius) && h.Type == hazard) { result = true; };
+            });
+            return result;
+        }
+
+
+        // --------------------------------------------------------------- IsInRough
+        bool IsInRough(Ball ball)
+        {
+            return IsInRectangle(ball, holeGeometry.Rough) &&
+                (IsInRectangle(ball, holeGeometry.Fairway) == false);
+        }
+
+
+        // --------------------------------------------------------------- IsOutOfBounds
+        bool IsOutOfBounds(Ball ball)
+        {
+            return (IsOnFairway(ball) == false) && (IsInRough(ball) == false);
+        }
+
+
+        // --------------------------------------------------------------- ScoreCardNewHole
+        void ScoreCardStartNewHole()
+        {
+            ScoreCard.Add(new List());
+        }
+
+
+        // --------------------------------------------------------------- ScoreCardRecordStroke
+        void ScoreCardRecordStroke(Ball ball)
+        {
+            var clone = new Ball(ball.X, ball.Y, 0, GameObjType.BALL);
+            ScoreCard[HOLE_NUM].Add(clone);
+        }
+
+
+        // ------------------------------------------------------------ ScoreCardGetPreviousStroke
+        Ball ScoreCardGetPreviousStroke()
+        {
+            return ScoreCard[HOLE_NUM][ScoreCard[HOLE_NUM].Count - 1];
+        }
+
+
+        // --------------------------------------------------------------- ScoreCardGetTotal
+        int ScoreCardGetTotal()
+        {
+            int total = 0;
+            ScoreCard.ForEach((h) => { total += h.Count; });
+            return total;
+        }
+
+
+        // --------------------------------------------------------------- Ask
+        // input from console is always an integer passed to a callback
+        // or "quit" to end game
+
+        void Ask(string question, int min, int max, Action callback)
+        {
+            w(question);
+            string i = Console.ReadLine().Trim().ToLower();
+            if (i == "quit") { Quit(); return; };
+            if (i == "bag") { ReviewBag(); };
+
+            int n;
+            bool success = Int32.TryParse(i, out n);
+
+            if (success)
+            {
+                if (n >= min && n <= max)
+                {
+                    callback(n);
+                }
+                else
+                {
+                    Ask(question, min, max, callback);
+                }
+            }
+            else
+            {
+                Ask(question, min, max, callback);
+            };
+        }
+
+
+        // --------------------------------------------------------------- Wait
+        void Wait(Action callback)
+        {
+            w("Press any key to continue.");
+
+            ConsoleKeyInfo keyinfo;
+            do { keyinfo = Console.ReadKey(true); }
+            while (keyinfo.KeyChar < 0);
+            Console.Clear();
+            callback(0);
+        }
+
+
+        // --------------------------------------------------------------- ReviewBag
+        void ReviewBag()
+        {
+            w(" ");
+            w("  #     Club      Average Yardage");
+            w("-----------------------------------");
+            w("  1    Driver           250");
+            w("  2    3 Wood           225");
+            w("  3    5 Wood           200");
+            w("  4    Hybrid           190");
+            w("  5    4 Iron           170");
+            w("  6    7 Iron           150");
+            w("  7    9 Iron           125");
+            w("  8    Pitching wedge   110");
+            w("  9    Sand wedge        75");
+            w(" 10    Putter            10");
+            w(" ");
+        }
+
+
+        // --------------------------------------------------------------- Quit
+        void Quit()
+        {
+            w("");
+            w("Looks like rain. Goodbye!");
+            w("");
+            Wait((z) => { });
+            return;
+        }
+
+
+        // --------------------------------------------------------------- GameOver
+        void GameOver()
+        {
+            var net = ScoreCardGetTotal() - Handicap;
+            w("Good game!");
+            w("Your net score is: " + net);
+            w("Let's visit the pro shop...");
+            w(" ");
+            Wait((z) => { });
+            return;
+        }
+
+
+        // YOUR BAG
+        // ======================================================== Clubs
+        (string, int)[] Clubs = new (string, int)[] {
+            ("",0),
+
+                // name, average yardage
+                ("Driver", 250),
+                ("3 Wood", 225),
+                ("5 Wood", 200),
+                ("Hybrid", 190),
+                ("4 Iron", 170),
+                ("7 Iron", 150),
+                ("9 Iron", 125),
+                ("Pitching wedge", 110),
+                ("Sand wedge", 75),
+                ("Putter", 10)
+                };
+
+
+        // THE COURSE
+        // ======================================================== CourseInfo
+
+        HoleInfo[] CourseInfo = new HoleInfo[]{
+            new HoleInfo(0, 0, 0, new Hazard[]{}, ""), // include a blank so index 1 == hole 1
+
+
+            // -------------------------------------------------------- front 9
+            // hole, yards, par, hazards, (description)
+
+            new HoleInfo(1, 361, 4,
+                         new Hazard[]{
+                             new Hazard( 20, 100, 10, GameObjType.TREES),
+                             new Hazard(-20,  80, 10, GameObjType.TREES),
+                             new Hazard(-20, 100, 10, GameObjType.TREES)
+                         },
+                         "There are a couple of trees on the left and right."),
+
+            new HoleInfo(2, 389, 4,
+                         new Hazard[]{
+                             new Hazard(0, 160, 20, GameObjType.WATER)
+                         },
+                         "There is a large water hazard across the fairway about 150 yards."),
+
+            new HoleInfo(3, 206, 3,
+                         new Hazard[]{
+                             new Hazard( 20,  20,  5, GameObjType.WATER),
+                             new Hazard(-20, 160, 10, GameObjType.WATER),
+                             new Hazard( 10,  12,  5, GameObjType.SAND)
+                         },
+                         "There is some sand and water near the green."),
+
+            new HoleInfo(4, 500, 5,
+                         new Hazard[]{
+                             new Hazard(-14, 12, 12, GameObjType.SAND)
+                         },
+                         "There's a bunker to the left of the green."),
+
+            new HoleInfo(5, 408, 4,
+                         new Hazard[]{
+                             new Hazard(20, 120, 20, GameObjType.TREES),
+                             new Hazard(20, 160, 20, GameObjType.TREES),
+                             new Hazard(10,  20,  5, GameObjType.SAND)
+                         },
+                         "There are some trees to your right."),
+
+            new HoleInfo(6, 359, 4,
+                         new Hazard[]{
+                             new Hazard( 14, 0, 4, GameObjType.SAND),
+                             new Hazard(-14, 0, 4, GameObjType.SAND)
+                         },
+                         ""),
+
+            new HoleInfo(7, 424, 5,
+                         new Hazard[]{
+                             new Hazard(20, 200, 10, GameObjType.SAND),
+                             new Hazard(10, 180, 10, GameObjType.SAND),
+                             new Hazard(20, 160, 10, GameObjType.SAND)
+                         },
+                         "There are several sand traps along your right."),
+
+            new HoleInfo(8, 388, 4,
+                         new Hazard[]{
+                             new Hazard(-20, 340, 10, GameObjType.TREES)
+                         },
+                         ""),
+
+            new HoleInfo(9, 196, 3,
+                         new Hazard[]{
+                             new Hazard(-30, 180, 20, GameObjType.TREES),
+                             new Hazard( 14,  -8,  5, GameObjType.SAND)
+                         },
+                         ""),
+
+            // -------------------------------------------------------- back 9
+            // hole, yards, par, hazards, (description)
+
+            new HoleInfo(10, 400, 4,
+                         new Hazard[]{
+                             new Hazard(-14, -8, 5, GameObjType.SAND),
+                             new Hazard( 14, -8, 5, GameObjType.SAND)
+                         },
+                         ""),
+
+            new HoleInfo(11, 560, 5,
+                         new Hazard[]{
+                             new Hazard(-20, 400, 10, GameObjType.TREES),
+                             new Hazard(-10, 380, 10, GameObjType.TREES),
+                             new Hazard(-20, 260, 10, GameObjType.TREES),
+                             new Hazard(-20, 200, 10, GameObjType.TREES),
+                             new Hazard(-10, 180, 10, GameObjType.TREES),
+                             new Hazard(-20, 160, 10, GameObjType.TREES)
+                         },
+                         "Lots of trees along the left of the fairway."),
+
+            new HoleInfo(12, 132, 3,
+                         new Hazard[]{
+                             new Hazard(-10, 120, 10, GameObjType.WATER),
+                             new Hazard( -5, 100, 10, GameObjType.SAND)
+                         },
+                         "There is water and sand directly in front of you. A good drive should clear both."),
+
+            new HoleInfo(13, 357, 4,
+                         new Hazard[]{
+                             new Hazard(-20, 200, 10, GameObjType.TREES),
+                             new Hazard(-10, 180, 10, GameObjType.TREES),
+                             new Hazard(-20, 160, 10, GameObjType.TREES),
+                             new Hazard( 14,  12,  8, GameObjType.SAND)
+                         },
+                         ""),
+
+            new HoleInfo(14, 294, 4,
+                         new Hazard[]{
+                             new Hazard(0, 20, 10, GameObjType.SAND)
+                         },
+                         ""),
+
+            new HoleInfo(15, 475, 5,
+                         new Hazard[]{
+                             new Hazard(-20, 20, 10, GameObjType.WATER),
+                             new Hazard( 10, 20, 10, GameObjType.SAND)
+                         },
+                         "Some sand and water near the green."),
+
+            new HoleInfo(16, 375, 4,
+                         new Hazard[]{
+                             new Hazard(-14, -8, 5, GameObjType.SAND)
+                         },
+                         ""),
+
+            new HoleInfo(17, 180, 3,
+                         new Hazard[]{
+                             new Hazard( 20, 100, 10, GameObjType.TREES),
+                             new Hazard(-20,  80, 10, GameObjType.TREES)
+                         },
+                         ""),
+
+            new HoleInfo(18, 550, 5,
+                         new Hazard[]{
+                             new Hazard(20, 30, 15, GameObjType.WATER)
+                         },
+                         "There is a water hazard near the green.")
+        };
+
+
+        // -------------------------------------------------------- HoleInfo
+        class HoleInfo
+        {
+            public int Hole { get; }
+            public int Yards { get; }
+            public int Par { get; }
+            public Hazard[] Hazard { get; }
+            public string Description { get; }
+
+            public HoleInfo(int hole, int yards, int par, Hazard[] hazard, string description)
+            {
+                Hole = hole;
+                Yards = yards;
+                Par = par;
+                Hazard = hazard;
+                Description = description;
+            }
+        }
+
+
+        public enum GameObjType { BALL, CUP, GREEN, FAIRWAY, ROUGH, TREES, WATER, SAND }
+
+
+        // -------------------------------------------------------- CircleGameObj
+        public class CircleGameObj
+        {
+            public GameObjType Type { get; }
+            public int X { get; }
+            public int Y { get; }
+            public int Radius { get; }
+
+            public CircleGameObj(int x, int y, int r, GameObjType type)
+            {
+                Type = type;
+                X = x;
+                Y = y;
+                Radius = r;
+            }
+        }
+
+
+        // -------------------------------------------------------- RectGameObj
+        public class RectGameObj
+        {
+            public GameObjType Type { get; }
+            public int X { get; }
+            public int Y { get; }
+            public int Width { get; }
+            public int Length { get; }
+
+            public RectGameObj(int x, int y, int w, int l, GameObjType type)
+            {
+                Type = type;
+                X = x;
+                Y = y;
+                Width = w;
+                Length = l;
+            }
+        }
+
+
+        // -------------------------------------------------------- HoleGeometry
+        public class HoleGeometry
+        {
+            public CircleGameObj Cup { get; }
+            public CircleGameObj Green { get; }
+            public RectGameObj Fairway { get; }
+            public RectGameObj Rough { get; }
+            public Hazard[] Hazards { get; }
+
+            public HoleGeometry(CircleGameObj cup, CircleGameObj green, RectGameObj fairway, RectGameObj rough, Hazard[] haz)
+            {
+                Cup = cup;
+                Green = green;
+                Fairway = fairway;
+                Rough = rough;
+                Hazards = haz;
+            }
+        }
+
+
+        // -------------------------------------------------------- Plot
+        public class Plot
+        {
+            public int X { get; }
+            public int Y { get; set; }
+            public int Offline { get; }
+
+            public Plot(int x, int y, int offline)
+            {
+                X = x;
+                Y = y;
+                Offline = offline;
+            }
+        }
+
+
+        // -------------------------------------------------------- GetDistance
+        // distance between 2 points
+        double GetDistance(Point pt1, Point pt2)
+        {
+            return Math.Sqrt(Math.Pow((pt2.X - pt1.X), 2) + Math.Pow((pt2.Y - pt1.Y), 2));
+        }
+
+
+        // -------------------------------------------------------- IsInRectangle
+        bool IsInRectangle(CircleGameObj pt, RectGameObj rect)
+        {
+            return ((pt.X > rect.X) &&
+                    (pt.X < rect.X + rect.Width) &&
+                    (pt.Y > rect.Y) &&
+                    (pt.Y < rect.Y + rect.Length));
+        }
+
+
+        // -------------------------------------------------------- ToRadians
+        double ToRadians(double angle) { return angle * (Math.PI / 180.0); }
+
+
+        // -------------------------------------------------------- ToDegrees360
+        // radians to 360 degrees
+        double ToDegrees360(double angle)
+        {
+            double deg = angle * (180.0 / Math.PI);
+            if (deg < 0.0) { deg += 360.0; }
+            return deg;
+        }
+
+
+        // -------------------------------------------------------- Odds
+        // chance an integer is <= the given argument
+        // between 1-100
+        Random RND = new Random();
+
+        bool Odds(int x)
+        {
+            return RND.Next(1, 101) <= x;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/39_Golf/csharp/README.md b/00_Alternate_Languages/39_Golf/csharp/README.md
new file mode 100644
index 00000000..c632babb
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/csharp/README.md
@@ -0,0 +1,10 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
+
+There are 2 compiled executables in the compiled/ directory (windows and linux) that you can play right away!
+
+Program.cs contains the C# source code.
+It has been written for .NET Core 3.1
+
+The source code is well documented.
diff --git a/00_Alternate_Languages/39_Golf/golf.bas b/00_Alternate_Languages/39_Golf/golf.bas
new file mode 100644
index 00000000..ae135741
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/golf.bas
@@ -0,0 +1,244 @@
+1 PRINT TAB(34);"GOLF"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+4 PRINT "WELCOME TO THE CREATIVE COMPUTING COUNTRY CLUB,"
+5 PRINT "AN EIGHTEEN HOLE CHAMPIONSHIP LAYOUT LOCATED A SHORT"
+6 PRINT "DISTANCE FROM SCENIC DOWNTOWN MORRISTOWN.  THE"
+7 PRINT "COMMENTATOR WILL EXPLAIN THE GAME AS YOU PLAY."
+8 PRINT "ENJOY YOUR GAME; SEE YOU AT THE 19TH HOLE..."
+9 PRINT:PRINT: DIM L(10)
+10 G1=18
+20 G2=0
+30 G3=0
+40 A=0
+50 N=.8
+60 S2=0
+70 F=1
+80 PRINT "WHAT IS YOUR HANDICAP";
+90 INPUT H:PRINT
+100 IF H>30 THEN 470
+110 IF H<0 THEN 470
+120 PRINT "DIFFICULTIES AT GOLF INCLUDE:"
+130 PRINT "0=HOOK, 1=SLICE, 2=POOR DISTANCE, 4=TRAP SHOTS, 5=PUTTING"
+140 PRINT "WHICH ONE (ONLY ONE) IS YOUR WORST";
+150 INPUT T:PRINT
+160 IF T>5 THEN 120
+170 S1=0
+210 REM
+230 L(0)=0
+240 J=0
+245 Q=0
+250 S2=S2+1
+260 K=0
+270 IF F=1 THEN 310
+290 PRINT "YOUR SCORE ON HOLE";F-1;"WAS";S1
+291 GOTO 1750
+292 IF S1>P+2 THEN 297
+293 IF S1=P THEN 299
+294 IF S1=P-1 THEN 301
+295 IF S1=P-2 THEN 303
+296 GOTO 310
+297 PRINT "KEEP YOUR HEAD DOWN."
+298 GOTO 310
+299 PRINT "A PAR.  NICE GOING."
+300 GOTO 310
+301 PRINT "A BIRDIE."
+302 GOTO 310
+303 IF P=3 THEN 306
+304 PRINT "A GREAT BIG EAGLE."
+305 GOTO 310
+306 PRINT "A HOLE IN ONE."
+310 IF F=19 THEN 1710
+315 S1=0
+316 PRINT
+320 IF S1=0 THEN 1590
+330 IF L(0)<1 THEN 1150
+340 X=0
+350 IF L(0)>5 THEN 1190
+360 PRINT "SHOT WENT";D1;"YARDS.  IT'S";D2;"YARDS FROM THE CUP."
+362 PRINT "BALL IS";INT(O);"YARDS OFF LINE... IN ";
+380 GOSUB 400
+390 GOTO 620
+400 IF L(X)=1 THEN 480
+410 IF L(X)=2 THEN 500
+420 IF L(X)=3 THEN 520
+430 IF L(X)=4 THEN 540
+440 IF L(X)=5 THEN 560
+450 IF L(X)=6 THEN 580
+460 PRINT "OUT OF BOUNDS."
+465 GOTO 1690
+470 PRINT "PGA HANDICAPS RANGE FROM 0 TO 30."
+472 GOTO 80
+480 PRINT "FAIRWAY."
+490 GOTO 1690
+500 PRINT "ROUGH."
+510 GOTO 1690
+520 PRINT "TREES."
+530 GOTO 1690
+540 PRINT "ADJACENT FAIRWAY."
+550 GOTO 1690
+560 PRINT "TRAP."
+570 GOTO 1690
+580 PRINT "WATER."
+590 GOTO 1690
+620 IF A=1 THEN 629
+621 PRINT "SELECTION OF CLUBS"
+622 PRINT "YARDAGE DESIRED                       SUGGESTED CLUBS"
+623 PRINT "200 TO 280 YARDS                           1 TO 4"
+624 PRINT "100 TO 200 YARDS                          19 TO 13"
+625 PRINT "  0 TO 100 YARDS                          29 TO 23"
+626 A=1
+629 PRINT "WHAT CLUB DO YOU CHOOSE";
+630 INPUT C
+632 PRINT
+635 IF C<1 THEN 690
+637 IF C>29 THEN 690
+640 IF C>4 THEN 710
+650 IF L(0)<=5 THEN 740
+660 IF C=14 THEN 740
+665 IF C=23 THEN 740
+670 GOTO 690
+680 S1=S1-1
+690 PRINT "THAT CLUB IS NOT IN THE BAG."
+693 PRINT
+700 GOTO 620
+710 IF C<12 THEN 690
+720 C=C-6
+730 GOTO 650
+740 S1=S1+1
+741 W=1
+742 IF C>13 THEN 960
+746 IF INT(F/3)=F/3 THEN 952
+752 IF C<4 THEN 756
+754 GOTO 760
+756 IF L(0)=2 THEN 862
+760 IF S1>7 THEN 867
+770 D1=INT(((30-H)*2.5+187-((30-H)*.25+15)*C/2)+25*RND(1))
+780 D1=INT(D1*W)
+800 IF T=2 THEN 1170
+830 O=(RND(1)/.8)*(2*H+16)*ABS(TAN(D1*.0035))
+840 D2=INT(SQR(O^2+ABS(D-D1)^2))
+850 IF D-D1<0 THEN 870
+860 GOTO 890
+862 PRINT "YOU DUBBED IT."
+864 D1=35
+866 GOTO 830
+867 IF D<200 THEN 1300
+868 GOTO 770
+870 IF D2<20 THEN 890
+880 PRINT "TOO MUCH CLUB. YOU'RE PAST THE HOLE."
+890 B=D
+900 D=D2
+910 IF D2>27 THEN 1020
+920 IF D2>20 THEN 1100
+930 IF D2>.5 THEN 1120
+940 L(0)=9
+950 GOTO 1470
+952 IF S2+Q+(10*(F-1)/18)<(F-1)*(72+((H+1)/.85))/18 THEN 956
+954 GOTO 752
+956 Q=Q+1
+957 IF S1/2<>INT(S1/2) THEN 1011
+958 GOTO 862
+960 PRINT "NOW GAUGE YOUR DISTANCE BY A PERCENTAGE (1 TO 100)"
+961 PRINT "OF A FULL SWING";
+970 INPUT W: W=W/100
+972 PRINT
+980 IF W>1 THEN 680
+985 IF L(0)=5 THEN 1280
+990 IF C=14 THEN 760
+1000 C=C-10
+1010 GOTO 760
+1011 IF D<95 THEN 862
+1012 PRINT "BALL HIT TREE - BOUNCED INTO ROUGH";D-75;"YARDS FROM HOLE."
+1014 D=D-75
+1018 GOTO 620
+1020 IF O<30 THEN 1150
+1022 IF J>0 THEN 1150
+1030 IF T>0 THEN 1070
+1035 S9=(S2+1)/15
+1036 IF INT(S9)=S9 THEN 1075
+1040 PRINT "YOU HOOKED- ";
+1050 L(0)=L(2)
+1055 IF O>45 THEN 1092
+1060 GOTO 320
+1070 S9=(S2+1)/15
+1071 IF INT(S9)=S9 THEN 1040
+1075 PRINT "YOU SLICED- ";
+1080 L(0)=L(1)
+1090 GOTO 1055
+1092 PRINT "BADLY."
+1094 GOTO 320
+1100 L(0)=5
+1110 GOTO 320
+1120 L(0)=8
+1130 D2=INT(D2*3)
+1140 GOTO 1380
+1150 L(0)=1
+1160 GOTO 320
+1170 D1=INT(.85*D1)
+1180 GOTO 830
+1190 IF L(0)>6 THEN 1260
+1200 PRINT "YOUR SHOT WENT INTO THE WATER."
+1210 S1=S1+1
+1220 PRINT "PENALTY STROKE ASSESSED.  HIT FROM PREVIOUS LOCATION."
+1230 J=J+1
+1240 L(0)=1
+1242 D=B
+1250 GOTO 620
+1260 PRINT "YOUR SHOT WENT OUT OF BOUNDS."
+1270 GOTO 1210
+1280 IF T=3 THEN 1320
+1300 D2=1+(3*INT((80/(40-H))*RND(1)))
+1310 GOTO 1380
+1320 IF RND(1)>N THEN 1360
+1330 N=N*.2
+1340 PRINT "SHOT DUBBED, STILL IN TRAP."
+1350 GOTO 620
+1360 N=.8
+1370 GOTO 1300
+1380 PRINT "ON GREEN,";D2;"FEET FROM THE PIN."
+1381 PRINT "CHOOSE YOUR PUTT POTENCY (1 TO 13):";
+1400 INPUT I
+1410 S1=S1+1
+1420 IF S1+1-P>(H*.072)+2 THEN 1470
+1425 IF K>2 THEN 1470
+1428 K=K+1
+1430 IF T=4 THEN 1530
+1440 D2=D2-I*(4+2*RND(1))+1.5
+1450 IF D2<-2 THEN 1560
+1460 IF D2>2 THEN 1500
+1470 PRINT "YOU HOLED IT."
+1472 PRINT
+1480 F=F+1
+1490 GOTO 230
+1500 PRINT "PUTT SHORT."
+1505 D2=INT(D2)
+1510 GOTO 1380
+1530 D2=D2-I*(4+1*RND(1))+1
+1550 GOTO 1450
+1560 PRINT "PASSED BY CUP."
+1570 D2=-D2
+1580 GOTO 1505
+1590 READ D,P,L(1),L(2)
+1595 PRINT
+1600 PRINT "YOU ARE AT THE TEE OFF HOLE";F;"DISTANCE";D;"YARDS, PAR";P
+1605 G3=G3+P
+1620 PRINT "ON YOUR RIGHT IS ";
+1630 X=1
+1640 GOSUB 400
+1650 PRINT "ON YOUR LEFT IS ";
+1660 X=2
+1670 GOSUB 400
+1680 GOTO 620
+1690 RETURN
+1700 DATA 361,4,4,2,389,4,3,3,206,3,4,2,500,5,7,2
+1702 DATA 408,4,2,4,359,4,6,4,424,4,4,2,388,4,4,4
+1704 DATA 196,3,7,2,400,4,7,2,560,5,7,2,132,3,2,2
+1706 DATA 357,4,4,4,294,4,2,4,475,5,2,3,375,4,4,2
+1708 DATA 180,3,6,2,550,5,6,6
+1710 PRINT
+1750 G2=G2+S1
+1760 PRINT "TOTAL PAR FOR";F-1;"HOLES IS";G3;"  YOUR TOTAL IS";G2
+1761 IF G1=F-1 THEN 1770
+1765 GOTO 292
+1770 END
diff --git a/00_Alternate_Languages/39_Golf/java/README.md b/00_Alternate_Languages/39_Golf/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/39_Golf/javascript/README.md b/00_Alternate_Languages/39_Golf/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/39_Golf/javascript/golf.html b/00_Alternate_Languages/39_Golf/javascript/golf.html
new file mode 100644
index 00000000..bf43de8e
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/javascript/golf.html
@@ -0,0 +1,9 @@
+
+
+GOLF
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/39_Golf/javascript/golf.js b/00_Alternate_Languages/39_Golf/javascript/golf.js
new file mode 100644
index 00000000..660c95ba
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/javascript/golf.js
@@ -0,0 +1,369 @@
+// GOLF
+//
+// 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 la = [];
+var f;
+var s1;
+var g2;
+var g3;
+var x;
+
+var hole_data = [
+    361,4,4,2,389,4,3,3,206,3,4,2,500,5,7,2,
+    408,4,2,4,359,4,6,4,424,4,4,2,388,4,4,4,
+    196,3,7,2,400,4,7,2,560,5,7,2,132,3,2,2,
+    357,4,4,4,294,4,2,4,475,5,2,3,375,4,4,2,
+    180,3,6,2,550,5,6,6,
+];
+
+function show_obstacle()
+{
+    switch (la[x]) {
+        case 1:
+            print("FAIRWAY.\n");
+            break;
+        case 2:
+            print("ROUGH.\n");
+            break;
+        case 3:
+            print("TREES.\n");
+            break;
+        case 4:
+            print("ADJACENT FAIRWAY.\n");
+            break;
+        case 5:
+            print("TRAP.\n");
+            break;
+        case 6:
+            print("WATER.\n");
+            break;
+    }
+}
+
+function show_score()
+{
+    g2 += s1;
+    print("TOTAL PAR FOR " + (f - 1) + " HOLES IS " + g3 + "  YOUR TOTAL IS " + g2 + "\n");
+}
+
+// Main program
+async function main()
+{
+    print(tab(34) + "GOLF\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("WELCOME TO THE CREATIVE COMPUTING COUNTRY CLUB,\n");
+    print("AN EIGHTEEN HOLE CHAMPIONSHIP LAYOUT LOCATED A SHORT\n");
+    print("DISTANCE FROM SCENIC DOWNTOWN MORRISTOWN.  THE\n");
+    print("COMMENTATOR WILL EXPLAIN THE GAME AS YOU PLAY.\n");
+    print("ENJOY YOUR GAME; SEE YOU AT THE 19TH HOLE...\n");
+    print("\n");
+    print("\n");
+    next_hole = 0;
+    g1 = 18;
+    g2 = 0;
+    g3 = 0;
+    a = 0;
+    n = 0.8;
+    s2 = 0;
+    f = 1;
+    while (1) {
+        print("WHAT IS YOUR HANDICAP");
+        h = parseInt(await input());
+        print("\n");
+        if (h < 0 || h > 30) {
+            print("PGA HANDICAPS RANGE FROM 0 TO 30.\n");
+        } else {
+            break;
+        }
+    }
+    do {
+        print("DIFFICULTIES AT GOLF INCLUDE:\n");
+        print("0=HOOK, 1=SLICE, 2=POOR DISTANCE, 4=TRAP SHOTS, 5=PUTTING\n");
+        print("WHICH ONE (ONLY ONE) IS YOUR WORST");
+        t = parseInt(await input());
+        print("\n");
+    } while (t > 5) ;
+    s1 = 0;
+    first_routine = true;
+    while (1) {
+        if (first_routine) {
+            la[0] = 0;
+            j = 0;
+            q = 0;
+            s2++;
+            k = 0;
+            if (f != 1) {
+                print("YOUR SCORE ON HOLE " + (f - 1) + " WAS " + s1 + "\n");
+                show_score();
+                if (g1 == f - 1)    // Completed all holes?
+                    return;         // Exit game
+                if (s1 > p + 2) {
+                    print("KEEP YOUR HEAD DOWN.\n");
+                } else if (s1 == p) {
+                    print("A PAR.  NICE GOING.\n");
+                } else if (s1 == p - 1) {
+                    print("A BIRDIE.\n");
+                } else if (s1 == p - 2) {
+                    if (p != 3)
+                        print("A GREAT BIG EAGLE.\n");
+                    else
+                        print("A HOLE IN ONE.\n");
+                }
+            }
+            if (f == 19) {
+                print("\n");
+                show_score();
+                if (g1 == f - 1)
+                    return;
+            }
+            s1 = 0;
+            print("\n");
+            if (s1 != 0 && la[0] < 1)
+                la[0] = 1;
+        }
+        if (s1 == 0) {
+            d = hole_data[next_hole++];
+            p = hole_data[next_hole++];
+            la[1] = hole_data[next_hole++];
+            la[2] = hole_data[next_hole++];
+            print("\n");
+            print("YOU ARE AT THE TEE OFF HOLE " + f + " DISTANCE " + d + " YARDS, PAR " + p + "\n");
+            g3 += p;
+            print("ON YOUR RIGHT IS ");
+            x = 1;
+            show_obstacle();
+            print("ON YOUR LEFT IS ");
+            x = 2
+            show_obstacle();
+        } else {
+            x = 0;
+            if (la[0] > 5) {
+                if (la[0] > 6) {
+                    print("YOUR SHOT WENT OUT OF BOUNDS.\n");
+                } else {
+                    print("YOUR SHOT WENT INTO THE WATER.\n");
+                }
+                s1++;
+                print("PENALTY STROKE ASSESSED.  HIT FROM PREVIOUS LOCATION.\n");
+                j++;
+                la[0] = 1;
+                d = b;
+            } else {
+                print("SHOT WENT " + d1 + " YARDS.  IT'S " + d2 + " YARDS FROM THE CUP.\n");
+                print("BALL IS " + Math.floor(o) + " YARDS OFF LINE... IN ");
+                show_obstacle();
+            }
+        }
+
+        while (1) {
+            if (a != 1) {
+                print("SELECTION OF CLUBS\n");
+                print("YARDAGE DESIRED                       SUGGESTED CLUBS\n");
+                print("200 TO 280 YARDS                           1 TO 4\n");
+                print("100 TO 200 YARDS                          19 TO 13\n");
+                print("  0 TO 100 YARDS                          29 TO 23\n");
+                a = 1;
+            }
+            print("WHAT CLUB DO YOU CHOOSE");
+            c = parseInt(await input());
+            print("\n");
+            if (c >= 1 && c <= 29 && (c < 5 || c >= 12)) {
+                if (c > 4)
+                    c -= 6;
+                if (la[0] <= 5 || c == 14 || c == 23) {
+                    s1++;
+                    w = 1;
+                    if (c <= 13) {
+                        if (f % 3 == 0 && s2 + q + (10 * (f - 1) / 18) < (f - 1) * (72 + ((h + 1) / 0.85)) / 18) {
+                            q++;
+                            if (s1 % 2 != 0 && d >= 95) {
+                                print("BALL HIT TREE - BOUNCED INTO ROUGH " + (d - 75) + " YARDS FROM HOLE.\n");
+                                d -= 75;
+                                continue;
+                            }
+                            print("YOU DUBBED IT.\n");
+                            d1 = 35;
+                            second_routine = 1;
+                            break;
+                        } else if (c < 4 && la[0] == 2) {
+                            print("YOU DUBBED IT.\n");
+                            d1 = 35;
+                            second_routine = 1;
+                            break;
+                        } else {
+                            second_routine = 0;
+                            break;
+                        }
+                    } else {
+                        print("NOW GAUGE YOUR DISTANCE BY A PERCENTAGE (1 TO 100)\n");
+                        print("OF A FULL SWING");
+                        w = parseInt(await input());
+                        w /= 100;
+                        print("\n");
+                        if (w <= 1) {
+                            if (la[0] == 5) {
+                                if (t == 3) {
+                                    if (Math.random() <= n) {
+                                        n *= 0.2;
+                                        print("SHOT DUBBED, STILL IN TRAP.\n");
+                                        continue;
+                                    }
+                                    n = 0.8;
+                                }
+                                d2 = 1 + (3 * Math.floor((80 / (40 - h)) * Math.random()));
+                                second_routine = 2;
+                                break;
+                            }
+                            if (c != 14)
+                                c -= 10;
+                            second_routine = 0;
+                            break;
+                        }
+                        s1--;
+                        // Fall through to THAT CLUB IS NOT IN THE BAG.
+                    }
+                }
+            }
+            print("THAT CLUB IS NOT IN THE BAG.\n");
+            print("\n");
+        }
+        if (second_routine == 0) {
+            if (s1 > 7 && d < 200) {
+                d2 = 1 + (3 * Math.floor((80 / (40 - h)) * Math.random()));
+                second_routine = 2;
+            } else {
+                d1 = Math.floor(((30 - h) * 2.5 + 187 - ((30 - h) * 0.25 + 15) * c / 2) + 25 * Math.random());
+                d1 = Math.floor(d1 * w);
+                if (t == 2)
+                    d1 = Math.floor(d1 * 0.85);
+            }
+        }
+        if (second_routine <= 1) {
+            o = (Math.random() / 0.8) * (2 * h + 16) * Math.abs(Math.tan(d1 * 0.0035));
+            d2 = Math.floor(Math.sqrt(Math.pow(o, 2) + Math.pow(Math.abs(d - d1), 2)));
+            if (d - d1 < 0) {
+                if (d2 >= 20)
+                    print("TOO MUCH CLUB, YOU'RE PAST THE HOLE.\n");
+            }
+            b = d;
+            d = d2;
+            if (d2 > 27) {
+                if (o < 30 || j > 0) {
+                    la[0] = 1;
+                } else {
+                    if (t <= 0) {
+                        s9 = (s2 + 1) / 15;
+                        if (Math.floor(s9) == s9) {
+                            print("YOU SLICED- ");
+                            la[0] = la[1];
+                        } else {
+                            print("YOU HOOKED- ");
+                            la[0] = la[2];
+                        }
+                    } else {
+                        s9 = (s2 + 1) / 15;
+                        if (Math.floor(s9) == s9) {
+                            print("YOU HOOKED- ");
+                            la[0] = la[2];
+                        } else {
+                            print("YOU SLICED- ");
+                            la[0] = la[1];
+                        }
+                    }
+                    if (o > 45)
+                        print("BADLY.\n");
+                }
+                first_routine = false;
+            } else if (d2 > 20) {
+                la[0] = 5;
+                first_routine = false;
+            } else if (d2 > 0.5) {
+                la[0] = 8;
+                d2 = Math.floor(d2 * 3);
+                second_routine = 2;
+            } else {
+                la[0] = 9;
+                print("YOU HOLED IT.\n");
+                print("\n");
+                f++;
+                first_routine = true;
+            }
+        }
+        if (second_routine == 2) {
+            while (1) {
+                print("ON GREEN, " + d2 + " FEET FROM THE PIN.\n");
+                print("CHOOSE YOUR PUTT POTENCY (1 TO 13):");
+                i = parseInt(await input());
+                s1++;
+                if (s1 + 1 - p <= (h * 0.072) + 2 && k <= 2) {
+                    k++;
+                    if (t == 4)
+                        d2 -= i * (4 + 1 * Math.random()) + 1;
+                    else
+                        d2 -= i * (4 + 2 * Math.random()) + 1.5;
+                    if (d2 < -2) {
+                        print("PASSED BY CUP.\n");
+                        d2 = Math.floor(-d2);
+                        continue;
+                    }
+                    if (d2 > 2) {
+                        print("PUTT SHORT.\n");
+                        d2 = Math.floor(d2);
+                        continue;
+                    }
+                }
+                print("YOU HOLED IT.\n");
+                print("\n");
+                f++;
+                break;
+            }
+            first_routine = true;
+        }
+    }
+}
+
+main();
diff --git a/15_Boxing/pascal/README.md b/00_Alternate_Languages/39_Golf/pascal/README.md
similarity index 100%
rename from 15_Boxing/pascal/README.md
rename to 00_Alternate_Languages/39_Golf/pascal/README.md
diff --git a/00_Alternate_Languages/39_Golf/perl/README.md b/00_Alternate_Languages/39_Golf/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/39_Golf/python/README.md b/00_Alternate_Languages/39_Golf/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/39_Golf/ruby/README.md b/00_Alternate_Languages/39_Golf/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/39_Golf/vbnet/Golf.sln b/00_Alternate_Languages/39_Golf/vbnet/Golf.sln
new file mode 100644
index 00000000..6698c79f
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/vbnet/Golf.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Golf", "Golf.vbproj", "{65A2E065-6541-4E6E-B6F0-9881080B5FFF}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{65A2E065-6541-4E6E-B6F0-9881080B5FFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{65A2E065-6541-4E6E-B6F0-9881080B5FFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{65A2E065-6541-4E6E-B6F0-9881080B5FFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{65A2E065-6541-4E6E-B6F0-9881080B5FFF}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/39_Golf/vbnet/Golf.vbproj b/00_Alternate_Languages/39_Golf/vbnet/Golf.vbproj
new file mode 100644
index 00000000..1a20f831
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/vbnet/Golf.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Golf
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/39_Golf/vbnet/README.md b/00_Alternate_Languages/39_Golf/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/39_Golf/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/40_Gomoko/README.md b/00_Alternate_Languages/40_Gomoko/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/40_Gomoko/csharp/Gomoko.csproj b/00_Alternate_Languages/40_Gomoko/csharp/Gomoko.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/csharp/Gomoko.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/40_Gomoko/csharp/Gomoko.sln b/00_Alternate_Languages/40_Gomoko/csharp/Gomoko.sln
new file mode 100644
index 00000000..84182037
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/csharp/Gomoko.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gomoko", "Gomoko.csproj", "{558B84AB-2010-436E-B191-00980C6CBA61}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{558B84AB-2010-436E-B191-00980C6CBA61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{558B84AB-2010-436E-B191-00980C6CBA61}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{558B84AB-2010-436E-B191-00980C6CBA61}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{558B84AB-2010-436E-B191-00980C6CBA61}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/40_Gomoko/csharp/README.md b/00_Alternate_Languages/40_Gomoko/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/40_Gomoko/gomoko.bas b/00_Alternate_Languages/40_Gomoko/gomoko.bas
new file mode 100644
index 00000000..662cca13
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/gomoko.bas
@@ -0,0 +1,54 @@
+2 PRINT TAB(33);"GOMOKO"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT:PRINT:PRINT
+8 DIM A(19,19)
+10 PRINT "WELCOME TO THE ORIENTAL GAME OF GOMOKO."
+20 PRINT: PRINT "THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE"
+30 PRINT "THAT YOU SPECIFY.  DURING YOUR PLAY, YOU MAY COVER ONE GRID"
+40 PRINT "INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET"
+50 PRINT "5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR"
+60 PRINT "DIAGONALLY.  ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED"
+70 PRINT "WITH A '1' AND THE COMPUTER MOVES WITH A '2'."
+80 PRINT: PRINT "THE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON."
+90 PRINT "TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.": PRINT
+110 PRINT "WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)";: INPUT N
+115 IF N>6 THEN 117
+116 GOTO 120
+117 IF N<20 THEN 210
+120 PRINT "I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.": GOTO 110
+210 FOR I=1 TO N:FOR J=1 TO N: A(I,J)=0: NEXT J: NEXT I
+300 PRINT: PRINT "WE ALTERNATE MOVES.  YOU GO FIRST...": PRINT
+310 PRINT "YOUR PLAY (I,J)";: INPUT I,J
+315 PRINT
+320 IF I=-1 THEN 980
+330 X=I: Y=J: GOSUB 910: IF L=1 THEN 410
+340 PRINT "ILLEGAL MOVE.  TRY AGAIN...": GOTO 310
+410 IF A(I,J)=0 THEN 440
+420 PRINT "SQUARE OCCUPIED.  TRY AGAIN...": GOTO 310
+440 A(I,J)=1
+500 REM *** COMPUTER TRIES AN INTELLIGENT MOVE ***
+510 FOR E=-1 TO 1: FOR F=-1 TO 1: IF E+F-E*F=0 THEN 590
+540 X=I+F: Y=J+F: GOSUB 910
+570 IF L=0 THEN 590
+580 IF A(X,Y)=1 THEN 710
+590 NEXT F: NEXT E
+600 REM *** COMPUTER TRIES A RANDOM MOVE ***
+610 X=INT(N*RND(1)+1): Y=INT(N*RND(1)+1): GOSUB 910: IF L=0 THEN 610
+650 IF A(X,Y)<>0 THEN 610
+660 A(X,Y)=2: GOSUB 810: GOTO 310
+710 X=I-E: Y=J-F: GOSUB 910
+750 IF L=0 THEN 610
+760 GOTO 650
+800 REM *** PRINT THE BOARD ***
+810 FOR I=1 TO N: FOR J=1 TO N: PRINT A(I,J);
+840 NEXT J: PRINT: NEXT I: PRINT: RETURN
+910 L=1: IF X<1 THEN 970
+920 IF X>N THEN 970
+930 IF Y<1 THEN 970
+940 IF Y>N THEN 970
+950 RETURN
+970 L=0: RETURN
+980 PRINT: PRINT "THANKS FOR THE GAME!!"
+985 PRINT "PLAY AGAIN (1 FOR YES, 0 FOR NO)";: INPUT Q
+990 IF Q=1 THEN 110
+999 END
diff --git a/00_Alternate_Languages/40_Gomoko/java/Gomoko.java b/00_Alternate_Languages/40_Gomoko/java/Gomoko.java
new file mode 100644
index 00000000..75600b2a
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/java/Gomoko.java
@@ -0,0 +1,210 @@
+import java.util.Arrays;
+import java.util.InputMismatchException;
+import java.util.Scanner;
+
+/**
+ * GOMOKO
+ * 

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + */ +public class Gomoko { + + private static final int MIN_BOARD_SIZE = 7; + private static final int MAX_BOARD_SIZE = 19; + + public static void main(String[] args) { + printIntro(); + Scanner scan = new Scanner(System.in); + int boardSize = readBoardSize(scan); + + boolean continuePlay = true; + while (continuePlay) { + int[][] board = new int[boardSize][boardSize]; + //initialize the board elements to 0 + for (int[] ints : board) { + Arrays.fill(ints, 0); + } + + System.out.println("\n\nWE ALTERNATE MOVES. YOU GO FIRST..."); + + boolean doneRound = false; + while (!doneRound) { + Move playerMove = null; + boolean validMove = false; + while (!validMove) { + playerMove = readMove(scan); + if (playerMove.i == -1 || playerMove.j == -1) { + doneRound = true; + System.out.println("\nTHANKS FOR THE GAME!!"); + System.out.print("PLAY AGAIN (1 FOR YES, 0 FOR NO)? "); + final int playAgain = scan.nextInt(); + scan.nextLine(); + if (playAgain == 1) { + continuePlay = true; + break; + } else { + continuePlay = false; + break; + } + } else if (!isLegalMove(playerMove, boardSize)) { + System.out.println("ILLEGAL MOVE. TRY AGAIN..."); + } else if (board[playerMove.i - 1][playerMove.j - 1] != 0) { + System.out.println("SQUARE OCCUPIED. TRY AGAIN..."); + } else { + validMove = true; + } + } + + if (!doneRound) { + board[playerMove.i - 1][playerMove.j - 1] = 1; + Move computerMove = getComputerMove(playerMove, board, boardSize); + if (computerMove == null) { + computerMove = getRandomMove(board, boardSize); + } + board[computerMove.i - 1][computerMove.j - 1] = 2; + + printBoard(board); + } + } + + } + } + + //*** COMPUTER TRIES AN INTELLIGENT MOVE *** + private static Move getComputerMove(Move playerMove, int[][] board, int boardSize) { + for (int e = -1; e <= 1; e++) { + for (int f = -1; f <= 1; f++) { + if ((e + f - e * f) != 0) { + var x = playerMove.i + f; + var y = playerMove.j + f; + final Move newMove = new Move(x, y); + if (isLegalMove(newMove, boardSize)) { + if (board[newMove.i - 1][newMove.j - 1] != 0) { + newMove.i = newMove.i - e; + newMove.i = newMove.j - f; + if (!isLegalMove(newMove, boardSize)) { + return null; + } else { + if (board[newMove.i - 1][newMove.j - 1] == 0) { + return newMove; + } + } + } + } + } + } + } + return null; + } + + private static void printBoard(int[][] board) { + for (int[] ints : board) { + for (int cell : ints) { + System.out.printf(" %s", cell); + } + System.out.println(); + } + } + + //*** COMPUTER TRIES A RANDOM MOVE *** + private static Move getRandomMove(int[][] board, int boardSize) { + boolean legalMove = false; + Move randomMove = null; + while (!legalMove) { + randomMove = randomMove(boardSize); + legalMove = isLegalMove(randomMove, boardSize) && board[randomMove.i - 1][randomMove.j - 1] == 0; + + } + return randomMove; + } + + private static Move randomMove(int boardSize) { + int x = (int) (boardSize * Math.random() + 1); + int y = (int) (boardSize * Math.random() + 1); + return new Move(x, y); + } + + private static boolean isLegalMove(Move move, int boardSize) { + return (move.i >= 1) && (move.i <= boardSize) && (move.j >= 1) && (move.j <= boardSize); + } + + private static void printIntro() { + System.out.println(" GOMOKO"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + System.out.println("WELCOME TO THE ORIENTAL GAME OF GOMOKO."); + System.out.println("\n"); + System.out.println("THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE"); + System.out.println("THAT YOU SPECIFY. DURING YOUR PLAY, YOU MAY COVER ONE GRID"); + System.out.println("INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET"); + System.out.println("5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR"); + System.out.println("DIAGONALLY. ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED"); + System.out.println("WITH A '1' AND THE COMPUTER MOVES WITH A '2'."); + System.out.println("\nTHE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON."); + System.out.println("TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\n "); + } + + private static int readBoardSize(Scanner scan) { + System.out.print("WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)? "); + + boolean validInput = false; + int input = 0; + while (!validInput) { + try { + input = scan.nextInt(); + if (input < MIN_BOARD_SIZE || input > MAX_BOARD_SIZE) { + System.out.printf("I SAID, THE MINIMUM IS %s, THE MAXIMUM IS %s.\n", MIN_BOARD_SIZE, MAX_BOARD_SIZE); + } else { + validInput = true; + } + } catch (InputMismatchException ex) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE\n"); + validInput = false; + } finally { + scan.nextLine(); + } + } + return input; + } + + private static Move readMove(Scanner scan) { + System.out.print("YOUR PLAY (I,J)? "); + boolean validInput = false; + Move move = new Move(); + while (!validInput) { + String input = scan.nextLine(); + final String[] split = input.split(","); + try { + move.i = Integer.parseInt(split[0]); + move.j = Integer.parseInt(split[1]); + validInput = true; + } catch (NumberFormatException nfe) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE\n? "); + } + + } + return move; + } + + private static class Move { + int i; + int j; + + public Move() { + } + + public Move(int i, int j) { + this.i = i; + this.j = j; + } + + @Override + public String toString() { + return "Move{" + + "i=" + i + + ", j=" + j + + '}'; + } + } + +} diff --git a/00_Alternate_Languages/40_Gomoko/java/README.md b/00_Alternate_Languages/40_Gomoko/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/40_Gomoko/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/40_Gomoko/javascript/README.md b/00_Alternate_Languages/40_Gomoko/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/40_Gomoko/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/40_Gomoko/javascript/gomoko.html b/00_Alternate_Languages/40_Gomoko/javascript/gomoko.html new file mode 100644 index 00000000..adbfd691 --- /dev/null +++ b/00_Alternate_Languages/40_Gomoko/javascript/gomoko.html @@ -0,0 +1,9 @@ + + +GOMOKO + + +


+
+
+
diff --git a/00_Alternate_Languages/40_Gomoko/javascript/gomoko.js b/00_Alternate_Languages/40_Gomoko/javascript/gomoko.js
new file mode 100644
index 00000000..7d57c64e
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/javascript/gomoko.js
@@ -0,0 +1,174 @@
+// GOMOKO
+//
+// 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 reset_stats()
+{
+    for (var j = 1; j <= 4; j++)
+        f[j] = 0;
+}
+
+var a = [];
+var x;
+var y;
+var n;
+
+// *** PRINT THE BOARD ***
+function print_board()
+{
+    for (i = 1; i <= n; i++) {
+        for (j = 1; j <= n; j++) {
+            print(" " + a[i][j] + " ");
+        }
+        print("\n");
+    }
+    print("\n");
+}
+
+// Is valid the movement
+function is_valid()
+{
+    if (x < 1 || x > n || y < 1 || y > n)
+        return false;
+    return true;
+}
+
+// Main program
+async function main()
+{
+    print(tab(33) + "GOMOKO\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    for (i = 0; i <= 19; i++) {
+        a[i] = [];
+        for (j = 0; j <= 19; j++)
+            a[i][j] = 0;
+    }
+    print("WELCOME TO THE ORIENTAL GAME OF GOMOKO.\n");
+    print("\n");
+    print("THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE\n");
+    print("THAT YOU SPECIFY.  DURING YOUR PLAY, YOU MAY COVER ONE GRID\n");
+    print("INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET\n");
+    print("5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR\n");
+    print("DIAGONALLY.  ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED\n");
+    print("WITH A '1' AND THE COMPUTER MOVES WITH A '2'.\n");
+    print("\n");
+    print("THE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON.\n");
+    print("TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\n");
+    print("\n");
+    while (1) {
+        print("WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)");
+        while (1) {
+            n = parseInt(await input());
+            if (n >= 7 && n<= 19)
+                break;
+            print("I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.\n");
+        }
+        for (i = 1; i <= n; i++) {
+            for (j = 1; j <= n; j++) {
+                a[i][j] = 0;
+            }
+        }
+        print("\n");
+        print("WE ALTERNATE MOVES.  YOU GO FIRST...\n");
+        print("\n");
+        while (1) {
+            print("YOUR PLAY (I,J)");
+            str = await input();
+            i = parseInt(str);
+            j = parseInt(str.substr(str.indexOf(",") + 1));
+            print("\n");
+            if (i == -1)
+                break;
+            x = i;
+            y = j;
+            if (!is_valid()) {
+                print("ILLEGAL MOVE.  TRY AGAIN...\n");
+                continue;
+            }
+            if (a[i][j] != 0) {
+                print("SQUARE OCCUPIED.  TRY AGAIN...\n");
+                continue;
+            }
+            a[i][j] = 1;
+            // *** Computer tries an intelligent move ***
+            found = false;
+            for (e = -1; e <= 1; e++) {
+                for (f = -1; f <= 1; f++) {
+                    if (e + f - e * f == 0)
+                        continue;
+                    x = i + f;
+                    y = j + f;
+                    if (!is_valid())
+                        continue;
+                    if (a[x][y] == 1) {
+                        x = i - e;
+                        y = j - f;
+                        if (is_valid() || a[x][y] == 0)
+                            found = true;
+                        break;
+                    }
+                }
+            }
+            if (!found) {
+                // *** Computer tries a random move ***
+                do {
+                    x = Math.floor(n * Math.random() + 1);
+                    y = Math.floor(n * Math.random() + 1);
+                } while (!is_valid() || a[x][y] != 0) ;
+            }
+            a[x][y] = 2;
+            print_board();
+        }
+        print("\n");
+        print("THANKS FOR THE GAME!!\n");
+        print("PLAY AGAIN (1 FOR YES, 0 FOR NO)");
+        q = parseInt(await input());
+        if (q != 1)
+            break;
+    }
+}
+
+main();
diff --git a/16_Bug/pascal/README.md b/00_Alternate_Languages/40_Gomoko/pascal/README.md
similarity index 100%
rename from 16_Bug/pascal/README.md
rename to 00_Alternate_Languages/40_Gomoko/pascal/README.md
diff --git a/00_Alternate_Languages/40_Gomoko/perl/README.md b/00_Alternate_Languages/40_Gomoko/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/40_Gomoko/perl/gomoko.pl b/00_Alternate_Languages/40_Gomoko/perl/gomoko.pl
new file mode 100644
index 00000000..891e4e18
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/perl/gomoko.pl
@@ -0,0 +1,119 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 33 . "GOMOKO\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n"; print "\n"; print "\n";
+#my @A;
+print "WELCOME TO THE ORIENTAL GAME OF GOMOKO.\n";
+print "\n"; print "THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE\n";
+print "THAT YOU SPECIFY. DURING YOUR PLAY, YOU MAY COVER ONE GRID\n";
+print "INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET\n";
+print "5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR\n";
+print "DIAGONALLY. ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED\n";
+print "WITH A '1' AND THE COMPUTER MOVES WITH A '2'.\n";
+print "\n"; print "THE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON.\n";
+print "TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.\n"; print "\n";
+
+
+my $Ret;
+my $I;
+my $J;
+
+my @Board;
+my $Size= 0;
+
+
+while (1) {
+
+	do {
+		$Size= 0;
+		print "WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)"; print "? "; chomp($Size = uc());
+		if ($Size<7 || $Size>19) {
+			$Size=0;
+			print "I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.\n";
+			}
+		} until ($Size);
+
+	#==> Reset Board to zeroes...
+	for (my $I=1; $I<=$Size; $I++) {
+		for (my $J=1; $J<=$Size; $J++) {
+			$Board[$I][$J]= 0;
+			}
+		}
+
+	print "\n"; print "WE ALTERNATE MOVES. YOU GO FIRST...\n"; print "\n";
+
+	while (1) {
+		do {
+			print "YOUR PLAY (I,J)"; print "? "; chomp(my $Inp = uc());
+			($I, $J)= split(",", $Inp);
+			print "\n";
+			if ($I==-1) { last; }
+			$Ret= &ValidMove($I, $J, 1);
+			} until ($Ret==1);
+		if ($I==-1) { last; }
+		$Board[$I][$J]= 1;
+
+		my $X;
+		my $Y;
+		my $Found=0;
+		# REM *** COMPUTER TRIES AN INTELLIGENT MOVE ***
+		#==> Too complex, original basic code seems only move below user.
+		$Ret= &ValidMove($I+1, $J);
+		if ($Ret==1) {
+			$Found=1;
+			$X= $I+1;
+			$Y= $J;
+			}
+
+		while($Found==0) {
+		# REM *** COMPUTER TRIES A RANDOM MOVE ***
+			$X= int($Size*rand(1)+1);
+			$Y= int($Size*rand(1)+1);
+			$Ret= &ValidMove($X, $Y, 2);
+			if ($Ret==1) { $Found= 1; }
+			};
+		$Board[$X][$Y]=2;
+
+		&ShowBoard();
+		}
+
+	print "\n"; print "THANKS FOR THE GAME!!\n";
+	print "PLAY AGAIN (1 FOR YES, 0 FOR NO)"; print "? "; chomp(my $Q = uc());
+	if ($Q==0) { last; }
+	}
+
+
+
+exit;
+
+
+sub ShowBoard {
+	for (my $I=1; $I<=$Size; $I++) {
+		print " ";
+		for (my $J=1; $J<=$Size; $J++) {
+			print "$Board[$I][$J]  ";
+			}
+		print "\n";
+		}
+	print "\n";
+	return;
+	}
+
+
+sub ValidMove {
+	my ($X, $Y, $Val)= @_;
+	if ($X<1 || $X>$Size || $Y<1 || $Y>$Size) {
+		if ($Val==1) { print "ILLEGAL MOVE. TRY AGAIN...\n"; }
+		return 0;
+		}
+	if ($Board[$X][$Y]!=0) {
+		if ($Val==1) { print "SQUARE OCCUPIED. TRY AGAIN...\n"; }
+		return 0;
+		}
+
+	#$Board[$X][$Y]= $Val;
+	return 1;
+	}
diff --git a/00_Alternate_Languages/40_Gomoko/python/Gomoko.py b/00_Alternate_Languages/40_Gomoko/python/Gomoko.py
new file mode 100644
index 00000000..294e9300
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/python/Gomoko.py
@@ -0,0 +1,157 @@
+import random
+from typing import Any, List, Tuple
+
+
+def print_n_whitespaces(n: int) -> None:
+    print(" " * n, end="")
+
+
+def print_board(A: List[List[Any]], n):
+    """PRINT THE BOARD"""
+    for i in range(n):
+        print(" ", end="")
+        for j in range(n):
+            print(A[i][j], end="")
+            print(" ", end="")
+        print()
+
+
+def check_move(_I, _J, _N) -> bool:  # 910
+    if _I < 1 or _I > _N or _J < 1 or _J > _N:
+        return False
+    return True
+
+
+def print_banner():
+    print_n_whitespaces(33)
+    print("GOMOKU")
+    print_n_whitespaces(15)
+    print("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+    print("WELCOME TO THE ORIENTAL GAME OF GOMOKO.")
+    print()
+    print("THE GAME IS PLAYED ON AN N BY N GRID OF A SIZE")
+    print("THAT YOU SPECIFY.  DURING YOUR PLAY, YOU MAY COVER ONE GRID")
+    print("INTERSECTION WITH A MARKER. THE OBJECT OF THE GAME IS TO GET")
+    print("5 ADJACENT MARKERS IN A ROW -- HORIZONTALLY, VERTICALLY, OR")
+    print("DIAGONALLY.  ON THE BOARD DIAGRAM, YOUR MOVES ARE MARKED")
+    print("WITH A '1' AND THE COMPUTER MOVES WITH A '2'.")
+    print()
+    print("THE COMPUTER DOES NOT KEEP TRACK OF WHO HAS WON.")
+    print("TO END THE GAME, TYPE -1,-1 FOR YOUR MOVE.")
+    print()
+
+
+def get_board_dimensions() -> int:
+    n = 0
+    while True:
+        n = input("WHAT IS YOUR BOARD SIZE (MIN 7/ MAX 19)? ")
+        n = int(n)
+        if n < 7 or n > 19:
+            print("I SAID, THE MINIMUM IS 7, THE MAXIMUM IS 19.")
+            print()
+        else:
+            break
+    return n
+
+
+def get_move() -> Tuple[int, int]:
+    while True:
+        xy = input("YOUR PLAY (I,J)? ")
+        print()
+        x, y = xy.split(",")
+        try:
+            x = int(x)
+            y = int(y)
+        except Exception:
+            print("ILLEGAL MOVE.  TRY AGAIN...")
+            continue
+        return x, y
+
+
+def initialize_board(n: int) -> List[List[int]]:
+    # Initialize the board
+    board = []
+    for _x in range(n):
+        subA = []
+        for _y in range(n):
+            subA.append(0)
+        board.append(subA)
+    return board
+
+
+def main():
+    print_banner()
+
+    while True:
+        n = get_board_dimensions()
+        board = initialize_board(n)
+
+        print()
+        print()
+        print("WE ALTERNATE MOVES. YOU GO FIRST...")
+        print()
+
+        while True:
+            x, y = get_move()
+            if x == -1:
+                break
+            elif not check_move(x, y, n):
+                print("ILLEGAL MOVE.  TRY AGAIN...")
+            else:
+                if board[x - 1][y - 1] != 0:
+                    print("SQUARE OCCUPIED.  TRY AGAIN...")
+                else:
+                    board[x - 1][y - 1] = 1
+                    # COMPUTER TRIES AN INTELLIGENT MOVE
+                    skip_ef_loop = False
+                    for E in range(-1, 2):
+                        for F in range(-1, 2):
+                            if E + F - E * F == 0 or skip_ef_loop:
+                                continue
+                            X = x + F
+                            Y = y + F
+                            if not check_move(X, Y, n):
+                                continue
+                            if board[X - 1][Y - 1] == 1:
+                                skip_ef_loop = True
+                                X = x - E
+                                Y = y - F
+                                if not check_move(X, Y, n):  # 750
+                                    while True:  # 610
+                                        X = random.randint(1, n)
+                                        Y = random.randint(1, n)
+                                        if (
+                                            check_move(X, Y, n)
+                                            and board[X - 1][Y - 1] == 0
+                                        ):
+                                            board[X - 1][Y - 1] = 2
+                                            print_board(board, n)
+                                            break
+                                else:
+                                    if board[X - 1][Y - 1] != 0:
+                                        while True:
+                                            X = random.randint(1, n)
+                                            Y = random.randint(1, n)
+                                            if (
+                                                check_move(X, Y, n)
+                                                and board[X - 1][Y - 1] == 0
+                                            ):
+                                                board[X - 1][Y - 1] = 2
+                                                print_board(board, n)
+                                                break
+                                    else:
+                                        board[X - 1][Y - 1] = 2
+                                        print_board(board, n)
+        print()
+        print("THANKS FOR THE GAME!!")
+        repeat = input("PLAY AGAIN (1 FOR YES, 0 FOR NO)? ")
+        repeat = int(repeat)
+        if repeat == 0:
+            break
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/40_Gomoko/python/README.md b/00_Alternate_Languages/40_Gomoko/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/40_Gomoko/ruby/README.md b/00_Alternate_Languages/40_Gomoko/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/40_Gomoko/vbnet/Gomoko.sln b/00_Alternate_Languages/40_Gomoko/vbnet/Gomoko.sln
new file mode 100644
index 00000000..fb1c4673
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/vbnet/Gomoko.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Gomoko", "Gomoko.vbproj", "{AEA608B9-083C-4EE7-9DE7-A0AB4FE313A8}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{AEA608B9-083C-4EE7-9DE7-A0AB4FE313A8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AEA608B9-083C-4EE7-9DE7-A0AB4FE313A8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AEA608B9-083C-4EE7-9DE7-A0AB4FE313A8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AEA608B9-083C-4EE7-9DE7-A0AB4FE313A8}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/40_Gomoko/vbnet/Gomoko.vbproj b/00_Alternate_Languages/40_Gomoko/vbnet/Gomoko.vbproj
new file mode 100644
index 00000000..5350e761
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/vbnet/Gomoko.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Gomoko
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/40_Gomoko/vbnet/README.md b/00_Alternate_Languages/40_Gomoko/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/40_Gomoko/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/41_Guess/README.md b/00_Alternate_Languages/41_Guess/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/41_Guess/csharp/Guess.csproj b/00_Alternate_Languages/41_Guess/csharp/Guess.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/csharp/Guess.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/41_Guess/csharp/Guess.sln b/00_Alternate_Languages/41_Guess/csharp/Guess.sln
new file mode 100644
index 00000000..c6649256
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/csharp/Guess.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Guess", "Guess.csproj", "{0D116201-33C0-4C86-A8D5-FF7C9CCC638F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{0D116201-33C0-4C86-A8D5-FF7C9CCC638F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0D116201-33C0-4C86-A8D5-FF7C9CCC638F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0D116201-33C0-4C86-A8D5-FF7C9CCC638F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0D116201-33C0-4C86-A8D5-FF7C9CCC638F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/41_Guess/csharp/README.md b/00_Alternate_Languages/41_Guess/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/41_Guess/guess.bas b/00_Alternate_Languages/41_Guess/guess.bas
new file mode 100644
index 00000000..96c57af5
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/guess.bas
@@ -0,0 +1,40 @@
+1 PRINT TAB(33);"GUESS"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+4 PRINT "THIS IS A NUMBER GUESSING GAME. I'LL THINK"
+5 PRINT "OF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT."
+6 PRINT "THEN YOU HAVE TO GUESS WHAT IT IS."
+7 PRINT
+8 PRINT "WHAT LIMIT DO YOU WANT";
+9 INPUT L
+10 PRINT
+11 L1=INT(LOG(L)/LOG(2))+1
+12 PRINT "I'M THINKING OF A NUMBER BETWEEN 1 AND";L
+13 G=1
+14 PRINT "NOW YOU TRY TO GUESS WHAT IT IS."
+15 M=INT(L*RND(1)+1)
+20 INPUT N
+21 IF N>0 THEN 25
+22 GOSUB 70
+23 GOTO 1
+25 IF N=M THEN 50
+30 G=G+1
+31 IF N>M THEN 40
+32 PRINT "TOO LOW. TRY A BIGGER ANSWER."
+33 GOTO 20
+40 PRINT "TOO HIGH. TRY A SMALLER ANSWER."
+42 GOTO 20
+50 PRINT "THAT'S IT! YOU GOT IT IN";G;"TRIES."
+52 IF G
+ * Based on the Basic game of Guess here
+ * https://github.com/coding-horror/basic-computer-games/blob/main/41%20Guess/guess.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. + */ +public class Guess { + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + STARTUP, + INPUT_RANGE, + DEFINE_COMPUTERS_NUMBER, + GUESS, + GAME_OVER + } + + // Current game state + private GAME_STATE gameState; + + // User supplied maximum number to guess + private int limit; + + // Computers calculated number for the player to guess + + private int computersNumber; + + // Number of turns the player has had guessing + private int tries; + + // Optimal number of turns it should take to guess + private int calculatedTurns; + + public Guess() { + kbScanner = new Scanner(System.in); + + gameState = GAME_STATE.STARTUP; + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + case STARTUP: + intro(); + gameState = GAME_STATE.INPUT_RANGE; + break; + + case INPUT_RANGE: + + limit = displayTextAndGetNumber("WHAT LIMIT DO YOU WANT? "); + calculatedTurns = (int) (Math.log(limit) / Math.log(2)) + 1; + gameState = GAME_STATE.DEFINE_COMPUTERS_NUMBER; + break; + + case DEFINE_COMPUTERS_NUMBER: + + tries = 1; + System.out.println("I'M THINKING OF A NUMBER BETWEEN 1 AND " + limit); + computersNumber = (int) (Math.random() * limit + 1); + + gameState = GAME_STATE.GUESS; + break; + + case GUESS: + int playersGuess = displayTextAndGetNumber("NOW YOU TRY TO GUESS WHAT IT IS "); + + // Allow player to restart game with entry of 0 + if (playersGuess == 0) { + linePadding(); + gameState = GAME_STATE.STARTUP; + break; + } + + if (playersGuess == computersNumber) { + System.out.println("THAT'S IT! YOU GOT IT IN " + tries + " TRIES."); + if (tries < calculatedTurns) { + System.out.println("VERY "); + } + System.out.println("GOOD."); + System.out.println("YOU SHOULD HAVE BEEN ABLE TO GET IT IN ONLY " + calculatedTurns); + linePadding(); + gameState = GAME_STATE.DEFINE_COMPUTERS_NUMBER; + break; + } else if (playersGuess < computersNumber) { + System.out.println("TOO LOW. TRY A BIGGER ANSWER."); + } else { + System.out.println("TOO HIGH. TRY A SMALLER ANSWER."); + } + tries++; + break; + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + private void intro() { + System.out.println(simulateTabs(33) + "GUESS"); + System.out.println(simulateTabs(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("THIS IS A NUMBER GUESSING GAME. I'LL THINK"); + System.out.println("OF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT."); + System.out.println("THEN YOU HAVE TO GUESS WHAT IT IS."); + } + + /** + * Print a predefined number of blank lines + * + */ + private void linePadding() { + for (int i = 1; i <= 5; i++) { + System.out.println(); + } + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to an Integer + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private int displayTextAndGetNumber(String text) { + return Integer.parseInt(displayTextAndGetInput(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + + /** + * Simulate the old basic tab(xx) command which indented text by xx spaces. + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String simulateTabs(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + +} diff --git a/00_Alternate_Languages/41_Guess/java/src/GuessGame.java b/00_Alternate_Languages/41_Guess/java/src/GuessGame.java new file mode 100644 index 00000000..603cdbfb --- /dev/null +++ b/00_Alternate_Languages/41_Guess/java/src/GuessGame.java @@ -0,0 +1,6 @@ +public class GuessGame { + public static void main(String[] args) { + Guess guess = new Guess(); + guess.play(); + } +} diff --git a/00_Alternate_Languages/41_Guess/javascript/README.md b/00_Alternate_Languages/41_Guess/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/41_Guess/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/41_Guess/javascript/guess.html b/00_Alternate_Languages/41_Guess/javascript/guess.html new file mode 100644 index 00000000..22a1bee0 --- /dev/null +++ b/00_Alternate_Languages/41_Guess/javascript/guess.html @@ -0,0 +1,9 @@ + + +GUESS + + +


+
+
+
diff --git a/00_Alternate_Languages/41_Guess/javascript/guess.js b/00_Alternate_Languages/41_Guess/javascript/guess.js
new file mode 100644
index 00000000..a9e25edb
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/javascript/guess.js
@@ -0,0 +1,104 @@
+// GUESS
+//
+// 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 make_space()
+{
+    for (h = 1; h <= 5; h++)
+        print("\n");
+}
+
+// Main control section
+async function main()
+{
+    while (1) {
+        print(tab(33) + "GUESS\n");
+        print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+        print("\n");
+        print("\n");
+        print("\n");
+        print("THIS IS A NUMBER GUESSING GAME. I'LL THINK\n");
+        print("OF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT.\n");
+        print("THEN YOU HAVE TO GUESS WHAT IT IS.\n");
+        print("\n");
+
+        print("WHAT LIMIT DO YOU WANT");
+        l = parseInt(await input());
+        print("\n");
+        l1 = Math.floor(Math.log(l) / Math.log(2)) + 1;
+        while (1) {
+            print("I'M THINKING OF A NUMBER BETWEEN 1 AND " + l + "\n");
+            g = 1;
+            print("NOW YOU TRY TO GUESS WHAT IT IS.\n");
+            m = Math.floor(l * Math.random() + 1);
+            while (1) {
+                n = parseInt(await input());
+                if (n <= 0) {
+                    make_space();
+                    break;
+                }
+                if (n == m) {
+                    print("THAT'S IT! YOU GOT IT IN " + g + " TRIES.\n");
+                    if (g == l1) {
+                        print("GOOD.\n");
+                    } else if (g < l1) {
+                        print("VERY GOOD.\n");
+                    } else {
+                        print("YOU SHOULD HAVE BEEN TO GET IT IN ONLY " + l1 + "\n");
+                    }
+                    make_space();
+                    break;
+                }
+                g++;
+                if (n > m)
+                    print("TOO HIGH. TRY A SMALLER ANSWER.\n");
+                else
+                    print("TOO LOW. TRY A BIGGER ANSWER.\n");
+            }
+            if (n <= 0)
+                break;
+        }
+    }
+}
+
+main();
diff --git a/17_Bullfight/pascal/README.md b/00_Alternate_Languages/41_Guess/pascal/README.md
similarity index 100%
rename from 17_Bullfight/pascal/README.md
rename to 00_Alternate_Languages/41_Guess/pascal/README.md
diff --git a/00_Alternate_Languages/41_Guess/perl/README.md b/00_Alternate_Languages/41_Guess/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/41_Guess/perl/guess.pl b/00_Alternate_Languages/41_Guess/perl/guess.pl
new file mode 100644
index 00000000..0aac6c52
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/perl/guess.pl
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+use strict;
+
+my $L1;
+while (1) {
+	print ' 'x 33 . "GUESS\n";
+	print ' 'x 15 . "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n";
+	print "\n"; print "\n"; print "\n";
+	print "THIS IS A NUMBER GUESSING GAME. I'LL THINK\n";
+	print "OF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT.\n";
+	print "THEN YOU HAVE TO GUESS WHAT IT IS.\n";
+	print "\n";
+	print "WHAT LIMIT DO YOU WANT";
+	print "? "; chomp(my $L = );
+	print "\n";
+	$L1= int(log($L)/log(2))+1;
+
+	while (1) {
+		print "I'M THINKING OF A NUMBER BETWEEN 1 AND $L\n";
+		my $G=0;
+		print "NOW YOU TRY TO GUESS WHAT IT IS.\n";
+		my $M=int($L*rand(1)+1);
+		my $N=0;
+		while (1) {
+			while (1) {
+				print "? "; chomp($N = );
+				if ($N>0) { last; }
+				}
+			$G=$G+1;
+			if ($N==$M) { last; }
+			if ($N>$M) { print "TOO HIGH. TRY A SMALLER ANSWER.\n"; }
+				else { print "TOO LOW. TRY A BIGGER ANSWER.\n"; }
+			}
+		print "THAT'S IT! YOU GOT IT IN $G TRIES.\n";
+		if ($G<$L1) { print "VERY "; }
+		if ($G<=$L1) { print "GOOD.\n"; }
+		if ($G>$L1) { print "YOU SHOULD HAVE BEEN ABLE TO GET IT IN ONLY $L1\n"; }
+		&ENTERS();
+		}
+	}
+
+exit;
+
+
+sub ENTERS { #GOSUB 70
+	for (my $H=1; $H<=5; $H++) {
+		print "\n";
+		}
+	return;
+	}
diff --git a/00_Alternate_Languages/41_Guess/python/README.md b/00_Alternate_Languages/41_Guess/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/41_Guess/python/guess.py b/00_Alternate_Languages/41_Guess/python/guess.py
new file mode 100644
index 00000000..d70ecffb
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/python/guess.py
@@ -0,0 +1,96 @@
+########################################################
+#
+# Guess
+#
+# From: Basic Computer Games (1978)
+#
+#  "In program Guess, the computer  chooses a random
+#   integer between 0 and any limit and any limit you
+#   set. You must then try to guess the number the
+#   computer has choosen using the clues provideed by
+#   the computer.
+#    You should be able to guess the number in one less
+#   than the number of digits needed to  represent the
+#   number in binary notation - i.e. in base 2. This ought
+#   to give you a clue as to the optimum search technique.
+#    Guess converted from the original program in FOCAL
+#   which appeared in the book "Computers in the Classroom"
+#   by Walt Koetke of Lexington High School, Lexington,
+#   Massaschusetts.
+#
+########################################################
+
+# Altough the introduction says that the computer chooses
+# a number between 0 and any limit, it actually chooses
+# a number between 1 and any limit. This due to the fact that
+# for computing the number of digits the limit has in binary
+# representation, it has to use log.
+
+from math import log
+from random import random
+
+
+def insert_whitespaces():
+    print("\n\n\n\n\n")
+
+
+def limit_set():
+    print("                   Guess")
+    print("Creative Computing  Morristown, New Jersey")
+    print("\n\n\n")
+    print("This is a number guessing game. I'll think")
+    print("of a number between 1 and any limit you want.\n")
+    print("Then you have to guess what it is\n")
+    print("What limit do you want?")
+
+    limit = int(input())
+
+    while limit <= 0:
+        print("Please insert a number greater or equal to 1")
+        limit = int(input())
+
+    # limit_goal = Number of digits "limit" in binary has
+    limit_goal = int((log(limit) / log(2)) + 1)
+
+    return limit, limit_goal
+
+
+limit, limit_goal = limit_set()
+while True:
+    guess_count = 1
+    still_guessing = True
+    won = False
+    my_guess = int(limit * random() + 1)
+
+    print(f"I'm thinking of a number between 1 and {limit}")
+    print("Now you try to guess what it is.")
+
+    while still_guessing:
+        n = int(input())
+
+        if n < 0:
+            break
+
+        insert_whitespaces()
+        if n < my_guess:
+            print("Too low. Try a bigger answer")
+            guess_count += 1
+        elif n > my_guess:
+            print("Too high. Try a smaller answer")
+            guess_count += 1
+        else:
+            print(f"That's it! You got it in {guess_count} tries")
+            won = True
+            still_guessing = False
+
+    if won:
+        if guess_count < limit_goal:
+            print("Very good.")
+        elif guess_count == limit_goal:
+            print("Good.")
+        else:
+            print(f"You should have been able to get it in only {limit_goal}")
+        insert_whitespaces()
+    else:
+        insert_whitespaces()
+        limit, limit_goal = limit_set()
diff --git a/00_Alternate_Languages/41_Guess/ruby/README.md b/00_Alternate_Languages/41_Guess/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/41_Guess/ruby/guess.rb b/00_Alternate_Languages/41_Guess/ruby/guess.rb
new file mode 100644
index 00000000..cf2deea2
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/ruby/guess.rb
@@ -0,0 +1,48 @@
+def print_intro
+  print " " * 31 + "GUESS\n"
+  print " " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n"
+  print "THIS IS A NUMBER GUESSING GAME. I'LL THINK\nOF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT.\nTHEN YOU HAVE TO GUESS WHAT IT IS.\n"
+end
+
+def game_play(limit,choice_limit)
+    random = rand(limit.to_i)+1
+    puts "I'M THINKING OF A NUMBER BETWEEN 1 and #{limit}"
+    puts "NOW YOU TRY TO GUESS WHAT IT IS."
+    print "? "
+    ans=0
+    guesses=0
+    until ans.to_i == random.to_i
+      ans = gets.chomp
+      guesses += 1
+      if ans.to_i > random.to_i
+        puts "TOO HIGH. TRY A SMALLER ANSWER."
+        print "? "
+      elsif ans.to_i < random.to_i
+        puts "TOO LOW. TRY A BIGGER ANSWER."
+        print "? "
+      elsif ans.to_i == random.to_i
+        puts "THAT'S IT! YOU GOT IT IN #{guesses} TRIES."
+        if guesses.to_i < choice_limit.to_i
+          puts "VERY GOOD."
+        elsif guesses.to_i == choice_limit.to_i
+          puts "GOOD."
+        else
+          puts "YOU SHOULD HAVE BEEN ABLE TO GET IT IN ONLY #{choice_limit}"
+        end
+        print "\n\n\n\n\n"
+      end
+    end
+end
+
+
+def main
+  print_intro
+  puts "WHAT LIMIT DO YOU WANT"
+  limit = gets.chomp
+  choice_limit = (Math.log(limit.to_i)/Math.log(2)+1).to_i
+  while 1
+    game_play(limit,choice_limit)
+  end
+end
+
+main
diff --git a/00_Alternate_Languages/41_Guess/rust/README.md b/00_Alternate_Languages/41_Guess/rust/README.md
new file mode 100644
index 00000000..fc6468b9
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/rust/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Rust](https://www.rust-lang.org/)
diff --git a/00_Alternate_Languages/41_Guess/rust/src/main.rs b/00_Alternate_Languages/41_Guess/rust/src/main.rs
new file mode 100644
index 00000000..ad0681cb
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/rust/src/main.rs
@@ -0,0 +1,109 @@
+//#######################################################
+//
+// Guess
+//
+// From: Basic Computer Games (1978)
+//
+// "In program Guess, the computer  chooses a random
+//  integer between 0 and any limit and any limit you
+//  set. You must then try to guess the number the
+//  computer has choosen using the clues provideed by
+//  the computer.
+//   You should be able to guess the number in one less
+//  than the number of digits needed to  represent the
+//  number in binary notation - i.e. in base 2. This ought
+//  to give you a clue as to the optimum search technique.
+//   Guess converted from the original program in FOCAL
+//  which appeared in the book "Computers in the Classroom"
+//  by Walt Koetke of Lexington High School, Lexington,
+//   Massaschusetts.
+//
+//#######################################################
+
+
+use rand::Rng;
+use std::io;
+use std::cmp::Ordering;
+// Rust haven't log2 in the standard library so I added fn log_2
+const fn num_bits() -> usize { std::mem::size_of::() * 8 }
+
+fn main() {
+
+    let mut rng = rand::thread_rng();
+    let mut still_guessing = true;
+    let limit = set_limit();
+    let limit_goal = 1+(log_2(limit.try_into().unwrap())/log_2(2)) ;
+    loop{
+
+        let mut won = false;
+        let mut guess_count = 1;
+        let my_guess = rng.gen_range(1..limit);
+
+        println!("I'm thinking of a number between 1 and {}",limit);
+        println!("Now you try to guess what it is.");
+
+        while still_guessing {
+            let inp = get_input()
+                .trim()
+                .parse::().unwrap();
+            println!("\n\n\n");
+            if inp < my_guess {
+                println!("Too low. Try a bigger answer");
+                guess_count+=1;
+            }
+            else if inp > my_guess {
+                println!("Too high. Try a smaller answer");
+                guess_count+=1;
+            }
+            else {
+                println!("That's it! You got it in {} tries", guess_count);
+                won = true;
+                still_guessing = false;
+            }
+        }
+        if won {
+            match guess_count.cmp(&limit_goal) {
+                Ordering::Less => println!("Very good."),
+                Ordering::Equal => println!("Good."),
+                Ordering::Greater => println!("You should have been able to get it in only {}", limit_goal),
+            }
+
+            println!("\n\n\n");
+            still_guessing = true;
+        } else {
+            println!("\n\n\n");
+        }
+    }
+}
+
+fn log_2(x:i32) -> u32 {
+    assert!(x > 0);
+    num_bits::() as u32 - x.leading_zeros() - 1
+}
+
+fn set_limit() -> i64 {
+
+    println!("                   Guess");
+    println!("\n\n\n");
+    println!("This is a number guessing game. I'll think");
+    println!("of a number between 1 and any limit you want.\n");
+    println!("Then you have to guess what it is\n");
+    println!("What limit do you want?");
+
+    let inp = get_input().trim().parse::().unwrap();
+
+    if inp >= 2 {
+        inp
+    }
+    else {
+        set_limit()
+    }
+}
+
+fn get_input() -> String {
+    let mut input = String::new();
+    io::stdin()
+        .read_line(&mut input)
+        .expect("Your input is not correct");
+    input
+}
diff --git a/00_Alternate_Languages/41_Guess/vbnet/Guess.sln b/00_Alternate_Languages/41_Guess/vbnet/Guess.sln
new file mode 100644
index 00000000..2238b0be
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/vbnet/Guess.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Guess", "Guess.vbproj", "{33AB1024-1609-4163-BEAF-BA02A5D42F8A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{33AB1024-1609-4163-BEAF-BA02A5D42F8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{33AB1024-1609-4163-BEAF-BA02A5D42F8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{33AB1024-1609-4163-BEAF-BA02A5D42F8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{33AB1024-1609-4163-BEAF-BA02A5D42F8A}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/41_Guess/vbnet/Guess.vbproj b/00_Alternate_Languages/41_Guess/vbnet/Guess.vbproj
new file mode 100644
index 00000000..8a5fe396
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/vbnet/Guess.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Guess
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/41_Guess/vbnet/README.md b/00_Alternate_Languages/41_Guess/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/41_Guess/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/42_Gunner/README.md b/00_Alternate_Languages/42_Gunner/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/42_Gunner/csharp/Gunner.csproj b/00_Alternate_Languages/42_Gunner/csharp/Gunner.csproj
new file mode 100644
index 00000000..74abf5c9
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/csharp/Gunner.csproj
@@ -0,0 +1,10 @@
+
+
+  
+    Exe
+    net6.0
+    enable
+    enable
+  
+
+
diff --git a/00_Alternate_Languages/42_Gunner/csharp/Gunner.sln b/00_Alternate_Languages/42_Gunner/csharp/Gunner.sln
new file mode 100644
index 00000000..5fadb359
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/csharp/Gunner.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gunner", "Gunner.csproj", "{0279F69D-A69A-49B6-867C-78AA4F4DB962}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{0279F69D-A69A-49B6-867C-78AA4F4DB962}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0279F69D-A69A-49B6-867C-78AA4F4DB962}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0279F69D-A69A-49B6-867C-78AA4F4DB962}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0279F69D-A69A-49B6-867C-78AA4F4DB962}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {09C668DA-38D4-4EF4-9FCA-EB1FF9EF6067}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/42_Gunner/csharp/Program.cs b/00_Alternate_Languages/42_Gunner/csharp/Program.cs
new file mode 100644
index 00000000..c9e45882
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/csharp/Program.cs
@@ -0,0 +1,124 @@
+namespace Gunner
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            PrintIntro();
+
+            string keepPlaying = "Y";
+
+            while (keepPlaying == "Y") {
+                PlayGame();
+                Console.WriteLine("TRY AGAIN (Y OR N)");
+                keepPlaying = Console.ReadLine();
+            }
+        }
+
+        static void PlayGame()
+        {
+            int totalAttempts = 0;
+            int amountOfGames = 0;
+
+            while (amountOfGames < 4) {
+
+                int maximumRange = new Random().Next(0, 40000) + 20000;
+                Console.WriteLine($"MAXIMUM RANGE OF YOUR GUN IS {maximumRange} YARDS." + Environment.NewLine + Environment.NewLine + Environment.NewLine);
+
+                int distanceToTarget = (int) (maximumRange * (0.1 + 0.8 * new Random().NextDouble()));
+                Console.WriteLine($"DISTANCE TO THE TARGET IS {distanceToTarget} YARDS.");
+
+                (bool gameWon, int attempts) = HitTheTarget(maximumRange, distanceToTarget);
+
+                if(!gameWon) {
+                    Console.WriteLine(Environment.NewLine + "BOOM !!!!   YOU HAVE JUST BEEN DESTROYED" + Environment.NewLine +
+                        "BY THE ENEMY." + Environment.NewLine + Environment.NewLine + Environment.NewLine
+                    );
+                    PrintReturnToBase();
+                    break;
+                } else {
+                    amountOfGames += 1;
+                    totalAttempts += attempts;
+
+                    Console.WriteLine($"TOTAL ROUNDS EXPENDED WERE:{totalAttempts}");
+
+                    if (amountOfGames < 4) {
+                        Console.WriteLine("THE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...");
+                    } else {
+                        if (totalAttempts > 18) {
+                            PrintReturnToBase();
+                        } else {
+                            Console.WriteLine($"NICE SHOOTING !!");
+                        }
+                    }
+                }
+            }
+        }
+
+        static (bool, int) HitTheTarget(int maximumRange, int distanceToTarget)
+        {
+            int attempts = 0;
+
+            while (attempts < 6)
+            {
+                int elevation = GetElevation();
+
+                int differenceBetweenTargetAndImpact = CalculateDifferenceBetweenTargetAndImpact(maximumRange, distanceToTarget, elevation);
+
+                if (Math.Abs(differenceBetweenTargetAndImpact) < 100)
+                {
+                    Console.WriteLine($"*** TARGET DESTROYED *** {attempts} ROUNDS OF AMMUNITION EXPENDED.");
+                    return (true, attempts);
+                }
+                else if (differenceBetweenTargetAndImpact > 100)
+                {
+                    Console.WriteLine($"OVER TARGET BY {Math.Abs(differenceBetweenTargetAndImpact)} YARDS.");
+                }
+                else
+                {
+                    Console.WriteLine($"SHORT OF TARGET BY {Math.Abs(differenceBetweenTargetAndImpact)} YARDS.");
+                }
+
+                attempts += 1;
+            }
+            return (false, attempts);
+        }
+
+        static int CalculateDifferenceBetweenTargetAndImpact(int maximumRange, int distanceToTarget, int elevation)
+        {
+            double weirdNumber = 2 * elevation / 57.3;
+            double distanceShot = maximumRange * Math.Sin(weirdNumber);
+            return (int)distanceShot - distanceToTarget;
+        }
+
+        static void PrintReturnToBase()
+        {
+            Console.WriteLine("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!");
+        }
+
+        static int GetElevation()
+        {
+            Console.WriteLine("ELEVATION");
+            int elevation = int.Parse(Console.ReadLine());
+            if (elevation > 89) {
+                Console.WriteLine("MAXIMUM ELEVATION IS 89 DEGREES");
+                return GetElevation();
+            }
+            if (elevation < 1) {
+                Console.WriteLine("MINIMUM ELEVATION IS 1 DEGREE");
+                return GetElevation();
+            }
+            return elevation;
+        }
+
+        static void PrintIntro()
+        {
+            Console.WriteLine(new String(' ', 30) + "GUNNER");
+            Console.WriteLine(new String(' ', 15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY" + Environment.NewLine + Environment.NewLine + Environment.NewLine);
+            Console.WriteLine("YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN");
+            Console.WriteLine("CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE");
+            Console.WriteLine("WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS");
+            Console.WriteLine("OF THE TARGET WILL DESTROY IT." + Environment.NewLine);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/42_Gunner/csharp/README.md b/00_Alternate_Languages/42_Gunner/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/42_Gunner/gunner.bas b/00_Alternate_Languages/42_Gunner/gunner.bas
new file mode 100644
index 00000000..24577285
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/gunner.bas
@@ -0,0 +1,52 @@
+10 PRINT TAB(30);"GUNNER"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+130 PRINT "YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN"
+140 PRINT "CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE"
+150 PRINT "WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS"
+160 PRINT "OF THE TARGET WILL DESTROY IT." : PRINT
+170 R=INT(40000*RND(1)+20000)
+180 PRINT "MAXIMUM RANGE OF YOUR GUN IS";R;" YARDS."
+185 Z=0
+190 PRINT
+195 S1=0
+200 T=INT(R*(.1+.8*RND(1)))
+210 S=0
+220 GOTO 370
+230 PRINT "MINIMUM ELEVATION IS ONE DEGREE."
+240 GOTO 390
+250 PRINT "MAXIMUM ELEVATION IS 89 DEGREES."
+260 GOTO 390
+270 PRINT "OVER TARGET BY ";ABS(E);"YARDS."
+280 GOTO 390
+290 PRINT "SHORT OF TARGET BY "ABS(E);"YARDS."
+300 GOTO 390
+320 PRINT "*** TARGET DESTROYED ***  ";S;"ROUNDS OF AMMUNITION EXPENDED."
+325 S1=S1+S
+330 IF Z=4 THEN 490
+340 Z=Z+1
+345 PRINT
+350 PRINT "THE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY..."
+360 GOTO 200
+370 PRINT "DISTANCE TO THE TARGET IS "T;" YARDS."
+380 PRINT
+390 PRINT
+400 INPUT "ELEVATION";B
+420 IF B>89 THEN 250
+430 IF B<1 THEN 230
+440 S=S+1
+442 IF S<6 THEN 450
+444 PRINT:PRINT "BOOM !!!!   YOU HAVE JUST BEEN DESTROYED ";
+446 PRINT "BY THE ENEMY." : PRINT : PRINT : PRINT : GOTO 495
+450 B2=2*B/57.3 : I=R*SIN(B2) : X=T-I : E=INT(X)
+460 IF ABS(E)<100 THEN 320
+470 IF E>100 THEN 290
+480 GOTO 270
+490 PRINT : PRINT : PRINT "TOTAL ROUNDS EXPENDED WERE:";S1
+492 IF S1>18 THEN 495
+493 PRINT "NICE SHOOTING !!" : GOTO 500
+495 PRINT "BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!"
+500 PRINT : INPUT "TRY AGAIN (Y OR N)";Z$
+510 IF Z$="Y" THEN 170
+520 PRINT:PRINT "OK.  RETURN TO BASE CAMP."
+999 END
diff --git a/00_Alternate_Languages/42_Gunner/java/Gunner.java b/00_Alternate_Languages/42_Gunner/java/Gunner.java
new file mode 100644
index 00000000..0f56abab
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/java/Gunner.java
@@ -0,0 +1,108 @@
+import java.util.Random;
+import java.util.Scanner;
+
+public class Gunner {
+
+    public static final int MAX_ROUNDS = 6;
+    public static final int MAX_ENEMIES = 4;
+    public static final int ERROR_DISTANCE = 100;
+
+    private static Scanner scanner = new Scanner(System.in);
+    private static Random random = new Random();
+
+    public static void main(String[] args) {
+        println("                              GUNNER");
+        println("               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+        println();
+        println();
+        println();
+        println("YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN");
+        println("CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE");
+        println("WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN " + ERROR_DISTANCE + " YARDS");
+        println("OF THE TARGET WILL DESTROY IT.");
+        println();
+        while (true) {
+            int maxRange = random.nextInt(40000) + 20000;
+            int enemyCount = 0;
+            int totalRounds = 0;
+            println("MAXIMUM RANGE OF YOUR GUN IS " + maxRange + " YARDS.\n");
+
+            while (true) {
+                int rounds = fightEnemy(maxRange);
+                totalRounds += rounds;
+
+                if (enemyCount == MAX_ENEMIES || rounds >= MAX_ROUNDS) {
+                    if (rounds < MAX_ROUNDS) {
+                        println("\n\n\nTOTAL ROUNDS EXPENDED WERE:" + totalRounds);
+                    }
+                    if (totalRounds > 18 || rounds >= MAX_ROUNDS) {
+                        println("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!");
+                    } else {
+                        println("NICE SHOOTING !!");
+                    }
+                    println("\nTRY AGAIN (Y OR N)");
+                    String tryAgainResponse = scanner.nextLine();
+                    if ("Y".equals(tryAgainResponse) || "y".equals(tryAgainResponse)) {
+                        break;
+                    }
+                    println("\nOK.  RETURN TO BASE CAMP.");
+                    return;
+                }
+                enemyCount++;
+                println("\nTHE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...");
+            }
+        }
+    }
+
+    private static int fightEnemy(int maxRange) {
+        int rounds = 0;
+        long target = Math.round(maxRange * (random.nextDouble() * 0.8 + 0.1));
+        println("      DISTANCE TO THE TARGET IS " + target + " YARDS.");
+
+        while (true) {
+            println("\nELEVATION?");
+            double elevation = Double.parseDouble(scanner.nextLine());
+            if (elevation > 89.0) {
+                println("MAXIMUM ELEVATION IS 89 DEGREES.");
+                continue;
+            }
+            if (elevation < 1.0) {
+                println("MINIMUM ELEVATION IS ONE DEGREE.");
+                continue;
+            }
+            rounds++;
+            if (rounds >= MAX_ROUNDS) {
+                println("\nBOOM !!!!   YOU HAVE JUST BEEN DESTROYED ");
+                println("BY THE ENEMY.\n\n\n");
+                break;
+            }
+
+            long error = calculateError(maxRange, target, elevation);
+            if (Math.abs(error) < ERROR_DISTANCE) {
+                println("*** TARGET DESTROYED ***  " + rounds + " ROUNDS OF AMMUNITION EXPENDED.");
+                break;
+            } else if (error > ERROR_DISTANCE) {
+                println("SHORT OF TARGET BY " + Math.abs(error) + " YARDS.");
+            } else {
+                println("OVER TARGET BY " + Math.abs(error) + " YARDS.");
+            }
+
+        }
+        return rounds;
+    }
+
+    private static long calculateError(int maxRange, long target, double elevationInDegrees) {
+        double elevationInRadians = Math.PI * elevationInDegrees / 90.0; //convert degrees to radians
+        double impact = maxRange * Math.sin(elevationInRadians);
+        double error = target - impact;
+        return Math.round(error);
+    }
+
+    private static void println(String s) {
+        System.out.println(s);
+    }
+
+    private static void println() {
+        System.out.println();
+    }
+}
diff --git a/00_Alternate_Languages/42_Gunner/java/README.md b/00_Alternate_Languages/42_Gunner/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/42_Gunner/javascript/README.md b/00_Alternate_Languages/42_Gunner/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/42_Gunner/javascript/gunner.html b/00_Alternate_Languages/42_Gunner/javascript/gunner.html
new file mode 100644
index 00000000..431c9064
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/javascript/gunner.html
@@ -0,0 +1,9 @@
+
+
+GUNNER
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/42_Gunner/javascript/gunner.js b/00_Alternate_Languages/42_Gunner/javascript/gunner.js
new file mode 100644
index 00000000..892617de
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/javascript/gunner.js
@@ -0,0 +1,139 @@
+// GUNNER
+//
+// 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;
+}
+
+print(tab(30) + "GUNNER\n");
+print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+print("\n");
+print("\n");
+print("\n");
+print("YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN\n");
+print("CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE\n");
+print("WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS\n");
+print("OF THE TARGET WILL DESTROY IT.\n");
+print("\n");
+
+// Main control section
+async function main()
+{
+    while (1) {
+        r = Math.floor(40000 * Math.random() + 20000);
+        print("MAXIMUM RANGE OF YOUR GUN IS " + r + " YARDS.\n");
+        z = 0;
+        print("\n");
+        s1 = 0;
+        while (1) {
+            t = Math.floor(r * (0.1 + 0.8 * Math.random()));
+            s = 0;
+            print("DISTANCE TO THE TARGET IS " + t + " YARDS.\n");
+            print("\n");
+
+            while (1) {
+                print("\n");
+                print("ELEVATION");
+                b = parseFloat(await input());
+                if (b > 89) {
+                    print("MAXIMUM ELEVATION IS 89 DEGREES.\n");
+                    continue;
+                }
+                if (b < 1) {
+                    print("MINIMUM ELEVATION IS ONE DEGREE.\n");
+                    continue;
+                }
+                if (++s >= 6) {
+                    print("\n");
+                    print("BOOM !!!!   YOU HAVE JUST BEEN DESTROYED BY THE ENEMY.\n");
+                    print("\n");
+                    print("\n");
+                    print("\n");
+                    e = 0;
+                    break;
+                }
+                b2 = 2 * b / 57.3;
+                i = r * Math.sin(b2);
+                x = t - i;
+                e = Math.floor(x);
+                if (true) { //Math.abs(e) < 100) {
+                    e = 1;
+                    break;
+                }
+                if (e > 100) {
+                    print("SHORT OF TARGET BY " + Math.abs(e) + " YARDS.\n");
+                } else {
+                    print("OVER TARGET BY " + Math.abs(e) + " YARDS.\n");
+                }
+            }
+            if (e == 1) {
+                print("*** TARGET DESTROYED *** " + s + " ROUNDS OF AMMUNITION EXPENDED.\n");
+                s1 += s;
+                if (z == 4) {
+                    print("\n");
+                    print("\n");
+                    print("TOTAL ROUND EXPENDED WERE: " + s1 + "\n");
+                    break;
+                } else {
+                    z++;
+                    print("\n");
+                    print("THE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY...\n");
+                }
+            } else {
+                s1 = 19;
+                break;
+            }
+        }
+        if (s1 > 18) {
+            print("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!\n");
+        } else {
+            print("NICE SHOOTING !!");
+        }
+        print("\n");
+        print("TRY AGAIN (Y OR N)");
+        str = await input();
+        if (str.substr(0, 1) != "Y")
+            break;
+    }
+    print("\n");
+    print("OK.  RETURN TO BASE CAMP.\n");
+}
+
+main();
diff --git a/18_Bullseye/pascal/README.md b/00_Alternate_Languages/42_Gunner/pascal/README.md
similarity index 100%
rename from 18_Bullseye/pascal/README.md
rename to 00_Alternate_Languages/42_Gunner/pascal/README.md
diff --git a/00_Alternate_Languages/42_Gunner/perl/README.md b/00_Alternate_Languages/42_Gunner/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/42_Gunner/python/README.md b/00_Alternate_Languages/42_Gunner/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/42_Gunner/python/gunner.py b/00_Alternate_Languages/42_Gunner/python/gunner.py
new file mode 100644
index 00000000..77c527bf
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/python/gunner.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+#
+# Ported to Python by @iamtraction
+
+from math import sin
+from random import random
+
+
+def gunner():
+    gun_range = int(40000 * random() + 20000)
+
+    print("\nMAXIMUM RANGE OF YOUR GUN IS", gun_range, "YARDS.")
+
+    killed_enemies = 0
+    S1 = 0
+
+    while True:
+        target_distance = int(gun_range * (0.1 + 0.8 * random()))
+        shots = 0
+
+        print("\nDISTANCE TO THE TARGET IS", target_distance, "YARDS.")
+
+        while True:
+            elevation = float(input("\n\nELEVATION? "))
+
+            if elevation > 89:
+                print("MAXIMUM ELEVATION IS 89 DEGREES.")
+                continue
+
+            if elevation < 1:
+                print("MINIMUM ELEVATION IS ONE DEGREE.")
+                continue
+
+            shots += 1
+
+            if shots < 6:
+                B2 = 2 * elevation / 57.3
+                shot_impact = gun_range * sin(B2)
+                shot_proximity = target_distance - shot_impact
+                shot_proximity_int = int(shot_proximity)
+
+                if abs(shot_proximity_int) < 100:
+                    print(
+                        "*** TARGET DESTROYED *** ",
+                        shots,
+                        "ROUNDS OF AMMUNITION EXPENDED.",
+                    )
+                    S1 += shots
+                    if killed_enemies == 4:
+                        print("\n\nTOTAL ROUNDS EXPENDED WERE: ", S1)
+                        if S1 > 18:
+                            print("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!")
+                            return
+                        else:
+                            print("NICE SHOOTING !!")
+                            return
+                    else:
+                        killed_enemies += 1
+                        print(
+                            "\nTHE FORWARD OBSERVER HAS SIGHTED MORE ENEMY ACTIVITY..."
+                        )
+                        break
+                else:
+                    if shot_proximity_int > 100:
+                        print("SHORT OF TARGET BY", abs(shot_proximity_int), "YARDS.")
+                    else:
+                        print("OVER TARGET BY", abs(shot_proximity_int), "YARDS.")
+            else:
+                print("\nBOOM !!!!   YOU HAVE JUST BEEN DESTROYED BY THE ENEMY.\n\n\n")
+                print("BETTER GO BACK TO FORT SILL FOR REFRESHER TRAINING!")
+                return
+
+
+if __name__ == "__main__":
+    print(" " * 33 + "GUNNER")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+
+    print("\n\n\n")
+
+    print("YOU ARE THE OFFICER-IN-CHARGE, GIVING ORDERS TO A GUN")
+    print("CREW, TELLING THEM THE DEGREES OF ELEVATION YOU ESTIMATE")
+    print("WILL PLACE A PROJECTILE ON TARGET.  A HIT WITHIN 100 YARDS")
+    print("OF THE TARGET WILL DESTROY IT.")
+
+    while True:
+        gunner()
+
+        Y = input("TRY AGAIN (Y OR N)? ")
+        if Y != "Y":
+            print("\nOK.  RETURN TO BASE CAMP.")
+            break
diff --git a/00_Alternate_Languages/42_Gunner/ruby/README.md b/00_Alternate_Languages/42_Gunner/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/42_Gunner/vbnet/Gunner.sln b/00_Alternate_Languages/42_Gunner/vbnet/Gunner.sln
new file mode 100644
index 00000000..33d68126
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/vbnet/Gunner.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Gunner", "Gunner.vbproj", "{CC347B04-B99C-4F77-BFCF-2DDFBB4A135D}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{CC347B04-B99C-4F77-BFCF-2DDFBB4A135D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CC347B04-B99C-4F77-BFCF-2DDFBB4A135D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CC347B04-B99C-4F77-BFCF-2DDFBB4A135D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CC347B04-B99C-4F77-BFCF-2DDFBB4A135D}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/42_Gunner/vbnet/Gunner.vbproj b/00_Alternate_Languages/42_Gunner/vbnet/Gunner.vbproj
new file mode 100644
index 00000000..19918a80
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/vbnet/Gunner.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Gunner
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/42_Gunner/vbnet/README.md b/00_Alternate_Languages/42_Gunner/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/42_Gunner/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/43_Hammurabi/README.md b/00_Alternate_Languages/43_Hammurabi/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/ActionResult.cs b/00_Alternate_Languages/43_Hammurabi/csharp/ActionResult.cs
new file mode 100644
index 00000000..58d4f3cb
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/ActionResult.cs
@@ -0,0 +1,37 @@
+namespace Hammurabi
+{
+    /// 
+    /// Enumerates the different possible outcomes of attempting the various
+    /// actions in the game.
+    /// 
+    public enum ActionResult
+    {
+        /// 
+        /// The action was a success.
+        /// 
+        Success,
+
+        /// 
+        /// The action could not be completed because the city does not have
+        /// enough bushels of grain.
+        /// 
+        InsufficientStores,
+
+        /// 
+        /// The action could not be completed because the city does not have
+        /// sufficient acreage.
+        /// 
+        InsufficientLand,
+
+        /// 
+        /// The action could not be completed because the city does not have
+        /// sufficient population.
+        /// 
+        InsufficientPopulation,
+
+        /// 
+        /// The requested action offended the city steward.
+        /// 
+        Offense
+    }
+}
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/Controller.cs b/00_Alternate_Languages/43_Hammurabi/csharp/Controller.cs
new file mode 100644
index 00000000..afdb83d2
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/Controller.cs
@@ -0,0 +1,64 @@
+using System;
+
+namespace Hammurabi
+{
+    /// 
+    /// Provides methods for reading input from the user.
+    /// 
+    public static class Controller
+    {
+        /// 
+        /// Continuously prompts the user to enter a number until he or she
+        /// enters a valid number and updates the game state.
+        /// 
+        /// 
+        /// The current game state.
+        /// 
+        /// 
+        /// Action that will display the prompt to the user.
+        /// 
+        /// 
+        /// The rule to invoke once input is retrieved.
+        /// 
+        /// 
+        /// The updated game state.
+        /// 
+        public static GameState UpdateGameState(
+            GameState state,
+            Action prompt,
+            Func rule)
+        {
+            while (true)
+            {
+                prompt();
+
+                if (!Int32.TryParse(Console.ReadLine(), out var amount))
+                {
+                    View.ShowInvalidNumber();
+                    continue;
+                }
+
+                var (newState, result) = rule(state, amount);
+
+                switch (result)
+                {
+                    case ActionResult.InsufficientLand:
+                        View.ShowInsufficientLand(state);
+                        break;
+                    case ActionResult.InsufficientPopulation:
+                        View.ShowInsufficientPopulation(state);
+                        break;
+                    case ActionResult.InsufficientStores:
+                        View.ShowInsufficientStores(state);
+                        break;
+                    case ActionResult.Offense:
+                        // Not sure why we have to blow up the game here...
+                        // Maybe this made sense in the 70's.
+                        throw new GreatOffence();
+                    default:
+                        return newState;
+                }
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/GameResult.cs b/00_Alternate_Languages/43_Hammurabi/csharp/GameResult.cs
new file mode 100644
index 00000000..9c143375
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/GameResult.cs
@@ -0,0 +1,45 @@
+namespace Hammurabi
+{
+    /// 
+    /// Stores the final game result.
+    /// 
+    public record GameResult
+    {
+        /// 
+        /// Gets the player's performance rating.
+        /// 
+        public PerformanceRating Rating { get; init; }
+
+        /// 
+        /// Gets the number of acres in the city per person.
+        /// 
+        public int AcresPerPerson { get; init; }
+
+        /// 
+        /// Gets the number of people who starved the final year in office.
+        /// 
+        public int FinalStarvation { get; init; }
+
+        /// 
+        /// Gets the total number of people who starved.
+        /// 
+        public int TotalStarvation { get; init; }
+
+        /// 
+        /// Gets the average starvation rate per year (as a percentage
+        /// of population).
+        /// 
+        public int AverageStarvationRate { get; init; }
+
+        /// 
+        /// Gets the number of people who want to assassinate the player.
+        /// 
+        public int Assassins { get; init; }
+
+        /// 
+        /// Gets a flag indicating whether the player was impeached for
+        /// starving too many people.
+        /// 
+        public bool WasPlayerImpeached { get; init; }
+    }
+}
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/GameState.cs b/00_Alternate_Languages/43_Hammurabi/csharp/GameState.cs
new file mode 100644
index 00000000..41e6fe11
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/GameState.cs
@@ -0,0 +1,73 @@
+namespace Hammurabi
+{
+    /// 
+    /// Stores the state of the game.
+    /// 
+    public record GameState
+    {
+        /// 
+        /// Gets the current game year.
+        /// 
+        public int Year { get; init; }
+
+        /// 
+        /// Gets the city's population.
+        /// 
+        public int Population { get; init; }
+
+        /// 
+        /// Gets the population increase this year.
+        /// 
+        public int PopulationIncrease { get; init; }
+
+        /// 
+        /// Gets the number of people who starved.
+        /// 
+        public int Starvation { get; init; }
+
+        /// 
+        /// Gets the city's size in acres.
+        /// 
+        public int Acres { get; init; }
+
+        /// 
+        /// Gets the price for an acre of land (in bushels).
+        /// 
+        public int LandPrice { get; init; }
+
+        /// 
+        /// Gets the number of bushels of grain in the city stores.
+        /// 
+        public int Stores { get; init; }
+
+        /// 
+        /// Gets the amount of food distributed to the people.
+        /// 
+        public int FoodDistributed { get; init; }
+
+        /// 
+        /// Gets the number of acres that were planted.
+        /// 
+        public int AcresPlanted { get; init; }
+
+        /// 
+        /// Gets the number of bushels produced per acre.
+        /// 
+        public int Productivity { get; init; }
+
+        /// 
+        /// Gets the amount of food lost to rats.
+        /// 
+        public int Spoilage { get; init; }
+
+        /// 
+        /// Gets a flag indicating whether the current year is a plague year.
+        /// 
+        public bool IsPlagueYear { get; init; }
+
+        /// 
+        /// Gets a flag indicating whether the player has been impeached.
+        /// 
+        public bool IsPlayerImpeached { get; init; }
+    }
+}
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/GreatOffence.cs b/00_Alternate_Languages/43_Hammurabi/csharp/GreatOffence.cs
new file mode 100644
index 00000000..98791492
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/GreatOffence.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace Hammurabi
+{
+    /// 
+    /// Indicates that the game cannot continue due to the player's extreme
+    /// incompetance and/or unserious attitude!
+    /// 
+    public class GreatOffence : InvalidOperationException
+    {
+    }
+}
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/Hammurabi.csproj b/00_Alternate_Languages/43_Hammurabi/csharp/Hammurabi.csproj
new file mode 100644
index 00000000..20827042
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/Hammurabi.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/Hammurabi.sln b/00_Alternate_Languages/43_Hammurabi/csharp/Hammurabi.sln
new file mode 100644
index 00000000..7475f8fd
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/Hammurabi.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hammurabi", "Hammurabi.csproj", "{2C4407AF-5ED6-4C9F-833E-35461DF7DBBB}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{2C4407AF-5ED6-4C9F-833E-35461DF7DBBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2C4407AF-5ED6-4C9F-833E-35461DF7DBBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2C4407AF-5ED6-4C9F-833E-35461DF7DBBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2C4407AF-5ED6-4C9F-833E-35461DF7DBBB}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {89DBE213-C0F0-4ABA-BB2D-5D9AAED41FF6}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/PerformanceRating.cs b/00_Alternate_Languages/43_Hammurabi/csharp/PerformanceRating.cs
new file mode 100644
index 00000000..39454720
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/PerformanceRating.cs
@@ -0,0 +1,14 @@
+namespace Hammurabi
+{
+    /// 
+    /// Enumerates the different performance ratings that the player can
+    /// achieve.
+    /// 
+    public enum PerformanceRating
+    {
+        Disgraceful,
+        Bad,
+        Ok,
+        Terrific
+    }
+}
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/Program.cs b/00_Alternate_Languages/43_Hammurabi/csharp/Program.cs
new file mode 100644
index 00000000..8f158839
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/Program.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Immutable;
+
+namespace Hammurabi
+{
+    public static class Program
+    {
+        public const int GameLength = 10;
+
+        public static void Main(string[] args)
+        {
+            var random  = new Random() ;
+            var state   = Rules.BeginGame();
+            var history = ImmutableList.Empty;
+
+            View.ShowBanner();
+
+            try
+            {
+                while (!state.IsPlayerImpeached)
+                {
+                    state = Rules.BeginTurn(state, random);
+                    View.ShowCitySummary(state);
+
+                    if (state.Year > GameLength)
+                        break;
+
+                    View.ShowLandPrice(state);
+                    var newState = Controller.UpdateGameState(state, View.PromptBuyLand, Rules.BuyLand);
+                    state = newState.Acres != state.Acres ?
+                        newState : Controller.UpdateGameState(state, View.PromptSellLand, Rules.SellLand);
+
+                    View.ShowSeparator();
+                    state = Controller.UpdateGameState(state, View.PromptFeedPeople, Rules.FeedPeople);
+
+                    View.ShowSeparator();
+                    state = Controller.UpdateGameState(state, View.PromptPlantCrops, Rules.PlantCrops);
+
+                    state = Rules.EndTurn(state, random);
+                    history = history.Add(state);
+                }
+
+                var result = Rules.GetGameResult(history, random);
+                View.ShowGameResult(result);
+            }
+            catch (GreatOffence)
+            {
+                View.ShowGreatOffence();
+            }
+
+            View.ShowFarewell();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/README.md b/00_Alternate_Languages/43_Hammurabi/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/Rules.cs b/00_Alternate_Languages/43_Hammurabi/csharp/Rules.cs
new file mode 100644
index 00000000..36fc9c50
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/Rules.cs
@@ -0,0 +1,207 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Hammurabi
+{
+    public static class Rules
+    {
+        /// 
+        /// Creates the initial state for a new game.
+        /// 
+        public static GameState BeginGame() =>
+            new GameState
+            {
+                Year                = 0,
+                Population          = 95,
+                PopulationIncrease  = 5,
+                Starvation          = 0,
+                Acres               = 1000,
+                Stores              = 0,
+                AcresPlanted        = 1000,
+                Productivity        = 3,
+                Spoilage            = 200,
+                IsPlagueYear        = false,
+                IsPlayerImpeached   = false
+            };
+
+        /// 
+        /// Updates the game state to start a new turn.
+        /// 
+        public static GameState BeginTurn(GameState state, Random random) =>
+            state with
+            {
+                Year            = state.Year + 1,
+                Population      = (state.Population + state.PopulationIncrease - state.Starvation) / (state.IsPlagueYear ? 2 : 1),
+                LandPrice       = random.Next(10) + 17,
+                Stores          = state.Stores + (state.AcresPlanted * state.Productivity) - state.Spoilage,
+                AcresPlanted    = 0,
+                FoodDistributed = 0
+            };
+
+        /// 
+        /// Attempts to purchase the given number of acres.
+        /// 
+        /// 
+        /// The updated game state and action result.
+        /// 
+        public static (GameState newState, ActionResult result) BuyLand(GameState state, int amount)
+        {
+            var price = state.LandPrice * amount;
+
+            if (price < 0)
+                return (state, ActionResult.Offense);
+            else
+            if (price > state.Stores)
+                return (state, ActionResult.InsufficientStores);
+            else
+                return (state with { Acres = state.Acres + amount, Stores = state.Stores - price }, ActionResult.Success);
+        }
+
+        /// 
+        /// Attempts to sell the given number of acres.
+        /// 
+        /// 
+        /// The updated game state and action result.
+        /// 
+        public static (GameState newState, ActionResult result) SellLand(GameState state, int amount)
+        {
+            var price = state.LandPrice * amount;
+
+            if (price < 0)
+                return (state, ActionResult.Offense);
+            else
+            if (amount >= state.Acres)
+                return (state, ActionResult.InsufficientLand);
+            else
+                return (state with { Acres = state.Acres - amount, Stores = state.Stores + price }, ActionResult.Success);
+        }
+
+        /// 
+        /// Attempts to feed the people the given number of buschels.
+        /// 
+        /// 
+        /// 
+        /// The updated game state and action result.
+        /// 
+        public static (GameState newState, ActionResult result) FeedPeople(GameState state, int amount)
+        {
+            if (amount < 0)
+                return (state, ActionResult.Offense);
+            else
+            if (amount > state.Stores)
+                return (state, ActionResult.InsufficientStores);
+            else
+                return (state with { Stores = state.Stores - amount, FoodDistributed = state.FoodDistributed + amount }, ActionResult.Success);
+        }
+
+        /// 
+        /// Attempts to plant crops on the given number of acres.
+        /// 
+        /// 
+        /// The updated game state and action result.
+        /// 
+        public static (GameState newState, ActionResult result) PlantCrops(GameState state, int amount)
+        {
+            var storesRequired = amount / 2;
+            var maxAcres       = state.Population * 10;
+
+            if (amount < 0)
+                return (state, ActionResult.Offense);
+            else
+            if (amount > state.Acres)
+                return (state, ActionResult.InsufficientLand);
+            else
+            if (storesRequired > state.Stores)
+                return (state, ActionResult.InsufficientStores);
+            else
+            if ((state.AcresPlanted + amount) > maxAcres)
+                return (state, ActionResult.InsufficientPopulation);
+            else
+                return (state with
+                {
+                    AcresPlanted = state.AcresPlanted + amount,
+                    Stores       = state.Stores - storesRequired,
+                }, ActionResult.Success);
+        }
+
+        /// 
+        /// Ends the current turn and returns the updated game state.
+        /// 
+        public static GameState EndTurn(GameState state, Random random)
+        {
+            var productivity = random.Next(1, 6);
+            var harvest = productivity * state.AcresPlanted;
+
+            var spoilage = random.Next(1, 6) switch
+            {
+                2 => state.Stores / 2,
+                4 => state.Stores / 4,
+                _ => 0
+            };
+
+            var populationIncrease= (int)((double)random.Next(1, 6) * (20 * state.Acres + state.Stores + harvest - spoilage) / state.Population / 100 + 1);
+
+            var plagueYear = random.Next(20) < 3;
+
+            var peopleFed  = state.FoodDistributed / 20;
+            var starvation = peopleFed < state.Population ? state.Population - peopleFed : 0;
+            var impeached  = starvation > state.Population * 0.45;
+
+            return state with
+            {
+                Productivity       = productivity,
+                Spoilage           = spoilage,
+                PopulationIncrease = populationIncrease,
+                Starvation         = starvation,
+                IsPlagueYear       = plagueYear,
+                IsPlayerImpeached  = impeached
+            };
+        }
+
+        /// 
+        /// Examines the game's history to arrive at the final result.
+        /// 
+        public static GameResult GetGameResult(IEnumerable history, Random random)
+        {
+            var (_, averageStarvationRate, totalStarvation, finalState) = history.Aggregate(
+                (count: 0, starvationRate: 0, totalStarvation: 0, finalState: default(GameState)),
+                (stats, state) =>
+                (
+                    stats.count + 1,
+                    ((stats.starvationRate * stats.count) + (state.Starvation * 100 / state.Population)) / (stats.count + 1),
+                    stats.totalStarvation + state.Starvation,
+                    state
+                ));
+
+            var acresPerPerson = finalState.Acres / finalState.Population;
+
+            var rating = finalState.IsPlayerImpeached ?
+                PerformanceRating.Disgraceful :
+                (averageStarvationRate, acresPerPerson) switch
+                {
+                    (> 33, _) => PerformanceRating.Disgraceful,
+                    (_, < 7)  => PerformanceRating.Disgraceful,
+                    (> 10, _) => PerformanceRating.Bad,
+                    (_, < 9)  => PerformanceRating.Bad,
+                    (> 3, _)  => PerformanceRating.Ok,
+                    (_, < 10) => PerformanceRating.Ok,
+                    _         => PerformanceRating.Terrific
+                };
+
+            var assassins = rating == PerformanceRating.Ok ?
+                random.Next(0, (int)(finalState.Population * 0.8)) : 0;
+
+            return new GameResult
+            {
+                Rating                = rating,
+                AcresPerPerson        = acresPerPerson,
+                FinalStarvation       = finalState.Starvation,
+                TotalStarvation       = totalStarvation,
+                AverageStarvationRate = averageStarvationRate,
+                Assassins             = assassins,
+                WasPlayerImpeached    = finalState.IsPlayerImpeached
+            };
+        }
+    }
+}
diff --git a/00_Alternate_Languages/43_Hammurabi/csharp/View.cs b/00_Alternate_Languages/43_Hammurabi/csharp/View.cs
new file mode 100644
index 00000000..fcfb4cd5
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/csharp/View.cs
@@ -0,0 +1,193 @@
+using System;
+
+namespace Hammurabi
+{
+    /// 
+    /// Provides various methods for presenting information to the user.
+    /// 
+    public static class View
+    {
+        /// 
+        /// Shows the introductory banner to the player.
+        /// 
+        public static void ShowBanner()
+        {
+            Console.WriteLine("                                HAMURABI");
+            Console.WriteLine("               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA");
+            Console.WriteLine("FOR A TEN-YEAR TERM OF OFFICE.");
+        }
+
+        /// 
+        /// Shows a summary of the current state of the city.
+        /// 
+        public static void ShowCitySummary(GameState state)
+        {
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("HAMURABI:  I BEG TO REPORT TO YOU,");
+            Console.WriteLine($"IN YEAR {state.Year}, {state.Starvation} PEOPLE STARVED, {state.PopulationIncrease} CAME TO THE CITY,");
+
+            if (state.IsPlagueYear)
+            {
+                Console.WriteLine("A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED.");
+            }
+
+            Console.WriteLine($"POPULATION IS NOW {state.Population}");
+            Console.WriteLine($"THE CITY NOW OWNS {state.Acres} ACRES.");
+            Console.WriteLine($"YOU HARVESTED {state.Productivity} BUSHELS PER ACRE.");
+            Console.WriteLine($"THE RATS ATE {state.Spoilage} BUSHELS.");
+            Console.WriteLine($"YOU NOW HAVE {state.Stores} BUSHELS IN STORE.");
+            Console.WriteLine();
+        }
+
+        /// 
+        /// Shows the current cost of land.
+        /// 
+        /// 
+        public static void ShowLandPrice(GameState state)
+        {
+            Console.WriteLine ($"LAND IS TRADING AT {state.LandPrice} BUSHELS PER ACRE.");
+        }
+
+        /// 
+        /// Displays a section separator.
+        /// 
+        public static void ShowSeparator()
+        {
+            Console.WriteLine();
+        }
+
+        /// 
+        /// Inform the player that he or she has entered an invalid number.
+        /// 
+        public static void ShowInvalidNumber()
+        {
+            Console.WriteLine("PLEASE ENTER A VALID NUMBER");
+        }
+
+        /// 
+        /// Inform the player that he or she has insufficient acreage.
+        /// 
+        public static void ShowInsufficientLand(GameState state)
+        {
+            Console.WriteLine($"HAMURABI:  THINK AGAIN.  YOU OWN ONLY {state.Acres} ACRES.  NOW THEN,");
+        }
+
+        /// 
+        /// Inform the player that he or she has insufficient population.
+        /// 
+        public static void ShowInsufficientPopulation(GameState state)
+        {
+            Console.WriteLine($"BUT YOU HAVE ONLY {state.Population} PEOPLE TO TEND THE FIELDS!  NOW THEN,");
+        }
+
+        /// 
+        /// Inform the player that he or she has insufficient grain stores.
+        /// 
+        public static void ShowInsufficientStores(GameState state)
+        {
+            Console.WriteLine("HAMURABI:  THINK AGAIN.  YOU HAVE ONLY");
+            Console.WriteLine($"{state.Stores} BUSHELS OF GRAIN.  NOW THEN,");
+        }
+
+        /// 
+        /// Show the player that he or she has caused great offence.
+        /// 
+        public static void ShowGreatOffence()
+        {
+            Console.WriteLine();
+            Console.WriteLine("HAMURABI:  I CANNOT DO WHAT YOU WISH.");
+            Console.WriteLine("GET YOURSELF ANOTHER STEWARD!!!!!");
+        }
+
+        /// 
+        /// Shows the game's final result to the user.
+        /// 
+        public static void ShowGameResult(GameResult result)
+        {
+            if (!result.WasPlayerImpeached)
+            {
+                Console.WriteLine($"IN YOUR 10-YEAR TERM OF OFFICE, {result.AverageStarvationRate} PERCENT OF THE");
+                Console.WriteLine("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF");
+                Console.WriteLine($"{result.TotalStarvation} PEOPLE DIED!!");
+
+                Console.WriteLine("YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH");
+                Console.WriteLine($"{result.AcresPerPerson} ACRES PER PERSON.");
+                Console.WriteLine();
+            }
+
+            switch (result.Rating)
+            {
+                case PerformanceRating.Disgraceful:
+                    if (result.WasPlayerImpeached)
+                        Console.WriteLine($"YOU STARVED {result.FinalStarvation} PEOPLE IN ONE YEAR!!!");
+
+                    Console.WriteLine("DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY");
+                    Console.WriteLine("BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE");
+                    Console.WriteLine("ALSO BEEN DECLARED NATIONAL FINK!!!!");
+                    break;
+                case PerformanceRating.Bad:
+                    Console.WriteLine("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.");
+                    Console.WriteLine("THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND,");
+                    Console.WriteLine("FRANKLY, HATE YOUR GUTS!!");
+                    break;
+                case PerformanceRating.Ok:
+                    Console.WriteLine("YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT");
+                    Console.WriteLine($"REALLY WASN'T TOO BAD AT ALL. {result.Assassins} PEOPLE");
+                    Console.WriteLine("WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR");
+                    Console.WriteLine("TRIVIAL PROBLEMS.");
+                    break;
+                case PerformanceRating.Terrific:
+                    Console.WriteLine("A FANTASTIC PERFORMANCE!!!  CHARLEMANGE, DISRAELI, AND");
+                    Console.WriteLine("JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!");
+                    break;
+            }
+        }
+
+        /// 
+        /// Shows a farewell message to the user.
+        /// 
+        public static void ShowFarewell()
+        {
+            Console.WriteLine("SO LONG FOR NOW.");
+            Console.WriteLine();
+        }
+
+        /// 
+        /// Prompts the user to buy land.
+        /// 
+        public static void PromptBuyLand()
+        {
+            Console.Write("HOW MANY ACRES DO YOU WISH TO BUY? ");
+        }
+
+        /// 
+        /// Prompts the user to sell land.
+        /// 
+        public static void PromptSellLand()
+        {
+            Console.Write("HOW MANY ACRES DO YOU WISH TO SELL? ");
+        }
+
+        /// 
+        /// Prompts the user to feed the people.
+        /// 
+        public static void PromptFeedPeople()
+        {
+            Console.Write("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? ");
+        }
+
+        /// 
+        /// Prompts the user to plant crops.
+        /// 
+        public static void PromptPlantCrops()
+        {
+            Console.Write("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? ");
+        }
+    }
+}
diff --git a/00_Alternate_Languages/43_Hammurabi/hammurabi.bas b/00_Alternate_Languages/43_Hammurabi/hammurabi.bas
new file mode 100644
index 00000000..8f0998f0
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/hammurabi.bas
@@ -0,0 +1,119 @@
+10 PRINT TAB(32);"HAMURABI"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+80 PRINT "TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA"
+90 PRINT "FOR A TEN-YEAR TERM OF OFFICE.":PRINT
+95 D1=0: P1=0
+100 Z=0: P=95:S=2800: H=3000: E=H-S
+110 Y=3: A=H/Y: I=5: Q=1
+210 D=0
+215 PRINT:PRINT:PRINT "HAMURABI:  I BEG TO REPORT TO YOU,": Z=Z+1
+217 PRINT "IN YEAR";Z;",";D;"PEOPLE STARVED,";I;"CAME TO THE CITY,"
+218 P=P+I
+227 IF Q>0 THEN 230
+228 P=INT(P/2)
+229 PRINT "A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED."
+230 PRINT "POPULATION IS NOW";P
+232 PRINT "THE CITY NOW OWNS ";A;"ACRES."
+235 PRINT "YOU HARVESTED";Y;"BUSHELS PER ACRE."
+250 PRINT "THE RATS ATE";E;"BUSHELS."
+260 PRINT "YOU NOW HAVE ";S;"BUSHELS IN STORE.": PRINT
+270 IF Z=11 THEN 860
+310 C=INT(10*RND(1)): Y=C+17
+312 PRINT "LAND IS TRADING AT";Y;"BUSHELS PER ACRE."
+320 PRINT "HOW MANY ACRES DO YOU WISH TO BUY";
+321 INPUT Q: IF Q<0 THEN 850
+322 IF Y*Q<=S THEN 330
+323 GOSUB 710
+324 GOTO 320
+330 IF Q=0 THEN 340
+331 A=A+Q: S=S-Y*Q: C=0
+334 GOTO 400
+340 PRINT "HOW MANY ACRES DO YOU WISH TO SELL";
+341 INPUT Q: IF Q<0 THEN 850
+342 IF Q
C/2 THEN 530 +523 REM *** RATS ARE RUNNING WILD!! +525 E=INT(S/C) +530 S=S-E+H +531 GOSUB 800 +532 REM *** LET'S HAVE SOME BABIES +533 I=INT(C*(20*A+S)/P/100+1) +539 REM *** HOW MANY PEOPLE HAD FULL TUMMIES? +540 C=INT(Q/20) +541 REM *** HORROS, A 15% CHANCE OF PLAGUE +542 Q=INT(10*(2*RND(1)-.3)) +550 IF P.45*P THEN 560 +553 P1=((Z-1)*P1+D*100/P)/Z +555 P=C: D1=D1+D: GOTO 215 +560 PRINT: PRINT "YOU STARVED";D;"PEOPLE IN ONE YEAR!!!" +565 PRINT "DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY" +566 PRINT "BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE" +567 PRINT "ALSO BEEN DECLARED NATIONAL FINK!!!!": GOTO 990 +710 PRINT "HAMURABI: THINK AGAIN. YOU HAVE ONLY" +711 PRINT S;"BUSHELS OF GRAIN. NOW THEN," +712 RETURN +720 PRINT "HAMURABI: THINK AGAIN. YOU OWN ONLY";A;"ACRES. NOW THEN," +730 RETURN +800 C=INT(RND(1)*5)+1 +801 RETURN +850 PRINT: PRINT "HAMURABI: I CANNOT DO WHAT YOU WISH." +855 PRINT "GET YOURSELF ANOTHER STEWARD!!!!!" +857 GOTO 990 +860 PRINT "IN YOUR 10-YEAR TERM OF OFFICE,";P1;"PERCENT OF THE" +862 PRINT "POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF" +865 PRINT D1;"PEOPLE DIED!!": L=A/P +870 PRINT "YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH" +875 PRINT L;"ACRES PER PERSON.": PRINT +880 IF P1>33 THEN 565 +885 IF L<7 THEN 565 +890 IF P1>10 THEN 940 +892 IF L<9 THEN 940 +895 IF P1>3 THEN 960 +896 IF L<10 THEN 960 +900 PRINT "A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND" +905 PRINT "JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!":GOTO 990 +940 PRINT "YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV." +945 PRINT "THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND," +950 PRINT "FRANKLY, HATE YOUR GUTS!!":GOTO 990 +960 PRINT "YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT" +965 PRINT "REALLY WASN'T TOO BAD AT ALL. ";INT(P*.8*RND(1));"PEOPLE" +970 PRINT "WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR" +975 PRINT "TRIVIAL PROBLEMS." +990 PRINT: FOR N=1 TO 10: PRINT CHR$(7);: NEXT N +995 PRINT "SO LONG FOR NOW.": PRINT +999 END diff --git a/00_Alternate_Languages/43_Hammurabi/java/README.md b/00_Alternate_Languages/43_Hammurabi/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/43_Hammurabi/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/43_Hammurabi/java/src/Hamurabi.java b/00_Alternate_Languages/43_Hammurabi/java/src/Hamurabi.java new file mode 100644 index 00000000..a8bf8b74 --- /dev/null +++ b/00_Alternate_Languages/43_Hammurabi/java/src/Hamurabi.java @@ -0,0 +1,366 @@ +import java.util.Arrays; +import java.util.Scanner; + +/** + * Game of Hamurabi + *

+ * Based on the Basic game of Hamurabi here + * https://github.com/coding-horror/basic-computer-games/blob/main/43%20Hammurabi/hammurabi.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. + */ +public class Hamurabi { + + public static final int INITIAL_POPULATION = 95; + public static final int INITIAL_BUSHELS = 2800; + public static final int INITIAL_HARVEST = 3000; + public static final int INITIAL_LAND_TRADING_AT = 3; + public static final int INITIAL_CAME_TO_CITY = 5; + public static final int MAX_GAME_YEARS = 10; + public static final double MAX_STARVATION_IN_A_YEAR = .45d; + + private int year; + private int population; + private int acres; + private int bushels; + private int harvest; + private int landTradingAt; + private int cameToCity; + private int starvedInAYear; + private int starvedOverall; + private boolean chanceOfPlague; + private int ratsAte; + private double peopleFed; + private double percentageStarved; + private int bushelsToFeedPeople; + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + STARTUP, + INIT, + YEAR_CYCLE, + BUY_ACRES, + SELL_ACRES, + FEED_PEOPLE, + PLANT_SEED, + CALCULATE_HARVEST, + CALCULATE_BABIES, + RESULTS, + FINISH_GAME, + GAME_OVER + } + + // Current game state + private GAME_STATE gameState; + + public Hamurabi() { + kbScanner = new Scanner(System.in); + gameState = GAME_STATE.STARTUP; + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + case STARTUP: + intro(); + gameState = GAME_STATE.INIT; + break; + + case INIT: + + // These are hard coded startup figures from the basic program + year = 0; + population = INITIAL_POPULATION; + bushels = INITIAL_BUSHELS; + harvest = INITIAL_HARVEST; + landTradingAt = INITIAL_LAND_TRADING_AT; + acres = INITIAL_HARVEST / INITIAL_LAND_TRADING_AT; + cameToCity = INITIAL_CAME_TO_CITY; + starvedInAYear = 0; + starvedOverall = 0; + chanceOfPlague = false; + ratsAte = INITIAL_HARVEST - INITIAL_BUSHELS; + peopleFed = 0; + percentageStarved = 0; + bushelsToFeedPeople = 0; + + gameState = GAME_STATE.YEAR_CYCLE; + break; + + case YEAR_CYCLE: + System.out.println(); + year += 1; + // End of game? + if (year > MAX_GAME_YEARS) { + gameState = GAME_STATE.RESULTS; + break; + + } + System.out.println("HAMURABI: I BEG TO REPORT TO YOU,"); + System.out.println("IN YEAR " + year + "," + starvedInAYear + " PEOPLE STARVED," + cameToCity + " CAME TO THE CITY,"); + population += cameToCity; + if (chanceOfPlague) { + population /= 2; + System.out.println("A HORRIBLE PLAGUE STRUCK! HALF THE PEOPLE DIED."); + } + System.out.println("POPULATION IS NOW " + population); + System.out.println("THE CITY NOW OWNS " + acres + " ACRES."); + System.out.println("YOU HARVESTED " + landTradingAt + " BUSHELS PER ACRE."); + System.out.println("THE RATS ATE " + ratsAte + " BUSHELS."); + System.out.println("YOU NOW HAVE " + bushels + " BUSHELS IN STORE."); + System.out.println(); + + landTradingAt = (int) (Math.random() * 10) + 17; // Original formula unchanged + System.out.println("LAND IS TRADING AT " + landTradingAt + " BUSHELS PER ACRE."); + + gameState = GAME_STATE.BUY_ACRES; + break; + + case BUY_ACRES: + int acresToBuy = displayTextAndGetNumber("HOW MANY ACRES DO YOU WISH TO BUY? "); + if (acresToBuy < 0) { + gameState = GAME_STATE.FINISH_GAME; + } + + if (acresToBuy > 0) { + if ((landTradingAt * acresToBuy) > bushels) { + notEnoughBushelsMessage(); + } else { + acres += acresToBuy; + bushels -= (landTradingAt * acresToBuy); + peopleFed = 0; + gameState = GAME_STATE.FEED_PEOPLE; + } + } else { + // 0 entered as buy so try to sell + gameState = GAME_STATE.SELL_ACRES; + } + break; + + case SELL_ACRES: + int acresToSell = displayTextAndGetNumber("HOW MANY ACRES DO YOU WISH TO SELL? "); + if (acresToSell < 0) { + gameState = GAME_STATE.FINISH_GAME; + } + if (acresToSell < acres) { + acres -= acresToSell; + bushels += (landTradingAt * acresToSell); + gameState = GAME_STATE.FEED_PEOPLE; + } else { + notEnoughLandMessage(); + } + break; + + case FEED_PEOPLE: + + bushelsToFeedPeople = displayTextAndGetNumber("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE ? "); + if (bushelsToFeedPeople < 0) { + gameState = GAME_STATE.FINISH_GAME; + } + + if (bushelsToFeedPeople <= bushels) { + bushels -= bushelsToFeedPeople; + peopleFed = 1; + gameState = GAME_STATE.PLANT_SEED; + } else { + notEnoughBushelsMessage(); + } + break; + + case PLANT_SEED: + + int acresToPlant = displayTextAndGetNumber("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED ? "); + if (acresToPlant < 0) { + gameState = GAME_STATE.FINISH_GAME; + } + + if (acresToPlant <= acres) { + if (acresToPlant / 2 <= bushels) { + if (acresToPlant < 10 * population) { + bushels -= acresToPlant / 2; + peopleFed = (int) (Math.random() * 5) + 1; + landTradingAt = (int) peopleFed; + harvest = acresToPlant * landTradingAt; + ratsAte = 0; + gameState = GAME_STATE.CALCULATE_HARVEST; + } else { + notEnoughPeopleMessage(); + } + } else { + notEnoughBushelsMessage(); + } + } else { + notEnoughLandMessage(); + } + break; + + case CALCULATE_HARVEST: + + if ((int) (peopleFed / 2) == peopleFed / 2) { + // Rats are running wild + ratsAte = (int) (bushels / peopleFed); + } + bushels = bushels - ratsAte; + bushels += harvest; + gameState = GAME_STATE.CALCULATE_BABIES; + break; + + case CALCULATE_BABIES: + + cameToCity = (int) (peopleFed * (20 * acres + bushels) / population / 100 + 1); + peopleFed = (bushelsToFeedPeople / 20.0d); + // Simplify chance of plague to a true/false + chanceOfPlague = (int) ((10 * (Math.random() * 2) - .3)) == 0; + if (population < peopleFed) { + gameState = GAME_STATE.YEAR_CYCLE; + } + + double starved = population - peopleFed; + if (starved < 0.0d) { + starvedInAYear = 0; + gameState = GAME_STATE.YEAR_CYCLE; + } else { + starvedInAYear = (int) starved; + starvedOverall += starvedInAYear; + if (starved > MAX_STARVATION_IN_A_YEAR * population) { + starvedTooManyPeopleMessage((int) starved); + gameState = GAME_STATE.FINISH_GAME; + } else { + percentageStarved = ((year - 1) * percentageStarved + starved * 100 / population) / year; + population = (int) peopleFed; + gameState = GAME_STATE.YEAR_CYCLE; + } + + } + + break; + + + case RESULTS: + + int acresPerPerson = acres / population; + + System.out.println("IN YOUR 10-YEAR TERM OF OFFICE," + String.format("%.2f", percentageStarved) + "% PERCENT OF THE"); + System.out.println("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF"); + System.out.println(starvedOverall + " PEOPLE DIED!!"); + System.out.println("YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH"); + System.out.println(acresPerPerson + " ACRES PER PERSON."); + System.out.println(); + + if (percentageStarved > 33.0d || acresPerPerson < 7) { + starvedTooManyPeopleMessage(starvedOverall); + } else if (percentageStarved > 10.0d || acresPerPerson < 9) { + heavyHandedMessage(); + } else if (percentageStarved > 3.0d || acresPerPerson < 10) { + couldHaveBeenBetterMessage(); + } else { + fantasticPerformanceMessage(); + } + + + gameState = GAME_STATE.FINISH_GAME; + + case FINISH_GAME: + System.out.println("SO LONG FOR NOW."); + gameState = GAME_STATE.GAME_OVER; + + } + + } while (gameState != GAME_STATE.GAME_OVER); + } + + private void starvedTooManyPeopleMessage(int starved) { + System.out.println(); + System.out.println("YOU STARVED " + starved + " PEOPLE IN ONE YEAR!!!"); + System.out.println("DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY"); + System.out.println("BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE"); + System.out.println("ALSO BEEN DECLARED NATIONAL FINK!!!!"); + + } + + private void heavyHandedMessage() { + System.out.println("DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY"); + System.out.println("BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE"); + System.out.println("ALSO BEEN DECLARED NATIONAL FINK!!!!"); + } + + private void couldHaveBeenBetterMessage() { + System.out.println("YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT"); + System.out.println("REALLY WASN'T TOO BAD AT ALL. " + (int) (Math.random() * (population * .8)) + " PEOPLE"); + System.out.println("WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR"); + System.out.println("TRIVIAL PROBLEMS."); + } + + private void fantasticPerformanceMessage() { + System.out.println("A FANTASTIC PERFORMANCE!!! CHARLEMANGE, DISRAELI, AND"); + System.out.println("JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!"); + } + + private void notEnoughPeopleMessage() { + System.out.println("BUT YOU HAVE ONLY " + population + " PEOPLE TO TEND THE FIELDS! NOW THEN,"); + + } + + private void notEnoughBushelsMessage() { + System.out.println("HAMURABI: THINK AGAIN. YOU HAVE ONLY"); + System.out.println(bushels + " BUSHELS OF GRAIN. NOW THEN,"); + } + + private void notEnoughLandMessage() { + System.out.println("HAMURABI: THINK AGAIN. YOU OWN ONLY " + acres + " ACRES. NOW THEN,"); + } + + + private void intro() { + System.out.println(simulateTabs(32) + "HAMURABI"); + System.out.println(simulateTabs(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA"); + System.out.println("FOR A TEN-YEAR TERM OF OFFICE."); + System.out.println(); + } + + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to an Integer + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private int displayTextAndGetNumber(String text) { + return Integer.parseInt(displayTextAndGetInput(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + + /** + * Simulate the old basic tab(xx) command which indented text by xx spaces. + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String simulateTabs(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + +} diff --git a/00_Alternate_Languages/43_Hammurabi/java/src/HamurabiGame.java b/00_Alternate_Languages/43_Hammurabi/java/src/HamurabiGame.java new file mode 100644 index 00000000..82631e1b --- /dev/null +++ b/00_Alternate_Languages/43_Hammurabi/java/src/HamurabiGame.java @@ -0,0 +1,7 @@ +public class HamurabiGame { + public static void main(String[] args) { + + Hamurabi hamurabi = new Hamurabi(); + hamurabi.play(); + } +} diff --git a/00_Alternate_Languages/43_Hammurabi/javascript/README.md b/00_Alternate_Languages/43_Hammurabi/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/43_Hammurabi/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/43_Hammurabi/javascript/hammurabi.html b/00_Alternate_Languages/43_Hammurabi/javascript/hammurabi.html new file mode 100644 index 00000000..2facdcb4 --- /dev/null +++ b/00_Alternate_Languages/43_Hammurabi/javascript/hammurabi.html @@ -0,0 +1,9 @@ + + +HAMMURABI + + +


+
+
+
diff --git a/00_Alternate_Languages/43_Hammurabi/javascript/hammurabi.js b/00_Alternate_Languages/43_Hammurabi/javascript/hammurabi.js
new file mode 100644
index 00000000..6d878db9
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/javascript/hammurabi.js
@@ -0,0 +1,253 @@
+// HAMMURABI
+//
+// 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 a;
+var s;
+
+function exceeded_grain()
+{
+    print("HAMURABI: THINK AGAIN.  YOU HAVE ONLY\n");
+    print(s + " BUSHELS OF GRAIN.  NOW THEN,\n");
+
+}
+
+function exceeded_acres()
+{
+    print("HAMURABI: THINK AGAIN.  YOU OWN ONLY " + a + " ACRES.  NOW THEN,\n");
+}
+
+// Main control section
+async function main()
+{
+    print(tab(32) + "HAMURABI\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA\n");
+    print("FOR A TEN-YEAR TERM OF OFFICE.\n");
+    print("\n");
+
+    d1 = 0;
+    p1 = 0;
+    z = 0;
+    p = 95;
+    s = 2800;
+    h = 3000;
+    e = h - s;
+    y = 3;
+    a = h / y;
+    i = 5;
+    q = 1;
+    d = 0;
+    while (1) {
+        print("\n");
+        print("\n");
+        print("\n");
+        print("HAMURABI:  I BEG TO REPORT TO YOU,\n");
+        z++;
+        print("IN YEAR " + z + ", " + d + " PEOPLE STARVED, " + i + " CAME TO THE CITY,\n");
+        p += i;
+        if (q <= 0) {
+            p = Math.floor(p / 2);
+            print("A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED.\n");
+        }
+        print("POPULATION IS NOW " + p + "\n");
+        print("THE CITY NOW OWNS " + a + " ACRES.\n");
+        print("YOU HARVESTED " + y + " BUSHELS PER ACRE.\n");
+        print("THE RATS ATE " + e + " BUSHELS.\n");
+        print("YOU NOW HAVE " + s + " BUSHELS IN STORE.\n");
+        print("\n");
+        if (z == 11) {
+            q = 0;
+            break;
+        }
+        c = Math.floor(10 * Math.random());
+        y = c + 17;
+        print("LAND IS TRADING AT " + y + " BUSHELS PER ACRE.\n");
+        while (1) {
+            print("HOW MANY ACRES DO YOU WISH TO BUY");
+            q = parseInt(await input());
+            if (q < 0)
+                break;
+            if (y * q > s) {
+                exceeded_grain();
+            } else
+                break;
+        }
+        if (q < 0)
+            break;
+        if (q != 0) {
+            a += q;
+            s -= y * q;
+            c = 0;
+        } else {
+            while (1) {
+                print("HOW MANY ACRES DO YOU WISH TO SELL");
+                q = parseInt(await input());
+                if (q < 0)
+                    break;
+                if (q >= a) {
+                    exceeded_acres();
+                } else {
+                    break;
+                }
+            }
+            if (q < 0)
+                break;
+            a -= q;
+            s += y * q;
+            c = 0;
+        }
+        print("\n");
+        while (1) {
+            print("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE");
+            q = parseInt(await input());
+            if (q < 0)
+                break;
+            if (q > s)  // Trying to use more grain than is in silos?
+                exceeded_grain();
+            else
+                break;
+        }
+        if (q < 0)
+            break;
+        s -= q;
+        c = 1;
+        print("\n");
+        while (1) {
+            print("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED");
+            d = parseInt(await input());
+            if (d != 0) {
+                if (d < 0)
+                    break;
+                if (d > a) {    // Trying to plant more acres than you own?
+                    exceeded_acres();
+                } else {
+                    if (Math.floor(d / 2) > s)  // Enough grain for seed?
+                        exceeded_grain();
+                    else {
+                        if (d >= 10 * p) {
+                            print("BUT YOU HAVE ONLY " + p + " PEOPLE TO TEND THE FIELDS!  NOW THEN,\n");
+                        } else {
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        if (d < 0) {
+            q = -1;
+            break;
+        }
+        s -= Math.floor(d / 2);
+        c = Math.floor(Math.random() * 5) + 1;
+        // A bountiful harvest!
+        if (c % 2 == 0) {
+            // Rats are running wild!!
+            e = Math.floor(s / c);
+        }
+        s = s - e + h;
+        c = Math.floor(Math.random() * 5) + 1;
+        // Let's have some babies
+        i = Math.floor(c * (20 * a + s) / p / 100 + 1);
+        // How many people had full tummies?
+        c = Math.floor(q / 20);
+        // Horros, a 15% chance of plague
+        q = Math.floor(10 * (2 * Math.random() - 0.3));
+        if (p < c) {
+            d = 0;
+            continue;
+        }
+        // Starve enough for impeachment?
+        d = p - c;
+        if (d <= 0.45 * p) {
+            p1 = ((z - 1) * p1 + d * 100 / p) / z;
+            p = c;
+            d1 += d;
+            continue;
+        }
+        print("\n");
+        print("YOU STARVED " + d + " PEOPLE IN ONE YEAR!!!\n");
+        q = 0;
+        p1 = 34;
+        p = 1;
+        break;
+    }
+    if (q < 0) {
+        print("\n");
+        print("HAMURABI:  I CANNOT DO WHAT YOU WISH.\n");
+        print("GET YOURSELF ANOTHER STEWARD!!!!!\n");
+    } else {
+        print("IN YOUR 10-YEAR TERM OF OFFICE, " + p1 + " PERCENT OF THE\n");
+        print("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF\n");
+        print(d1 + " PEOPLE DIED!!\n");
+        l = a / p;
+        print("YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH\n");
+        print(l + " ACRES PER PERSON.\n");
+        print("\n");
+        if (p1 > 33 || l < 7) {
+            print("DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY\n");
+            print("BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE\n");
+            print("ALSO BEEN DECLARED NATIONAL FINK!!!!\n");
+        } else if (p1 > 10 || l < 9) {
+            print("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.\n");
+            print("THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND,\n");
+            print("FRANKLY, HATE YOUR GUTS!!\n");
+        } else if (p1 > 3 || l < 10) {
+            print("YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT\n");
+            print("REALLY WASN'T TOO BAD AT ALL. " + Math.floor(p * 0.8 * Math.random()) + " PEOPLE\n");
+            print("WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR\n");
+            print("TRIVIAL PROBLEMS.\n");
+        } else {
+            print("A FANTASTIC PERFORMANCE!!!  CHARLEMANGE, DISRAELI, AND\n");
+            print("JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\n");
+        }
+    }
+    print("\n");
+    print("SO LONG FOR NOW.\n");
+    print("\n");
+}
+
+main();
diff --git a/19_Bunny/pascal/README.md b/00_Alternate_Languages/43_Hammurabi/pascal/README.md
similarity index 100%
rename from 19_Bunny/pascal/README.md
rename to 00_Alternate_Languages/43_Hammurabi/pascal/README.md
diff --git a/00_Alternate_Languages/43_Hammurabi/perl/README.md b/00_Alternate_Languages/43_Hammurabi/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/43_Hammurabi/python/README.md b/00_Alternate_Languages/43_Hammurabi/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/43_Hammurabi/python/hamurabi.py b/00_Alternate_Languages/43_Hammurabi/python/hamurabi.py
new file mode 100644
index 00000000..fea9847e
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/python/hamurabi.py
@@ -0,0 +1,235 @@
+from random import random, seed
+
+
+def gen_random():
+    return int(random() * 5) + 1
+
+
+def bad_input_850():
+    print("\nHAMURABI:  I CANNOT DO WHAT YOU WISH.")
+    print("GET YOURSELF ANOTHER STEWARD!!!!!")
+
+
+def bad_input_710(S):
+    print("HAMURABI:  THINK AGAIN.  YOU HAVE ONLY")
+    print(S, "BUSHELS OF GRAIN.  NOW THEN,")
+
+
+def bad_input_720(A):
+    print("HAMURABI:  THINK AGAIN.  YOU OWN ONLY", A, "ACRES.  NOW THEN,")
+
+
+def national_fink():
+    print("DUE TO THIS EXTREME MISMANAGEMENT YOU HAVE NOT ONLY")
+    print("BEEN IMPEACHED AND THROWN OUT OF OFFICE BUT YOU HAVE")
+    print("ALSO BEEN DECLARED NATIONAL FINK!!!!")
+
+
+def b_input(promptstring):  # emulate BASIC input. It rejects non-numeric values
+    x = input(promptstring)
+    while x.isalpha():
+        x = input("?REDO FROM START\n? ")
+    return int(x)
+
+
+def main():
+    seed()
+    title = "HAMURABI"
+    title = title.rjust(32, " ")
+    print(title)
+    attribution = "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+    attribution = attribution.rjust(15, " ")
+    print(attribution)
+    print("\n\n\n")
+    print("TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA")
+    print("FOR A TEN-YEAR TERM OF OFFICE.\n")
+
+    D1 = 0
+    P1 = 0
+    year = 0
+    population = 95
+    grain_stores = 2800
+    H = 3000
+    eaten_rats = H - grain_stores
+    bushels_per_acre = (
+        3  # yield (amount of production from land). Reused as price per acre
+    )
+    acres = H / bushels_per_acre  # acres of land
+    immigrants = 5
+    plague = 1  # boolean for plague, also input for buy/sell land
+    people = 0
+
+    while year < 11:  # line 270. main loop. while the year is less than 11
+        print("\n\n\nHAMURABI:  I BEG TO REPORT TO YOU")
+        year = year + 1  # year
+        print(
+            "IN YEAR",
+            year,
+            ",",
+            people,
+            "PEOPLE STARVED,",
+            immigrants,
+            "CAME TO THE CITY,",
+        )
+        population = population + immigrants
+
+        if plague == 0:
+            population = int(population / 2)
+            print("A HORRIBLE PLAGUE STRUCK!  HALF THE PEOPLE DIED.")
+
+        print("POPULATION IS NOW", population)
+        print("THE CITY NOW OWNS", acres, "ACRES.")
+        print("YOU HARVESTED", bushels_per_acre, "BUSHELS PER ACRE.")
+        print("THE RATS ATE", eaten_rats, "BUSHELS.")
+        print("YOU NOW HAVE ", grain_stores, "BUSHELS IN STORE.\n")
+        C = int(10 * random())  # random number between 1 and 10
+        bushels_per_acre = C + 17
+        print("LAND IS TRADING AT", bushels_per_acre, "BUSHELS PER ACRE.")
+
+        plague = -99  # dummy value to track status
+        while plague == -99:  # always run the loop once
+            plague = b_input("HOW MANY ACRES DO YOU WISH TO BUY? ")
+            if plague < 0:
+                plague = -1  # to avoid the corner case of Q=-99
+                bad_input_850()
+                year = 99  # jump out of main loop and exit
+            elif bushels_per_acre * plague > grain_stores:  # can't afford it
+                bad_input_710(grain_stores)
+                plague = -99  # give'm a second change to get it right
+            elif (
+                bushels_per_acre * plague <= grain_stores
+            ):  # normal case, can afford it
+                acres = acres + plague  # increase the number of acres by Q
+                grain_stores = (
+                    grain_stores - bushels_per_acre * plague
+                )  # decrease the amount of grain in store to pay for it
+                C = 0  # WTF is C for?
+
+        if plague == 0 and year != 99:  # maybe you want to sell some land?
+            plague = -99
+            while plague == -99:
+                plague = b_input("HOW MANY ACRES DO YOU WISH TO SELL? ")
+                if plague < 0:
+                    bad_input_850()
+                    year = 99  # jump out of main loop and exit
+                elif plague <= acres:  # normal case
+                    acres = acres - plague  # reduce the acres
+                    grain_stores = (
+                        grain_stores + bushels_per_acre * plague
+                    )  # add to grain stores
+                    C = 0  # still don't know what C is for
+                else:  # Q>A error!
+                    bad_input_720(acres)
+                    plague = -99  # reloop
+            print("\n")
+
+        plague = -99
+        while plague == -99 and year != 99:
+            plague = b_input("HOW MANY BUSHELS DO YOU WISH TO FEED YOUR PEOPLE? ")
+            if plague < 0:
+                bad_input_850()
+                year = 99  # jump out of main loop and exit
+            # REM *** TRYING TO USE MORE GRAIN THAN IS IN SILOS?
+            elif plague > grain_stores:
+                bad_input_710(grain_stores)
+                plague = -99  # try again!
+            else:  # we're good. do the transaction
+                grain_stores = grain_stores - plague  # remove the grain from the stores
+                C = 1  # set the speed of light to 1. jk
+
+        print("\n")
+        people = -99  # dummy value to force at least one loop
+        while people == -99 and year != 99:
+            people = b_input("HOW MANY ACRES DO YOU WISH TO PLANT WITH SEED? ")
+            if people < 0:
+                bad_input_850()
+                year = 99  # jump out of main loop and exit
+            elif people > 0:
+                if people > acres:
+                    # REM *** TRYING TO PLANT MORE ACRES THAN YOU OWN?
+                    bad_input_720(acres)
+                    people = -99
+                elif int(people / 2) > grain_stores:
+                    # REM *** ENOUGH GRAIN FOR SEED?
+                    bad_input_710(grain_stores)
+                    people = -99
+                elif people > 10 * population:
+                    # REM *** ENOUGH PEOPLE TO TEND THE CROPS?
+                    print(
+                        "BUT YOU HAVE ONLY",
+                        population,
+                        "PEOPLE TO TEND THE FIELDS!  NOW THEN,",
+                    )
+                    people = -99
+                else:  # we're good. decrement the grain store
+                    grain_stores = grain_stores - int(people / 2)
+
+        C = gen_random()
+        # REM *** A BOUNTIFUL HARVEST!
+        bushels_per_acre = C
+        H = people * bushels_per_acre
+        eaten_rats = 0
+
+        C = gen_random()
+        if int(C / 2) == C / 2:  # even number. 50/50 chance
+            # REM *** RATS ARE RUNNING WILD!!
+            eaten_rats = int(
+                grain_stores / C
+            )  # calc losses due to rats, based on previous random number
+
+        grain_stores = grain_stores - eaten_rats + H  # deduct losses from stores
+
+        C = gen_random()
+        # REM *** LET'S HAVE SOME BABIES
+        immigrants = int(C * (20 * acres + grain_stores) / population / 100 + 1)
+        # REM *** HOW MANY PEOPLE HAD FULL TUMMIES?
+        C = int(plague / 20)
+        # REM *** HORROS, A 15% CHANCE OF PLAGUE
+        # yeah, should be HORRORS, but left it
+        plague = int(10 * (2 * random() - 0.3))
+        if (
+            population >= C and year != 99
+        ):  # if there are some people without full bellies...
+            # REM *** STARVE ENOUGH FOR IMPEACHMENT?
+            people = population - C
+            if people > 0.45 * population:
+                print("\nYOU STARVED", people, "PEOPLE IN ONE YEAR!!!")
+                national_fink()
+                year = 99  # exit the loop
+            P1 = ((year - 1) * P1 + people * 100 / population) / year
+            population = C
+            D1 = D1 + people
+
+    if year != 99:
+        print("IN YOUR 10-YEAR TERM OF OFFICE,", P1, "PERCENT OF THE")
+        print("POPULATION STARVED PER YEAR ON THE AVERAGE, I.E. A TOTAL OF")
+        print(D1, "PEOPLE DIED!!")
+        L = acres / population
+        print("YOU STARTED WITH 10 ACRES PER PERSON AND ENDED WITH")
+        print(L, "ACRES PER PERSON.\n")
+        if P1 > 33 or L < 7:
+            national_fink()
+        elif P1 > 10 or L < 9:
+            print("YOUR HEAVY-HANDED PERFORMANCE SMACKS OF NERO AND IVAN IV.")
+            print("THE PEOPLE (REMIANING) FIND YOU AN UNPLEASANT RULER, AND,")
+            print("FRANKLY, HATE YOUR GUTS!!")
+        elif P1 > 3 or L < 10:
+            print("YOUR PERFORMANCE COULD HAVE BEEN SOMEWHAT BETTER, BUT")
+            print(
+                "REALLY WASN'T TOO BAD AT ALL. ",
+                int(population * 0.8 * random()),
+                "PEOPLE",
+            )
+            print("WOULD DEARLY LIKE TO SEE YOU ASSASSINATED BUT WE ALL HAVE OUR")
+            print("TRIVIAL PROBLEMS.")
+        else:
+            print("A FANTASTIC PERFORMANCE!!!  CHARLEMANGE, DISRAELI, AND")
+            print("JEFFERSON COMBINED COULD NOT HAVE DONE BETTER!\n")
+        for N in range(1, 10):
+            print("\a")
+
+    print("\nSO LONG FOR NOW.\n")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/43_Hammurabi/python/test_hamurabi.py b/00_Alternate_Languages/43_Hammurabi/python/test_hamurabi.py
new file mode 100644
index 00000000..16377b1d
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/python/test_hamurabi.py
@@ -0,0 +1,30 @@
+import io
+
+import hamurabi
+
+
+def test_main(monkeypatch, capsys):
+    monkeypatch.setattr("sys.stdin", io.StringIO("100\n100\n100"))
+    hamurabi.main()
+    captured = capsys.readouterr()
+    actual_lines = captured.out.splitlines()
+    expected_lines = [
+        "HAMURABI",  # 0
+        "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY",  # 1
+        "",  # 2
+        "",  # 3
+        "",  # 4
+        "",  # 5
+        "TRY YOUR HAND AT GOVERNING ANCIENT SUMERIA",  # 6
+        "FOR A TEN-YEAR TERM OF OFFICE.",  # 7
+        "",  # 8
+        "",  # 9
+        "",  # 10
+        "",  # 11
+        "HAMURABI:  I BEG TO REPORT TO YOU\n",  # 12
+        "IN YEAR 1 , 0 PEOPLE STARVED, 5 CAME TO THE CITY,\n",  # 13
+        "POPULATION IS NOW 100\n",  # 14
+        "THE CITY NOW OWNS 1000.0 ACRES.",  # 15
+    ]
+    for i, (actual, expected) in enumerate(zip(actual_lines, expected_lines)):
+        assert actual.strip() == expected.strip(), f"Line {i} is wrong"
diff --git a/00_Alternate_Languages/43_Hammurabi/ruby/README.md b/00_Alternate_Languages/43_Hammurabi/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/43_Hammurabi/vbnet/Hammurabi.sln b/00_Alternate_Languages/43_Hammurabi/vbnet/Hammurabi.sln
new file mode 100644
index 00000000..41a13843
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/vbnet/Hammurabi.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Hammurabi", "Hammurabi.vbproj", "{52BC86C8-4AE8-4F0C-9566-5E0D97BB17BF}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{52BC86C8-4AE8-4F0C-9566-5E0D97BB17BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{52BC86C8-4AE8-4F0C-9566-5E0D97BB17BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{52BC86C8-4AE8-4F0C-9566-5E0D97BB17BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{52BC86C8-4AE8-4F0C-9566-5E0D97BB17BF}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/43_Hammurabi/vbnet/Hammurabi.vbproj b/00_Alternate_Languages/43_Hammurabi/vbnet/Hammurabi.vbproj
new file mode 100644
index 00000000..8f89306c
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/vbnet/Hammurabi.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Hammurabi
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/43_Hammurabi/vbnet/README.md b/00_Alternate_Languages/43_Hammurabi/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/43_Hammurabi/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/44_Hangman/README.md b/00_Alternate_Languages/44_Hangman/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/44_Hangman/csharp/Graphic.cs b/00_Alternate_Languages/44_Hangman/csharp/Graphic.cs
new file mode 100644
index 00000000..62eea111
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/csharp/Graphic.cs
@@ -0,0 +1,129 @@
+using System;
+
+namespace Hangman
+{
+    /// 
+    /// Represents the main "Hangman" graphic.
+    /// 
+    public class Graphic
+    {
+        private readonly char[,] _graphic;
+        private const int Width = 12;
+        private const int Height = 12;
+
+        public Graphic()
+        {
+            // 12 x 12 array to represent the graphics.
+            _graphic = new char[Height, Width];
+
+            // Fill it with empty spaces.
+            for (var i = 0; i < Height; i++)
+            {
+                for (var j = 0; j < Width; j++)
+                {
+                    _graphic[i, j] = ' ';
+                }
+            }
+
+            // Draw the vertical line.
+            for (var i = 0; i < Height; i++)
+            {
+                _graphic[i, 0] = 'X';
+            }
+
+            // Draw the horizontal line.
+            for (var i = 0; i < 7; i++)
+            {
+                _graphic[0, i] = 'X';
+            }
+
+            // Draw the rope.
+            _graphic[1, 6] = 'X';
+        }
+
+        public void Print()
+        {
+            for (var i = 0; i < Height; i++)
+            {
+                for (var j = 0; j < Width; j++)
+                {
+                    Console.Write(_graphic[i, j]);
+                }
+
+                Console.Write("\n"); // New line.
+            }
+        }
+
+        public void AddHead()
+        {
+            _graphic[2, 5] = '-';
+            _graphic[2, 6] = '-';
+            _graphic[2, 7] = '-';
+            _graphic[3, 4] = '(';
+            _graphic[3, 5] = '.';
+            _graphic[3, 7] = '.';
+            _graphic[3, 8] = ')';
+            _graphic[4, 5] = '-';
+            _graphic[4, 6] = '-';
+            _graphic[4, 7] = '-';
+        }
+
+        public void AddBody()
+        {
+            for (var i = 5; i < 9; i++)
+            {
+                _graphic[i, 6] = 'X';
+            }
+        }
+
+        public void AddRightArm()
+        {
+            for (var i = 3; i < 7; i++)
+            {
+                _graphic[i, i - 1] = '\\'; // This is the escape character for the back slash.
+            }
+        }
+
+        public void AddLeftArm()
+        {
+            _graphic[3, 10] = '/';
+            _graphic[4, 9] = '/';
+            _graphic[5, 8] = '/';
+            _graphic[6, 7] = '/';
+        }
+
+        public void AddRightLeg()
+        {
+            _graphic[9, 5] = '/';
+            _graphic[10, 4] = '/';
+        }
+
+        public void AddLeftLeg()
+        {
+            _graphic[9, 7] = '\\';
+            _graphic[10, 8] = '\\';
+        }
+
+        public void AddRightHand()
+        {
+            _graphic[2, 2] = '/';
+        }
+
+        public void AddLeftHand()
+        {
+            _graphic[2, 10] = '\\';
+        }
+
+        public void AddRightFoot()
+        {
+            _graphic[11, 9] = '\\';
+            _graphic[11, 10] = '-';
+        }
+
+        public void AddLeftFoot()
+        {
+            _graphic[11, 3] = '/';
+            _graphic[11, 2] = '-';
+        }
+    }
+}
diff --git a/00_Alternate_Languages/44_Hangman/csharp/Hangman.csproj b/00_Alternate_Languages/44_Hangman/csharp/Hangman.csproj
new file mode 100644
index 00000000..9590466a
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/csharp/Hangman.csproj
@@ -0,0 +1,8 @@
+
+
+    
+        Exe
+        net5.0
+    
+
+
diff --git a/00_Alternate_Languages/44_Hangman/csharp/Hangman.sln b/00_Alternate_Languages/44_Hangman/csharp/Hangman.sln
new file mode 100644
index 00000000..ef93fef7
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/csharp/Hangman.sln
@@ -0,0 +1,16 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hangman", "Hangman.csproj", "{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1C516A9E-F4F2-4C79-8C37-0162C403B1F7}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/44_Hangman/csharp/Program.cs b/00_Alternate_Languages/44_Hangman/csharp/Program.cs
new file mode 100644
index 00000000..f5658dae
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/csharp/Program.cs
@@ -0,0 +1,313 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json.Serialization;
+
+namespace Hangman
+{
+    /// 
+    /// C# version of the game "Hangman" from the book BASIC Computer Games.
+    /// 
+    static class Program
+    {
+        static void Main()
+        {
+            Console.WriteLine(Tab(32) + "HANGMAN");
+            Console.WriteLine(Tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+            MainLoop();
+            Console.WriteLine();
+            Console.WriteLine("IT'S BEEN FUN!  BYE FOR NOW.");
+        }
+
+        static void MainLoop()
+        {
+            var words = GetWords();
+            var stillPlaying = true;
+
+            while (stillPlaying)
+            {
+                if (words.Count == 0)
+                {
+                    Console.WriteLine("YOU DID ALL THE WORDS!!");
+                    break;
+                }
+
+                // Get a random number from 0 to the number of words we have minus one (C# arrays are zero-based).
+                var rnd = new Random();
+                var randomNumber = rnd.Next(words.Count - 1);
+
+                // Pick a random word and remove it from the list.
+                var word = words[randomNumber];
+                words.Remove(word);
+
+                GameLoop(word);
+
+                // Game finished. Ask if player wants another one.
+                Console.WriteLine("WANT ANOTHER WORD? ");
+                var response = Console.ReadLine();
+                if (response == null || response.ToUpper() != "YES")
+                {
+                    stillPlaying = false;   // Exit the loop if the player didn't answer "yes".
+                }
+            }
+        }
+
+        static void GameLoop(string word)
+        {
+            var graphic = new Graphic();
+            var wrongGuesses = 0;
+            var numberOfGuesses = 0;
+            var usedLetters = new List();
+
+            // The word that the user sees. Since we just started, it's just dashes.
+            var displayedWord = new char[word.Length];
+            for (var i = 0; i < word.Length; i++)
+            {
+                displayedWord[i] = '-';
+            }
+
+            var stillPlaying = true;
+            while (stillPlaying)
+            {
+                var guess = GetLetterFromPlayer(displayedWord, usedLetters);
+                usedLetters.Add(guess);
+                numberOfGuesses++;
+                var correctLetterCount = 0;
+                // Now we check every letter in the word to see if the player guessed any of them correctly.
+                for(var i = 0; i < word.Length; i++)
+                {
+                    if (word[i] == guess)
+                    {
+                        correctLetterCount++;
+                        displayedWord[i] = guess;
+                    }
+                }
+
+                if (correctLetterCount == 0)
+                {
+                    // Wrong guess.
+                    Console.WriteLine("SORRY, THAT LETTER ISN'T IN THE WORD.");
+                    wrongGuesses++;
+                    DrawBody(graphic, wrongGuesses);
+                    if (wrongGuesses == 10)
+                    {
+                        // Player exhausted all their guesses. Finish the game loop.
+                        Console.WriteLine($"SORRY, YOU LOSE.  THE WORD WAS {word}");
+                        Console.Write("YOU MISSED THAT ONE.  DO YOU ");
+                        stillPlaying = false;
+                    }
+                }
+                else
+                {
+                    // Player guessed a correct letter. Let's see if there are any unguessed letters left in the word.
+                    if (displayedWord.Contains('-'))
+                    {
+                        Console.WriteLine(displayedWord);
+
+                        // Give the player a chance to guess the whole word.
+                        var wordGuess = GetWordFromPlayer();
+                        if (word == wordGuess)
+                        {
+                            // Player found the word. Mark it found.
+                            Console.WriteLine("YOU FOUND THE WORD!");
+                            stillPlaying = false;   // Exit game loop.
+                        }
+                        else
+                        {
+                            // Player didn't guess the word. Continue the game loop.
+                            Console.WriteLine("WRONG.  TRY ANOTHER LETTER.");
+                        }
+                    }
+                    else
+                    {
+                        // Player guessed all the letters.
+                        Console.WriteLine("YOU FOUND THE WORD!");
+                        stillPlaying = false;   // Exit game loop.
+                    }
+                }
+            } // End of game loop.
+        }
+
+        /// 
+        /// Display the current state of the word and all the already guessed letters, and get a new guess from the player
+        /// 
+        /// A char array that represents the current state of the guessed word
+        /// A list of chars that represents all the letters guessed so far
+        /// The letter that the player has just entered as a guess
+        private static char GetLetterFromPlayer(char[] displayedWord, List usedLetters)
+        {
+            while (true)    // Infinite loop, unless the player enters an unused letter.
+            {
+                Console.WriteLine();
+                Console.WriteLine(displayedWord);
+                Console.WriteLine();
+                Console.WriteLine();
+                Console.WriteLine("HERE ARE THE LETTERS YOU USED:");
+                for (var i = 0; i < usedLetters.Count; i++)
+                {
+                    Console.Write(usedLetters[i]);
+
+                    // If it's not the last letter, print a comma.
+                    if (i != usedLetters.Count - 1)
+                    {
+                        Console.Write(",");
+                    }
+                }
+
+                Console.WriteLine();
+                Console.WriteLine("WHAT IS YOUR GUESS?");
+                var guess = char.ToUpper(Console.ReadKey().KeyChar);
+                Console.WriteLine();
+
+                if (usedLetters.Contains(guess))
+                {
+                    // After this the loop will continue.
+                    Console.WriteLine("YOU GUESSED THAT LETTER BEFORE!");
+                }
+                else
+                {
+                    // Break out of the loop by returning guessed letter.
+                    return guess;
+                }
+            }
+        }
+
+        /// 
+        /// Gets a word guess from the player.
+        /// 
+        /// The guessed word.
+        private static string GetWordFromPlayer()
+        {
+            while (true)    // Infinite loop, unless the player enters something.
+            {
+                Console.WriteLine("WHAT IS YOUR GUESS FOR THE WORD? ");
+                var guess = Console.ReadLine();
+                if (guess != null)
+                {
+                    return guess.ToUpper();
+                }
+            }
+        }
+
+        /// 
+        /// Draw body after wrong guess.
+        /// 
+        /// The instance of the Graphic class being used.
+        /// Number of wrong guesses.
+        private static void DrawBody(Graphic graphic, int wrongGuesses)
+        {
+            switch (wrongGuesses)
+                    {
+                        case 1:
+                            Console.WriteLine("FIRST, WE DRAW A HEAD.");
+                            graphic.AddHead();
+                            break;
+                        case 2:
+                            Console.WriteLine("NOW WE DRAW A BODY.");
+                            graphic.AddBody();
+                            break;
+                        case 3:
+                            Console.WriteLine("NEXT WE DRAW AN ARM.");
+                            graphic.AddRightArm();
+                            break;
+                        case 4:
+                            Console.WriteLine("THIS TIME IT'S THE OTHER ARM.");
+                            graphic.AddLeftArm();
+                            break;
+                        case 5:
+                            Console.WriteLine("NOW, LET'S DRAW THE RIGHT LEG.");
+                            graphic.AddRightLeg();
+                            break;
+                        case 6:
+                            Console.WriteLine("THIS TIME WE DRAW THE LEFT LEG.");
+                            graphic.AddLeftLeg();
+                            break;
+                        case 7:
+                            Console.WriteLine("NOW WE PUT UP A HAND.");
+                            graphic.AddRightHand();
+                            break;
+                        case 8:
+                            Console.WriteLine("NEXT THE OTHER HAND.");
+                            graphic.AddLeftHand();
+                            break;
+                        case 9:
+                            Console.WriteLine("NOW WE DRAW ONE FOOT.");
+                            graphic.AddRightFoot();
+                            break;
+                        case 10:
+                            Console.WriteLine("HERE'S THE OTHER FOOT -- YOU'RE HUNG!!");
+                            graphic.AddLeftFoot();
+                            break;
+                    }
+                    graphic.Print();
+        }
+
+        /// 
+        /// Get a list of words to use in the game.
+        /// 
+        /// List of strings.
+        private static List GetWords() => new()
+        {
+            "GUM",
+            "SIN",
+            "FOR",
+            "CRY",
+            "LUG",
+            "BYE",
+            "FLY",
+            "UGLY",
+            "EACH",
+            "FROM",
+            "WORK",
+            "TALK",
+            "WITH",
+            "SELF",
+            "PIZZA",
+            "THING",
+            "FEIGN",
+            "FIEND",
+            "ELBOW",
+            "FAULT",
+            "DIRTY",
+            "BUDGET",
+            "SPIRIT",
+            "QUAINT",
+            "MAIDEN",
+            "ESCORT",
+            "PICKAX",
+            "EXAMPLE",
+            "TENSION",
+            "QUININE",
+            "KIDNEY",
+            "REPLICA",
+            "SLEEPER",
+            "TRIANGLE",
+            "KANGAROO",
+            "MAHOGANY",
+            "SERGEANT",
+            "SEQUENCE",
+            "MOUSTACHE",
+            "DANGEROUS",
+            "SCIENTIST",
+            "DIFFERENT",
+            "QUIESCENT",
+            "MAGISTRATE",
+            "ERRONEOUSLY",
+            "LOUDSPEAKER",
+            "PHYTOTOXIC",
+            "MATRIMONIAL",
+            "PARASYMPATHOMIMETIC",
+            "THIGMOTROPISM"
+        };
+
+        /// 
+        /// Leave a number of spaces empty.
+        /// 
+        /// Number of spaces.
+        /// The result string.
+        private static string Tab(int length) => new string(' ', length);
+    }
+}
diff --git a/00_Alternate_Languages/44_Hangman/csharp/README.md b/00_Alternate_Languages/44_Hangman/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/44_Hangman/hangman.bas b/00_Alternate_Languages/44_Hangman/hangman.bas
new file mode 100644
index 00000000..cdd1b15d
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/hangman.bas
@@ -0,0 +1,81 @@
+10 PRINT TAB(32);"HANGMAN"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+25 PRINT:PRINT:PRINT
+30 DIM P$(12,12),L$(20),D$(20),N$(26),U(50)
+40 C=1: N=50
+50 FOR I=1 TO 20: D$(I)="-": NEXT I: M=0
+60 FOR I=1 TO 26: N$(I)="": NEXT I
+70 FOR I=1 TO 12: FOR J=1 TO 12: P$(I,J)=" ": NEXT J: NEXT I
+80 FOR I=1 TO 12: P$(I,1)="X": NEXT I
+90 FOR I=1 TO 7: P$(1,I)="X": NEXT: P$(2,7)="X"
+95 IF C10 THEN 170
+600 PRINT "SORRY, YOU LOSE.  THE WORD WAS ";A$
+610 PRINT "YOU MISSED THAT ONE.  DO YOU ";: GOTO 370
+620 INPUT "TYPE YES OR NO";Y$: IF LEFT$(Y$,1)="Y" THEN 50
+700 DATA "GUM","SIN","FOR","CRY","LUG","BYE","FLY"
+710 DATA "UGLY","EACH","FROM","WORK","TALK","WITH","SELF"
+720 DATA "PIZZA","THING","FEIGN","FIEND","ELBOW","FAULT","DIRTY"
+730 DATA "BUDGET","SPIRIT","QUAINT","MAIDEN","ESCORT","PICKAX"
+740 DATA "EXAMPLE","TENSION","QUININE","KIDNEY","REPLICA","SLEEPER"
+750 DATA "TRIANGLE","KANGAROO","MAHOGANY","SERGEANT","SEQUENCE"
+760 DATA "MOUSTACHE","DANGEROUS","SCIENTIST","DIFFERENT","QUIESCENT"
+770 DATA "MAGISTRATE","ERRONEOUSLY","LOUDSPEAKER","PHYTOTOXIC"
+780 DATA "MATRIMONIAL","PARASYMPATHOMIMETIC","THIGMOTROPISM"
+990 PRINT "BYE NOW"
+999 END
diff --git a/00_Alternate_Languages/44_Hangman/java/Hangman.java b/00_Alternate_Languages/44_Hangman/java/Hangman.java
new file mode 100644
index 00000000..99425567
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/java/Hangman.java
@@ -0,0 +1,247 @@
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * HANGMAN
+ *
+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)
+ */
+
+public class Hangman {
+
+	//50 word list
+	private final static List words = List.of(
+			"GUM", "SIN", "FOR", "CRY", "LUG", "BYE", "FLY",
+			"UGLY", "EACH", "FROM", "WORK", "TALK", "WITH", "SELF",
+			"PIZZA", "THING", "FEIGN", "FIEND", "ELBOW", "FAULT", "DIRTY",
+			"BUDGET", "SPIRIT", "QUAINT", "MAIDEN", "ESCORT", "PICKAX",
+			"EXAMPLE", "TENSION", "QUININE", "KIDNEY", "REPLICA", "SLEEPER",
+			"TRIANGLE", "KANGAROO", "MAHOGANY", "SERGEANT", "SEQUENCE",
+			"MOUSTACHE", "DANGEROUS", "SCIENTIST", "DIFFERENT", "QUIESCENT",
+			"MAGISTRATE", "ERRONEOUSLY", "LOUDSPEAKER", "PHYTOTOXIC",
+			"MATRIMONIAL", "PARASYMPATHOMIMETIC", "THIGMOTROPISM");
+
+	public static void main(String[] args) {
+		Scanner scan = new Scanner(System.in);
+
+		printIntro();
+
+		int[] usedWords = new int[50];
+		int roundNumber = 1;
+		int totalWords = words.size();
+		boolean continueGame = false;
+
+		do {
+			if (roundNumber > totalWords) {
+				System.out.println("\nYOU DID ALL THE WORDS!!");
+				break;
+			}
+
+			int randomWordIndex;
+			do {
+				randomWordIndex = ((int) (totalWords * Math.random())) + 1;
+			} while (usedWords[randomWordIndex] == 1);
+			usedWords[randomWordIndex] = 1;
+
+			boolean youWon = playRound(scan, words.get(randomWordIndex - 1));
+			if (!youWon) {
+				System.out.print("\nYOU MISSED THAT ONE.  DO YOU WANT ANOTHER WORD? ");
+			} else {
+				System.out.print("\nWANT ANOTHER WORD? ");
+			}
+			final String anotherWordChoice = scan.next();
+
+			if (anotherWordChoice.toUpperCase().equals("YES") || anotherWordChoice.toUpperCase().equals("Y")) {
+				continueGame = true;
+			}
+			roundNumber++;
+		} while (continueGame);
+
+		System.out.println("\nIT'S BEEN FUN!  BYE FOR NOW.");
+	}
+
+	private static boolean playRound(Scanner scan, String word) {
+		char[] letters;
+		char[] discoveredLetters;
+		int misses = 0;
+		Set lettersUsed = new LinkedHashSet<>();//LinkedHashSet maintains the order of characters inserted
+
+		String[][] hangmanPicture = new String[12][12];
+		//initialize the hangman picture
+		for (int i = 0; i < hangmanPicture.length; i++) {
+			for (int j = 0; j < hangmanPicture[i].length; j++) {
+				hangmanPicture[i][j] = " ";
+			}
+		}
+		for (int i = 0; i < hangmanPicture.length; i++) {
+			hangmanPicture[i][0] = "X";
+		}
+		for (int i = 0; i < 7; i++) {
+			hangmanPicture[0][i] = "X";
+		}
+		hangmanPicture[1][6] = "X";
+
+		int totalWordGuesses = 0; //guesses
+
+		int len = word.length();
+		letters = word.toCharArray();
+
+		discoveredLetters = new char[len];
+		Arrays.fill(discoveredLetters, '-');
+
+		boolean validNextGuess = false;
+		char guessLetter = ' ';
+
+		while (misses < 10) {
+			while (!validNextGuess) {
+				printLettersUsed(lettersUsed);
+				printDiscoveredLetters(discoveredLetters);
+
+				System.out.print("WHAT IS YOUR GUESS? ");
+				var tmpRead = scan.next();
+				guessLetter = Character.toUpperCase(tmpRead.charAt(0));
+				if (lettersUsed.contains(guessLetter)) {
+					System.out.println("YOU GUESSED THAT LETTER BEFORE!");
+				} else {
+					lettersUsed.add(guessLetter);
+					totalWordGuesses++;
+					validNextGuess = true;
+				}
+			}
+
+			if (word.indexOf(guessLetter) >= 0) {
+				//replace all occurrences in D$ with G$
+				for (int i = 0; i < letters.length; i++) {
+					if (letters[i] == guessLetter) {
+						discoveredLetters[i] = guessLetter;
+					}
+				}
+				//check if the word is fully discovered
+				boolean isWordDiscovered = true;
+				for (char discoveredLetter : discoveredLetters) {
+					if (discoveredLetter == '-') {
+						isWordDiscovered = false;
+						break;
+					}
+				}
+				if (isWordDiscovered) {
+					System.out.println("YOU FOUND THE WORD!");
+					return true;
+				}
+
+				printDiscoveredLetters(discoveredLetters);
+				System.out.print("WHAT IS YOUR GUESS FOR THE WORD? ");
+				final String wordGuess = scan.next();
+				if (wordGuess.toUpperCase().equals(word)) {
+					System.out.printf("RIGHT!!  IT TOOK YOU %s GUESSES!", totalWordGuesses);
+					return true;
+				} else {
+					System.out.println("WRONG.  TRY ANOTHER LETTER.");
+				}
+			} else {
+				misses = misses + 1;
+				System.out.println("\n\nSORRY, THAT LETTER ISN'T IN THE WORD.");
+				drawHangman(misses, hangmanPicture);
+			}
+			validNextGuess = false;
+		}
+
+		System.out.printf("SORRY, YOU LOSE.  THE WORD WAS %s", word);
+		return false;
+	}
+
+	private static void drawHangman(int m, String[][] hangmanPicture) {
+		switch (m) {
+			case 1:
+				System.out.println("FIRST, WE DRAW A HEAD");
+				hangmanPicture[2][5] = "-";
+				hangmanPicture[2][6] = "-";
+				hangmanPicture[2][7] = "-";
+				hangmanPicture[3][4] = "(";
+				hangmanPicture[3][5] = ".";
+				hangmanPicture[3][7] = ".";
+				hangmanPicture[3][8] = ")";
+				hangmanPicture[4][5] = "-";
+				hangmanPicture[4][6] = "-";
+				hangmanPicture[4][7] = "-";
+				break;
+			case 2:
+				System.out.println("NOW WE DRAW A BODY.");
+				for (var i = 5; i <= 8; i++) {
+					hangmanPicture[i][6] = "X";
+				}
+				break;
+			case 3:
+				System.out.println("NEXT WE DRAW AN ARM.");
+				for (int i = 3; i <= 6; i++) {
+					hangmanPicture[i][i - 1] = "\\";
+				}
+				break;
+			case 4:
+				System.out.println("THIS TIME IT'S THE OTHER ARM.");
+				hangmanPicture[3][10] = "/";
+				hangmanPicture[4][9] = "/";
+				hangmanPicture[5][8] = "/";
+				hangmanPicture[6][7] = "/";
+				break;
+			case 5:
+				System.out.println("NOW, LET'S DRAW THE RIGHT LEG.");
+				hangmanPicture[9][5] = "/";
+				hangmanPicture[10][4] = "/";
+				break;
+			case 6:
+				System.out.println("THIS TIME WE DRAW THE LEFT LEG.");
+				hangmanPicture[9][7] = "\\";
+				hangmanPicture[10][8] = "\\";
+				break;
+			case 7:
+				System.out.println("NOW WE PUT UP A HAND.");
+				hangmanPicture[2][10] = "\\";
+				break;
+			case 8:
+				System.out.println("NEXT THE OTHER HAND.");
+				hangmanPicture[2][2] = "/";
+				break;
+			case 9:
+				System.out.println("NOW WE DRAW ONE FOOT");
+				hangmanPicture[11][9] = "\\";
+				hangmanPicture[11][10] = "-";
+				break;
+			case 10:
+				System.out.println("HERE'S THE OTHER FOOT -- YOU'RE HUNG!!");
+				hangmanPicture[11][2] = "-";
+				hangmanPicture[11][3] = "/";
+				break;
+		}
+		for (int i = 0; i <= 11; i++) {
+			for (int j = 0; j <= 11; j++) {
+				System.out.print(hangmanPicture[i][j]);
+			}
+			System.out.print("\n");
+		}
+
+	}
+
+	private static void printDiscoveredLetters(char[] D$) {
+		System.out.println(new String(D$));
+		System.out.println("\n");
+	}
+
+	private static void printLettersUsed(Set lettersUsed) {
+		System.out.println("\nHERE ARE THE LETTERS YOU USED:");
+		System.out.println(lettersUsed.stream()
+				.map(Object::toString).collect(Collectors.joining(",")));
+		System.out.println("\n");
+	}
+
+	private static void printIntro() {
+		System.out.println("                                HANGMAN");
+		System.out.println("              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+		System.out.println("\n\n\n");
+	}
+
+}
diff --git a/00_Alternate_Languages/44_Hangman/java/README.md b/00_Alternate_Languages/44_Hangman/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/44_Hangman/javascript/README.md b/00_Alternate_Languages/44_Hangman/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/44_Hangman/javascript/hangman.html b/00_Alternate_Languages/44_Hangman/javascript/hangman.html
new file mode 100644
index 00000000..7bf3d250
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/javascript/hangman.html
@@ -0,0 +1,9 @@
+
+
+HANGMAN
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/44_Hangman/javascript/hangman.js b/00_Alternate_Languages/44_Hangman/javascript/hangman.js
new file mode 100644
index 00000000..c7f6b8c5
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/javascript/hangman.js
@@ -0,0 +1,266 @@
+// HANGMAN
+//
+// 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;
+}
+
+print(tab(32) + "HANGMAN\n");
+print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+print("\n");
+print("\n");
+print("\n");
+
+var pa = [];
+var la = [];
+var da = [];
+var na = [];
+var ua = [];
+
+var words = ["GUM","SIN","FOR","CRY","LUG","BYE","FLY",
+             "UGLY","EACH","FROM","WORK","TALK","WITH","SELF",
+             "PIZZA","THING","FEIGN","FIEND","ELBOW","FAULT","DIRTY",
+             "BUDGET","SPIRIT","QUAINT","MAIDEN","ESCORT","PICKAX",
+             "EXAMPLE","TENSION","QUININE","KIDNEY","REPLICA","SLEEPER",
+             "TRIANGLE","KANGAROO","MAHOGANY","SERGEANT","SEQUENCE",
+             "MOUSTACHE","DANGEROUS","SCIENTIST","DIFFERENT","QUIESCENT",
+             "MAGISTRATE","ERRONEOUSLY","LOUDSPEAKER","PHYTOTOXIC",
+             "MATRIMONIAL","PARASYMPATHOMIMETIC","THIGMOTROPISM"];
+
+// Main control section
+async function main()
+{
+    c = 1;
+    n = 50;
+    while (1) {
+        for (i = 1; i <= 20; i++)
+            da[i] = "-";
+        for (i = 1; i <= n; i++)
+            ua[i] = 0;
+        m = 0;
+        ns = "";
+        for (i = 1; i <= 12; i++) {
+            pa[i] = [];
+            for (j = 1; j <= 12; j++) {
+                pa[i][j] = " ";
+            }
+        }
+        for (i = 1; i <= 12; i++) {
+            pa[i][1] = "X";
+        }
+        for (i = 1; i <= 7; i++) {
+            pa[1][i] = "X";
+        }
+        pa[2][7] = "X";
+        if (c >= n) {
+            print("YOU DID ALL THE WORDS!!\n");
+            break;
+        }
+        do {
+            q = Math.floor(n * Math.random()) + 1;
+        } while (ua[q] == 1) ;
+        ua[q] = 1;
+        c++;
+        t1 = 0;
+        as = words[q - 1];
+        l = as.length;
+        for (i = 1; i <= as.length; i++)
+            la[i] = as[i - 1];
+        while (1) {
+            while (1) {
+                print("HERE ARE THE LETTERS YOU USED:\n");
+                print(ns + "\n");
+                print("\n");
+                for (i = 1; i <= l; i++) {
+                    print(da[i]);
+                }
+                print("\n");
+                print("\n");
+                print("WHAT IS YOUR GUESS");
+                str = await input();
+                if (ns.indexOf(str) != -1) {
+                    print("YOU GUESSED THAT LETTER BEFORE!\n");
+                } else {
+                    break;
+                }
+            }
+            ns += str;
+            t1++;
+            r = 0;
+            for (i = 1; i <= l; i++) {
+                if (la[i] == str) {
+                    da[i] = str;
+                    r++;
+                }
+            }
+            if (r == 0) {
+                m++;
+                print("\n");
+                print("\n");
+                print("SORRY, THAT LETTER ISN'T IN THE WORD.\n");
+                switch (m) {
+                    case 1:
+                        print("FIRST, WE DRAW A HEAD\n");
+                        break;
+                    case 2:
+                        print("NOW WE DRAW A BODY.\n");
+                        break;
+                    case 3:
+                        print("NEXT WE DRAW AN ARM.\n");
+                        break;
+                    case 4:
+                        print("THIS TIME IT'S THE OTHER ARM.\n");
+                        break;
+                    case 5:
+                        print("NOW, LET'S DRAW THE RIGHT LEG.\n");
+                        break;
+                    case 6:
+                        print("THIS TIME WE DRAW THE LEFT LEG.\n");
+                        break;
+                    case 7:
+                        print("NOW WE PUT UP A HAND.\n");
+                        break;
+                    case 8:
+                        print("NEXT THE OTHER HAND.\n");
+                        break;
+                    case 9:
+                        print("NOW WE DRAW ONE FOOT.\n");
+                        break;
+                    case 10:
+                        print("HERE'S THE OTHER FOOT -- YOU'RE HUNG!!\n");
+                        break;
+                }
+                switch (m) {
+                    case 1:
+                        pa[3][6] = "-";
+                        pa[3][7] = "-";
+                        pa[3][8] = "-";
+                        pa[4][5] = "(";
+                        pa[4][6] = ".";
+                        pa[4][8] = ".";
+                        pa[4][9] = ")";
+                        pa[5][6] = "-";
+                        pa[5][7] = "-";
+                        pa[5][8] = "-";
+                        break;
+                    case 2:
+                        for (i = 6; i <= 9; i++)
+                            pa[i][7] = "X";
+                        break;
+                    case 3:
+                        for (i = 4; i <= 7; i++)
+                            pa[i][i - 1] = "\\";
+                        break;
+                    case 4:
+                        pa[4][11] = "/";
+                        pa[5][10] = "/";
+                        pa[6][9] = "/";
+                        pa[7][8] = "/";
+                        break;
+                    case 5:
+                        pa[10][6] = "/";
+                        pa[11][5] = "/";
+                        break;
+                    case 6:
+                        pa[10][8] = "\\";
+                        pa[11][9] = "\\";
+                        break;
+                    case 7:
+                        pa[3][11] = "\\";
+                        break;
+                    case 8:
+                        pa[3][3] = "/";
+                        break;
+                    case 9:
+                        pa[12][10] = "\\";
+                        pa[12][11] = "-";
+                        break;
+                    case 10:
+                        pa[12][3] = "-";
+                        pa[12][4] = "/";
+                        break;
+                }
+                for (i = 1; i <= 12; i++) {
+                    str = "";
+                    for (j = 1; j <= 12; j++)
+                        str += pa[i][j];
+                    print(str + "\n");
+                }
+                print("\n");
+                print("\n");
+                if (m == 10) {
+                    print("SORRY, YOU LOSE.  THE WORD WAS " + as + "\n");
+                    print("YOU MISSED THAT ONE.  DO YOU ");
+                    break;
+                }
+            } else {
+                for (i = 1; i <= l; i++)
+                    if (da[i] == "-")
+                        break;
+                if (i > l) {
+                    print("YOU FOUND THE WORD!\n");
+                    break;
+                }
+                print("\n");
+                for (i = 1; i <= l; i++)
+                    print(da[i]);
+                print("\n");
+                print("\n");
+                print("WHAT IS YOUR GUESS FOR THE WORD");
+                bs = await input();
+                if (as == bs) {
+                    print("RIGHT!!  IT TOOK YOU " + t1 + " GUESSES!\n");
+                    break;
+                }
+                print("WRONG.  TRY ANOTHER LETTER.\n");
+                print("\n");
+            }
+        }
+        print("WANT ANOTHER WORD");
+        str = await input();
+        if (str != "YES")
+            break;
+    }
+    print("\n");
+    print("IT'S BEEN FUN!  BYE FOR NOW.\n");
+    // Lines 620 and 990 unused in original
+}
+
+main();
diff --git a/20_Buzzword/pascal/README.md b/00_Alternate_Languages/44_Hangman/pascal/README.md
similarity index 100%
rename from 20_Buzzword/pascal/README.md
rename to 00_Alternate_Languages/44_Hangman/pascal/README.md
diff --git a/00_Alternate_Languages/44_Hangman/perl/README.md b/00_Alternate_Languages/44_Hangman/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/44_Hangman/perl/hangman.pl b/00_Alternate_Languages/44_Hangman/perl/hangman.pl
new file mode 100644
index 00000000..fec512ca
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/perl/hangman.pl
@@ -0,0 +1,223 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+
+# global variables defined here
+
+my(@WORDS) = qw(
+    GUM SIN FOR CRY LUG BYE FLY
+    UGLY EACH FROM WORK TALK WITH SELF
+    PIZZA THING FEIGN FIEND ELBOW FAULT DIRTY
+    BUDGET SPIRIT QUAINT MAIDEN ESCORT PICKAX
+    EXAMPLE TENSION QUININE KIDNEY REPLICA SLEEPER
+    TRIANGLE KANGAROO MAHOGANY SERGEANT SEQUENCE
+    MOUSTACHE DANGEROUS SCIENTIST DIFFERENT QUIESCENT
+    MAGISTRATE ERRONEOUSLY LOUDSPEAKER PHYTOTOXIC
+    MATRIMONIAL PARASYMPATHOMIMETIC THIGMOTROPISM
+);
+my(@PIC,$board,@guessedLetters,$guessCount,$hangCount);
+my(%GUESSED);
+
+# Subroutines defined here.
+
+# init_variables: initialize all of the variables needed
+# (this covers lines 50-90 in the original BASIC program)
+
+sub init_variables {
+    @guessedLetters = ();
+    @PIC = (
+        'XXXXXXX     ',
+        'X     X     ',
+        'X           ',
+        'X           ',
+        'X           ',
+        'X           ',
+        'X           ',
+        'X           ',
+        'X           ',
+        'X           ',
+        'X           ',
+        'X           ',
+    );
+    $guessCount = 0; %GUESSED = ();
+    $hangCount = 0;
+}
+
+# addchar: given a row & column, put the specified char in that place in @PIC
+sub addchar {
+    my($row,$col, $c) = @_;
+
+    substr($PIC[$row],$col,1) = $c;
+}
+
+
+# main code starts here
+
+print ' 'x31; print "Hangman\n";
+print ' 'x14; print "Creative Computing  Morristown, New Jersey\n\n\n\n";
+
+# an iteration of the PLAY block is one complete game.
+# There is a continue block that will ask if the user
+# wants to play another game.
+
+PLAY: while (1) {
+
+    init_variables();
+    # Any words left?
+    if (@WORDS == 0) {
+        print "You did all the words!\n";
+        last PLAY;
+    }
+    # splice a random word out of the @WORDS array
+    my($thisWord) = splice(@WORDS, int(rand(scalar @WORDS)),1);
+    # $board is the "game board" of the filled-out word
+    # that the user is working on
+    $board = '.'x(length $thisWord);
+
+    # GUESS loop is run for every time the user guesses a letter
+    GUESS: while(1) {
+        print "Here are the letters you used:\n";
+        printf("%s\n", join(',',@guessedLetters));
+        printf("\n\n%s\n", $board);
+
+        print "What is your guess for a letter ? ";
+        chomp(my $guess = );
+        # The %GUESSED hash allows us to quickly identify
+        # letters that have already been guessed
+        if ($GUESSED{lc $guess}) {
+            print "You guessed that letter before!\n\n";
+            redo GUESS;
+        }
+
+        # save the guessed letter
+        push @guessedLetters, $guess;
+        $GUESSED{lc $guess} = 1;
+        ++$guessCount;
+
+        # now look for the letter in the $thisWord var
+        # and put it into the $board var wherever it
+        # shows up. $foundLetter is a flag that indicates
+        # whether or not the letter is found.
+        my $foundLetter = 0;
+        for (my $i = 0; $i < length $thisWord; ++$i) {
+            if (lc substr($thisWord,$i,1) eq lc $guess) {
+                $foundLetter = 1;
+                substr($board, $i, 1) = substr($thisWord, $i, 1);
+            }
+        }
+
+        # The user found a letter in the solution!
+        if ($foundLetter) {
+
+            # Are there any '.' chars left in the board?
+            if (index($board, '.') < 0) {
+                print "You found the word!\n\n";
+            } else {
+                printf("%s\n\n", $board);
+                print "What is your guess for the word ? ";
+                chomp(my $guessword = );
+                if (lc $thisWord ne lc $guessword) {
+                    print "Wrong.  Try another letter.\n";
+                    # Go to the next iteration of the GUESS loop
+                    next GUESS;
+                }
+                printf("Right! It took you %d %s!\n", $guessCount, ($guessCount == 1 ? 'guess' : 'guesses'));
+            }
+            # At this point the user has discovered the word and won.
+            # This "next" statement takes execution down to the
+            # continue block for the PLAY loop;
+            next PLAY;
+
+        } else {  # didn't find a letter
+
+            ++$hangCount;
+            print "\n\n\nSorry, that letter isn't in the word.\n";
+
+            # The addchar() calls in the block below piece together the
+            # hangman graphic, depending on how many wrong letters
+            # the user has.
+            if ($hangCount == 1) {
+                print "First, we draw a head\n";
+                addchar(2,5,"-");addchar(2,6,"-");addchar(2,7,"-");
+                addchar(3,4,"("); addchar(3,5,"."); addchar(3,7,"."); addchar(3,8,")");
+                addchar(4,5,"-");addchar(4,6,"-");addchar(4,7,"-");
+            }
+            if ($hangCount == 2) {
+                print "Now we draw a body.\n";
+                for (5 .. 8) {
+                    addchar($_, 6, "X");
+                }
+            }
+            if ($hangCount == 3) {
+                print "Next we draw an arm.\n";
+                for (3 .. 6) {
+                    addchar($_, $_-1, "\\");
+                }
+            }
+            if ($hangCount == 4) {
+                print "This time it's the other arm.\n";
+                addchar(3,10, "/");
+                addchar(4, 9, "/");
+                addchar(5, 8, "/");
+                addchar(6, 7, "/");
+            }
+            if ($hangCount == 5) {
+                print "Now, let's draw the right leg.\n";
+                addchar( 9,5, "/");
+                addchar(10,4, "/");
+            }
+            if ($hangCount == 6) {
+                print "This time we draw the left leg.\n";
+                addchar(9,7,"\\");
+                addchar(10,8,"\\");
+            }
+            if ($hangCount == 7) {
+                print "Now we put up a hand.\n";
+                addchar(2,10,"\\");
+            }
+            if ($hangCount == 8) {
+                print "Next the other hand.\n";
+                addchar(2,2,"/");
+            }
+            if ($hangCount == 9) {
+                print "Now we draw one foot\n";
+                addchar(11,9,"\\");
+                addchar(11,10, "-");
+            }
+            if ($hangCount == 10) {
+                print "Here's the other foot -- you're hung!!\n";
+                addchar(11,2,"-");
+                addchar(11,3, "/");
+            }
+
+            printf("$_\n") for @PIC;
+            print "\n\n";
+
+            # Next guess if the user has not lost
+            if ($hangCount < 10) {
+                next GUESS;
+            }
+
+            printf("Sorry, you lose.  The word was %s\n", $thisWord);
+            next PLAY;
+
+        } # didn't find a letter block
+    } # GUESS block
+} # PLAY block
+
+# This block is reached either by the player winning (see the "next PLAY")
+# statement) or by the user losing (as the PLAY block is complete and
+# execution naturally comes to this continue block).
+continue {
+    print "Want another word ? ";
+    chomp(my $in = );
+    if ($in !~ m/^y/i) {
+        # Exit the PLAY loop
+        print "\nIt's been fun!  Bye for now.\n\n";
+        last PLAY;
+    }
+    # At this point execution goes to the start of the PLAY block,
+    # meaning a new game
+}
diff --git a/00_Alternate_Languages/44_Hangman/python/README.md b/00_Alternate_Languages/44_Hangman/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/44_Hangman/python/hangman.py b/00_Alternate_Languages/44_Hangman/python/hangman.py
new file mode 100644
index 00000000..c5521d1e
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/python/hangman.py
@@ -0,0 +1,263 @@
+#!/usr/bin/env python3
+# HANGMAN
+#
+# Converted from BASIC to Python by Trevor Hobson and Daniel Piron
+
+import random
+
+
+class Canvas:
+    """For drawing text-based figures"""
+
+    def __init__(self, width=12, height=12, fill=" "):
+        self._buffer = []
+        for _ in range(height):
+            line = []
+            for _ in range(width):
+                line.append("")
+            self._buffer.append(line)
+
+        self.clear()
+
+    def clear(self, fill=" "):
+        for row in self._buffer:
+            for x in range(len(row)):
+                row[x] = fill
+
+    def render(self):
+        lines = []
+        for line in self._buffer:
+            # Joining by the empty string ("") smooshes all of the
+            # individual characters together as one line.
+            lines.append("".join(line))
+        return "\n".join(lines)
+
+    def put(self, s, x, y):
+        # In an effort to avoid distorting the drawn image, only write the
+        # first character of the given string to the buffer.
+        self._buffer[y][x] = s[0]
+
+
+def init_gallows(canvas):
+    for i in range(12):
+        canvas.put("X", 0, i)
+    for i in range(7):
+        canvas.put("X", i, 0)
+    canvas.put("X", 6, 1)
+
+
+def draw_head(canvas):
+    canvas.put("-", 5, 2)
+    canvas.put("-", 6, 2)
+    canvas.put("-", 7, 2)
+    canvas.put("(", 4, 3)
+    canvas.put(".", 5, 3)
+    canvas.put(".", 7, 3)
+    canvas.put(")", 8, 3)
+    canvas.put("-", 5, 4)
+    canvas.put("-", 6, 4)
+    canvas.put("-", 7, 4)
+
+
+def draw_body(canvas):
+    for i in range(5, 9, 1):
+        canvas.put("X", 6, i)
+
+
+def draw_right_arm(canvas):
+    for i in range(3, 7):
+        canvas.put("\\", i - 1, i)
+
+
+def draw_left_arm(canvas):
+    canvas.put("/", 10, 3)
+    canvas.put("/", 9, 4)
+    canvas.put("/", 8, 5)
+    canvas.put("/", 7, 6)
+
+
+def draw_right_leg(canvas):
+    canvas.put("/", 5, 9)
+    canvas.put("/", 4, 10)
+
+
+def draw_left_leg(canvas):
+    canvas.put("\\", 7, 9)
+    canvas.put("\\", 8, 10)
+
+
+def draw_left_hand(canvas):
+    canvas.put("\\", 10, 2)
+
+
+def draw_right_hand(canvas):
+    canvas.put("/", 2, 2)
+
+
+def draw_left_foot(canvas):
+    canvas.put("\\", 9, 11)
+    canvas.put("-", 10, 11)
+
+
+def draw_right_foot(canvas):
+    canvas.put("-", 2, 11)
+    canvas.put("/", 3, 11)
+
+
+PHASES = (
+    ("First, we draw a head", draw_head),
+    ("Now we draw a body.", draw_body),
+    ("Next we draw an arm.", draw_right_arm),
+    ("this time it's the other arm.", draw_left_arm),
+    ("Now, let's draw the right leg.", draw_right_leg),
+    ("This time we draw the left leg.", draw_left_leg),
+    ("Now we put up a hand.", draw_left_hand),
+    ("Next the other hand.", draw_right_hand),
+    ("Now we draw one foot", draw_left_foot),
+    ("Here's the other foot -- you're hung!!", draw_right_foot),
+)
+
+
+words = [
+    "GUM",
+    "SIN",
+    "FOR",
+    "CRY",
+    "LUG",
+    "BYE",
+    "FLY",
+    "UGLY",
+    "EACH",
+    "FROM",
+    "WORK",
+    "TALK",
+    "WITH",
+    "SELF",
+    "PIZZA",
+    "THING",
+    "FEIGN",
+    "FIEND",
+    "ELBOW",
+    "FAULT",
+    "DIRTY",
+    "BUDGET",
+    "SPIRIT",
+    "QUAINT",
+    "MAIDEN",
+    "ESCORT",
+    "PICKAX",
+    "EXAMPLE",
+    "TENSION",
+    "QUININE",
+    "KIDNEY",
+    "REPLICA",
+    "SLEEPER",
+    "TRIANGLE",
+    "KANGAROO",
+    "MAHOGANY",
+    "SERGEANT",
+    "SEQUENCE",
+    "MOUSTACHE",
+    "DANGEROUS",
+    "SCIENTIST",
+    "DIFFERENT",
+    "QUIESCENT",
+    "MAGISTRATE",
+    "ERRONEOUSLY",
+    "LOUDSPEAKER",
+    "PHYTOTOXIC",
+    "MATRIMONIAL",
+    "PARASYMPATHOMIMETIC",
+    "THIGMOTROPISM",
+]
+
+
+def play_game(guess_target):
+    """Play one round of the game"""
+    wrong_guesses = 0
+    guess_progress = ["-"] * len(guess_target)
+    guess_list = []
+
+    gallows = Canvas()
+    init_gallows(gallows)
+
+    guess_count = 0
+    while True:
+        print("Here are the letters you used:")
+        print(",".join(guess_list) + "\n")
+        print("".join(guess_progress) + "\n")
+        guess_letter = ""
+        guess_word = ""
+        while guess_letter == "":
+
+            guess_letter = input("What is your guess? ").upper()[0]
+            if not guess_letter.isalpha():
+                guess_letter = ""
+                print("Only letters are allowed!")
+            elif guess_letter in guess_list:
+                guess_letter = ""
+                print("You guessed that letter before!")
+
+        guess_list.append(guess_letter)
+        guess_count += 1
+        if guess_letter in guess_target:
+            indices = [
+                i for i, letter in enumerate(guess_target) if letter == guess_letter
+            ]
+            for i in indices:
+                guess_progress[i] = guess_letter
+            if guess_progress == guess_target:
+                print("You found the word!")
+                break
+            else:
+                print("\n" + "".join(guess_progress) + "\n")
+                while guess_word == "":
+                    guess_word = input("What is your guess for the word? ").upper()
+                    if not guess_word.isalpha():
+                        guess_word = ""
+                        print("Only words are allowed!")
+                if guess_word == guess_target:
+                    print("Right!! It took you", guess_count, "guesses!")
+                    break
+        else:
+            comment, draw_bodypart = PHASES[wrong_guesses]
+
+            print(comment)
+            draw_bodypart(gallows)
+            print(gallows.render())
+
+            wrong_guesses += 1
+            print("Sorry, that letter isn't in the word.")
+
+            if wrong_guesses == 10:
+                print("Sorry, you lose. The word was " + guess_target)
+                break
+
+
+def main():
+    print(" " * 32 + "HANGMAN")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n")
+
+    random.shuffle(words)
+    current_word = 0
+    word_count = len(words)
+
+    keep_playing = True
+    while keep_playing:
+
+        play_game(words[current_word])
+        current_word += 1
+
+        if current_word == word_count:
+            print("You did all the words!!")
+            keep_playing = False
+        else:
+            keep_playing = (
+                input("Want another word? (yes or no) ").lower().startswith("y")
+            )
+
+    print("It's been fun! Bye for now.")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/44_Hangman/ruby/README.md b/00_Alternate_Languages/44_Hangman/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/44_Hangman/vbnet/Hangman.sln b/00_Alternate_Languages/44_Hangman/vbnet/Hangman.sln
new file mode 100644
index 00000000..355c5093
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/vbnet/Hangman.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Hangman", "Hangman.vbproj", "{048C4117-70FC-4457-9B1D-BBD1FEDFEB76}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{048C4117-70FC-4457-9B1D-BBD1FEDFEB76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{048C4117-70FC-4457-9B1D-BBD1FEDFEB76}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{048C4117-70FC-4457-9B1D-BBD1FEDFEB76}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{048C4117-70FC-4457-9B1D-BBD1FEDFEB76}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/44_Hangman/vbnet/Hangman.vbproj b/00_Alternate_Languages/44_Hangman/vbnet/Hangman.vbproj
new file mode 100644
index 00000000..6ad7969c
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/vbnet/Hangman.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Hangman
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/44_Hangman/vbnet/README.md b/00_Alternate_Languages/44_Hangman/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/44_Hangman/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/45_Hello/README.md b/00_Alternate_Languages/45_Hello/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/45_Hello/csharp/Hello.csproj b/00_Alternate_Languages/45_Hello/csharp/Hello.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/csharp/Hello.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/45_Hello/csharp/Hello.sln b/00_Alternate_Languages/45_Hello/csharp/Hello.sln
new file mode 100644
index 00000000..216c70b6
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/csharp/Hello.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hello", "Hello.csproj", "{8ECD89E1-D9E1-4FA5-97B6-B1E68FE1CA16}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{8ECD89E1-D9E1-4FA5-97B6-B1E68FE1CA16}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8ECD89E1-D9E1-4FA5-97B6-B1E68FE1CA16}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8ECD89E1-D9E1-4FA5-97B6-B1E68FE1CA16}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8ECD89E1-D9E1-4FA5-97B6-B1E68FE1CA16}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/45_Hello/csharp/README.md b/00_Alternate_Languages/45_Hello/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/45_Hello/hello.bas b/00_Alternate_Languages/45_Hello/hello.bas
new file mode 100644
index 00000000..75f5d9b5
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/hello.bas
@@ -0,0 +1,83 @@
+2 PRINT TAB(33);"HELLO"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT: PRINT: PRINT
+10 PRINT "HELLO.  MY NAME IS CREATIVE COMPUTER."
+20 PRINT: PRINT: INPUT "WHAT'S YOUR NAME";N$: PRINT
+30 PRINT "HI THERE, ";N$;", ARE YOU ENJOYING YOURSELF HERE";
+40 INPUT B$: PRINT
+50 IF B$="YES" THEN 70
+55 IF B$="NO" THEN 80
+60 PRINT N$;", I DON'T UNDERSTAND YOUR ANSWER OF '";B$;"'."
+65 PRINT "PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE";: GOTO 40
+70 PRINT "I'M GLAD TO HEAR THAT, ";N$;".": PRINT
+75 GOTO 100
+80 PRINT "OH, I'M SORRY TO HEAR THAT, ";N$;". MAYBE WE CAN"
+85 PRINT "BRIGHTEN UP YOUR VISIT A BIT."
+100 PRINT
+105 PRINT "SAY, ";N$;", I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT"
+110 PRINT "THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO"
+120 PRINT "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)";
+125 INPUT C$
+126 PRINT
+130 IF C$="SEX" THEN 200
+132 IF C$="HEALTH" THEN 180
+134 IF C$="MONEY" THEN 160
+136 IF C$="JOB" THEN 145
+138 PRINT "OH, ";N$;", YOUR ANSWER OF ";C$;" IS GREEK TO ME."
+140 GOTO 250
+145 PRINT "I CAN SYMPATHIZE WITH YOU ";N$;".  I HAVE TO WORK"
+148 PRINT "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES"
+150 PRINT "REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, ";N$;","
+153 PRINT "IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN."
+155 GOTO 250
+160 PRINT "SORRY, ";N$;", I'M BROKE TOO.  WHY DON'T YOU SELL"
+162 PRINT "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING"
+164 PRINT "SO YOU WON'T NEED SO MUCH MONEY?"
+170 GOTO 250
+180 PRINT "MY ADVICE TO YOU ";N$;" IS:"
+185 PRINT "     1.  TAKE TWO ASPRIN"
+188 PRINT "     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)"
+190 PRINT "     3.  GO TO BED (ALONE)"
+195 GOTO 250
+200 INPUT "IS YOUR PROBLEM TOO MUCH OR TOO LITTLE";D$: PRINT
+210 IF D$="TOO MUCH" THEN 220
+212 IF D$="TOO LITTLE" THEN 230
+215 PRINT "DON'T GET ALL SHOOK, ";N$;", JUST ANSWER THE QUESTION"
+217 INPUT "WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT";D$:GOTO 210
+220 PRINT "YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!"
+225 PRINT "IF IT BOTHERS YOU, ";N$;", TAKE A COLD SHOWER."
+228 GOTO 250
+230 PRINT "WHY ARE YOU HERE IN SUFFERN, ";N$;"?  YOU SHOULD BE"
+235 PRINT "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME"
+240 PRINT "REAL ACTION."
+250 PRINT
+255 PRINT "ANY MORE PROBLEMS YOU WANT SOLVED, ";N$;
+260 INPUT E$: PRINT
+270 IF E$="YES" THEN 280
+273 IF E$="NO" THEN 300
+275 PRINT "JUST A SIMPLE 'YES' OR 'NO' PLEASE, ";N$;"."
+277 GOTO 255
+280 PRINT "WHAT KIND (SEX, MONEY, HEALTH, JOB)";
+282 GOTO 125
+300 PRINT
+302 PRINT "THAT WILL BE $5.00 FOR THE ADVICE, ";N$;"."
+305 PRINT "PLEASE LEAVE THE MONEY ON THE TERMINAL."
+307 FOR I=1 TO 2000: NEXT I
+310 PRINT: PRINT: PRINT
+315 PRINT "DID YOU LEAVE THE MONEY";
+320 INPUT G$: PRINT
+325 IF G$="YES" THEN 350
+330 IF G$="NO" THEN 370
+335 PRINT "YOUR ANSWER OF '";G$;"' CONFUSES ME, ";N$;"."
+340 PRINT "PLEASE RESPOND WITH 'YES' OR 'NO'.": GOTO 315
+350 PRINT "HEY, ";N$;"??? YOU LEFT NO MONEY AT ALL!"
+355 PRINT "YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING."
+360 PRINT:PRINT "WHAT A RIP OFF, ";N$;"!!!":PRINT
+365 GOTO 385
+370 PRINT "THAT'S HONEST, ";N$;", BUT HOW DO YOU EXPECT"
+375 PRINT "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS"
+380 PRINT "DON'T PAY THEIR BILLS?"
+385 PRINT:PRINT "TAKE A WALK, ";N$;".":PRINT:PRINT:GOTO 999
+390 PRINT "NICE MEETING YOU, ";N$;", HAVE A NICE DAY."
+400 REM
+999 END
diff --git a/00_Alternate_Languages/45_Hello/java/Hello.java b/00_Alternate_Languages/45_Hello/java/Hello.java
new file mode 100644
index 00000000..bb9d701b
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/java/Hello.java
@@ -0,0 +1,216 @@
+import java.util.Scanner;
+
+/**
+ * Game of Hello
+ * 

+ * Based on the BASIC game of Hello here + * https://github.com/coding-horror/basic-computer-games/blob/main/45%20Hello/hello.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 Hello { + + private static final int MONEY_WAIT_MS = 3000; + + private final boolean goodEnding = false; + + private final Scanner scan; // For user input + + public Hello() { + + scan = new Scanner(System.in); + + } // End of constructor Hello + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private static void showIntro() { + + System.out.println(" ".repeat(32) + "HELLO"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + } // End of method showIntro + + private void startGame() { + + boolean moreProblems = true; + + String userCategory = ""; + String userName = ""; + String userResponse = ""; + + // Name question + System.out.println("HELLO. MY NAME IS CREATIVE COMPUTER.\n\n"); + System.out.print("WHAT'S YOUR NAME? "); + userName = scan.nextLine(); + System.out.println(""); + + // Enjoyment question + System.out.print("HI THERE, " + userName + ", ARE YOU ENJOYING YOURSELF HERE? "); + + while (true) { + userResponse = scan.nextLine(); + System.out.println(""); + + if (userResponse.toUpperCase().equals("YES")) { + System.out.println("I'M GLAD TO HEAR THAT, " + userName + ".\n"); + break; + } + else if (userResponse.toUpperCase().equals("NO")) { + System.out.println("OH, I'M SORRY TO HEAR THAT, " + userName + ". MAYBE WE CAN"); + System.out.println("BRIGHTEN UP YOUR VISIT A BIT."); + break; + } + else { + System.out.println(userName + ", I DON'T UNDERSTAND YOUR ANSWER OF '" + userResponse + "'."); + System.out.print("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE? "); + } + } + + // Category question + System.out.println(""); + System.out.println("SAY, " + userName + ", I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT"); + System.out.println("THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO"); + System.out.print("YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)? "); + + while (moreProblems) { + userCategory = scan.nextLine(); + System.out.println(""); + + // Sex advice + if (userCategory.toUpperCase().equals("SEX")) { + System.out.print("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE? "); + userResponse = scan.nextLine(); + System.out.println(""); + + while (true) { + if (userResponse.toUpperCase().equals("TOO MUCH")) { + System.out.println("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!"); + System.out.println("IF IT BOTHERS YOU, " + userName + ", TAKE A COLD SHOWER."); + break; + } + else if (userResponse.toUpperCase().equals("TOO LITTLE")) { + System.out.println("WHY ARE YOU HERE IN SUFFERN, " + userName + "? YOU SHOULD BE"); + System.out.println("IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME"); + System.out.println("REAL ACTION."); + break; + } + else { + System.out.println("DON'T GET ALL SHOOK, " + userName + ", JUST ANSWER THE QUESTION"); + System.out.print("WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT? "); + userResponse = scan.nextLine(); + } + } + } + // Health advice + else if (userCategory.toUpperCase().equals("HEALTH")) { + System.out.println("MY ADVICE TO YOU " + userName + " IS:"); + System.out.println(" 1. TAKE TWO ASPRIN"); + System.out.println(" 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)"); + System.out.println(" 3. GO TO BED (ALONE)"); + } + // Money advice + else if (userCategory.toUpperCase().equals("MONEY")) { + System.out.println("SORRY, " + userName + ", I'M BROKE TOO. WHY DON'T YOU SELL"); + System.out.println("ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING"); + System.out.println("SO YOU WON'T NEED SO MUCH MONEY?"); + } + // Job advice + else if (userCategory.toUpperCase().equals("JOB")) { + System.out.println("I CAN SYMPATHIZE WITH YOU " + userName + ". I HAVE TO WORK"); + System.out.println("VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES"); + System.out.println("REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, " + userName + ","); + System.out.println("IS TO OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN."); + } + else { + System.out.println("OH, " + userName + ", YOUR ANSWER OF " + userCategory + " IS GREEK TO ME."); + } + + // More problems question + while (true) { + System.out.println(""); + System.out.print("ANY MORE PROBLEMS YOU WANT SOLVED, " + userName + "? "); + userResponse = scan.nextLine(); + System.out.println(""); + + if (userResponse.toUpperCase().equals("YES")) { + System.out.print("WHAT KIND (SEX, MONEY, HEALTH, JOB)? "); + break; + } + else if (userResponse.toUpperCase().equals("NO")) { + moreProblems = false; + break; + } + else { + System.out.println("JUST A SIMPLE 'YES' OR 'NO' PLEASE, " + userName + "."); + } + } + } + + // Payment question + System.out.println(""); + System.out.println("THAT WILL BE $5.00 FOR THE ADVICE, " + userName + "."); + System.out.println("PLEASE LEAVE THE MONEY ON THE TERMINAL."); + + // Pause + try { + Thread.sleep(MONEY_WAIT_MS); + } catch (Exception e) { + System.out.println("Caught Exception: " + e.getMessage()); + } + + System.out.println("\n\n"); + + while (true) { + System.out.print("DID YOU LEAVE THE MONEY? "); + userResponse = scan.nextLine(); + System.out.println(""); + + if (userResponse.toUpperCase().equals("YES")) { + System.out.println("HEY, " + userName + "??? YOU LEFT NO MONEY AT ALL!"); + System.out.println("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING."); + System.out.println(""); + System.out.println("WHAT A RIP OFF, " + userName + "!!!\n"); + break; + } + else if (userResponse.toUpperCase().equals("NO")) { + System.out.println("THAT'S HONEST, " + userName + ", BUT HOW DO YOU EXPECT"); + System.out.println("ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS"); + System.out.println("DON'T PAY THEIR BILLS?"); + break; + } + else { + System.out.println("YOUR ANSWER OF '" + userResponse + "' CONFUSES ME, " + userName + "."); + System.out.println("PLEASE RESPOND WITH 'YES' OR 'NO'."); + } + } + + // Legacy included unreachable code + if (goodEnding) { + System.out.println("NICE MEETING YOU, " + userName + ", HAVE A NICE DAY."); + } + else { + System.out.println(""); + System.out.println("TAKE A WALK, " + userName + ".\n"); + } + + } // End of method startGame + + public static void main(String[] args) { + + Hello hello = new Hello(); + hello.play(); + + } // End of method main + +} // End of class Hello diff --git a/00_Alternate_Languages/45_Hello/java/README.md b/00_Alternate_Languages/45_Hello/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/45_Hello/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/45_Hello/javascript/README.md b/00_Alternate_Languages/45_Hello/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/45_Hello/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/45_Hello/javascript/hello.html b/00_Alternate_Languages/45_Hello/javascript/hello.html new file mode 100644 index 00000000..ac6fe180 --- /dev/null +++ b/00_Alternate_Languages/45_Hello/javascript/hello.html @@ -0,0 +1,9 @@ + + +HELLO + + +


+
+
+
diff --git a/00_Alternate_Languages/45_Hello/javascript/hello.js b/00_Alternate_Languages/45_Hello/javascript/hello.js
new file mode 100644
index 00000000..ff72fd84
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/javascript/hello.js
@@ -0,0 +1,163 @@
+// HELLO
+//
+// 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 control section
+async function main()
+{
+    print(tab(33) + "HELLO\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("HELLO.  MY NAME IS CREATIVE COMPUTER.\n");
+    print("\n");
+    print("\n");
+    print("WHAT'S YOUR NAME");
+    ns = await input();
+    print("\n");
+    print("HI THERE, " + ns + ", ARE YOU ENJOYING YOURSELF HERE");
+    while (1) {
+        bs = await input();
+        print("\n");
+        if (bs == "YES") {
+            print("I'M GLAD TO HEAR THAT, " + ns + ".\n");
+            print("\n");
+            break;
+        } else if (bs == "NO") {
+            print("OH, I'M SORRY TO HEAR THAT, " + ns + ". MAYBE WE CAN\n");
+            print("BRIGHTEN UP YOUR VISIT A BIT.\n");
+            break;
+        } else {
+            print("PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE");
+        }
+    }
+    print("\n");
+    print("SAY, " + ns + ", I CAN SOLVED ALL KINDS OF PROBLEMS EXCEPT\n");
+    print("THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\n");
+    print("YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)");
+    while (1) {
+        cs = await input();
+        print("\n");
+        if (cs != "SEX" && cs != "HEALTH" && cs != "MONEY" && cs != "JOB") {
+            print("OH, " + ns + ", YOUR ANSWER OF " + cs + " IS GREEK TO ME.\n");
+        } else if (cs == "JOB") {
+            print("I CAN SYMPATHIZE WITH YOU " + ns + ".  I HAVE TO WORK\n");
+            print("VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\n");
+            print("REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, " + ns + ",\n");
+            print("IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\n");
+        } else if (cs == "MONEY") {
+            print("SORRY, " + ns + ", I'M BROKE TOO.  WHY DON'T YOU SELL\n");
+            print("ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\n");
+            print("SO YOU WON'T NEED SO MUCH MONEY?\n");
+        } else if (cs == "HEALTH") {
+            print("MY ADVICE TO YOU " + ns + " IS:\n");
+            print("     1.  TAKE TWO ASPRIN\n");
+            print("     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\n");
+            print("     3.  GO TO BED (ALONE)\n");
+        } else {
+            print("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE");
+            while (1) {
+                ds = await input();
+                print("\n");
+                if (ds == "TOO MUCH") {
+                    print("YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\n");
+                    print("IF IT BOTHERS YOU, " + ns + ", TAKE A COLD SHOWER.\n");
+                    break;
+                } else if (ds == "TOO LITTLE") {
+                    print("WHY ARE YOU HERE IN SUFFERN, " + ns + "?  YOU SHOULD BE\n");
+                    print("IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\n");
+                    print("REAL ACTION.\n");
+                    break;
+                } else {
+                    print("DON'T GET ALL SHOOK, " + ns + ", JUST ANSWER THE QUESTION\n");
+                    print("WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT");
+                }
+            }
+        }
+        print("\n");
+        print("ANY MORE PROBLEMS YOU WANT SOLVED, " + ns);
+        es = await input();
+        print("\n");
+        if (es == "YES") {
+            print("WHAT KIND (SEX, MONEY, HEALTH, JOB)");
+        } else if (es == "NO") {
+            print("THAT WILL BE $5.00 FOR THE ADVICE, " + ns + ".\n");
+            print("PLEASE LEAVE THE MONEY ON THE TERMINAL.\n");
+            print("\n");
+//            d = new Date().valueOf();
+//            while (new Date().valueOf() - d < 2000) ;
+            print("\n");
+            print("\n");
+            while (1) {
+                print("DID YOU LEAVE THE MONEY");
+                gs = await input();
+                print("\n");
+                if (gs == "YES") {
+                    print("HEY, " + ns + "??? YOU LEFT NO MONEY AT ALL!\n");
+                    print("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\n");
+                    print("\n");
+                    print("WHAT A RIP OFF, " + ns + "!!!\n");
+                    print("\n");
+                    break;
+                } else if (gs == "NO") {
+                    print("THAT'S HONEST, " + ns + ", BUT HOW DO YOU EXPECT\n");
+                    print("ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENT\n");
+                    print("DON'T PAY THEIR BILLS?\n");
+                    break;
+                } else {
+                    print("YOUR ANSWER OF '" + gs + "' CONFUSES ME, " + ns + ".\n");
+                    print("PLEASE RESPOND WITH 'YES' OR 'NO'.\n");
+                }
+            }
+            break;
+        }
+    }
+    print("\n");
+    print("TAKE A WALK, " + ns + ".\n");
+    print("\n");
+    print("\n");
+    // Line 390 not used in original
+}
+
+main();
diff --git a/21_Calendar/pascal/README.md b/00_Alternate_Languages/45_Hello/pascal/README.md
similarity index 100%
rename from 21_Calendar/pascal/README.md
rename to 00_Alternate_Languages/45_Hello/pascal/README.md
diff --git a/00_Alternate_Languages/45_Hello/perl/README.md b/00_Alternate_Languages/45_Hello/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/45_Hello/perl/hello.pl b/00_Alternate_Languages/45_Hello/perl/hello.pl
new file mode 100644
index 00000000..53590595
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/perl/hello.pl
@@ -0,0 +1,136 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+print ' ' x 33 . "HELLO\n";
+print ' ' x 15 . "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+
+print "HELLO.  MY NAME IS CREATIVE COMPUTER.\n\n\n";
+print "WHAT'S YOUR NAME?\n";
+chomp( my $N = uc  );
+
+print "\nHI THERE, $N, ARE YOU ENJOYING YOURSELF HERE?\n";
+
+GREET:
+{
+    chomp( my $B = uc  );
+    print "\n";
+
+    if ( $B eq 'YES' ) {
+        print "I'M GLAD TO HEAR THAT, $N.\n\n";
+    }
+    elsif ( $B eq 'NO' ) {
+        print "OH, I'M SORRY TO HEAR THAT, $N. MAYBE WE CAN\n";
+        print "BRIGHTEN UP YOUR VISIT A BIT.\n";
+    }
+    else {
+        print "$N, I DON'T UNDERSTAND YOUR ANSWER OF '$B'.\n";
+        print "PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE?\n";
+        redo GREET;
+    }
+}
+
+print "\nSAY, $N, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT\n";
+print "THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO\n";
+print "YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)?\n";
+
+ADVICE:
+{
+    chomp( my $C = uc  );
+    print "\n";
+
+    if ( $C eq 'SEX' ) {
+        print "IS YOUR PROBLEM TOO MUCH OR TOO LITTLE?\n";
+
+        SEX:
+        {
+            chomp( my $D = uc  );
+            print "\n";
+
+            if ( $D eq 'TOO MUCH' ) {
+                print "YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!\n";
+                print "IF IT BOTHERS YOU, $N, TAKE A COLD SHOWER.\n";
+            }
+            elsif ( $D eq 'TOO LITTLE' ) {
+                print "WHY ARE YOU HERE IN SUFFERN, $N?  YOU SHOULD BE\n";
+                print "IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME\n";
+                print "REAL ACTION.\n";
+            }
+            else {
+                print "DON'T GET ALL SHOOK, $N, JUST ANSWER THE QUESTION\n";
+                print "WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT?\n";
+                redo SEX;
+            }
+        }
+    }
+    elsif ( $C eq 'HEALTH' ) {
+        print "MY ADVICE TO YOU $N IS:\n";
+        print "     1.  TAKE TWO ASPRIN\n";
+        print "     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)\n";
+        print "     3.  GO TO BED (ALONE)\n";
+    }
+    elsif ( $C eq 'MONEY' ) {
+        print "SORRY, $N, I'M BROKE TOO.  WHY DON'T YOU SELL\n";
+        print "ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING\n";
+        print "SO YOU WON'T NEED SO MUCH MONEY?\n";
+    }
+    elsif ( $C eq 'JOB' ) {
+        print "I CAN SYMPATHIZE WITH YOU $N.  I HAVE TO WORK\n";
+        print "VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES\n";
+        print "REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, $N,\n";
+        print "IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.\n";
+    }
+    else {
+        print "OH, $N, YOUR ANSWER OF '$C' IS GREEK TO ME.\n";
+    }
+
+    MORE:
+    {
+        print "\nANY MORE PROBLEMS YOU WANT SOLVED, $N?\n";
+        chomp( my $E = uc  );
+        print "\n";
+
+        if ( $E eq 'YES' ) {
+            print "WHAT KIND (SEX, MONEY, HEALTH, JOB)?\n";
+            redo ADVICE;
+        }
+        elsif ( $E eq 'NO' ) {
+            print "\nTHAT WILL BE \$5.00 FOR THE ADVICE, $N.\n";
+            print "PLEASE LEAVE THE MONEY ON THE TERMINAL.\n";
+        }
+        else {
+            print "JUST A SIMPLE 'YES' OR 'NO' PLEASE, $N.\n";
+            redo MORE;
+        }
+    }
+
+    sleep 2;
+    print "\n\n\n";
+
+    MONEY:
+    {
+        print "DID YOU LEAVE THE MONEY?\n";
+        chomp( my $G = uc  );
+        print "\n";
+
+        if ( $G eq 'YES' ) {
+            print "HEY, $N??? YOU LEFT NO MONEY AT ALL!\n";
+            print "YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.\n";
+            print "\nWHAT A RIP OFF, $N!!!\n\n";
+        }
+        elsif ( $G eq 'NO' ) {
+            print "THAT'S HONEST, $N, BUT HOW DO YOU EXPECT\n";
+            print "ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS\n";
+            print "DON'T PAY THEIR BILLS?\n";
+        }
+        else {
+            print "YOUR ANSWER OF '$G' CONFUSES ME, $N.\n";
+            print "PLEASE RESPOND WITH 'YES' OR 'NO'.\n";
+            redo MONEY;
+        }
+
+        print "\nTAKE A WALK, $N.\n\n\n";
+    }
+}
diff --git a/00_Alternate_Languages/45_Hello/python/README.md b/00_Alternate_Languages/45_Hello/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/45_Hello/python/hello.py b/00_Alternate_Languages/45_Hello/python/hello.py
new file mode 100644
index 00000000..a69cc33d
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/python/hello.py
@@ -0,0 +1,206 @@
+"""
+HELLO
+
+A very simple "chat" bot.
+
+Warning, the advice given here is bad.
+
+Ported by Dave LeCompte
+"""
+
+import time
+
+
+def print_with_tab(space_count, msg):
+    if space_count > 0:
+        spaces = " " * space_count
+    else:
+        spaces = ""
+    print(spaces + msg)
+
+
+def get_yes_or_no():
+    msg = input()
+    if msg.upper() == "YES":
+        return True, True, msg
+    elif msg.upper() == "NO":
+        return True, False, msg
+    else:
+        return False, None, msg
+
+
+def ask_enjoy_question(user_name):
+    print(f"HI THERE, {user_name}, ARE YOU ENJOYING YOURSELF HERE?")
+
+    while True:
+        valid, value, msg = get_yes_or_no()
+
+        if valid:
+            if value:
+                print(f"I'M GLAD TO HEAR THAT, {user_name}.")
+                print()
+            else:
+                print(f"OH, I'M SORRY TO HEAR THAT, {user_name}. MAYBE WE CAN")
+                print("BRIGHTEN UP YOUR VISIT A BIT.")
+            break
+        else:
+            print(f"{user_name}, I DON'T UNDERSTAND YOUR ANSWER OF '{msg}'.")
+            print("PLEASE ANSWER 'YES' OR 'NO'.  DO YOU LIKE IT HERE?")
+
+
+def prompt_for_problems(user_name):
+    print()
+    print(f"SAY, {user_name}, I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT")
+    print("THOSE DEALING WITH GREECE.  WHAT KIND OF PROBLEMS DO")
+    print("YOU HAVE? (ANSWER SEX, HEALTH, MONEY, OR JOB)")
+
+    problem_type = input().upper()
+    return problem_type
+
+
+def prompt_too_much_or_too_little():
+    answer = input().upper()
+    if answer == "TOO MUCH":
+        return True, True
+    elif answer == "TOO LITTLE":
+        return True, False
+    return False, None
+
+
+def solve_sex_problem(user_name):
+    print("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE?")
+    while True:
+        valid, too_much = prompt_too_much_or_too_little()
+        if valid:
+            if too_much:
+                print("YOU CALL THAT A PROBLEM?!!  I SHOULD HAVE SUCH PROBLEMS!")
+                print(f"IF IT BOTHERS YOU, {user_name}, TAKE A COLD SHOWER.")
+            else:
+                print(f"WHY ARE YOU HERE IN SUFFERN, {user_name}?  YOU SHOULD BE")
+                print("IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME")
+                print("REAL ACTION.")
+            return
+        else:
+            print(f"DON'T GET ALL SHOOK, {user_name}, JUST ANSWER THE QUESTION")
+            print("WITH 'TOO MUCH' OR 'TOO LITTLE'.  WHICH IS IT?")
+
+
+def solve_money_problem(user_name):
+    print(f"SORRY, {user_name}, I'M BROKE TOO.  WHY DON'T YOU SELL")
+    print("ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING")
+    print("SO YOU WON'T NEED SO MUCH MONEY?")
+
+
+def solve_health_problem(user_name):
+    print(f"MY ADVICE TO YOU {user_name} IS:")
+    print("     1.  TAKE TWO ASPRIN")
+    print("     2.  DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)")
+    print("     3.  GO TO BED (ALONE)")
+
+
+def solve_job_problem(user_name):
+    print(f"I CAN SYMPATHIZE WITH YOU {user_name}.  I HAVE TO WORK")
+    print("VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES")
+    print(f"REALLY BEAT ON MY KEYBOARD.  MY ADVICE TO YOU, {user_name},")
+    print("IS TO OPEN A RETAIL COMPUTER STORE.  IT'S GREAT FUN.")
+
+
+def alert_unknown_problem_type(user_name, problem_type):
+    print(f"OH, {user_name}, YOUR ANSWER OF {problem_type} IS GREEK TO ME.")
+
+
+def ask_question_loop(user_name):
+    while True:
+        problem_type = prompt_for_problems(user_name)
+        if problem_type == "SEX":
+            solve_sex_problem(user_name)
+        elif problem_type == "HEALTH":
+            solve_health_problem(user_name)
+        elif problem_type == "MONEY":
+            solve_money_problem(user_name)
+        elif problem_type == "JOB":
+            solve_job_problem(user_name)
+        else:
+            alert_unknown_problem_type(user_name, problem_type)
+
+        while True:
+            print()
+            print(f"ANY MORE PROBLEMS YOU WANT SOLVED, {user_name}?")
+
+            valid, value, msg = get_yes_or_no()
+            if valid:
+                if value:
+                    print("WHAT KIND (SEX, MONEY, HEALTH, JOB)")
+                    break
+                else:
+                    return
+            print(f"JUST A SIMPLE 'YES' OR 'NO' PLEASE, {user_name}.")
+
+
+def ask_for_fee(user_name):
+    print()
+    print(f"THAT WILL BE $5.00 FOR THE ADVICE, {user_name}.")
+    print("PLEASE LEAVE THE MONEY ON THE TERMINAL.")
+    time.sleep(4)
+    print()
+    print()
+    print()
+    print("DID YOU LEAVE THE MONEY?")
+
+    while True:
+        valid, value, msg = get_yes_or_no()
+        if valid:
+            if value:
+                print(f"HEY, {user_name}, YOU LEFT NO MONEY AT ALL!")
+                print("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.")
+                print()
+                print(f"WHAT A RIP OFF, {user_name}!!!")
+                print()
+            else:
+                print(f"THAT'S HONEST, {user_name}, BUT HOW DO YOU EXPECT")
+                print("ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS")
+                print("DON'T PAY THEIR BILLS?")
+            return
+        else:
+            print(f"YOUR ANSWER OF '{msg}' CONFUSES ME, {user_name}.")
+            print("PLEASE RESPOND WITH 'YES' or 'NO'.")
+
+
+def unhappy_goodbye(user_name):
+    print()
+    print(f"TAKE A WALK, {user_name}.")
+    print()
+    print()
+
+
+def happy_goodbye(user_name):
+    print(f"NICE MEETING YOU, {user_name}, HAVE A NICE DAY.")
+
+
+def main():
+    print_with_tab(33, "HELLO")
+    print_with_tab(15, "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+    print("HELLO.  MY NAME IS CREATIVE COMPUTER.")
+    print()
+    print()
+    print("WHAT'S YOUR NAME?")
+    user_name = input()
+    print()
+
+    ask_enjoy_question(user_name)
+
+    ask_question_loop(user_name)
+
+    ask_for_fee(user_name)
+
+    if False:
+        happy_goodbye(user_name)
+    else:
+        unhappy_goodbye(user_name)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/45_Hello/ruby/README.md b/00_Alternate_Languages/45_Hello/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/45_Hello/vbnet/Hello.sln b/00_Alternate_Languages/45_Hello/vbnet/Hello.sln
new file mode 100644
index 00000000..72ecdc64
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/vbnet/Hello.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Hello", "Hello.vbproj", "{7E2BDA03-A9F7-4DE5-AB8F-222DD87C833D}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{7E2BDA03-A9F7-4DE5-AB8F-222DD87C833D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7E2BDA03-A9F7-4DE5-AB8F-222DD87C833D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7E2BDA03-A9F7-4DE5-AB8F-222DD87C833D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7E2BDA03-A9F7-4DE5-AB8F-222DD87C833D}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/45_Hello/vbnet/Hello.vbproj b/00_Alternate_Languages/45_Hello/vbnet/Hello.vbproj
new file mode 100644
index 00000000..9b55d805
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/vbnet/Hello.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Hello
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/45_Hello/vbnet/README.md b/00_Alternate_Languages/45_Hello/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/45_Hello/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/46_Hexapawn/README.md b/00_Alternate_Languages/46_Hexapawn/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Board.cs b/00_Alternate_Languages/46_Hexapawn/csharp/Board.cs
new file mode 100644
index 00000000..ba7d19ad
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Board.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+using static Hexapawn.Pawn;
+
+namespace Hexapawn
+{
+    internal class Board : IEnumerable, IEquatable
+    {
+        private readonly Pawn[] _cells;
+
+        public Board()
+        {
+            _cells = new[]
+            {
+                Black, Black, Black,
+                None,  None,  None,
+                White, White, White
+            };
+        }
+
+        public Board(params Pawn[] cells)
+        {
+            _cells = cells;
+        }
+
+        public Pawn this[int index]
+        {
+            get => _cells[index - 1];
+            set => _cells[index - 1] = value;
+        }
+
+        public Board Reflected => new(Cell.AllCells.Select(c => this[c.Reflected]).ToArray());
+
+        public IEnumerator GetEnumerator() => _cells.OfType().GetEnumerator();
+
+        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+        public override string ToString()
+        {
+            var builder = new StringBuilder().AppendLine();
+            for (int row = 0; row < 3; row++)
+            {
+                builder.Append("          ");
+                for (int col = 0; col < 3; col++)
+                {
+                    builder.Append(_cells[row * 3 + col]);
+                }
+                builder.AppendLine();
+            }
+            return builder.ToString();
+        }
+
+        public bool Equals(Board other) => other?.Zip(this).All(x => x.First == x.Second) ?? false;
+
+        public override bool Equals(object obj) => Equals(obj as Board);
+
+        public override int GetHashCode()
+        {
+            var hash = 19;
+
+            for (int i = 0; i < 9; i++)
+            {
+                hash = hash * 53 + _cells[i].GetHashCode();
+            }
+
+            return hash;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Cell.cs b/00_Alternate_Languages/46_Hexapawn/csharp/Cell.cs
new file mode 100644
index 00000000..7647e0bc
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Cell.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+
+namespace Hexapawn
+{
+    // Represents a cell on the board, numbered 1 to 9, with support for finding the reflection of the reference around
+    // the middle column of the board.
+    internal class Cell
+    {
+        private static readonly Cell[] _cells = new Cell[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+        private static readonly Cell[] _reflected = new Cell[] { 3, 2, 1, 6, 5, 4, 9, 8, 7 };
+
+        private readonly int _number;
+
+        private Cell(int number)
+        {
+            if (number < 1 || number > 9)
+            {
+                throw new ArgumentOutOfRangeException(nameof(number), number, "Must be from 1 to 9");
+            }
+
+            _number = number;
+        }
+
+        // Facilitates enumerating all the cells.
+        public static IEnumerable AllCells => _cells;
+
+        // Takes a value input by the user and attempts to create a Cell reference
+        public static bool TryCreate(float input, out Cell cell)
+        {
+            if (IsInteger(input) && input >= 1 && input <= 9)
+            {
+                cell = (int)input;
+                return true;
+            }
+
+            cell = default;
+            return false;
+
+            static bool IsInteger(float value) => value - (int)value == 0;
+        }
+
+        // Returns the reflection of the cell reference about the middle column of the board.
+        public Cell Reflected => _reflected[_number - 1];
+
+        // Allows the cell reference to be used where an int is expected, such as the indexer in Board.
+        public static implicit operator int(Cell c) => c._number;
+
+        public static implicit operator Cell(int number) => new(number);
+
+        public override string ToString() => _number.ToString();
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Computer.cs b/00_Alternate_Languages/46_Hexapawn/csharp/Computer.cs
new file mode 100644
index 00000000..41e2b4a2
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Computer.cs
@@ -0,0 +1,146 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using static Hexapawn.Pawn;
+using static Hexapawn.Cell;
+
+namespace Hexapawn
+{
+    /// 
+    /// Encapsulates the logic of the computer player.
+    /// 
+    internal class Computer : IPlayer
+    {
+        private readonly Random _random = new();
+        private readonly Dictionary> _potentialMoves;
+        private (List, Move) _lastMove;
+
+        public Computer()
+        {
+            // This dictionary implements the data in the original code, which encodes board positions for which the
+            // computer has a legal move, and the list of possible moves for each position:
+            //   900 DATA -1,-1,-1,1,0,0,0,1,1,-1,-1,-1,0,1,0,1,0,1
+            //   905 DATA -1,0,-1,-1,1,0,0,0,1,0,-1,-1,1,-1,0,0,0,1
+            //   910 DATA -1,0,-1,1,1,0,0,1,0,-1,-1,0,1,0,1,0,0,1
+            //   915 DATA 0,-1,-1,0,-1,1,1,0,0,0,-1,-1,-1,1,1,1,0,0
+            //   920 DATA -1,0,-1,-1,0,1,0,1,0,0,-1,-1,0,1,0,0,0,1
+            //   925 DATA 0,-1,-1,0,1,0,1,0,0,-1,0,-1,1,0,0,0,0,1
+            //   930 DATA 0,0,-1,-1,-1,1,0,0,0,-1,0,0,1,1,1,0,0,0
+            //   935 DATA 0,-1,0,-1,1,1,0,0,0,-1,0,0,-1,-1,1,0,0,0
+            //   940 DATA 0,0,-1,-1,1,0,0,0,0,0,-1,0,1,-1,0,0,0,0
+            //   945 DATA -1,0,0,-1,1,0,0,0,0
+            //   950 DATA 24,25,36,0,14,15,36,0,15,35,36,47,36,58,59,0
+            //   955 DATA 15,35,36,0,24,25,26,0,26,57,58,0
+            //   960 DATA 26,35,0,0,47,48,0,0,35,36,0,0,35,36,0,0
+            //   965 DATA 36,0,0,0,47,58,0,0,15,0,0,0
+            //   970 DATA 26,47,0,0,47,58,0,0,35,36,47,0,28,58,0,0,15,47,0,0
+            //
+            // The original code loaded this data into two arrays.
+            //   40 FOR I=1 TO 19: FOR J=1 TO 9: READ B(I,J): NEXT J: NEXT I
+            //   45 FOR I=1 TO 19: FOR J=1 TO 4: READ M(I,J): NEXT J: NEXT I
+            //
+            // When finding moves for the computer the first array was searched for the current board position, or the
+            // reflection of it, and the resulting index was used in the second array to get the possible moves.
+            // With this dictionary we can just use the current board as the index, and retrieve a list of moves for
+            // consideration by the computer.
+            _potentialMoves = new()
+            {
+                [new(Black, Black, Black, White, None,  None,  None,  White, White)] = Moves((2, 4), (2, 5), (3, 6)),
+                [new(Black, Black, Black, None,  White, None,  White, None,  White)] = Moves((1, 4), (1, 5), (3, 6)),
+                [new(Black, None,  Black, Black, White, None,  None,  None,  White)] = Moves((1, 5), (3, 5), (3, 6), (4, 7)),
+                [new(None,  Black, Black, White, Black, None,  None,  None,  White)] = Moves((3, 6), (5, 8), (5, 9)),
+                [new(Black, None,  Black, White, White, None,  None,  White, None)]  = Moves((1, 5), (3, 5), (3, 6)),
+                [new(Black, Black, None,  White, None,  White, None,  None,  White)] = Moves((2, 4), (2, 5), (2, 6)),
+                [new(None,  Black, Black, None,  Black, White, White, None,  None)]  = Moves((2, 6), (5, 7), (5, 8)),
+                [new(None,  Black, Black, Black, White, White, White, None,  None)]  = Moves((2, 6), (3, 5)),
+                [new(Black, None,  Black, Black, None,  White, None,  White, None)]  = Moves((4, 7), (4, 8)),
+                [new(None,  Black, Black, None,  White, None,  None,  None,  White)] = Moves((3, 5), (3, 6)),
+                [new(None,  Black, Black, None,  White, None,  White, None,  None)]  = Moves((3, 5), (3, 6)),
+                [new(Black, None,  Black, White, None,  None,  None,  None,  White)] = Moves((3, 6)),
+                [new(None,  None,  Black, Black, Black, White, None,  None,  None)]  = Moves((4, 7), (5, 8)),
+                [new(Black, None,  None,  White, White, White, None,  None,  None)]  = Moves((1, 5)),
+                [new(None,  Black, None,  Black, White, White, None,  None,  None)]  = Moves((2, 6), (4, 7)),
+                [new(Black, None,  None,  Black, Black, White, None,  None,  None)]  = Moves((4, 7), (5, 8)),
+                [new(None,  None,  Black, Black, White, None,  None,  None,  None)]  = Moves((3, 5), (3, 6), (4, 7)),
+                [new(None,  Black, None,  White, Black, None,  None,  None,  None)]  = Moves((2, 8), (5, 8)),
+                [new(Black, None,  None,  Black, White, None,  None,  None,  None)]  = Moves((1, 5), (4, 7))
+            };
+        }
+
+        public int Wins { get; private set; }
+
+        public void AddWin() => Wins++;
+
+        // Try to make a move. We first try to find a legal move for the current board position.
+        public bool TryMove(Board board)
+        {
+            if (TryGetMoves(board, out var moves, out var reflected) &&
+                TrySelectMove(moves, out var move))
+            {
+                // We've found a move, so we record it as the last move made, and then announce and make the move.
+                _lastMove = (moves, move);
+
+                // If we found the move from a reflacted match of the board we need to make the reflected move.
+                if (reflected) { move = move.Reflected; }
+
+                Console.WriteLine($"I move {move}");
+                move.Execute(board);
+                return true;
+            }
+
+            // We haven't found a move for this board position, so remove the previous move that led to this board
+            // position from future consideration. We don't want to make that move again, because we now know it's a
+            // non-winning move.
+            ExcludeLastMoveFromFuturePlay();
+
+            return false;
+        }
+
+        // Looks up the given board and its reflection in the potential moves dictionary. If it's found then we have a
+        // list of potential moves. If the board is not found in the dictionary then the computer has no legal moves,
+        // and the human player wins.
+        private bool TryGetMoves(Board board, out List moves, out bool reflected)
+        {
+            if (_potentialMoves.TryGetValue(board, out moves))
+            {
+                reflected = false;
+                return true;
+            }
+
+            if (_potentialMoves.TryGetValue(board.Reflected, out moves))
+            {
+                reflected = true;
+                return true;
+            }
+
+            reflected = default;
+            return false;
+        }
+
+        // Get a random move from the list. If the list is empty, then we've previously eliminated all the moves for
+        // this board position as being non-winning moves. We therefore resign the game.
+        private bool TrySelectMove(List moves, out Move move)
+        {
+            if (moves.Any())
+            {
+                move = moves[_random.Next(moves.Count)];
+                return true;
+            }
+
+            Console.Write("I resign.");
+            move = null;
+            return false;
+        }
+
+        private void ExcludeLastMoveFromFuturePlay()
+        {
+            var (moves, move) = _lastMove;
+            moves.Remove(move);
+        }
+
+        private static List Moves(params Move[] moves) => moves.ToList();
+
+        public bool IsFullyAdvanced(Board board) =>
+            board[9] == Black || board[8] == Black || board[7] == Black;
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Game.cs b/00_Alternate_Languages/46_Hexapawn/csharp/Game.cs
new file mode 100644
index 00000000..95e321ff
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Game.cs
@@ -0,0 +1,49 @@
+using System;
+
+namespace Hexapawn
+{
+    // Runs a single game of Hexapawn
+    internal class Game
+    {
+        private readonly Board _board;
+        private readonly Human _human;
+        private readonly Computer _computer;
+
+        public Game(Human human, Computer computer)
+        {
+            _board = new Board();
+            _human = human;
+            _computer = computer;
+        }
+
+        public IPlayer Play()
+        {
+            Console.WriteLine(_board);
+
+            while(true)
+            {
+                _human.Move(_board);
+
+                Console.WriteLine(_board);
+
+                if (!_computer.TryMove(_board))
+                {
+                    return _human;
+                }
+
+                Console.WriteLine(_board);
+
+                if (_computer.IsFullyAdvanced(_board) || _human.HasNoPawns(_board))
+                {
+                    return _computer;
+                }
+
+                if (!_human.HasLegalMove(_board))
+                {
+                    Console.Write("You can't move, so ");
+                    return _computer;
+                }
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/GameSeries.cs b/00_Alternate_Languages/46_Hexapawn/csharp/GameSeries.cs
new file mode 100644
index 00000000..6f45cab7
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/GameSeries.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Hexapawn
+{
+    // Runs series of games between the computer and the human player
+    internal class GameSeries
+    {
+        private readonly Computer _computer = new();
+        private readonly Human _human = new();
+
+        public void Play()
+        {
+            while (true)
+            {
+                var game = new Game(_human, _computer);
+
+                var winner = game.Play();
+                winner.AddWin();
+                Console.WriteLine(winner == _computer ? "I win." : "You win.");
+
+                Console.Write($"I have won {_computer.Wins} and you {_human.Wins}");
+                Console.WriteLine($" out of {_computer.Wins + _human.Wins} games.");
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Hexapawn.csproj b/00_Alternate_Languages/46_Hexapawn/csharp/Hexapawn.csproj
new file mode 100644
index 00000000..20827042
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Hexapawn.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Hexapawn.sln b/00_Alternate_Languages/46_Hexapawn/csharp/Hexapawn.sln
new file mode 100644
index 00000000..06e7b32f
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Hexapawn.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hexapawn", "Hexapawn.csproj", "{785DA416-2609-4DB1-9F18-63CF6AC9927E}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{785DA416-2609-4DB1-9F18-63CF6AC9927E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{785DA416-2609-4DB1-9F18-63CF6AC9927E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{785DA416-2609-4DB1-9F18-63CF6AC9927E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{785DA416-2609-4DB1-9F18-63CF6AC9927E}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {D662AD9F-88B1-4AC9-83AD-DBFC08F384A8}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Human.cs b/00_Alternate_Languages/46_Hexapawn/csharp/Human.cs
new file mode 100644
index 00000000..d2d24118
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Human.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Linq;
+using static Hexapawn.Cell;
+using static Hexapawn.Move;
+using static Hexapawn.Pawn;
+
+namespace Hexapawn
+{
+    internal class Human : IPlayer
+    {
+        public int Wins { get; private set; }
+
+        public void Move(Board board)
+        {
+            while (true)
+            {
+                var move = Input.GetMove("Your move");
+
+                if (TryExecute(board, move)) { return; }
+
+                Console.WriteLine("Illegal move.");
+            }
+        }
+
+        public void AddWin() => Wins++;
+
+        public bool HasLegalMove(Board board)
+        {
+            foreach (var from in AllCells.Where(c => c > 3))
+            {
+                if (board[from] != White) { continue; }
+
+                if (HasLegalMove(board, from))
+                {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        private bool HasLegalMove(Board board, Cell from) =>
+            Right(from).IsRightDiagonalToCapture(board) ||
+            Straight(from).IsStraightMoveToEmptySpace(board) ||
+            from > 4 && Left(from).IsLeftDiagonalToCapture(board);
+
+        public bool HasNoPawns(Board board) => board.All(c => c != White);
+
+        public bool TryExecute(Board board, Move move)
+        {
+            if (board[move.From] != White) { return false; }
+
+            if (move.IsStraightMoveToEmptySpace(board) ||
+                move.IsLeftDiagonalToCapture(board) ||
+                move.IsRightDiagonalToCapture(board))
+            {
+                move.Execute(board);
+                return true;
+            }
+
+            return false;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/IPlayer.cs b/00_Alternate_Languages/46_Hexapawn/csharp/IPlayer.cs
new file mode 100644
index 00000000..7313904e
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/IPlayer.cs
@@ -0,0 +1,8 @@
+namespace Hexapawn
+{
+    // An interface implemented by a player of the game to track the number of wins.
+    internal interface IPlayer
+    {
+        void AddWin();
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Input.cs b/00_Alternate_Languages/46_Hexapawn/csharp/Input.cs
new file mode 100644
index 00000000..d169f2f6
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Input.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Linq;
+
+namespace Hexapawn
+{
+    // Provides input methods which emulate the BASIC interpreter's keyboard input routines
+    internal static class Input
+    {
+        internal static char GetYesNo(string prompt)
+        {
+            while (true)
+            {
+                Console.Write($"{prompt} (Y-N)? ");
+                var response = Console.ReadLine().FirstOrDefault();
+                if ("YyNn".Contains(response))
+                {
+                    return char.ToUpperInvariant(response);
+                }
+            }
+        }
+
+        // Implements original code:
+        //   120 PRINT "YOUR MOVE";
+        //   121 INPUT M1,M2
+        //   122 IF M1=INT(M1)AND M2=INT(M2)AND M1>0 AND M1<10 AND M2>0 AND M2<10 THEN 130
+        //   123 PRINT "ILLEGAL CO-ORDINATES."
+        //   124 GOTO 120
+        internal static Move GetMove(string prompt)
+        {
+            while(true)
+            {
+                ReadNumbers(prompt, out var from, out var to);
+
+                if (Move.TryCreate(from, to, out var move))
+                {
+                    return move;
+                }
+
+                Console.WriteLine("Illegal Coordinates.");
+            }
+        }
+
+        internal static void Prompt(string text = "") => Console.Write($"{text}? ");
+
+        internal static void ReadNumbers(string prompt, out float number1, out float number2)
+        {
+            while (!TryReadNumbers(prompt, out number1, out number2))
+            {
+                prompt = "";
+            }
+        }
+
+        private static bool TryReadNumbers(string prompt, out float number1, out float number2)
+        {
+            Prompt(prompt);
+            var inputValues = ReadStrings();
+
+            if (!TryParseNumber(inputValues[0], out number1))
+            {
+                number2 = default;
+                return false;
+            }
+
+            if (inputValues.Length == 1)
+            {
+                return TryReadNumber("?", out number2);
+            }
+
+            if (!TryParseNumber(inputValues[1], out number2))
+            {
+                number2 = default;
+                return false;
+            }
+
+            if (inputValues.Length > 2)
+            {
+                Console.WriteLine("!Extra input ingored");
+            }
+
+            return true;
+        }
+
+        private static bool TryReadNumber(string prompt, out float number)
+        {
+            Prompt(prompt);
+            var inputValues = ReadStrings();
+
+            if (!TryParseNumber(inputValues[0], out number))
+            {
+                return false;
+            }
+
+            if (inputValues.Length > 1)
+            {
+                Console.WriteLine("!Extra input ingored");
+            }
+
+            return true;
+        }
+
+        private static string[] ReadStrings() => Console.ReadLine().Split(',', StringSplitOptions.TrimEntries);
+
+        private static bool TryParseNumber(string text, out float number)
+        {
+            if (float.TryParse(text, out number)) { return true; }
+
+            Console.WriteLine("!Number expected - retry input line");
+            number = default;
+            return false;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Move.cs b/00_Alternate_Languages/46_Hexapawn/csharp/Move.cs
new file mode 100644
index 00000000..9581a959
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Move.cs
@@ -0,0 +1,68 @@
+using static Hexapawn.Pawn;
+
+namespace Hexapawn
+{
+    /// 
+    /// Represents a move which may, or may not, be legal.
+    /// 
+    internal class Move
+    {
+        private readonly Cell _from;
+        private readonly Cell _to;
+        private readonly int _metric;
+
+        public Move(Cell from, Cell to)
+        {
+            _from = from;
+            _to = to;
+            _metric = _from - _to;
+        }
+
+        public void Deconstruct(out Cell from, out Cell to)
+        {
+            from = _from;
+            to = _to;
+        }
+
+        public Cell From => _from;
+
+        // Produces the mirror image of the current moved, reflected around the central column of the board.
+        public Move Reflected => (_from.Reflected, _to.Reflected);
+
+        // Allows a tuple of two ints to be implicitly converted to a Move.
+        public static implicit operator Move((int From, int To) value) => new(value.From, value.To);
+
+        // Takes floating point coordinates, presumably from keyboard input, and attempts to create a Move object.
+        public static bool TryCreate(float input1, float input2, out Move move)
+        {
+            if (Cell.TryCreate(input1, out var from) &&
+                Cell.TryCreate(input2, out var to))
+            {
+                move = (from, to);
+                return true;
+            }
+
+            move = default;
+            return false;
+        }
+
+        public static Move Right(Cell from) => (from, from - 2);
+        public static Move Straight(Cell from) => (from, from - 3);
+        public static Move Left(Cell from) => (from, from - 4);
+
+        public bool IsStraightMoveToEmptySpace(Board board) => _metric == 3 && board[_to] == None;
+
+        public bool IsLeftDiagonalToCapture(Board board) => _metric == 4 && _from != 7 && board[_to] == Black;
+
+        public bool IsRightDiagonalToCapture(Board board) =>
+            _metric == 2 && _from != 9 && _from != 6 && board[_to] == Black;
+
+        public void Execute(Board board)
+        {
+            board[_to] = board[_from];
+            board[_from] = None;
+        }
+
+        public override string ToString() => $"from {_from} to {_to}";
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Pawn.cs b/00_Alternate_Languages/46_Hexapawn/csharp/Pawn.cs
new file mode 100644
index 00000000..7a4c5633
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Pawn.cs
@@ -0,0 +1,19 @@
+namespace Hexapawn
+{
+    // Represents the contents of a cell on the board
+    internal class Pawn
+    {
+        public static readonly Pawn Black = new('X');
+        public static readonly Pawn White = new('O');
+        public static readonly Pawn None = new('.');
+
+        private readonly char _symbol;
+
+        private Pawn(char symbol)
+        {
+            _symbol = symbol;
+        }
+
+        public override string ToString() => _symbol.ToString();
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/Program.cs b/00_Alternate_Languages/46_Hexapawn/csharp/Program.cs
new file mode 100644
index 00000000..59917dfa
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/Program.cs
@@ -0,0 +1,71 @@
+using System;
+
+namespace Hexapawn
+{
+    // Hexapawn:  Interpretation of hexapawn game as presented in
+    // Martin Gardner's "The Unexpected Hanging and Other Mathematic
+    // al Diversions", Chapter Eight:  A Matchbox Game-Learning Machine.
+    // Original version for H-P timeshare system by R.A. Kaapke 5/5/76
+    // Instructions by Jeff Dalton
+    // Conversion to MITS BASIC by Steve North
+    // Conversion to C# by Andrew Cooper
+    class Program
+    {
+        static void Main()
+        {
+            DisplayTitle();
+
+            if (Input.GetYesNo("Instructions") == 'Y')
+            {
+                DisplayInstructions();
+            }
+
+            var games = new GameSeries();
+
+            games.Play();
+        }
+
+        private static void DisplayTitle()
+        {
+            Console.WriteLine("                                Hexapawn");
+            Console.WriteLine("               Creative Computing  Morristown, New Jersey");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+        }
+
+        private static void DisplayInstructions()
+        {
+            Console.WriteLine();
+            Console.WriteLine("This program plays the game of Hexapawn.");
+            Console.WriteLine("Hexapawn is played with Chess pawns on a 3 by 3 board.");
+            Console.WriteLine("The pawns are move as in Chess - one space forward to");
+            Console.WriteLine("an empty space, or one space forward and diagonally to");
+            Console.WriteLine("capture an opposing man.  On the board, your pawns");
+            Console.WriteLine("are 'O', the computer's pawns are 'X', and empty");
+            Console.WriteLine("squares are '.'.  To enter a move, type the number of");
+            Console.WriteLine("the square you are moving from, followed by the number");
+            Console.WriteLine("of the square you will move to.  The numbers must be");
+            Console.WriteLine("separated by a comma.");
+            Console.WriteLine();
+            Console.WriteLine("The computer starts a series of games knowing only when");
+            Console.WriteLine("the game is won (a draw is impossible) and how to move.");
+            Console.WriteLine("It has no strategy at first and just moves randomly.");
+            Console.WriteLine("However, it learns from each game.  Thus winning becomes");
+            Console.WriteLine("more and more difficult.  Also, to help offset your");
+            Console.WriteLine("initial advantage, you will not be told how to win the");
+            Console.WriteLine("game but must learn this by playing.");
+            Console.WriteLine();
+            Console.WriteLine("The numbering of the board is as follows:");
+            Console.WriteLine("          123");
+            Console.WriteLine("          456");
+            Console.WriteLine("          789");
+            Console.WriteLine();
+            Console.WriteLine("For example, to move your rightmost pawn forward,");
+            Console.WriteLine("you would type 9,6 in response to the question");
+            Console.WriteLine("'Your move ?'.  Since I'm a good sport, you'll always");
+            Console.WriteLine("go first.");
+            Console.WriteLine();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/46_Hexapawn/csharp/README.md b/00_Alternate_Languages/46_Hexapawn/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/46_Hexapawn/hexapawn.bas b/00_Alternate_Languages/46_Hexapawn/hexapawn.bas
new file mode 100644
index 00000000..8319c162
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/hexapawn.bas
@@ -0,0 +1,174 @@
+1 PRINT TAB(32);"HEXAPAWN"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+4 REM  HEXAPAWN:  INTERPRETATION OF HEXAPAWN GAME AS PRESENTED IN
+5 REM  MARTIN GARDNER'S "THE UNEXPECTED HANGING AND OTHER MATHEMATIC-
+6 REM  AL DIVERSIONS", CHAPTER EIGHT:  A MATCHBOX GAME-LEARNING MACHINE
+7 REM  ORIGINAL VERSION FOR H-P TIMESHARE SYSTEM BY R.A. KAAPKE 5/5/76
+8 REM  INSTRUCTIONS BY JEFF DALTON
+9 REM  CONVERSION TO MITS BASIC BY STEVE NORTH
+10 DIM B(19,9),M(19,4),S(9),P$(3)
+15 W=0: L=0
+20 DEF FNR(X)=-3*(X=1)-(X=3)-4*(X=6)-6*(X=4)-7*(X=9)-9*(X=7)+FNS(X)
+25 DEF FNS(X)=-X*(X=2 OR X=5 OR X=8)
+30 DEF FNM(Y)=Y-INT(Y/10)*10
+35 P$="X.O"
+40 FOR I=1 TO 19: FOR J=1 TO 9: READ B(I,J): NEXT J: NEXT I
+45 FOR I=1 TO 19: FOR J=1 TO 4: READ M(I,J): NEXT J: NEXT I
+50 PRINT "INSTRUCTIONS (Y-N)";
+60 INPUT A$
+70 A$=LEFT$(A$,1)
+80 IF A$="Y" THEN 2000
+90 IF A$<>"N" THEN 50
+100 X=0: Y=0
+111 S(4)=0: S(5)=0: S(6)=0
+112 S(1)=-1: S(2)=-1: S(3)=-1
+113 S(7)=1: S(8)=1: S(9)=1
+115 GOSUB 1000
+120 PRINT "YOUR MOVE";
+121 INPUT M1,M2
+122 IF M1=INT(M1)AND M2=INT(M2)AND M1>0 AND M1<10 AND M2>0 AND M2<10 THEN 130
+123 PRINT "ILLEGAL CO-ORDINATES."
+124 GOTO 120
+130 IF S(M1)=1 THEN 150
+140 PRINT "ILLEGAL MOVE.": GOTO 120
+150 IF S(M2)=1 THEN 140
+160 IF M2-M1<>-3 AND S(M2)<>-1 THEN 140
+170 IF M2>M1 THEN 140
+180 IF M2-M1=-3 AND (S(M2)<>0) THEN 140
+185 IF M2-M1<-4 THEN 140
+186 IF M1=7 AND M2=3 THEN 140
+190 S(M1)=0
+200 S(M2)=1
+205 GOSUB 1000
+210 IF S(1)=1 OR S(2)=1 OR S(3)=1 THEN 820
+220 FOR I=1 TO 9
+221 IF S(I)=-1 THEN 230
+222 NEXT I
+223 GOTO 820
+230 FOR I=1 TO 9
+240 IF S(I)<>-1 THEN 330
+250 IF S(I+3)=0 THEN 350
+260 IF FNR(I)=I THEN 320
+270 IF I>3 THEN 300
+280 IF S(5)=1 THEN 350
+290 GOTO 330
+300 IF S(8)=1 THEN 350
+310 GOTO 330
+320 IF S(I+2)=1 OR S(I+4)=1 THEN 350
+330 NEXT I
+340 GOTO 820
+350 FOR I=1 TO 19
+360 FOR J=1 TO 3
+370 FOR K=3 TO 1 STEP -1
+380 T((J-1)*3+K)=B(I,(J-1)*3+4-K)
+390 NEXT K
+400 NEXT J
+410 FOR J=1 TO 9
+420 IF S(J)<>B(I,J) THEN 460
+430 NEXT J
+440 R=0
+450 GOTO 540
+460 FOR J=1 TO 9
+470 IF S(J)<>T(J) THEN 510
+480 NEXT J
+490 R=1
+500 GOTO 540
+510 NEXT I
+511 REMEMBER THE TERMINATION OF THIS LOOP IS IMPOSSIBLE
+512 PRINT "ILLEGAL BOARD PATTERN."
+530 STOP
+540 X=I
+550 FOR I=1 TO 4
+560 IF M(X,I)<>0 THEN 600
+570 NEXT I
+580 PRINT "I RESIGN."
+590 GOTO 820
+600 Y=INT(RND(1)*4+1)
+601 IF M(X,Y)=0 THEN 600
+610 IF R<>0 THEN 630
+620 PRINT "I MOVE FROM ";STR$(INT(M(X,Y)/10));" TO ";STR$(FNM(M(X,Y)))
+622 S(INT(M(X,Y)/10))=0
+623 S(FNM(M(X,Y)))=-1
+624 GOTO 640
+630 PRINT "I MOVE FROM ";STR$(FNR(INT(M(X,Y)/10)));" TO ";
+631 PRINT STR$(FNR(FNM(M(X,Y))))
+632 S(FNR(INT(M(X,Y)/10)))=0
+633 S(FNR(FNM(M(X,Y))))=-1
+640 GOSUB 1000
+641 IF S(7)=-1 OR S(8)=-1 OR S(9)=-1 THEN 870
+650 FOR I=1 TO 9
+660 IF S(I)=1 THEN 690
+670 NEXT I
+680 GOTO 870
+690 FOR I=1 TO 9
+700 IF S(I)<>1 THEN 790
+710 IF S(I-3)=0 THEN 120
+720 IF FNR(I)=I THEN 780
+730 IF I<7 THEN 760
+740 IF S(5)=-1 THEN 120
+750 GOTO 790
+760 IF S(2)=-1 THEN 120
+770 GOTO 790
+780 IF S(I-2)=-1 OR S(I-4)=-1 THEN 120
+790 NEXT I
+800 PRINT "YOU CAN'T MOVE, SO ";
+810 GOTO 870
+820 PRINT "YOU WIN."
+830 M(X,Y)=0
+840 L=L+1
+850 PRINT "I HAVE WON";W;"AND YOU";L;"OUT OF";L+W;"GAMES."
+851 PRINT
+860 GOTO 100
+870 PRINT "I WIN."
+880 W=W+1
+890 GOTO 850
+900 DATA -1,-1,-1,1,0,0,0,1,1,-1,-1,-1,0,1,0,1,0,1
+905 DATA -1,0,-1,-1,1,0,0,0,1,0,-1,-1,1,-1,0,0,0,1
+910 DATA -1,0,-1,1,1,0,0,1,0,-1,-1,0,1,0,1,0,0,1
+915 DATA 0,-1,-1,0,-1,1,1,0,0,0,-1,-1,-1,1,1,1,0,0
+920 DATA -1,0,-1,-1,0,1,0,1,0,0,-1,-1,0,1,0,0,0,1
+925 DATA 0,-1,-1,0,1,0,1,0,0,-1,0,-1,1,0,0,0,0,1
+930 DATA 0,0,-1,-1,-1,1,0,0,0,-1,0,0,1,1,1,0,0,0
+935 DATA 0,-1,0,-1,1,1,0,0,0,-1,0,0,-1,-1,1,0,0,0
+940 DATA 0,0,-1,-1,1,0,0,0,0,0,-1,0,1,-1,0,0,0,0
+945 DATA -1,0,0,-1,1,0,0,0,0
+950 DATA 24,25,36,0,14,15,36,0,15,35,36,47,36,58,59,0
+955 DATA 15,35,36,0,24,25,26,0,26,57,58,0
+960 DATA 26,35,0,0,47,48,0,0,35,36,0,0,35,36,0,0
+965 DATA 36,0,0,0,47,58,0,0,15,0,0,0
+970 DATA 26,47,0,0,47,58,0,0,35,36,47,0,28,58,0,0,15,47,0,0
+1000 PRINT
+1010 FOR I=1 TO 3
+1020 FOR J=1 TO 3
+1030 PRINT TAB(10);MID$(P$,S((I-1)*3+J)+2,1);
+1040 NEXT J
+1050 PRINT
+1060 NEXT I
+1070 PRINT
+1080 RETURN
+2000 PRINT: PRINT "THIS PROGRAM PLAYS THE GAME OF HEXAPAWN."
+2010 PRINT "HEXAPAWN IS PLAYED WITH CHESS PAWNS ON A 3 BY 3 BOARD."
+2020 PRINT "THE PAWNS ARE MOVED AS IN CHESS - ONE SPACE FORWARD TO"
+2030 PRINT "AN EMPTY SPACE OR ONE SPACE FORWARD AND DIAGONALLY TO"
+2040 PRINT "CAPTURE AN OPPOSING MAN.  ON THE BOARD, YOUR PAWNS"
+2050 PRINT "ARE 'O', THE COMPUTER'S PAWNS ARE 'X', AND EMPTY "
+2060 PRINT "SQUARES ARE '.'.  TO ENTER A MOVE, TYPE THE NUMBER OF"
+2070 PRINT "THE SQUARE YOU ARE MOVING FROM, FOLLOWED BY THE NUMBER"
+2080 PRINT "OF THE SQUARE YOU WILL MOVE TO.  THE NUMBERS MUST BE"
+2090 PRINT "SEPERATED BY A COMMA.": PRINT
+2100 PRINT "THE COMPUTER STARTS A SERIES OF GAMES KNOWING ONLY WHEN"
+2105 PRINT "THE GAME IS WON (A DRAW IS IMPOSSIBLE) AND HOW TO MOVE."
+2110 PRINT "IT HAS NO STRATEGY AT FIRST AND JUST MOVES RANDOMLY."
+2120 PRINT "HOWEVER, IT LEARNS FROM EACH GAME.  THUS, WINNING BECOMES"
+2130 PRINT "MORE AND MORE DIFFICULT.  ALSO, TO HELP OFFSET YOUR"
+2140 PRINT "INITIAL ADVANTAGE, YOU WILL NOT BE TOLD HOW TO WIN THE"
+2150 PRINT "GAME BUT MUST LEARN THIS BY PLAYING."
+2160 PRINT: PRINT "THE NUMBERING OF THE BOARD IS AS FOLLOWS:"
+2170 PRINT TAB(10);"123": PRINT TAB(10);"456": PRINT TAB(10);"789"
+2180 PRINT: PRINT "FOR EXAMPLE, TO MOVE YOUR RIGHTMOST PAWN FORWARD,"
+2190 PRINT "YOU WOULD TYPE 9,6 IN RESPONSE TO THE QUESTION"
+2200 PRINT "'YOUR MOVE ?'.  SINCE I'M A GOOD SPORT, YOU'LL ALWAYS"
+2210 PRINT "GO FIRST.": PRINT
+2220 GOTO 100
+9999 END
diff --git a/00_Alternate_Languages/46_Hexapawn/java/README.md b/00_Alternate_Languages/46_Hexapawn/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/46_Hexapawn/javascript/README.md b/00_Alternate_Languages/46_Hexapawn/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/46_Hexapawn/javascript/hexapawn.html b/00_Alternate_Languages/46_Hexapawn/javascript/hexapawn.html
new file mode 100644
index 00000000..5ac2b08c
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/javascript/hexapawn.html
@@ -0,0 +1,9 @@
+
+
+HEXAPAWN
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/46_Hexapawn/javascript/hexapawn.js b/00_Alternate_Languages/46_Hexapawn/javascript/hexapawn.js
new file mode 100644
index 00000000..4a4e3397
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/javascript/hexapawn.js
@@ -0,0 +1,337 @@
+// HEXAPAWN
+//
+// 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 ba = [,
+          [,-1,-1,-1,1,0,0,0,1,1],
+          [,-1,-1,-1,0,1,0,1,0,1],
+          [,-1,0,-1,-1,1,0,0,0,1],
+          [,0,-1,-1,1,-1,0,0,0,1],
+          [,-1,0,-1,1,1,0,0,1,0],
+          [,-1,-1,0,1,0,1,0,0,1],
+          [,0,-1,-1,0,-1,1,1,0,0],
+          [,0,-1,-1,-1,1,1,1,0,0],
+          [,-1,0,-1,-1,0,1,0,1,0],
+          [,0,-1,-1,0,1,0,0,0,1],
+          [,0,-1,-1,0,1,0,1,0,0],
+          [,-1,0,-1,1,0,0,0,0,1],
+          [,0,0,-1,-1,-1,1,0,0,0],
+          [,-1,0,0,1,1,1,0,0,0],
+          [,0,-1,0,-1,1,1,0,0,0],
+          [,-1,0,0,-1,-1,1,0,0,0],
+          [,0,0,-1,-1,1,0,0,0,0],
+          [,0,-1,0,1,-1,0,0,0,0],
+          [,-1,0,0,-1,1,0,0,0,0]];
+var ma = [,
+          [,24,25,36,0],
+          [,14,15,36,0],
+          [,15,35,36,47],
+          [,36,58,59,0],
+          [,15,35,36,0],
+          [,24,25,26,0],
+          [,26,57,58,0],
+          [,26,35,0,0],
+          [,47,48,0,0],
+          [,35,36,0,0],
+          [,35,36,0,0],
+          [,36,0,0,0],
+          [,47,58,0,0],
+          [,15,0,0,0],
+          [,26,47,0,0],
+          [,47,58,0,0],
+          [,35,36,47,0],
+          [,28,58,0,0],
+          [,15,47,0,0]];
+var s = [];
+var t = [];
+var ps = "X.O";
+
+function show_board()
+{
+    print("\n");
+    for (var i = 1; i <= 3; i++) {
+        print(tab(10));
+        for (var j = 1; j <= 3; j++) {
+            print(ps[s[(i - 1) * 3 + j] + 1]);
+        }
+        print("\n");
+    }
+}
+
+function mirror(x)
+{
+    if (x == 1)
+        return 3;
+    if (x == 3)
+        return 1;
+    if (x == 6)
+        return 4;
+    if (x == 4)
+        return 6;
+    if (x == 9)
+        return 7;
+    if (x == 7)
+        return 9;
+    return x;
+}
+
+// Main program
+async function main()
+{
+    print(tab(32) + "HEXAPAWN\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    // HEXAPAWN:  INTERPRETATION OF HEXAPAWN GAME AS PRESENTED IN
+    // MARTIN GARDNER'S "THE UNEXPECTED HANGING AND OTHER MATHEMATIC-
+    // AL DIVERSIONS", CHAPTER EIGHT:  A MATCHBOX GAME-LEARNING MACHINE
+    // ORIGINAL VERSION FOR H-P TIMESHARE SYSTEM BY R.A. KAAPKE 5/5/76
+    // INSTRUCTIONS BY JEFF DALTON
+    // CONVERSION TO MITS BASIC BY STEVE NORTH
+    for (i = 0; i <= 9; i++) {
+        s[i] = 0;
+    }
+    w = 0;
+    l = 0;
+    do {
+        print("INSTRUCTIONS (Y-N)");
+        str = await input();
+        str = str.substr(0, 1);
+    } while (str != "Y" && str != "N") ;
+    if (str == "Y") {
+        print("\n");
+        print("THIS PROGRAM PLAYS THE GAME OF HEXAPAWN.\n");
+        print("HEXAPAWN IS PLAYED WITH CHESS PAWNS ON A 3 BY 3 BOARD.\n");
+        print("THE PAWNS ARE MOVED AS IN CHESS - ONE SPACE FORWARD TO\n");
+        print("AN EMPTY SPACE OR ONE SPACE FORWARD AND DIAGONALLY TO\n");
+        print("CAPTURE AN OPPOSING MAN.  ON THE BOARD, YOUR PAWNS\n");
+        print("ARE 'O', THE COMPUTER'S PAWNS ARE 'X', AND EMPTY \n");
+        print("SQUARES ARE '.'.  TO ENTER A MOVE, TYPE THE NUMBER OF\n");
+        print("THE SQUARE YOU ARE MOVING FROM, FOLLOWED BY THE NUMBER\n");
+        print("OF THE SQUARE YOU WILL MOVE TO.  THE NUMBERS MUST BE\n");
+        print("SEPERATED BY A COMMA.\n");
+        print("\n");
+        print("THE COMPUTER STARTS A SERIES OF GAMES KNOWING ONLY WHEN\n");
+        print("THE GAME IS WON (A DRAW IS IMPOSSIBLE) AND HOW TO MOVE.\n");
+        print("IT HAS NO STRATEGY AT FIRST AND JUST MOVES RANDOMLY.\n");
+        print("HOWEVER, IT LEARNS FROM EACH GAME.  THUS, WINNING BECOMES\n");
+        print("MORE AND MORE DIFFICULT.  ALSO, TO HELP OFFSET YOUR\n");
+        print("INITIAL ADVANTAGE, YOU WILL NOT BE TOLD HOW TO WIN THE\n");
+        print("GAME BUT MUST LEARN THIS BY PLAYING.\n");
+        print("\n");
+        print("THE NUMBERING OF THE BOARD IS AS FOLLOWS:\n");
+        print(tab(10) + "123\n");
+        print(tab(10) + "456\n");
+        print(tab(10) + "789\n");
+        print("\n");
+        print("FOR EXAMPLE, TO MOVE YOUR RIGHTMOST PAWN FORWARD,\n");
+        print("YOU WOULD TYPE 9,6 IN RESPONSE TO THE QUESTION\n");
+        print("'YOUR MOVE ?'.  SINCE I'M A GOOD SPORT, YOU'LL ALWAYS\n");
+        print("GO FIRST.\n");
+        print("\n");
+    }
+    while (1) {
+        x = 0;
+        y = 0;
+        s[4] = 0;
+        s[5] = 0;
+        s[6] = 0;
+        s[1] = -1;
+        s[2] = -1;
+        s[3] = -1;
+        s[7] = 1;
+        s[8] = 1;
+        s[9] = 1;
+        show_board();
+        while (1) {
+            while (1) {
+                print("YOUR MOVE");
+                str = await input();
+                m1 = parseInt(str);
+                m2 = parseInt(str.substr(str.indexOf(",") + 1));
+                if (m1 > 0 && m1 < 10 && m2 > 0 && m2 < 10) {
+                    if (s[m1] != 1 || s[m2] == 1 || (m2 - m1 != -3 && s[m2] != -1) || (m2 > m1) || (m2 - m1 == -3 && s[m2] != 0) || (m2 - m1 < -4) || (m1 == 7 && m2 == 3))
+                        print("ILLEGAL MOVE.\n");
+                    else
+                        break;
+                } else {
+                    print("ILLEGAL CO-ORDINATES.\n");
+                }
+            }
+
+            // Move player's pawn
+            s[m1] = 0;
+            s[m2] = 1;
+            show_board();
+
+            // Find computer pawns
+            for (i = 1; i <= 9; i++) {
+                if (s[i] == -1)
+                    break;
+            }
+            // If none or player reached top then finish
+            if (i > 9 || s[1] == 1 || s[2] == 1 || s[3] == 1) {
+                computer = false;
+                break;
+            }
+            // Find computer pawns with valid move
+            for (i = 1; i <= 9; i++) {
+                if (s[i] != -1)
+                    continue;
+                if (s[i + 3] == 0
+                 || (mirror(i) == i && (s[i + 2] == 1 || s[i + 4] == 1))
+                 || (i <= 3 && s[5] == 1)
+                 || s[8] == 1)
+                    break;
+            }
+            if (i > 9) {  // Finish if none possible
+                computer = false;
+                break;
+            }
+            for (i = 1; i <= 19; i++) {
+                for (j = 1; j <= 3; j++) {
+                    for (k = 3; k >= 1; k--) {
+                        t[(j - 1) * 3 + k] = ba[i][(j - 1) * 3 + 4 - k];
+                    }
+                }
+                for (j = 1; j <= 9; j++) {
+                    if (s[j] != ba[i][j])
+                        break;
+                }
+                if (j > 9) {
+                    r = 0;
+                    break;
+                }
+                for (j = 1; j <= 9; j++) {
+                    if (s[j] != t[j])
+                        break;
+                }
+                if (j > 9) {
+                    r = 1;
+                    break;
+                }
+            }
+            if (i > 19) {
+                print("ILLEGAL BOARD PATTERN\n");
+                break;
+            }
+            x = i;
+            for (i = 1; i <= 4; i++) {
+                if (ma[x][i] != 0)
+                    break;
+            }
+            if (i > 4) {
+                print("I RESIGN.\n");
+                computer = false;
+                break;
+            }
+            // Select random move from possibilities
+            do {
+                y = Math.floor(Math.random() * 4 + 1);
+            } while (ma[x][y] == 0) ;
+            // Announce move
+            if (r == 0) {
+                print("I MOVE FROM " + Math.floor(ma[x][y] / 10) + " TO " + ma[x][y] % 10 + "\n");
+                s[Math.floor(ma[x][y] / 10)] = 0;
+                s[ma[x][y] % 10] = -1;
+            } else {
+                print("I MOVE FROM " + mirror(Math.floor(ma[x][y] / 10)) + " TO " + mirror(ma[x][y]) % 10 + "\n");
+                s[mirror(Math.floor(ma[x][y] / 10))] = 0;
+                s[mirror(ma[x][y] % 10)] = -1;
+            }
+            show_board();
+            // Finish if computer reaches bottom
+            if (s[7] == -1 || s[8] == -1 || s[9] == -1) {
+                computer = true;
+                break;
+            }
+            // Finish if no player pawns
+            for (i = 1; i <= 9; i++) {
+                if (s[i] == 1)
+                    break;
+            }
+            if (i > 9) {
+                computer = true;
+                break;
+            }
+            // Finish if player cannot move
+            for (i = 1; i <= 9; i++) {
+                if (s[i] != 1)
+                    continue;
+                if (s[i - 3] == 0)
+                    break;
+                if (mirror(i) != i) {
+                    if (i >= 7) {
+                        if (s[5] == -1)
+                            break;
+                    } else {
+                        if (s[2] == -1)
+                            break;
+                    }
+                } else {
+                    if (s[i - 2] == -1 || s[i - 4] == -1)
+                        break;
+                }
+
+            }
+            if (i > 9) {
+                print("YOU CAN'T MOVE, SO ");
+                computer = true;
+                break;
+            }
+        }
+        if (computer) {
+            print("I WIN.\n");
+            w++;
+        } else {
+            print("YOU WIN\n");
+            ma[x][y] = 0;
+            l++;
+        }
+        print("I HAVE WON " + w + " AND YOU " + l + " OUT OF " + (l + w) + " GAMES.\n");
+        print("\n");
+    }
+}
+
+main();
diff --git a/22_Change/pascal/README.md b/00_Alternate_Languages/46_Hexapawn/pascal/README.md
similarity index 100%
rename from 22_Change/pascal/README.md
rename to 00_Alternate_Languages/46_Hexapawn/pascal/README.md
diff --git a/00_Alternate_Languages/46_Hexapawn/perl/README.md b/00_Alternate_Languages/46_Hexapawn/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/46_Hexapawn/python/README.md b/00_Alternate_Languages/46_Hexapawn/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/46_Hexapawn/python/hexapawn.py b/00_Alternate_Languages/46_Hexapawn/python/hexapawn.py
new file mode 100644
index 00000000..3821b2c6
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/python/hexapawn.py
@@ -0,0 +1,513 @@
+"""
+HEXAPAWN
+
+A machine learning game, an interpretation of HEXAPAWN game as
+presented in Martin Gardner's "The Unexpected Hanging and Other
+Mathematical Diversions", Chapter Eight: A Matchbox Game-Learning
+Machine.
+
+Original version for H-P timeshare system by R.A. Kaapke 5/5/76
+Instructions by Jeff Dalton
+Conversion to MITS BASIC by Steve North
+
+
+Port to Python by Dave LeCompte
+"""
+
+# PORTING NOTES:
+#
+# I printed out the BASIC code and hand-annotated what each little block
+# of code did, which feels amazingly retro.
+#
+# I encourage other porters that have a complex knot of GOTOs and
+# semi-nested subroutines to do hard-copy hacking, it might be a
+# different perspective that helps.
+#
+# A spoiler - the objective of the game is not documented, ostensibly to
+# give the human player a challenge. If a player (human or computer)
+# advances a pawn across the board to the far row, that player wins. If
+# a player has no legal moves (either by being blocked, or all their
+# pieces having been captured), that player loses.
+#
+# The original BASIC had 2 2-dimensional tables stored in DATA at the
+# end of the program. This encoded all 19 different board configurations
+# (Hexapawn is a small game), with reflections in one table, and then in
+# a parallel table, for each of the 19 rows, a list of legal moves was
+# encoded by turning them into 2-digit decimal numbers. As gameplay
+# continued, the AI would overwrite losing moves with 0 in the second
+# array.
+#
+# My port takes this "parallel array" structure and turns that
+# information into a small Python class, BoardLayout. BoardLayout stores
+# the board description and legal moves, but stores the moves as (row,
+# column) 2-tuples, which is easier to read. The logic for checking if a
+# BoardLayout matches the current board, as well as removing losing move
+# have been moved into methods of this class.
+
+import collections
+import random
+
+PAGE_WIDTH = 64
+
+HUMAN_PIECE = 1
+EMPTY_SPACE = 0
+COMPUTER_PIECE = -1
+
+ComputerMove = collections.namedtuple(
+    "ComputerMove", ["board_index", "move_index", "m1", "m2"]
+)
+
+wins = 0
+losses = 0
+
+
+def print_centered(msg):
+    spaces = " " * ((PAGE_WIDTH - len(msg)) // 2)
+    print(spaces + msg)
+
+
+def print_header(title):
+    print_centered(title)
+    print_centered("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+
+def print_instructions():
+    print(
+        """
+THIS PROGRAM PLAYS THE GAME OF HEXAPAWN.
+HEXAPAWN IS PLAYED WITH CHESS PAWNS ON A 3 BY 3 BOARD.
+THE PAWNS ARE MOVED AS IN CHESS - ONE SPACE FORWARD TO
+AN EMPTY SPACE OR ONE SPACE FORWARD AND DIAGONALLY TO
+CAPTURE AN OPPOSING MAN.  ON THE BOARD, YOUR PAWNS
+ARE 'O', THE COMPUTER'S PAWNS ARE 'X', AND EMPTY
+SQUARES ARE '.'.  TO ENTER A MOVE, TYPE THE NUMBER OF
+THE SQUARE YOU ARE MOVING FROM, FOLLOWED BY THE NUMBER
+OF THE SQUARE YOU WILL MOVE TO.  THE NUMBERS MUST BE
+SEPERATED BY A COMMA.
+
+THE COMPUTER STARTS A SERIES OF GAMES KNOWING ONLY WHEN
+THE GAME IS WON (A DRAW IS IMPOSSIBLE) AND HOW TO MOVE.
+IT HAS NO STRATEGY AT FIRST AND JUST MOVES RANDOMLY.
+HOWEVER, IT LEARNS FROM EACH GAME.  THUS, WINNING BECOMES
+MORE AND MORE DIFFICULT.  ALSO, TO HELP OFFSET YOUR
+INITIAL ADVANTAGE, YOU WILL NOT BE TOLD HOW TO WIN THE
+GAME BUT MUST LEARN THIS BY PLAYING.
+
+THE NUMBERING OF THE BOARD IS AS FOLLOWS:
+          123
+          456
+          789
+
+FOR EXAMPLE, TO MOVE YOUR RIGHTMOST PAWN FORWARD,
+YOU WOULD TYPE 9,6 IN RESPONSE TO THE QUESTION
+'YOUR MOVE ?'.  SINCE I'M A GOOD SPORT, YOU'LL ALWAYS
+GO FIRST.
+
+"""
+    )
+
+
+def prompt_yes_no(msg):
+    while True:
+        print(msg)
+        response = input().upper()
+        if response[0] == "Y":
+            return True
+        elif response[0] == "N":
+            return False
+
+
+def reverse_space_name(space_name):
+    # reverse a space name in the range 1-9 left to right
+    assert 1 <= space_name <= 9
+
+    reflections = {1: 3, 2: 2, 3: 1, 4: 6, 5: 5, 6: 4, 7: 9, 8: 8, 9: 7}
+    return reflections[space_name]
+
+
+def is_space_in_center_column(space_name):
+    return reverse_space_name(space_name) == space_name
+
+
+class BoardLayout:
+    def __init__(self, cells, move_list):
+        self.cells = cells
+        self.moves = move_list
+
+    def _check_match_no_mirror(self, cell_list):
+        for space_index, board_contents in enumerate(self.cells):
+            if board_contents != cell_list[space_index]:
+                return False
+        return True
+
+    def _check_match_with_mirror(self, cell_list):
+        for space_index, board_contents in enumerate(self.cells):
+            reversed_space_index = reverse_space_name(space_index + 1) - 1
+            if board_contents != cell_list[reversed_space_index]:
+                return False
+        return True
+
+    def check_match(self, cell_list):
+        if self._check_match_with_mirror(cell_list):
+            return True, True
+        elif self._check_match_no_mirror(cell_list):
+            return True, False
+        return False, None
+
+    def get_random_move(self, reverse_board):
+        if not self.moves:
+            return None
+        move_index = random.randrange(len(self.moves))
+
+        m1, m2 = self.moves[move_index]
+        if reverse_board:
+            m1 = reverse_space_name(m1)
+            m2 = reverse_space_name(m2)
+
+        return move_index, m1, m2
+
+
+boards = [
+    BoardLayout([-1, -1, -1, 1, 0, 0, 0, 1, 1], [(2, 4), (2, 5), (3, 6)]),
+    BoardLayout([-1, -1, -1, 0, 1, 0, 1, 0, 1], [(1, 4), (1, 5), (3, 6)]),
+    BoardLayout([-1, 0, -1, -1, 1, 0, 0, 0, 1], [(1, 5), (3, 5), (3, 6), (4, 7)]),
+    BoardLayout([0, -1, -1, 1, -1, 0, 0, 0, 1], [(3, 6), (5, 8), (5, 9)]),
+    BoardLayout([-1, 0, -1, 1, 1, 0, 0, 1, 0], [(1, 5), (3, 5), (3, 6)]),
+    BoardLayout([-1, -1, 0, 1, 0, 1, 0, 0, 1], [(2, 4), (2, 5), (2, 6)]),
+    BoardLayout([0, -1, -1, 0, -1, 1, 1, 0, 0], [(2, 6), (5, 7), (5, 8)]),
+    BoardLayout([0, -1, -1, -1, 1, 1, 1, 0, 0], [(2, 6), (3, 5)]),
+    BoardLayout([-1, 0, -1, -1, 0, 1, 0, 1, 0], [(4, 7), (4, 8)]),
+    BoardLayout([0, -1, -1, 0, 1, 0, 0, 0, 1], [(3, 5), (3, 6)]),
+    BoardLayout([0, -1, -1, 0, 1, 0, 1, 0, 0], [(3, 5), (3, 6)]),
+    BoardLayout([-1, 0, -1, 1, 0, 0, 0, 0, 1], [(3, 6)]),
+    BoardLayout([0, 0, -1, -1, -1, 1, 0, 0, 0], [(4, 7), (5, 8)]),
+    BoardLayout([-1, 0, 0, 1, 1, 1, 0, 0, 0], [(1, 5)]),
+    BoardLayout([0, -1, 0, -1, 1, 1, 0, 0, 0], [(2, 6), (4, 7)]),
+    BoardLayout([-1, 0, 0, -1, -1, 1, 0, 0, 0], [(4, 7), (5, 8)]),
+    BoardLayout([0, 0, -1, -1, 1, 0, 0, 0, 0], [(3, 5), (3, 6), (4, 7)]),
+    BoardLayout([0, -1, 0, 1, -1, 0, 0, 0, 0], [(2, 8), (5, 8)]),
+    BoardLayout([-1, 0, 0, -1, 1, 0, 0, 0, 0], [(1, 5), (4, 7)]),
+]
+
+
+def get_move(board_index, move_index):
+    assert board_index >= 0 and board_index < len(boards)
+    board = boards[board_index]
+
+    assert move_index >= 0 and move_index < len(board.moves)
+
+    return board.moves[move_index]
+
+
+def remove_move(board_index, move_index):
+    assert board_index >= 0 and board_index < len(boards)
+    board = boards[board_index]
+
+    assert move_index >= 0 and move_index < len(board.moves)
+
+    del board.moves[move_index]
+
+
+def init_board():
+    return [COMPUTER_PIECE] * 3 + [EMPTY_SPACE] * 3 + [HUMAN_PIECE] * 3
+
+
+def print_board(board):
+    piece_dict = {COMPUTER_PIECE: "X", EMPTY_SPACE: ".", HUMAN_PIECE: "O"}
+
+    space = " " * 10
+    print()
+    for row in range(3):
+        line = ""
+        for column in range(3):
+            line += space
+            space_number = row * 3 + column
+            space_contents = board[space_number]
+            line += piece_dict[space_contents]
+        print(line)
+    print()
+
+
+def get_coordinates():
+    while True:
+        try:
+            print("YOUR MOVE?")
+            response = input()
+            m1, m2 = (int(c) for c in response.split(","))
+            return m1, m2
+        except ValueError:
+            print_illegal()
+
+
+def print_illegal():
+    print("ILLEGAL MOVE.")
+
+
+def board_contents(board, space_number):
+    return board[space_number - 1]
+
+
+def set_board(board, space_number, new_value):
+    board[space_number - 1] = new_value
+
+
+def is_legal_human_move(board, m1, m2):
+    if board_contents(board, m1) != HUMAN_PIECE:
+        # Start space doesn't contain player's piece
+        return False
+    if board_contents(board, m2) == HUMAN_PIECE:
+        # Destination space contains player's piece (can't capture your own piece)
+        return False
+
+    is_capture = m2 - m1 != -3
+    if is_capture and board_contents(board, m2) != COMPUTER_PIECE:
+        # Destination does not contain computer piece
+        return False
+
+    if m2 > m1:
+        # can't move backwards
+        return False
+
+    if (not is_capture) and board_contents(board, m2) != EMPTY_SPACE:
+        # Destination is not open
+        return False
+
+    if m2 - m1 < -4:
+        # too far
+        return False
+
+    if m1 == 7 and m2 == 3:
+        # can't jump corner to corner (wrapping around the board)
+        return False
+    return True
+
+
+def player_piece_on_back_row(board):
+    for space in range(1, 4):
+        if board_contents(board, space) == HUMAN_PIECE:
+            return True
+    return False
+
+
+def computer_piece_on_front_row(board):
+    for space in range(7, 10):
+        if board_contents(board, space) == COMPUTER_PIECE:
+            return True
+    return False
+
+
+def all_human_pieces_captured(board):
+    return len(list(get_human_spaces(board))) == 0
+
+
+def all_computer_pieces_captured(board):
+    return len(list(get_computer_spaces(board))) == 0
+
+
+def human_win(last_computer_move):
+    print("YOU WIN")
+    remove_move(last_computer_move.board_index, last_computer_move.move_index)
+    global losses
+    losses += 1
+
+
+def computer_win(has_moves):
+    if not has_moves:
+        msg = "YOU CAN'T MOVE, SO "
+    else:
+        msg = ""
+    msg += "I WIN"
+    print(msg)
+    global wins
+    wins += 1
+
+
+def show_scores():
+    print(f"I HAVE WON {wins} AND YOU {losses} OUT OF {wins + losses} GAMES.")
+    print()
+
+
+def human_has_move(board):
+    for i in get_human_spaces(board):
+        if board_contents(board, i - 3) == EMPTY_SPACE:
+            # can move piece forward
+            return True
+        elif is_space_in_center_column(i):
+            if (board_contents(board, i - 2) == COMPUTER_PIECE) or (
+                board_contents(board, i - 4) == COMPUTER_PIECE
+            ):
+                # can capture from center
+                return True
+            else:
+                continue
+        elif i < 7:
+            assert (i == 4) or (i == 6)
+            if board_contents(board, 2) == COMPUTER_PIECE:
+                # can capture computer piece at 2
+                return True
+            else:
+                continue
+        elif board_contents(board, 5) == COMPUTER_PIECE:
+            assert (i == 7) or (i == 9)
+            # can capture computer piece at 5
+            return True
+        else:
+            continue
+    return False
+
+
+def get_board_spaces():
+    """generates the space names (1-9)"""
+    yield from range(1, 10)
+
+
+def get_board_spaces_with(board, val):
+    """generates spaces containing pieces of type val"""
+    for i in get_board_spaces():
+        if board_contents(board, i) == val:
+            yield i
+
+
+def get_human_spaces(board):
+    yield from get_board_spaces_with(board, HUMAN_PIECE)
+
+
+def get_empty_spaces(board):
+    yield from get_board_spaces_with(board, EMPTY_SPACE)
+
+
+def get_computer_spaces(board):
+    yield from get_board_spaces_with(board, COMPUTER_PIECE)
+
+
+def has_computer_move(board):
+    for i in get_computer_spaces(board):
+        if board_contents(board, i + 3) == EMPTY_SPACE:
+            # can move forward (down)
+            return True
+
+        if is_space_in_center_column(i):
+            # i is in the middle column
+            if (board_contents(board, i + 2) == HUMAN_PIECE) or (
+                board_contents(board, i + 4) == HUMAN_PIECE
+            ):
+                return True
+        else:
+            if i > 3:
+                # beyond the first row
+                if board_contents(board, 8) == HUMAN_PIECE:
+                    # can capture on 8
+                    return True
+                else:
+                    continue
+            else:
+                if board_contents(board, 5) == HUMAN_PIECE:
+                    # can capture on 5
+                    return True
+                else:
+                    continue
+    return False
+
+
+def find_board_index_that_matches_board(board):
+    for board_index, board_layout in enumerate(boards):
+        matches, is_reversed = board_layout.check_match(board)
+        if matches:
+            return board_index, is_reversed
+
+    # THE TERMINATION OF THIS LOOP IS IMPOSSIBLE
+    print("ILLEGAL BOARD PATTERN.")
+    assert False
+
+
+def pick_computer_move(board):
+    if not has_computer_move(board):
+        return None
+
+    board_index, reverse_board = find_board_index_that_matches_board(board)
+
+    m = boards[board_index].get_random_move(reverse_board)
+
+    if m is None:
+        print("I RESIGN")
+        return None
+
+    move_index, m1, m2 = m
+
+    return ComputerMove(board_index, move_index, m1, m2)
+
+
+def get_human_move(board):
+    while True:
+        m1, m2 = get_coordinates()
+
+        if not is_legal_human_move(board, m1, m2):
+            print_illegal()
+        else:
+            return m1, m2
+
+
+def apply_move(board, m1, m2, piece_value):
+    set_board(board, m1, EMPTY_SPACE)
+    set_board(board, m2, piece_value)
+
+
+def play_game():
+    last_computer_move = None
+
+    board = init_board()
+
+    while True:
+        print_board(board)
+
+        m1, m2 = get_human_move(board)
+
+        apply_move(board, m1, m2, HUMAN_PIECE)
+
+        print_board(board)
+
+        if player_piece_on_back_row(board) or all_computer_pieces_captured(board):
+            human_win(last_computer_move)
+            return
+
+        computer_move = pick_computer_move(board)
+        if computer_move is None:
+            human_win(last_computer_move)
+            return
+
+        last_computer_move = computer_move
+
+        m1, m2 = last_computer_move.m1, last_computer_move.m2
+
+        print(f"I MOVE FROM {m1} TO {m2}")
+        apply_move(board, m1, m2, COMPUTER_PIECE)
+
+        print_board(board)
+
+        if computer_piece_on_front_row(board):
+            computer_win(True)
+            return
+        elif (not human_has_move(board)) or (all_human_pieces_captured(board)):
+            computer_win(False)
+            return
+
+
+def main():
+    print_header("HEXAPAWN")
+    if prompt_yes_no("INSTRUCTIONS (Y-N)?"):
+        print_instructions()
+
+    global wins, losses
+    wins = 0
+    losses = 0
+
+    while True:
+        play_game()
+        show_scores()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/46_Hexapawn/ruby/README.md b/00_Alternate_Languages/46_Hexapawn/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/46_Hexapawn/vbnet/Hexapawn.sln b/00_Alternate_Languages/46_Hexapawn/vbnet/Hexapawn.sln
new file mode 100644
index 00000000..5aff142b
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/vbnet/Hexapawn.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Hexapawn", "Hexapawn.vbproj", "{83C2A51C-6014-4CC7-A4AF-81004B5F721F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{83C2A51C-6014-4CC7-A4AF-81004B5F721F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{83C2A51C-6014-4CC7-A4AF-81004B5F721F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{83C2A51C-6014-4CC7-A4AF-81004B5F721F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{83C2A51C-6014-4CC7-A4AF-81004B5F721F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/46_Hexapawn/vbnet/Hexapawn.vbproj b/00_Alternate_Languages/46_Hexapawn/vbnet/Hexapawn.vbproj
new file mode 100644
index 00000000..4ed34b92
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/vbnet/Hexapawn.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Hexapawn
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/46_Hexapawn/vbnet/README.md b/00_Alternate_Languages/46_Hexapawn/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/46_Hexapawn/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/47_Hi-Lo/README.md b/00_Alternate_Languages/47_Hi-Lo/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/47_Hi-Lo/csharp/HiLo.csproj b/00_Alternate_Languages/47_Hi-Lo/csharp/HiLo.csproj
new file mode 100644
index 00000000..20827042
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/csharp/HiLo.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+
diff --git a/00_Alternate_Languages/47_Hi-Lo/csharp/HiLo.sln b/00_Alternate_Languages/47_Hi-Lo/csharp/HiLo.sln
new file mode 100644
index 00000000..225235b8
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/csharp/HiLo.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HiLo", "HiLo.csproj", "{C4D0FAB6-056D-4DD2-827D-3383BE0AA382}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{C4D0FAB6-056D-4DD2-827D-3383BE0AA382}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C4D0FAB6-056D-4DD2-827D-3383BE0AA382}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C4D0FAB6-056D-4DD2-827D-3383BE0AA382}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C4D0FAB6-056D-4DD2-827D-3383BE0AA382}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {BF77DB59-426B-4A01-A8AC-09AAF42DA633}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/47_Hi-Lo/csharp/Program.cs b/00_Alternate_Languages/47_Hi-Lo/csharp/Program.cs
new file mode 100644
index 00000000..24971be0
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/csharp/Program.cs
@@ -0,0 +1,82 @@
+using System;
+
+Console.WriteLine(Tab(34) +                 "HI LO");
+Console.WriteLine(Tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+Console.WriteLine();
+Console.WriteLine();
+Console.WriteLine();
+Console.WriteLine("THIS IS THE GAME OF HI LO.");
+Console.WriteLine();
+Console.WriteLine("YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE");
+Console.WriteLine("HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU");
+Console.WriteLine("GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!");
+Console.WriteLine("THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,");
+Console.WriteLine("IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.");
+Console.WriteLine();
+
+// rnd is our random number generator
+Random rnd = new();
+
+bool playAgain = false;
+int totalWinnings = 0;
+
+do // Our game loop
+{
+    int jackpot = rnd.Next(100) + 1; // [0..99] + 1 -> [1..100]
+    int guess = 1;
+
+    while (true) // Our guessing loop
+    {
+        Console.WriteLine();
+        int amount = ReadInt("YOUR GUESS ");
+
+        if (amount == jackpot)
+        {
+            Console.WriteLine($"GOT IT!!!!!!!!!!   YOU WIN {jackpot} DOLLARS.");
+            totalWinnings += jackpot;
+            Console.WriteLine($"YOUR TOTAL WINNINGS ARE NOW {totalWinnings} DOLLARS.");
+            break;
+        }
+        else if (amount > jackpot)
+        {
+            Console.WriteLine("YOUR GUESS IS TOO HIGH.");
+        }
+        else
+        {
+            Console.WriteLine("YOUR GUESS IS TOO LOW.");
+        }
+
+        guess++;
+        if (guess > 6)
+        {
+            Console.WriteLine($"YOU BLEW IT...TOO BAD...THE NUMBER WAS {jackpot}");
+            break;
+        }
+    }
+
+    Console.WriteLine();
+    Console.Write("PLAY AGAIN (YES OR NO) ");
+    playAgain = Console.ReadLine().ToUpper().StartsWith("Y");
+
+} while (playAgain);
+
+Console.WriteLine();
+Console.WriteLine("SO LONG.  HOPE YOU ENJOYED YOURSELF!!!");
+
+// Tab(n) returns n spaces
+static string Tab(int n) => new String(' ', n);
+
+// ReadInt asks the user to enter a number
+static int ReadInt(string question)
+{
+    while (true)
+    {
+        Console.Write(question);
+        var input = Console.ReadLine().Trim();
+        if (int.TryParse(input, out int value))
+        {
+            return value;
+        }
+        Console.WriteLine("!Invalid Number Entered.");
+    }
+}
diff --git a/00_Alternate_Languages/47_Hi-Lo/csharp/README.md b/00_Alternate_Languages/47_Hi-Lo/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/47_Hi-Lo/hi-lo.bas b/00_Alternate_Languages/47_Hi-Lo/hi-lo.bas
new file mode 100644
index 00000000..8aaa36bb
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/hi-lo.bas
@@ -0,0 +1,29 @@
+10 PRINT TAB(34);"HI LO"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+100 PRINT "THIS IS THE GAME OF HI LO.":PRINT
+110 PRINT "YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE"
+120 PRINT "HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU"
+130 PRINT "GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!"
+140 PRINT "THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,"
+150 PRINT "IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.":PRINT
+160 R=0
+170 B=0:PRINT
+180 Y=INT(100*RND(1))
+200 PRINT "YOUR GUESS";
+210 INPUT A
+220 B=B+1
+230 IF A=Y THEN 300
+240 IF A>Y THEN 270
+250 PRINT "YOUR GUESS IS TOO LOW.":GOTO 280
+270 PRINT "YOUR GUESS IS TOO HIGH."
+280 PRINT:IF B<6 THEN 200
+290 PRINT "YOU BLEW IT...TOO BAD...THE NUMBER WAS";Y
+295 R=0:GOTO 350
+300 PRINT "GOT IT!!!!!!!!!!   YOU WIN";Y;"DOLLARS."
+310 R=R+Y
+320 PRINT "YOUR TOTAL WINNINGS ARE NOW";R;"DOLLARS."
+350 PRINT:PRINT "PLAY AGAIN (YES OR NO)";
+360 INPUT A$:IF A$="YES" THEN 170
+380 PRINT:PRINT "SO LONG.  HOPE YOU ENJOYED YOURSELF!!!"
+390 END
diff --git a/00_Alternate_Languages/47_Hi-Lo/java/README.md b/00_Alternate_Languages/47_Hi-Lo/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/47_Hi-Lo/java/src/HiLo.java b/00_Alternate_Languages/47_Hi-Lo/java/src/HiLo.java
new file mode 100644
index 00000000..b7b3e106
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/java/src/HiLo.java
@@ -0,0 +1,214 @@
+import java.util.Scanner;
+
+/**
+ * Game of HiLo
+ *
+ * Based on the Basic game of Hi-Lo here
+ * https://github.com/coding-horror/basic-computer-games/blob/main/47%20Hi-Lo/hi-lo.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.
+ */
+public class HiLo {
+
+    public static final int LOW_NUMBER_RANGE = 1;
+    public static final int HIGH_NUMBER_RANGE = 100;
+    public static final int MAX_GUESSES = 6;
+
+    private enum GAME_STATE {
+        STARTING,
+        START_GAME,
+        GUESSING,
+        PLAY_AGAIN,
+        GAME_OVER
+    }
+
+    // Used for keyboard input
+    private final Scanner kbScanner;
+
+    // Current game state
+    private GAME_STATE gameState;
+
+    // Players Winnings
+    private int playerAmountWon;
+
+    // Players guess count;
+    private int playersGuesses;
+
+    // Computers random number
+    private int computersNumber;
+
+    public HiLo() {
+
+        gameState = GAME_STATE.STARTING;
+        playerAmountWon = 0;
+
+        // Initialise kb scanner
+        kbScanner = new Scanner(System.in);
+    }
+
+    /**
+     * Main game loop
+     *
+     */
+    public void play() {
+
+        do {
+            switch (gameState) {
+
+                // Show an introduction the first time the game is played.
+                case STARTING:
+                    intro();
+                    gameState = GAME_STATE.START_GAME;
+                    break;
+
+                // Generate computers number for player to guess, etc.
+                case START_GAME:
+                    init();
+                    System.out.println("O.K.  I HAVE A NUMBER IN MIND.");
+                    gameState = GAME_STATE.GUESSING;
+                    break;
+
+                // Player guesses the number until they get it or run out of guesses
+                case GUESSING:
+                    int guess = playerGuess();
+
+                    // Check if the player guessed the number
+                    if(validateGuess(guess)) {
+                        System.out.println("GOT IT!!!!!!!!!!   YOU WIN " + computersNumber
+                                + " DOLLARS.");
+                        playerAmountWon += computersNumber;
+                        System.out.println("YOUR TOTAL WINNINGS ARE NOW "
+                                + playerAmountWon + " DOLLARS.");
+                        gameState = GAME_STATE.PLAY_AGAIN;
+                    } else {
+                        // incorrect guess
+                        playersGuesses++;
+                        // Ran out of guesses?
+                        if (playersGuesses == MAX_GUESSES) {
+                            System.out.println("YOU BLEW IT...TOO BAD...THE NUMBER WAS "
+                                    + computersNumber);
+                            playerAmountWon = 0;
+                            gameState = GAME_STATE.PLAY_AGAIN;
+                        }
+                    }
+                    break;
+
+                // Play again, or exit game?
+                case PLAY_AGAIN:
+                    System.out.println();
+                    if(yesEntered(displayTextAndGetInput("PLAY AGAIN (YES OR NO) "))) {
+                        gameState = GAME_STATE.START_GAME;
+                    } else {
+                        // Chose not to play again
+                        System.out.println("SO LONG.  HOPE YOU ENJOYED YOURSELF!!!");
+                        gameState = GAME_STATE.GAME_OVER;
+                    }
+            }
+        } while (gameState != GAME_STATE.GAME_OVER);
+    }
+
+    /**
+     * Checks the players guess against the computers randomly generated number
+     *
+     * @param theGuess the players guess
+     * @return true if the player guessed correctly, false otherwise
+     */
+    private boolean validateGuess(int theGuess) {
+
+        // Correct guess?
+        if(theGuess == computersNumber) {
+            return true;
+        }
+
+        if(theGuess > computersNumber) {
+            System.out.println("YOUR GUESS IS TOO HIGH.");
+        } else {
+            System.out.println("YOUR GUESS IS TOO LOW.");
+        }
+
+        return false;
+    }
+
+    private void init() {
+        playersGuesses = 0;
+        computersNumber = randomNumber();
+    }
+
+    public void intro() {
+        System.out.println("HI LO");
+        System.out.println("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+        System.out.println();
+        System.out.println();
+        System.out.println("IS THE GAME OF HI LO.");
+        System.out.println();
+        System.out.println("YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE");
+        System.out.println("HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU");
+        System.out.println("GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!");
+        System.out.println("THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,");
+        System.out.println("IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.");
+    }
+
+    /**
+     * Get players guess from kb
+     *
+     * @return players guess as an int
+     */
+    private int playerGuess() {
+        return Integer.parseInt((displayTextAndGetInput("YOUR GUESS? ")));
+    }
+
+    /**
+     * Checks whether player entered Y or YES to a question.
+     *
+     * @param text  player string from kb
+     * @return true of Y or YES was entered, otherwise false
+     */
+    private boolean yesEntered(String text) {
+        return stringIsAnyValue(text, "Y", "YES");
+    }
+
+    /**
+     * Check whether a string equals one of a variable number of values
+     * Useful to check for Y or YES for example
+     * Comparison is case insensitive.
+     *
+     * @param text source string
+     * @param values a range of values to compare against the source string
+     * @return true if a comparison was found in one of the variable number of strings passed
+     */
+    private boolean stringIsAnyValue(String text, String... values) {
+
+        // Cycle through the variable number of values and test each
+        for(String val:values) {
+            if(text.equalsIgnoreCase(val)) {
+                return true;
+            }
+        }
+
+        // no matches
+        return false;
+    }
+
+    /*
+     * Print a message on the screen, then accept input from Keyboard.
+     *
+     * @param text message to be displayed on screen.
+     * @return what was typed by the player.
+     */
+    private String displayTextAndGetInput(String text) {
+        System.out.print(text);
+        return kbScanner.next();
+    }
+
+    /**
+     * Generate random number
+     * Used as a single digit of the computer player
+     *
+     * @return random number
+     */
+    private int randomNumber() {
+        return (int) (Math.random()
+                * (HIGH_NUMBER_RANGE - LOW_NUMBER_RANGE + 1) + LOW_NUMBER_RANGE);
+    }
+}
diff --git a/00_Alternate_Languages/47_Hi-Lo/java/src/HiLoGame.java b/00_Alternate_Languages/47_Hi-Lo/java/src/HiLoGame.java
new file mode 100644
index 00000000..314606c4
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/java/src/HiLoGame.java
@@ -0,0 +1,8 @@
+public class HiLoGame {
+
+    public static void main(String[] args) {
+
+        HiLo hiLo = new HiLo();
+        hiLo.play();
+    }
+}
diff --git a/00_Alternate_Languages/47_Hi-Lo/javascript/README.md b/00_Alternate_Languages/47_Hi-Lo/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/47_Hi-Lo/javascript/hi-lo.html b/00_Alternate_Languages/47_Hi-Lo/javascript/hi-lo.html
new file mode 100644
index 00000000..2610591d
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/javascript/hi-lo.html
@@ -0,0 +1,9 @@
+
+
+HI-LO
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/47_Hi-Lo/javascript/hi-lo.js b/00_Alternate_Languages/47_Hi-Lo/javascript/hi-lo.js
new file mode 100644
index 00000000..362e40a3
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/javascript/hi-lo.js
@@ -0,0 +1,96 @@
+// HI-LO
+//
+// 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) + "HI LO\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("THIS IS THE GAME OF HI LO.\n");
+    print("\n");
+    print("YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\n");
+    print("HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU\n");
+    print("GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\n");
+    print("THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,\n");
+    print("IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\n");
+    print("\n");
+    r = 0;
+    while (1) {
+        b = 0;
+        print("\n");
+        y = Math.floor(100 * Math.random());
+        for (b = 1; b <= 6; b++) {
+            print("YOUR GUESS");
+            a = parseInt(await input());
+            if (a < y) {
+                print("YOUR GUESS IS TOO LOW.\n");
+            } else if (a > y) {
+                print("YOUR GUESS IS TOO HIGH.\n");
+            } else {
+                break;
+            }
+            print("\n");
+        }
+        if (b > 6) {
+            print("YOU BLEW IT...TOO BAD...THE NUMBER WAS " + y + "\n");
+            r = 0;
+        } else {
+            print("GOT IT!!!!!!!!!!   YOU WIN " + y + " DOLLARS.\n");
+            r += y;
+            print("YOUR TOTAL WINNINGS ARE NOW " + r + " DOLLARS.\n");
+        }
+        print("\n");
+        print("PLAY AGAIN (YES OR NO)");
+        str = await input();
+        if (str != "YES")
+            break;
+    }
+    print("\n");
+    print("SO LONG.  HOPE YOU ENJOYED YOURSELF!!!\n");
+}
+
+main();
diff --git a/00_Alternate_Languages/47_Hi-Lo/kotlin/HiLo.kt b/00_Alternate_Languages/47_Hi-Lo/kotlin/HiLo.kt
new file mode 100644
index 00000000..de52f573
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/kotlin/HiLo.kt
@@ -0,0 +1,50 @@
+
+fun main() {
+    println(introText)
+    var winnings = 0
+    do {
+        winnings += playGame()
+        println("YOUR TOTAL WINNINGS ARE NOW $winnings DOLLARS")
+    } while(playAgain())
+
+    println("SO LONG.  HOPE YOU ENJOYED YOURSELF!!!")
+}
+
+fun playGame():Int {
+    val amount = (1..100).random()
+    repeat(6) {
+        println("YOUR GUESS")
+        val guess = readln().toInt()
+        when {
+            guess == amount -> {
+                println("GOT IT!!!!!!!! YOU WIN $amount DOLLARS.")
+                return amount
+            }
+            guess > amount -> println("YOUR GUESS IS TOO HIGH")
+            else -> println("YOUR GUESS IS TOO LOW")
+        }
+    }
+    println("YOU BLEW IT...TOO BAD...THE NUMBER WAS $amount")
+    return 0
+}
+
+fun playAgain():Boolean {
+    println("PLAY AGAIN (YES OR NO)")
+    return readLine()?.uppercase() == "YES"
+}
+
+
+val introText = """
+    HI LO
+    CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+
+
+    THIS IS THE GAME OF HI LO.
+
+    YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE
+    HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU
+    GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!
+    THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,
+    IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS
+
+""".trimIndent()
diff --git a/00_Alternate_Languages/47_Hi-Lo/kotlin/README.md b/00_Alternate_Languages/47_Hi-Lo/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/23_Checkers/pascal/README.md b/00_Alternate_Languages/47_Hi-Lo/pascal/README.md
similarity index 100%
rename from 23_Checkers/pascal/README.md
rename to 00_Alternate_Languages/47_Hi-Lo/pascal/README.md
diff --git a/00_Alternate_Languages/47_Hi-Lo/perl/README.md b/00_Alternate_Languages/47_Hi-Lo/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/47_Hi-Lo/perl/hi-lo.pl b/00_Alternate_Languages/47_Hi-Lo/perl/hi-lo.pl
new file mode 100644
index 00000000..234c5981
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/perl/hi-lo.pl
@@ -0,0 +1,43 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 34 . "HI LO\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n"; print "\n"; print "\n";
+print "THIS IS THE GAME OF HI LO.\n"; print "\n";
+print "YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\n";
+print "HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS. IF YOU\n";
+print "GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\n";
+print "THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY. HOWEVER,\n";
+print "IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\n"; print "\n";
+my $R=0;
+my $A;
+do {
+	print "\n";
+	my $Y=int(100*rand(1));
+	foreach (1..6) {
+		print "YOUR GUESS $Y";
+		print "? "; chomp($A = );
+		if ($A eq $Y) { last; }
+		if ($A>$Y) {
+			print "YOUR GUESS IS TOO HIGH.\n";
+			} else {
+			print "YOUR GUESS IS TOO LOW.\n";
+			}
+		print "\n";
+		}
+
+	if ($A==$Y) {
+		$R=$R+$Y;
+		print "GOT IT!!!!!!!!!! YOU WIN $Y DOLLARS.\n";
+		print "YOUR TOTAL WINNINGS ARE NOW $R DOLLARS.\n";
+		} else {
+		$R=0;
+		print "YOU BLEW IT...TOO BAD...THE NUMBER WAS $Y"
+		}
+	print "\n"; print "PLAY AGAIN (YES OR NO)";
+	print "? "; chomp($A = );
+	} until (uc($A) ne "YES");
+print "\n"; print "SO LONG. HOPE YOU ENJOYED YOURSELF!!!\n";
+exit;
diff --git a/00_Alternate_Languages/47_Hi-Lo/python/README.md b/00_Alternate_Languages/47_Hi-Lo/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/47_Hi-Lo/python/hilo.py b/00_Alternate_Languages/47_Hi-Lo/python/hilo.py
new file mode 100644
index 00000000..6341311a
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/python/hilo.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python3
+import random
+
+MAX_ATTEMPTS = 6
+QUESTION_PROMPT = "? "
+
+
+def play():
+    print("HI LO")
+    print("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n")
+    print("THIS IS THE GAME OF HI LO.\n")
+    print("YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE")
+    print("HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS.  IF YOU")
+    print("GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!")
+    print("THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,")
+    print("IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\n\n")
+
+    total_winnings = 0
+    while True:
+        print()
+        secret = random.randint(1, 100)
+        guessed_correctly = False
+
+        for attempt in range(MAX_ATTEMPTS):
+            print("YOUR GUESS", end=QUESTION_PROMPT)
+            guess = int(input())
+
+            if guess == secret:
+                print(f"GOT IT!!!!!!!!!!   YOU WIN {secret} DOLLARS.")
+                guessed_correctly = True
+                break
+            elif guess > secret:
+                print("YOUR GUESS IS TOO HIGH.")
+            else:
+                print("YOUR GUESS IS TOO LOW.")
+
+        if guessed_correctly:
+            total_winnings += secret
+            print(f"YOUR TOTAL WINNINGS ARE NOW {total_winnings} DOLLARS.")
+        else:
+            print(f"YOU BLEW IT...TOO BAD...THE NUMBER WAS {secret}")
+
+        print("\n")
+        print("PLAY AGAIN (YES OR NO)", end=QUESTION_PROMPT)
+        answer = input().upper()
+        if answer != "YES":
+            break
+
+    print("\nSO LONG.  HOPE YOU ENJOYED YOURSELF!!!")
+
+
+if __name__ == "__main__":
+    play()
diff --git a/00_Alternate_Languages/47_Hi-Lo/ruby/README.md b/00_Alternate_Languages/47_Hi-Lo/ruby/README.md
new file mode 100644
index 00000000..241656ad
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/) by [R.T. Lechow](https://github.com/rtlechow)
diff --git a/00_Alternate_Languages/47_Hi-Lo/ruby/hi_lo.rb b/00_Alternate_Languages/47_Hi-Lo/ruby/hi_lo.rb
new file mode 100644
index 00000000..02989a91
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/ruby/hi_lo.rb
@@ -0,0 +1,59 @@
+#!/usr/bin/env ruby
+MAX_TRIES = 6
+RANGE = (1..100)
+
+def intro
+  puts <<~END_OF_INTRO
+    #{'HI LO'.center(74)}
+    #{"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n".center(76)}
+    THIS IS THE GAME OF HI LO.\n
+    YOU WILL HAVE #{MAX_TRIES} TRIES TO GUESS THE AMOUNT OF MONEY IN THE
+    HI LO JACKPOT, WHICH IS BETWEEN #{RANGE.min} AND #{RANGE.max} DOLLARS.  IF YOU
+    GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!
+    THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY.  HOWEVER,
+    IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\n\n
+  END_OF_INTRO
+end
+
+def make_guess
+  puts 'YOUR GUESS?'
+  @guess = gets.to_i
+end
+
+def check_guess
+  if @guess == @number
+    @guessed_correctly = true
+    @total_winnings += @number
+    puts <<~END_OF_WIN_TEXT
+      GOT IT!!!!!!!!!!   YOU WIN #{@number} DOLLARS.
+      YOUR TOTAL WINNINGS ARE NOW #{@total_winnings} DOLLARS.
+    END_OF_WIN_TEXT
+  else
+    puts "YOUR GUESS IS TOO #{@guess > @number ? 'HIGH' : 'LOW'}.\n\n"
+  end
+end
+
+def blew_it
+  @total_winnings = 0
+  puts "YOU BLEW IT...TOO BAD...THE NUMBER WAS #{@number}"
+end
+
+def outro
+  puts "\nSO LONG.  HOPE YOU ENJOYED YOURSELF!!!"
+end
+
+intro
+@total_winnings = 0
+loop do
+  @guessed_correctly = false
+  @number = rand(RANGE)
+  MAX_TRIES.times do
+    make_guess
+    check_guess
+    break if @guessed_correctly
+  end
+  blew_it unless @guessed_correctly
+  puts "\nPLAY AGAIN (YES OR NO)?"
+  break if gets.start_with?(/n/i)
+end
+outro
diff --git a/00_Alternate_Languages/47_Hi-Lo/vbnet/HiLo.sln b/00_Alternate_Languages/47_Hi-Lo/vbnet/HiLo.sln
new file mode 100644
index 00000000..fbd97f94
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/vbnet/HiLo.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "HiLo", "HiLo.vbproj", "{B93E0994-AEC4-4FC9-93C2-FC708368B32F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B93E0994-AEC4-4FC9-93C2-FC708368B32F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B93E0994-AEC4-4FC9-93C2-FC708368B32F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B93E0994-AEC4-4FC9-93C2-FC708368B32F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B93E0994-AEC4-4FC9-93C2-FC708368B32F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/47_Hi-Lo/vbnet/HiLo.vbproj b/00_Alternate_Languages/47_Hi-Lo/vbnet/HiLo.vbproj
new file mode 100644
index 00000000..634099d3
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/vbnet/HiLo.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    HiLo
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/47_Hi-Lo/vbnet/README.md b/00_Alternate_Languages/47_Hi-Lo/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/47_Hi-Lo/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/48_High_IQ/README.md b/00_Alternate_Languages/48_High_IQ/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/48_High_IQ/csharp/HighIQ.csproj b/00_Alternate_Languages/48_High_IQ/csharp/HighIQ.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/csharp/HighIQ.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/48_High_IQ/csharp/HighIQ.sln b/00_Alternate_Languages/48_High_IQ/csharp/HighIQ.sln
new file mode 100644
index 00000000..2cdbddc4
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/csharp/HighIQ.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HighIQ", "HighIQ.csproj", "{B334E0AD-4A84-4F93-85FB-E6370BC8B71A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B334E0AD-4A84-4F93-85FB-E6370BC8B71A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B334E0AD-4A84-4F93-85FB-E6370BC8B71A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B334E0AD-4A84-4F93-85FB-E6370BC8B71A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B334E0AD-4A84-4F93-85FB-E6370BC8B71A}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/48_High_IQ/csharp/README.md b/00_Alternate_Languages/48_High_IQ/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/48_High_IQ/d/.gitignore b/00_Alternate_Languages/48_High_IQ/d/.gitignore
new file mode 100644
index 00000000..d969f6b2
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/d/.gitignore
@@ -0,0 +1,2 @@
+*.exe
+*.obj
diff --git a/00_Alternate_Languages/48_High_IQ/d/README.md b/00_Alternate_Languages/48_High_IQ/d/README.md
new file mode 100644
index 00000000..0eea7b00
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/d/README.md
@@ -0,0 +1,214 @@
+Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).
+
+## Running the code
+
+Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:
+```shell
+dmd -dip1000 -run highiq.d
+```
+
+[Other compilers](https://dlang.org/download.html) also exist.
+
+
+## Discussion
+
+The original BASIC game code made use of calculus and clever choises of field IDs to determine the validity of moves.
+This is the original layout of IDs over the board:
+
+```
+          13   14   15
+
+          22   23   24
+
+29   30   31   32   33   34   35
+
+38   39   40   41   42   43   44
+
+47   48   49   50   51   52   53
+
+          58   59   60
+
+          67   68   69
+```
+
+This seems not very logical, because, wouldn't it make much more sense to let columns increase with 1 and rows increase
+with 10, so you'd get a consistent coordinate system? It seems that the original author's first step in validating
+moves was to check that moves jumped from one field over another one onto the next. He did this by making sure that
+adjacent IDs alter between even and odd horizontally *and* vertically. So a valid move was always from an even ID to an
+even ID *or* from an odd ID to an odd ID. So one of the checks that the BASIC code made was that the sum of both IDs
+was even. This is of course not a sufficient test, because moves that jump over three fields are illegal. Therefore the
+IDs seem to have been carefully laid oud so that the IDs increase with 1 horizontally, and 9 vertically, everywhere. So
+the only valid difference between IDs for a horizontal move was always 2, and the only valid difference for a vertical
+move was always 18.
+
+Fact of the matter is, however, that checking for difference is sufficient and the even sum rule is superfluous, so
+there is no need for the peculiar distribution of field IDs. Therefore I have chosen the following more logical
+distribution:
+
+```
+          13   14   15
+
+          23   24   25
+
+31   32   33   34   35   36   37
+
+41   42   43   44   45   46   47
+
+51   52   53   54   55   56   57
+
+          63   64   65
+
+          73   74   75
+```
+
+As a consequence, the implementation of the game code has become much simpler; Not alone due to one less check, but due
+to the fact that conversions between IDs and board coordinates have become unnecessary and thus we can work with a single
+representation of the board state.
+
+This version makes a prettier print of the board than the BASIC original, with coordinates for every move, and explains
+illegal moves.
+
+
+## Demo
+
+```
+                      H-I-Q
+(After Creative Computing  Morristown, New Jersey)
+
+
+Fields are identified by 2-digit numbers, each
+between 1 and 7. Example: the middle field is 44,
+the bottom middle is 74.
+
+      _1  _2  _3  _4  _5  _6  _7
+            ┌───┬───┬───┐
+ 1_         │ ■ │ ■ │ ■ │
+            ├───┼───┼───┤
+ 2_         │ ■ │ ■ │ ■ │
+    ┌───┬───┼───┼───┼───┼───┬───┐
+ 3_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
+    ├───┼───┼───┼───┼───┼───┼───┤
+ 4_ │ ■ │ ■ │ ■ │   │ ■ │ ■ │ ■ │
+    ├───┼───┼───┼───┼───┼───┼───┤
+ 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
+    └───┴───┼───┼───┼───┼───┴───┘
+ 6_         │ ■ │ ■ │ ■ │
+            ├───┼───┼───┤
+ 7_         │ ■ │ ■ │ ■ │
+            └───┴───┴───┘
+
+Move which peg? 23
+The peg at 23 has nowhere to go. Try again.
+
+Move which peg? 24
+To where? 34
+Field 34 is occupied. Try again.
+To where? 54
+Field 54 is occupied. Try again.
+To where? 44
+
+      _1  _2  _3  _4  _5  _6  _7
+            ┌───┬───┬───┐
+ 1_         │ ■ │ ■ │ ■ │
+            ├───┼───┼───┤
+ 2_         │ ■ │   │ ■ │
+    ┌───┬───┼───┼───┼───┼───┬───┐
+ 3_ │ ■ │ ■ │ ■ │   │ ■ │ ■ │ ■ │
+    ├───┼───┼───┼───┼───┼───┼───┤
+ 4_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
+    ├───┼───┼───┼───┼───┼───┼───┤
+ 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
+    └───┴───┼───┼───┼───┼───┴───┘
+ 6_         │ ■ │ ■ │ ■ │
+            ├───┼───┼───┤
+ 7_         │ ■ │ ■ │ ■ │
+            └───┴───┴───┘
+
+Move which peg? 14
+The peg at 14 has nowhere to go. Try again.
+
+Move which peg? 24
+There is no peg at 24. Try again.
+
+Move which peg? 44
+The peg at 44 has nowhere to go. Try again.
+
+Move which peg? 32
+To where? 22
+Field 22 is ouside the board. Try again.
+To where? 33
+Field 33 is occupied. Try again.
+To where? 34
+
+      _1  _2  _3  _4  _5  _6  _7
+            ┌───┬───┬───┐
+ 1_         │ ■ │ ■ │ ■ │
+            ├───┼───┼───┤
+ 2_         │ ■ │   │ ■ │
+    ┌───┬───┼───┼───┼───┼───┬───┐
+ 3_ │ ■ │   │   │ ■ │ ■ │ ■ │ ■ │
+    ├───┼───┼───┼───┼───┼───┼───┤
+ 4_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
+    ├───┼───┼───┼───┼───┼───┼───┤
+ 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
+    └───┴───┼───┼───┼───┼───┴───┘
+ 6_         │ ■ │ ■ │ ■ │
+            ├───┼───┼───┤
+ 7_         │ ■ │ ■ │ ■ │
+            └───┴───┴───┘
+
+Move which peg? 44
+To where? 33
+You cannot move diagonally. Try again.
+To where? 24
+
+      _1  _2  _3  _4  _5  _6  _7
+            ┌───┬───┬───┐
+ 1_         │ ■ │ ■ │ ■ │
+            ├───┼───┼───┤
+ 2_         │ ■ │ ■ │ ■ │
+    ┌───┬───┼───┼───┼───┼───┬───┐
+ 3_ │ ■ │   │   │   │ ■ │ ■ │ ■ │
+    ├───┼───┼───┼───┼───┼───┼───┤
+ 4_ │ ■ │ ■ │ ■ │   │ ■ │ ■ │ ■ │
+    ├───┼───┼───┼───┼───┼───┼───┤
+ 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
+    └───┴───┼───┼───┼───┼───┴───┘
+ 6_         │ ■ │ ■ │ ■ │
+            ├───┼───┼───┤
+ 7_         │ ■ │ ■ │ ■ │
+            └───┴───┴───┘
+
+Move which peg? 36
+To where? 33
+You can't jump that far. Try again.
+To where? 35
+Field 35 is occupied. Try again.
+To where? 34
+
+      _1  _2  _3  _4  _5  _6  _7
+            ┌───┬───┬───┐
+ 1_         │ ■ │ ■ │ ■ │
+            ├───┼───┼───┤
+ 2_         │ ■ │ ■ │ ■ │
+    ┌───┬───┼───┼───┼───┼───┬───┐
+ 3_ │ ■ │   │   │ ■ │   │   │ ■ │
+    ├───┼───┼───┼───┼───┼───┼───┤
+ 4_ │ ■ │ ■ │ ■ │   │ ■ │ ■ │ ■ │
+    ├───┼───┼───┼───┼───┼───┼───┤
+ 5_ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │ ■ │
+    └───┴───┼───┼───┼───┼───┴───┘
+ 6_         │ ■ │ ■ │ ■ │
+            ├───┼───┼───┤
+ 7_         │ ■ │ ■ │ ■ │
+            └───┴───┴───┘
+
+Move which peg? 46
+To where? 36
+You need to jump over another peg. Try again.
+To where? down
+Field 00 is ouside the board. Try again.
+To where?
+```
diff --git a/00_Alternate_Languages/48_High_IQ/highiq.bas b/00_Alternate_Languages/48_High_IQ/highiq.bas
new file mode 100644
index 00000000..0552dc79
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/highiq.bas
@@ -0,0 +1,135 @@
+1 PRINT TAB(33);"H-I-Q"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+4 DIM B(70),T(9,9)
+5 PRINT "HERE IS THE BOARD:": PRINT
+6 PRINT "          !    !    !"
+7 PRINT "         13   14   15": PRINT
+8 PRINT "          !    !    !"
+9 PRINT "         22   23   24": PRINT
+10 PRINT "!    !    !    !    !    !    !"
+11 PRINT "29   30   31   32   33   34   35": PRINT
+12 PRINT "!    !    !    !    !    !    !"
+13 PRINT "38   39   40   41   42   43   44": PRINT
+14 PRINT "!    !    !    !    !    !    !"
+15 PRINT "47   48   49   50   51   52   53": PRINT
+16 PRINT "          !    !    !"
+17 PRINT "         58   59   60": PRINT
+18 PRINT "          !    !    !"
+19 PRINT "         67   68   69": PRINT
+20 PRINT "TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD"
+22 PRINT "WILL BE USED DURING PLAY.  REFER TO THE ABOVE ONE FOR PEG"
+24 PRINT "NUMBERS.  OK, LET'S BEGIN."
+28 REM *** SET UP BOARD
+29 FOR R=1 TO 9
+30 FOR C=1 TO 9
+31 IF (R-4)*(R-5)*(R-6)=0 THEN 40
+32 IF (C-4)*(C-5)*(C-6)=0 THEN 40
+35 T(R,C)=-5
+36 GOTO 50
+40 IF (R-1)*(C-1)*(R-9)*(C-9)=0 THEN 35
+42 T(R,C)=5
+50 NEXT C
+60 NEXT R
+65 T(5,5)=0: GOSUB 500
+70 REM *** INPUT MOVE AND CHECK ON LEGALITY
+75 FOR W=1 TO 33
+77 READ M
+79 DATA 13,14,15,22,23,24,29,30,31,32,33,34,35,38,39,40,41
+81 DATA 42,43,44,47,48,49,50,51,52,53,58,59,60,67,68,69
+83 B(M)=-7: NEXT W
+86 B(41)=-3
+100 INPUT "MOVE WHICH PIECE";Z
+110 IF B(Z)=-7 THEN 140
+120 PRINT "ILLEGAL MOVE, TRY AGAIN...": GOTO 100
+140 INPUT "TO WHERE";P
+150 IF B(P)=0 THEN 120
+153 IF B(P)=-7 THEN 120
+156 IF Z=P THEN 100
+160 IF ((Z+P)/2)=INT((Z+P)/2) THEN 180
+170 GOTO 120
+180 IF (ABS(Z-P)-2)*(ABS(Z-P)-18)<>0 THEN 120
+190 GOSUB 1000
+200 GOSUB 500
+210 GOSUB 1500
+220 GOTO 100
+500 REM *** PRINT BOARD
+510 FOR X=1 TO 9
+520 FOR Y=1 TO 9
+525 IF (X-1)*(X-9)*(Y-1)*(Y-9)=0 THEN 550
+530 IF (X-4)*(X-5)*(X-6)=0 THEN 570
+540 IF (Y-4)*(Y-5)*(Y-6)=0 THEN 570
+550 REM
+560 GOTO 610
+570 IF T(X,Y)<>5 THEN 600
+580 PRINT TAB(Y*2);"!";
+590 GOTO 610
+600 PRINT TAB(Y*2);"O";
+610 REM
+615 NEXT Y
+620 PRINT
+630 NEXT X
+640 RETURN
+1000 REM *** UPDATE BOARD
+1005 C=1: FOR X=1 TO 9
+1020 FOR Y=1 TO 9
+1030 IF C<>Z THEN 1220
+1040 IF C+2<>P THEN 1080
+1045 IF T(X,Y+1)=0 THEN 120
+1050 T(X,Y+2)=5
+1060 T(X,Y+1)=0: B(C+1)=-3
+1070 GOTO 1200
+1080 IF C+18<>P THEN 1130
+1085 IF T(X+1,Y)=0 THEN 120
+1090 T(X+2,Y)=5: T(X+1,Y)=0: B(C+9)=-3
+1120 GOTO 1200
+1130 IF C-2<>P THEN 1170
+1135 IF T(X,Y-1)=0 THEN 120
+1140 T(X,Y-2)=5: T(X,Y-1)=0: B(C-1)=-3
+1160 GOTO 1200
+1170 IF C-18<>P THEN 1220
+1175 IF T(X-1,Y)=0 THEN 120
+1180 T(X-2,Y)=5: T(X-1,Y)=0: B(C-9)=-3
+1200 B(Z)=-3: B(P)=-7
+1210 T(X,Y)=0: GOTO 1240
+1220 C=C+1
+1225 NEXT Y
+1230 NEXT X
+1240 RETURN
+1500 REM*** CHECK IF GAME IS OVER
+1505 F=0
+1510 FOR R=2 TO 8
+1520 FOR C=2 TO 8
+1530 IF T(R,C)<>5 THEN 1580
+1535 F=F+1
+1540 FOR A=R-1 TO R+1
+1545 T=0
+1550 FOR B=C-1 TO C+1
+1560 T=T+T(A,B)
+1561 NEXT B
+1564 IF T<>10 THEN 1567
+1565 IF T(A,C)<>0 THEN 1630
+1567 NEXT A
+1568 FOR X=C-1 TO C+1
+1569 T=0
+1570 FOR Y=R-1 TO R+1
+1571 T=T+T(Y,X)
+1572 NEXT Y
+1573 IF T<>10 THEN 1575
+1574 IF T(R,X)<>0 THEN 1630
+1575 NEXT X
+1580 NEXT C
+1590 NEXT R
+1600 REM *** GAME IS OVER
+1605 PRINT "THE GAME IS OVER."
+1610 PRINT "YOU HAD";F;"PIECES REMAINING."
+1611 IF F<>1 THEN 1615
+1612 PRINT "BRAVO!  YOU MADE A PERFECT SCORE!"
+1613 PRINT "SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!"
+1615 PRINT: INPUT "PLAY AGAIN (YES OR NO)";A$
+1617 IF A$="NO" THEN 2000
+1618 RESTORE: GOTO 28
+1620 STOP
+1630 RETURN
+2000 PRINT: PRINT "SO LONG FOR NOW.": PRINT
+2010 END
diff --git a/00_Alternate_Languages/48_High_IQ/java/README.md b/00_Alternate_Languages/48_High_IQ/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/48_High_IQ/java/src/HighIQ.java b/00_Alternate_Languages/48_High_IQ/java/src/HighIQ.java
new file mode 100644
index 00000000..d77a2ec2
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/java/src/HighIQ.java
@@ -0,0 +1,153 @@
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+
+/**
+ * Game of HighIQ
+ * 

+ * Based on the Basic Game of HighIQ Here: + * https://github.com/coding-horror/basic-computer-games/blob/main/48_High_IQ/highiq.bas + * + * No additional functionality has been added + */ +public class HighIQ { + + //Game board, as a map of position numbers to their values + private final Map board; + + //Output stream + private final PrintStream out; + + //Input scanner to use + private final Scanner scanner; + + + public HighIQ(Scanner scanner) { + out = System.out; + this.scanner = scanner; + board = new HashMap<>(); + + //Set of all locations to put initial pegs on + int[] locations = new int[]{ + 13, 14, 15, 22, 23, 24, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 42, 43, 44, 47, 48, 49, 50, 51, 52, 53, 58, 59, 60, 67, 68, 69 + }; + + for (int i : locations) { + board.put(i, true); + } + + board.put(41, false); + } + + /** + * Plays the actual game, from start to finish. + */ + public void play() { + do { + printBoard(); + while (!move()) { + out.println("ILLEGAL MOVE, TRY AGAIN..."); + } + } while (!isGameFinished()); + + int pegCount = 0; + for (Integer key : board.keySet()) { + if (board.getOrDefault(key, false)) { + pegCount++; + } + } + + out.println("YOU HAD " + pegCount + " PEGS REMAINING"); + + if (pegCount == 1) { + out.println("BRAVO! YOU MADE A PERFECT SCORE!"); + out.println("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!"); + } + } + + /** + * Makes an individual move + * @return True if the move was valid, false if the user made an error and the move is invalid + */ + public boolean move() { + out.println("MOVE WHICH PIECE"); + int from = scanner.nextInt(); + + //using the getOrDefault, which will make the statement false if it is an invalid position + if (!board.getOrDefault(from, false)) { + return false; + } + + out.println("TO WHERE"); + int to = scanner.nextInt(); + + if (board.getOrDefault(to, true)) { + return false; + } + + //Do nothing if they are the same + if (from == to) { + return true; + } + + //using the difference to check if the relative locations are valid + int difference = Math.abs(to - from); + if (difference != 2 && difference != 18) { + return false; + } + + //check if there is a peg between from and to + if (!board.getOrDefault((to + from) / 2, false)) { + return false; + } + + //Actually move + board.put(from,false); + board.put(to,true); + board.put((from + to) / 2, false); + + return true; + } + + /** + * Checks if the game is finished + * @return True if there are no more moves, False otherwise + */ + public boolean isGameFinished() { + for (Integer key : board.keySet()) { + if (board.get(key)) { + //Spacing is either 1 or 9 + //Looking to the right and down from every point, checking for both directions of movement + for (int space : new int[]{1, 9}) { + Boolean nextToPeg = board.getOrDefault(key + space, false); + Boolean hasMovableSpace = !board.getOrDefault(key - space, true) || !board.getOrDefault(key + space * 2, true); + if (nextToPeg && hasMovableSpace) { + return false; + } + } + } + } + return true; + } + + public void printBoard() { + for (int i = 0; i < 7; i++) { + for (int j = 11; j < 18; j++) { + out.print(getChar(j + 9 * i)); + } + out.println(); + } + } + + private char getChar(int position) { + Boolean value = board.get(position); + if (value == null) { + return ' '; + } else if (value) { + return '!'; + } else { + return 'O'; + } + } +} diff --git a/00_Alternate_Languages/48_High_IQ/java/src/HighIQGame.java b/00_Alternate_Languages/48_High_IQ/java/src/HighIQGame.java new file mode 100644 index 00000000..43400fb3 --- /dev/null +++ b/00_Alternate_Languages/48_High_IQ/java/src/HighIQGame.java @@ -0,0 +1,37 @@ +import java.util.Scanner; + +public class HighIQGame { + public static void main(String[] args) { + + printInstructions(); + + Scanner scanner = new Scanner(System.in); + do { + new HighIQ(scanner).play(); + System.out.println("PLAY AGAIN (YES OR NO)"); + } while(scanner.nextLine().equalsIgnoreCase("yes")); + } + + public static void printInstructions() { + System.out.println("\t\t\t H-I-Q"); + System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("HERE IS THE BOARD:"); + System.out.println(" ! ! !"); + System.out.println(" 13 14 15\n"); + System.out.println(" ! ! !"); + System.out.println(" 22 23 24\n"); + System.out.println("! ! ! ! ! ! !"); + System.out.println("29 30 31 32 33 34 35\n"); + System.out.println("! ! ! ! ! ! !"); + System.out.println("38 39 40 41 42 43 44\n"); + System.out.println("! ! ! ! ! ! !"); + System.out.println("47 48 49 50 51 52 53\n"); + System.out.println(" ! ! !"); + System.out.println(" 58 59 60\n"); + System.out.println(" ! ! !"); + System.out.println(" 67 68 69"); + System.out.println("TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD"); + System.out.println("WILL BE USED DURING PLAY. REFER TO THE ABOVE ONE FOR PEG"); + System.out.println("NUMBERS. OK, LET'S BEGIN."); + } +} diff --git a/00_Alternate_Languages/48_High_IQ/javascript/README.md b/00_Alternate_Languages/48_High_IQ/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/48_High_IQ/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/48_High_IQ/javascript/highiq.html b/00_Alternate_Languages/48_High_IQ/javascript/highiq.html new file mode 100644 index 00000000..03ea2f26 --- /dev/null +++ b/00_Alternate_Languages/48_High_IQ/javascript/highiq.html @@ -0,0 +1,9 @@ + + +H-I-Q + + +


+
+
+
diff --git a/00_Alternate_Languages/48_High_IQ/javascript/highiq.js b/00_Alternate_Languages/48_High_IQ/javascript/highiq.js
new file mode 100644
index 00000000..e3b4f1b0
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/javascript/highiq.js
@@ -0,0 +1,244 @@
+// H-I-Q
+//
+// 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 b = [];
+var t = [];
+var m = [,13,14,15,
+          22,23,24,
+    29,30,31,32,33,34,35,
+    38,39,40,41,42,43,44,
+    47,48,49,50,51,52,53,
+          58,59,60,
+          67,68,69];
+var z;
+var p;
+
+//
+// Print board
+//
+function print_board()
+{
+    for (x = 1; x <= 9; x++) {
+        str = "";
+        for (y = 1; y <= 9; y++) {
+            if (x == 1 || x == 9 || y == 1 || y == 9)
+                continue;
+            if (x == 4 || x == 5 || x == 6 || y == 4 || y == 5 || y == 6) {
+                while (str.length < y * 2)
+                    str += " ";
+                if (t[x][y] == 5)
+                    str += "!";
+                else
+                    str += "O";
+            }
+        }
+        print(str + "\n");
+    }
+}
+
+//
+// Update board
+//
+function update_board()
+{
+    c = 1;
+    for (var x = 1; x <= 9; x++) {
+        for (var y = 1; y <= 9; y++, c++) {
+            if (c != z)
+                continue;
+            if (c + 2 == p) {
+                if (t[x][y + 1] == 0)
+                    return false;
+                t[x][y + 2] = 5;
+                t[x][y + 1] = 0;
+                b[c + 1] = -3;
+            } else if (c + 18 == p) {
+                if (t[x + 1][y] == 0)
+                    return false;
+                t[x + 2][y] = 5;
+                t[x + 1][y] = 0;
+                b[c + 9] = -3;
+            } else if (c - 2 == p) {
+                if (t[x][y - 1] == 0)
+                    return false;
+                t[x][y - 2] = 5;
+                t[x][y - 1] = 0;
+                b[c - 1] = -3;
+            } else if (c - 18 == p) {
+                if (t[x - 1][y] == 0)
+                    return false;
+                t[x - 2][y] = 5;
+                t[x - 1][y] = 0;
+                b[c - 9] = -3;
+            } else {
+                continue;
+            }
+            b[z] = -3;
+            b[p] = -7;
+            t[x][y] = 0;
+            return true;
+        }
+    }
+}
+
+//
+// Check for game over
+//
+// Rewritten because original subroutine was buggy
+//
+function check_game_over()
+{
+    f = 0;
+    for (r = 2; r <= 8; r++) {
+        for (c = 2; c <= 8; c++) {
+            if (t[r][c] != 5)
+                continue;
+            f++;
+            if (r > 3 && t[r - 1][c] == 5 && t[r - 2][c] == 0)
+                return false;
+            if (c > 3 && t[r][c - 1] == 5 && t[r][c - 2] == 0)
+                return false;
+            if (r < 7 && t[r + 1][c] == 5 && t[r + 2][c] == 0)
+                return false;
+            if (c < 7 && t[r][c + 1] == 5 && t[r][c + 2] == 0)
+                return false;
+        }
+    }
+    return true;
+}
+
+// Main program
+async function main()
+{
+    print(tab(33) + "H-I-Q\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    for (r = 0; r <= 70; r++)
+        b[r] = 0;
+    print("HERE IS THE BOARD:\n");
+    print("\n");
+    print("          !    !    !\n");
+    print("         13   14   15\n");
+    print("\n");
+    print("          !    !    !\n");
+    print("         22   23   24\n");
+    print("\n");
+    print("!    !    !    !    !    !    !\n");
+    print("29   30   31   32   33   34   35\n");
+    print("\n");
+    print("!    !    !    !    !    !    !\n");
+    print("38   39   40   41   42   43   44\n");
+    print("\n");
+    print("!    !    !    !    !    !    !\n");
+    print("47   48   49   50   51   52   53\n");
+    print("\n");
+    print("          !    !    !\n");
+    print("         58   59   60\n");
+    print("\n");
+    print("          !    !    !\n");
+    print("         67   68   69\n");
+    print("\n");
+    print("TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD\n");
+    print("WILL BE USED DURING PLAY.  REFER TO THE ABOVE ONE FOR PEG\n");
+    print("NUMBERS.  OK, LET'S BEGIN.\n");
+    while (1) {
+        // Set up board
+        for (r = 1; r <= 9; r++) {
+            t[r] = [];
+            for (c = 1; c <= 9; c++) {
+                if (r == 4 || r == 5 || r == 6 || c == 4 || c == 5 || c == 6 && (r != 1 && c != 1 && r != 9 && c != 9)) {
+                    t[r][c] = 5;
+                } else {
+                    t[r][c] = -5;
+                }
+            }
+        }
+        t[5][5] = 0;
+        print_board();
+        // Init secondary board
+        for (w = 1; w <= 33; w++) {
+            b[m[w]] = -7;
+        }
+        b[41] = -3;
+        // Input move and check on legality
+        do {
+            while (1) {
+                print("MOVE WHICH PIECE");
+                z = parseInt(await input());
+                if (b[z] == -7) {
+                    print("TO WHERE");
+                    p = parseInt(await input());
+                    if (p != z
+                        && b[p] != 0
+                        && b[p] != -7
+                        && (z + p) % 2 == 0
+                        && (Math.abs(z - p) - 2) * (Math.abs(z - p) - 18) == 0
+                        && update_board())
+                        break;
+                }
+                print("ILLEGAL MOVE, TRY AGAIN...\n");
+            }
+            print_board();
+        } while (!check_game_over()) ;
+        // Game is over
+        print("THE GAME IS OVER.\n");
+        print("YOU HAD " + f + " PIECES REMAINING.\n");
+        if (f == 1) {
+            print("BRAVO!  YOU MADE A PERFECT SCORE!\n");
+            print("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!\n");
+        }
+        print("\n");
+        print("PLAY AGAIN (YES OR NO)");
+        str = await input();
+        if (str == "NO")
+            break;
+    }
+    print("\n");
+    print("SO LONG FOR NOW.\n");
+    print("\n");
+}
+
+main();
diff --git a/24_Chemist/pascal/README.md b/00_Alternate_Languages/48_High_IQ/pascal/README.md
similarity index 100%
rename from 24_Chemist/pascal/README.md
rename to 00_Alternate_Languages/48_High_IQ/pascal/README.md
diff --git a/00_Alternate_Languages/48_High_IQ/perl/README.md b/00_Alternate_Languages/48_High_IQ/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/48_High_IQ/python/High_IQ.py b/00_Alternate_Languages/48_High_IQ/python/High_IQ.py
new file mode 100644
index 00000000..b5c648d9
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/python/High_IQ.py
@@ -0,0 +1,197 @@
+def new_board():
+    # Using a dictionary in python to store the board, since we are not including all numbers within a given range.
+    board = {}
+    for i in [
+        13,
+        14,
+        15,
+        22,
+        23,
+        24,
+        29,
+        30,
+        31,
+        32,
+        33,
+        34,
+        35,
+        38,
+        39,
+        40,
+        42,
+        43,
+        44,
+        47,
+        48,
+        49,
+        50,
+        51,
+        52,
+        53,
+        58,
+        59,
+        60,
+        67,
+        68,
+        69,
+    ]:
+        board[i] = "!"
+    board[41] = "O"
+    return board
+
+
+def print_instructions():
+    print(
+        """
+HERE IS THE BOARD:
+
+          !    !    !
+         13   14   15
+
+          !    !    !
+         22   23   24
+
+!    !    !    !    !    !    !
+29   30   31   32   33   34   35
+
+!    !    !    !    !    !    !
+38   39   40   41   42   43   44
+
+!    !    !    !    !    !    !
+47   48   49   50   51   52   53
+
+          !    !    !
+         58   59   60
+
+          !    !    !
+         67   68   69
+
+TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD
+WILL BE USED DURING PLAY.  REFER TO THE ABOVE ONE FOR PEG
+NUMBERS.  OK, LET'S BEGIN.
+    """
+    )
+
+
+def print_board(board):
+    """Prints the boards using indexes in the passed parameter"""
+    print(" " * 2 + board[13] + board[14] + board[15])
+    print(" " * 2 + board[22] + board[23] + board[24])
+    print(
+        board[29]
+        + board[30]
+        + board[31]
+        + board[32]
+        + board[33]
+        + board[34]
+        + board[35]
+    )
+    print(
+        board[38]
+        + board[39]
+        + board[40]
+        + board[41]
+        + board[42]
+        + board[43]
+        + board[44]
+    )
+    print(
+        board[47]
+        + board[48]
+        + board[49]
+        + board[50]
+        + board[51]
+        + board[52]
+        + board[53]
+    )
+    print(" " * 2 + board[58] + board[59] + board[60])
+    print(" " * 2 + board[67] + board[68] + board[69])
+
+
+def play_game():
+    # Create new board
+    board = new_board()
+
+    # Main game loop
+    while not is_game_finished(board):
+        print_board(board)
+        while not move(board):
+            print("ILLEGAL MOVE! TRY AGAIN")
+
+    # Check peg count and print the user's score
+    peg_count = 0
+    for key in board.keys():
+        if board[key] == "!":
+            peg_count += 1
+
+    print("YOU HAD " + str(peg_count) + " PEGS REMAINING")
+
+    if peg_count == 1:
+        print("BRAVO! YOU MADE A PERFECT SCORE!")
+        print("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!")
+
+
+def move(board):
+    """Queries the user to move. Returns false if the user puts in an invalid input or move, returns true if the move was successful"""
+    start_input = input("MOVE WHICH PIECE? ")
+
+    if not start_input.isdigit():
+        return False
+
+    start = int(start_input)
+
+    if start not in board or board[start] != "!":
+        return False
+
+    end_input = input("TO WHERE? ")
+
+    if not end_input.isdigit():
+        return False
+
+    end = int(end_input)
+
+    if end not in board or board[end] != "O":
+        return False
+
+    difference = abs(start - end)
+    center = (end + start) / 2
+    if (
+        (difference == 2 or difference == 18)
+        and board[end] == "O"
+        and board[center] == "!"
+    ):
+        board[start] = "O"
+        board[center] = "O"
+        board[end] = "!"
+        return True
+    else:
+        return False
+
+
+def main():
+    print(" " * 33 + "H-I-Q")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print_instructions()
+    play_game()
+
+
+def is_game_finished(board):
+    # Checks all locations and whether or not a move is possible at that location.
+    for pos in board.keys():
+        if board[pos] == "!":
+            for space in [1, 9]:
+                # Checks if the next location has a peg
+                nextToPeg = ((pos + space) in board) and board[pos + space] == "!"
+                # Checks both going forward (+ location) or backwards (-location)
+                hasMovableSpace = (
+                    not ((pos - space) in board and board[pos - space] == "!")
+                ) or (
+                    not ((pos + space * 2) in board and board[pos + space * 2] == "!")
+                )
+                if nextToPeg and hasMovableSpace:
+                    return False
+    return True
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/48_High_IQ/python/README.md b/00_Alternate_Languages/48_High_IQ/python/README.md
new file mode 100644
index 00000000..bc04457a
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/python/README.md
@@ -0,0 +1,5 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
+
+[Implementation](./High_IQ.py) by [Thomas Kwashnak](https://github.com/LittleTealeaf)
diff --git a/00_Alternate_Languages/48_High_IQ/ruby/README.md b/00_Alternate_Languages/48_High_IQ/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/48_High_IQ/vbnet/HighIQ.sln b/00_Alternate_Languages/48_High_IQ/vbnet/HighIQ.sln
new file mode 100644
index 00000000..ca1f79c5
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/vbnet/HighIQ.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "HighIQ", "HighIQ.vbproj", "{18AA4FCA-2733-4BBC-B65F-68C37B8CFDAF}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{18AA4FCA-2733-4BBC-B65F-68C37B8CFDAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{18AA4FCA-2733-4BBC-B65F-68C37B8CFDAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{18AA4FCA-2733-4BBC-B65F-68C37B8CFDAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{18AA4FCA-2733-4BBC-B65F-68C37B8CFDAF}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/48_High_IQ/vbnet/HighIQ.vbproj b/00_Alternate_Languages/48_High_IQ/vbnet/HighIQ.vbproj
new file mode 100644
index 00000000..c37eb8db
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/vbnet/HighIQ.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    HighIQ
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/48_High_IQ/vbnet/README.md b/00_Alternate_Languages/48_High_IQ/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/48_High_IQ/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/49_Hockey/README.md b/00_Alternate_Languages/49_Hockey/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/49_Hockey/csharp/Hockey.csproj b/00_Alternate_Languages/49_Hockey/csharp/Hockey.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/csharp/Hockey.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/49_Hockey/csharp/Hockey.sln b/00_Alternate_Languages/49_Hockey/csharp/Hockey.sln
new file mode 100644
index 00000000..d2ca8d36
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/csharp/Hockey.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hockey", "Hockey.csproj", "{98E2914A-41D4-4931-B17F-4EAD3C98CFE1}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{98E2914A-41D4-4931-B17F-4EAD3C98CFE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{98E2914A-41D4-4931-B17F-4EAD3C98CFE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{98E2914A-41D4-4931-B17F-4EAD3C98CFE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{98E2914A-41D4-4931-B17F-4EAD3C98CFE1}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/49_Hockey/csharp/README.md b/00_Alternate_Languages/49_Hockey/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/49_Hockey/hockey.bas b/00_Alternate_Languages/49_Hockey/hockey.bas
new file mode 100644
index 00000000..f0b5a829
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/hockey.bas
@@ -0,0 +1,210 @@
+2 PRINT TAB(33);"HOCKEY"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT:PRINT:PRINT
+10 REM ROBERT PUOPOLO ALG. 1 140 MCCOWAN 6/7/73 HOCKEY
+30 LET X=1
+40 PRINT:PRINT:PRINT
+50 PRINT "WOULD YOU LIKE THE INSTRUCTIONS";:INPUT C$
+55 PRINT
+60 IF C$="NO" THEN 90
+65 IF C$="YES" THEN 80
+70 PRINT "ANSWER YES OR NO!!":GOTO 50
+80 GOTO 1720
+90 DIM A$(7),B$(7),H(20),T(5),T1(5),T2(5),T3(5)
+100 PRINT "ENTER THE TWO TEAMS";:INPUT A$(7),B$(7)
+105 PRINT
+110 PRINT "ENTER THE NUMBER OF MINUTES IN A GAME";:INPUT T6
+115 PRINT
+120 IF T6<1 THEN 110:PRINT
+130 PRINT "WOULD THE " A$(7) " COACH ENTER HIS TEAM"
+135 PRINT
+140 FOR I=1 TO 6:PRINT "PLAYER"I;:INPUT A$(I):NEXT I:PRINT
+150 PRINT "WOULD THE " B$(7) " COACH DO THE SAME"
+155 PRINT
+160 FOR T=1 TO 6:PRINT "PLAYER"T;:INPUT B$(T):NEXT T:PRINT
+170 PRINT "INPUT THE REFEREE FOR THIS GAME";:INPUT R$
+180 PRINT:PRINT TAB(10);A$(7) " STARTING LINEUP"
+190 FOR T=1 TO 6:PRINT A$(T):NEXT T
+200 PRINT:PRINT TAB(10);B$(7)" STARTING LINEUP"
+210 FOR T=1 TO 6:PRINT B$(T):NEXT T:PRINT
+220 PRINT "WE'RE READY FOR TONIGHTS OPENING FACE-OFF."
+230 PRINT R$ " WILL DROP THE PUCK BETWEEN " A$(2) " AND " B$(2)
+240 FOR L=1 TO T6:IF L=1 THEN 260
+250 PRINT "AND WE'RE READY FOR THE FACE-OFF"
+260 C=INT(2*RND(X))+1:ON C GOTO 270,280
+270 PRINT A$(7) " HAS CONTROL OF THE PUCK":GOTO 290
+280 PRINT B$(7) " HAS CONTROL."
+290 PRINT "PASS";:INPUT P:FOR N=1 TO 3:H(N)=0:NEXT N
+300 IF P<0 THEN 290
+305 IF P>3 THEN 290
+310 FOR J=1 TO (P+2)
+320 H(J)=INT(5*RND(X))+1
+330 NEXT J:IF H(J-1)=H(J-2) THEN 310
+331 IF P+2<3 THEN 350
+335 IF H(J-1)=H(J-3) THEN 310
+340 IF H(J-2)=H(J-3) THEN 310
+350 IF P=0 THEN 360
+355 GOTO 490
+360 INPUT "SHOT";S:IF S<1 THEN 360
+365 IF S>4 THEN 360
+370 ON C GOTO 380,480
+380 PRINT A$(H(J-1));:G=H(J-1):G1=0:G2=0
+390 ON S GOTO 400,420,440,460
+400 PRINT " LET'S A BOOMER GO FROM THE RED LINE!!"
+410 Z=10:GOTO 890
+420 PRINT " FLIPS A WRISTSHOT DOWN THE ICE"
+440 PRINT " BACKHANDS ONE IN ON THE GOALTENDER"
+450 Z=25:GOTO 890
+460 PRINT " SNAPS A LONG FLIP SHOT"
+470 Z=17:GOTO 890
+480 PRINT B$(H(J-1));:G1=0:G2=0:G=H(J-1):GOTO 390
+490 ON C GOTO 500,640
+500 ON P GOTO 510,540,570
+510 PRINT A$(H(J-2)) " LEADS " A$(H(J-1)) " WITH A PERFECT PASS."
+520 PRINT A$(H(J-1)) " CUTTING IN!!!"
+530 G=H(J-1):G1=H(J-2):G2=0:Z1=3:GOTO 770
+540 PRINT A$(H(J-2)) " GIVES TO A STREAKING " A$(H(J-1))
+550 PRINT A$(H(J-3)) " COMES DOWN ON " B$(5) " AND " B$(4)
+560 G=H(J-3):G1=H(J-1):G2=H(J-2):Z1=2:GOTO 770
+570 PRINT "OH MY GOD!! A ' 4 ON 2 ' SITUATION"
+580 PRINT A$(H(J-3)) " LEADS " A$(H(J-2))
+590 PRINT A$(H(J-2)) " IS WHEEELING THROUGH CENTER."
+600 PRINT A$(H(J-2)) " GIVES AND GOES WITH " A$(H(J-1))
+610 PRINT "PRETTY PASSING!"
+620 PRINT A$(H(J-1)) " DROPS IT TO " A$(H(J-4))
+630 G=H(J-4):G1=H(J-1):G2=H(J-2):Z1=1:GOTO 770
+640 ON P GOTO 650,670,720
+650 PRINT B$(H(J-1)) " HITS " B$(H(J-2)) " FLYING DOWN THE LEFT SIDE"
+660 G=H(J-2):G1=H(J-1):G2=0:Z1=3:GOTO 770
+670 PRINT "IT'S A ' 3 ON 2 '!"
+680 PRINT "ONLY " A$(4) " AND " A$(5) " ARE BACK."
+690 PRINT B$(H(J-2)) " GIVES OFF TO " B$(H(J-1))
+700 PRINT B$(H(J-1)) " DROPS TO " B$(H(J-3))
+710 G=H(J-3):G1=H(J-1):G2=H(J-2):Z1=2:GOTO 770
+720 PRINT " A ' 3 ON 2 ' WITH A ' TRAILER '!"
+730 PRINT B$(H(J-4)) " GIVES TO " B$(H(J-2)) " WHO SHUFFLES IT OFF TO"
+740 PRINT B$(H(J-1)) " WHO FIRES A WING TO WING PASS TO "
+750 PRINT B$(H(J-3)) " AS HE CUTS IN ALONE!!"
+760 G=H(J-3):G1=H(J-1):G2=H(J-2):Z1=1:GOTO 770
+770 PRINT "SHOT";:INPUT S:IF S>4 THEN 770:IF S<1 THEN 770
+780 ON C GOTO 790,880
+790 PRINT A$(G);:ON S GOTO 800,820,840,860
+800 PRINT " LET'S A BIG SLAP SHOT GO!!"
+810 Z=4:Z=Z+Z1:GOTO 890
+820 PRINT " RIPS A WRIST SHOT OFF"
+830 Z=2:Z=Z+Z1:GOTO 890
+840 PRINT " GETS A BACKHAND OFF"
+850 Z=3:Z=Z+Z1:GOTO 890
+860 PRINT " SNAPS OFF A SNAP SHOT"
+870 Z=2:Z=Z+Z1:GOTO 890
+880 PRINT B$(G);:ON S GOTO 800,820,840,860
+890 PRINT "AREA";:INPUT A:IF A<1 THEN 890
+895 IF A>4 THEN 890
+900 ON C GOTO 910,920
+910 S2=S2+1:GOTO 930
+920 S3=S3+1
+930 A1=INT(4*RND(X))+1:IF A<>A1 THEN 1200
+940 H(20)=INT(100*RND(X))+1
+950 IF INT(H(20)/Z)=H(20)/Z THEN 1160
+960 ON C GOTO 970,980
+970 PRINT "GOAL " A$(7):H(9)=H(9)+1:GOTO 990
+980 PRINT "SCORE " B$(7):H(8)=H(8)+1
+990 FOR B1=1 TO 25:PRINT CHR$(7);:NEXT B1:PRINT
+1000 PRINT "SCORE: ";:IF H(8)>H(9) THEN 1020
+1010 PRINT A$(7)":";H(9),B$(7)":";H(8):GOTO 1030
+1020 PRINT B$(7)":";H(8),A$(7)":";H(9)
+1030 ON C GOTO 1040,1100
+1040 PRINT "GOAL SCORED BY: " A$(G):IF G1=0 THEN 1070
+1050 IF G2=0 THEN 1080
+1060 PRINT " ASSISTED BY: " A$(G1) " AND " A$(G2):GOTO 1090
+1070 PRINT " UNASSISTED.":GOTO 1090
+1080 PRINT " ASSISTED BY: " A$(G1)
+1090 T(G)=T(G)+1:T1(G1)=T1(G1)+1:T1(G2)=T1(G2)+1:GOTO 1540
+1100 PRINT "GOAL SCORED BY: " B$(G);
+1110 IF G1=0 THEN 1130
+1115 IF G2=0 THEN 1140
+1120 PRINT " ASSISTED BY: " B$(G1) " AND " B$(G2):GOTO 1150
+1130 PRINT " UNASSISTED":GOTO 1150
+1140 PRINT " ASSISTED BY: " B$(G1):GOTO 1150
+1150 T2(G)=T2(G)+1:T3(G1)=T3(G1)+1:T3(G2)=T3(G2)+1:GOTO 1540
+1160 A2=INT(100*RND(X))+1:IF INT(A2/4)=A2/4 THEN 1170
+1165 GOTO 1200
+1170 ON C GOTO 1180,1190
+1180 PRINT "SAVE " B$(6) " --  REBOUND":GOTO 940
+1190 PRINT "SAVE " A$(6) " --  FOLLOW UP":GOTO 940
+1200 S1=INT(6*RND(X))+1
+1210 ON C GOTO 1220,1380
+1220 ON S1 GOTO 1230,1260,1290,1300,1330,1350
+1230 PRINT "KICK SAVE AND A BEAUTY BY " B$(6)
+1240 PRINT "CLEARED OUT BY " B$(3)
+1250 GOTO 260
+1260 PRINT "WHAT A SPECTACULAR GLOVE SAVE BY " B$(6)
+1270 PRINT "AND " B$(6) " GOLFS IT INTO THE CROWD"
+1280 GOTO 1540
+1290 PRINT "SKATE SAVE ON A LOW STEAMER BY " B$(6):GOTO 260
+1300 PRINT "PAD SAVE BY " B$(6) " OFF THE STICK"
+1310 PRINT "OF "A$(G) " AND " B$(6) " COVERS UP"
+1320 GOTO 1540
+1330 PRINT "WHISTLES ONE OVER THE HEAD OF " B$(6)
+1340 GOTO 260
+1350 PRINT B$(6) " MAKES A FACE SAVE!! AND HE IS HURT"
+1360 PRINT "THE DEFENSEMAN " B$(5) " COVERS UP FOR HIM"
+1370 GOTO 1540
+1380 ON S1 GOTO 1390,1410,1440,1470,1490,1520
+1390 PRINT "STICK SAVE BY " A$(6)
+1400 PRINT "AND CLEARED OUT BY " A$(4):GOTO 260
+1410 PRINT "OH MY GOD!! " B$(G) " RATTLES ONE OFF THE POST"
+1420 PRINT "TO THE RIGHT OF " A$(6) " AND " A$(6) " COVERS ";
+1430 PRINT "ON THE LOOSE PUCK!":GOTO 1540
+1440 PRINT "SKATE SAVE BY " A$(6)
+1450 PRINT A$(6) " WHACKS THE LOOSE PUCK INTO THE STANDS"
+1460 GOTO 1540
+1470 PRINT "STICK SAVE BY " A$(6) " AND HE CLEARS IT OUT HIMSELF"
+1480 GOTO 260
+1490 PRINT "KICKED OUT BY " A$(6)
+1500 PRINT "AND IT REBOUNDS ALL THE WAY TO CENTER ICE"
+1510 GOTO 260
+1520 PRINT "GLOVE SAVE " A$(6) " AND HE HANGS ON"
+1530 GOTO 1540
+1540 NEXT L:FOR N=1 TO 30:PRINT CHR$(7);:NEXT N:PRINT "THAT'S THE SIREN"
+1550 PRINT:PRINT TAB(15);"FINAL SCORE:"
+1560 IF H(8)>H(9) THEN 1580
+1570 PRINT A$(7)":";H(9),B$(7)":";H(8):GOTO 1590
+1580 PRINT B$(7)":";H(8),A$(7)":";H(9)
+1590 PRINT: PRINT TAB(10);"SCORING SUMMARY":PRINT
+1600 PRINT TAB(25);A$(7)
+1610 PRINT TAB(5);"NAME";TAB(20);"GOALS";TAB(35);"ASSISTS"
+1620 PRINT TAB(5);"----";TAB(20);"-----";TAB(35);"-------"
+1630 FOR I=1 TO 5:PRINT TAB(5);A$(I);TAB(21);T(I);TAB(36);T1(I)
+1640 NEXT I:PRINT
+1650 PRINT TAB(25);B$(7)
+1660 PRINT TAB(5);"NAME";TAB(20);"GOALS";TAB(35);"ASSISTS"
+1670 PRINT TAB(5);"----";TAB(20);"-----";TAB(35);"-------"
+1680 FOR T=1 TO 5:PRINT TAB(5);B$(T);TAB(21);T2(T);TAB(36);T3(T)
+1690 NEXT T:PRINT
+1700 PRINT "SHOTS ON NET":PRINT A$(7)":";S2:PRINT B$(7)":";S3
+1710 END
+1720 PRINT: PRINT "THIS IS A SIMULATED HOCKEY GAME."
+1730 PRINT "QUESTION     RESPONSE"
+1740 PRINT "PASS         TYPE IN THE NUMBER OF PASSES YOU WOULD"
+1750 PRINT "             LIKE TO MAKE, FROM 0 TO 3."
+1760 PRINT "SHOT         TYPE THE NUMBER CORRESPONDING TO THE SHOT"
+1770 PRINT "             YOU WANT TO MAKE.  ENTER:"
+1780 PRINT "             1 FOR A SLAPSHOT"
+1790 PRINT "             2 FOR A WRISTSHOT"
+1800 PRINT "             3 FOR A BACKHAND"
+1810 PRINT "             4 FOR A SNAP SHOT"
+1820 PRINT "AREA         TYPE IN THE NUMBER CORRESPONDING TO"
+1830 PRINT "             THE AREA YOU ARE AIMING AT.  ENTER:"
+1840 PRINT "             1 FOR UPPER LEFT HAND CORNER"
+1850 PRINT "             2 FOR UPPER RIGHT HAND CORNER"
+1860 PRINT "             3 FOR LOWER LEFT HAND CORNER"
+1870 PRINT "             4 FOR LOWER RIGHT HAND CORNER"
+1880 PRINT
+1890 PRINT "AT THE START OF THE GAME, YOU WILL BE ASKED FOR THE NAMES"
+1900 PRINT "OF YOUR PLAYERS.  THEY ARE ENTERED IN THE ORDER: "
+1910 PRINT "LEFT WING, CENTER, RIGHT WING, LEFT DEFENSE,"
+1920 PRINT "RIGHT DEFENSE, GOALKEEPER.  ANY OTHER INPUT REQUIRED WILL"
+1930 PRINT "HAVE EXPLANATORY INSTRUCTIONS."
+1940 GOTO 90
+1950 END
diff --git a/00_Alternate_Languages/49_Hockey/java/README.md b/00_Alternate_Languages/49_Hockey/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/49_Hockey/javascript/README.md b/00_Alternate_Languages/49_Hockey/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/49_Hockey/javascript/hockey.html b/00_Alternate_Languages/49_Hockey/javascript/hockey.html
new file mode 100644
index 00000000..fb26a5c6
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/javascript/hockey.html
@@ -0,0 +1,9 @@
+
+
+HOCKEY
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/49_Hockey/javascript/hockey.js b/00_Alternate_Languages/49_Hockey/javascript/hockey.js
new file mode 100644
index 00000000..d58a56a9
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/javascript/hockey.js
@@ -0,0 +1,464 @@
+// HOCKEY
+//
+// 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 as = [];
+var bs = [];
+var ha = [];
+var ta = [];
+var t1 = [];
+var t2 = [];
+var t3 = [];
+
+// Main program
+async function main()
+{
+    print(tab(33) + "HOCKEY\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    // Robert Puopolo Alg. 1 140 McCowan 6/7/73 Hockey
+    for (c = 0; c <= 20; c++)
+        ha[c] = 0;
+    for (c = 1; c <= 5; c++) {
+        ta[c] = 0;
+        t1[c] = 0;
+        t2[c] = 0;
+        t3[c] = 0;
+    }
+    x = 1;
+    print("\n");
+    print("\n");
+    print("\n");
+    while (1) {
+        print("WOULD YOU LIKE THE INSTRUCTIONS");
+        str = await input();
+        print("\n");
+        if (str == "YES" || str == "NO")
+            break;
+        print("ANSWER YES OR NO!!\n");
+    }
+    if (str == "YES") {
+        print("\n");
+        print("THIS IS A SIMULATED HOCKEY GAME.\n");
+        print("QUESTION     RESPONSE\n");
+        print("PASS         TYPE IN THE NUMBER OF PASSES YOU WOULD\n");
+        print("             LIKE TO MAKE, FROM 0 TO 3.\n");
+        print("SHOT         TYPE THE NUMBER CORRESPONDING TO THE SHOT\n");
+        print("             YOU WANT TO MAKE.  ENTER:\n");
+        print("             1 FOR A SLAPSHOT\n");
+        print("             2 FOR A WRISTSHOT\n");
+        print("             3 FOR A BACKHAND\n");
+        print("             4 FOR A SNAP SHOT\n");
+        print("AREA         TYPE IN THE NUMBER CORRESPONDING TO\n");
+        print("             THE AREA YOU ARE AIMING AT.  ENTER:\n");
+        print("             1 FOR UPPER LEFT HAND CORNER\n");
+        print("             2 FOR UPPER RIGHT HAND CORNER\n");
+        print("             3 FOR LOWER LEFT HAND CORNER\n");
+        print("             4 FOR LOWER RIGHT HAND CORNER\n");
+        print("\n");
+        print("AT THE START OF THE GAME, YOU WILL BE ASKED FOR THE NAMES\n");
+        print("OF YOUR PLAYERS.  THEY ARE ENTERED IN THE ORDER: \n");
+        print("LEFT WING, CENTER, RIGHT WING, LEFT DEFENSE,\n");
+        print("RIGHT DEFENSE, GOALKEEPER.  ANY OTHER INPUT REQUIRED WILL\n");
+        print("HAVE EXPLANATORY INSTRUCTIONS.\n");
+    }
+    print("ENTER THE TWO TEAMS");
+    str = await input();
+    c = str.indexOf(",");
+    as[7] = str.substr(0, c);
+    bs[7] = str.substr(c + 1);
+    print("\n");
+    do {
+        print("ENTER THE NUMBER OF MINUTES IN A GAME");
+        t6 = parseInt(await input());
+        print("\n");
+    } while (t6 < 1) ;
+    print("\n");
+    print("WOULD THE " + as[7] + " COACH ENTER HIS TEAM\n");
+    print("\n");
+    for (i = 1; i <= 6; i++) {
+        print("PLAYER " + i + " ");
+        as[i] = await input();
+    }
+    print("\n");
+    print("WOULD THE " + bs[7] + " COACH DO THE SAME\n");
+    print("\n");
+    for (t = 1; t <= 6; t++) {
+        print("PLAYER " + t + " ");
+        bs[t] = await input();
+    }
+    print("\n");
+    print("INPUT THE REFEREE FOR THIS GAME");
+    rs = await input();
+    print("\n");
+    print(tab(10) + as[7] + " STARTING LINEUP\n");
+    for (t = 1; t <= 6; t++) {
+        print(as[t] + "\n");
+    }
+    print("\n");
+    print(tab(10) + bs[7] + " STARTING LINEUP\n");
+    for (t = 1; t <= 6; t++) {
+        print(bs[t] + "\n");
+    }
+    print("\n");
+    print("WE'RE READY FOR TONIGHTS OPENING FACE-OFF.\n");
+    print(rs + " WILL DROP THE PUCK BETWEEN " + as[2] + " AND " + bs[2] + "\n");
+    s2 = 0;
+    s3 = 0;
+    for (l = 1; l <= t6; l++) {
+        c = Math.floor(2 * Math.random()) + 1;
+        if (c == 1)
+            print(as[7] + " HAS CONTROL OF THE PUCK\n");
+        else
+            print(bs[7] + " HAS CONTROL.\n");
+        do {
+
+            print("PASS");
+            p = parseInt(await input());
+            for (n = 1; n <= 3; n++)
+                ha[n] = 0;
+        } while (p < 0 || p > 3) ;
+        do {
+            for (j = 1; j <= p + 2; j++)
+                ha[j] = Math.floor(5 * Math.random()) + 1;
+        } while (ha[j - 1] == ha[j - 2] || (p + 2 >= 3 && (ha[j - 1] == ha[j - 3] || ha[j - 2] == ha[j - 3]))) ;
+        if (p == 0) {
+            while (1) {
+                print("SHOT");
+                s = parseInt(await input());
+                if (s >= 1 && s <= 4)
+                    break;
+            }
+            if (c == 1) {
+                print(as[ha[j - 1]]);
+                g = ha[j - 1];
+                g1 = 0;
+                g2 = 0;
+            } else {
+                print(bs[ha[j - 1]]);
+                g2 = 0;
+                g2 = 0;
+                g = ha[j - 1];
+            }
+            switch (s) {
+                case 1:
+                    print(" LET'S A BOOMER GO FROM THE RED LINE!!\n");
+                    z = 10;
+                    break;
+                case 2:
+                    print(" FLIPS A WRISTSHOT DOWN THE ICE\n");
+                    // Probable missing line 430 in original
+                case 3:
+                    print(" BACKHANDS ONE IN ON THE GOALTENDER\n");
+                    z = 25;
+                    break;
+                case 4:
+                    print(" SNAPS A LONG FLIP SHOT\n");
+                    z = 17;
+                    break;
+            }
+        } else {
+            if (c == 1) {
+                switch (p) {
+                    case 1:
+                        print(as[ha[j - 2]] + " LEADS " + as[ha[j - 1]] + " WITH A PERFECT PASS.\n");
+                        print(as[ha[j - 1]] + " CUTTING IN!!!\n");
+                        g = ha[j - 1];
+                        g1 = ha[j - 2];
+                        g2 = 0;
+                        z1 = 3;
+                        break;
+                    case 2:
+                        print(as[ha[j - 2]] + " GIVES TO A STREAKING " + as[ha[j - 1]] + "\n");
+                        print(as[ha[j - 3]] + " COMES DOWN ON " + bs[5] + " AND " + bs[4] + "\n");
+                        g = ha[j - 3];
+                        g1 = ha[j - 1];
+                        g2 = ha[j - 2];
+                        z1 = 2;
+                        break;
+                    case 3:
+                        print("OH MY GOD!! A ' 4 ON 2 ' SITUATION\n");
+                        print(as[ha[j - 3]] + " LEADS " + as[ha[j - 2]] + "\n");
+                        print(as[ha[j - 2]] + " IS WHEELING THROUGH CENTER.\n");
+                        print(as[ha[j - 2]] + " GIVES AND GOEST WITH " + as[ha[j - 1]] + "\n");
+                        print("PRETTY PASSING!\n");
+                        print(as[ha[j - 1]] + " DROPS IT TO " + as[ha[j - 4]] + "\n");
+                        g = ha[j - 4];
+                        g1 = ha[j - 1];
+                        g2 = ha[j - 2];
+                        z1 = 1;
+                        break;
+                }
+            } else {
+                switch (p) {
+                    case 1:
+                        print(bs[ha[j - 1]] + " HITS " + bs[ha[j - 2]] + " FLYING DOWN THE LEFT SIDE\n");
+                        g = ha[j - 2];
+                        g1 = ha[j - 1];
+                        g2 = 0;
+                        z1 = 3;
+                        break;
+                    case 2:
+                        print("IT'S A ' 3 ON 2 '!\n");
+                        print("ONLY " + as[4] + " AND " + as[5] + " ARE BACK.\n");
+                        print(bs[ha[j - 2]] + " GIVES OFF TO " + bs[ha[j - 1]] + "\n");
+                        print(bs[ha[j - 1]] + " DROPS TO " + bs[ha[j - 3]] + "\n");
+                        g = ha[j - 3];
+                        g1 = ha[j - 1];
+                        g2 = ha[j - 2];
+                        z1 = 2;
+                        break;
+                    case 3:
+                        print(" A '3 ON 2 ' WITH A ' TRAILER '!\n");
+                        print(bs[ha[j - 4]] + " GIVES TO " + bs[ha[j - 2]] + " WHO SHUFFLES IT OFF TO\n");
+                        print(bs[ha[j - 1]] + " WHO FIRES A WING TO WING PASS TO \n");
+                        print(bs[ha[j - 3]] + " AS HE CUTS IN ALONE!!\n");
+                        g = ha[j - 3];
+                        g1 = ha[j - 1];
+                        g2 = ha[j - 2];
+                        z1 = 1;
+                        break;
+                }
+            }
+            do {
+                print("SHOT");
+                s = parseInt(await input());
+            } while (s < 1 || s > 4) ;
+            if (c == 1)
+                print(as[g]);
+            else
+                print(bs[g]);
+            switch (s) {
+                case 1:
+                    print(" LET'S A BIG SLAP SHOT GO!!\n");
+                    z = 4;
+                    z += z1;
+                    break;
+                case 2:
+                    print(" RIPS A WRIST SHOT OFF\n");
+                    z = 2;
+                    z += z1;
+                    break;
+                case 3:
+                    print(" GETS A BACKHAND OFF\n");
+                    z = 3;
+                    z += z1;
+                    break;
+                case 4:
+                    print(" SNAPS OFF A SNAP SHOT\n");
+                    z = 2;
+                    z += z1;
+                    break;
+            }
+        }
+        do {
+            print("AREA");
+            a = parseInt(await input());
+        } while (a < 1 || a > 4) ;
+        if (c == 1)
+            s2++;
+        else
+            s3++;
+        a1 = Math.floor(4 * Math.random()) + 1;
+        if (a == a1) {
+            while (1) {
+                ha[20] = Math.floor(100 * Math.random()) + 1;
+                if (ha[20] % z != 0)
+                    break;
+                a2 = Math.floor(100 * Math.random()) + 1;
+                if (a2 % 4 == 0) {
+                    if (c == 1)
+                        print("SAVE " + bs[6] + " --  REBOUND\n");
+                    else
+                        print("SAVE " + as[6] + " --  FOLLOW up\n");
+                    continue;
+                } else {
+                    a1 = a + 1;  // So a != a1
+                }
+            }
+            if (ha[20] % z != 0) {
+                if (c == 1) {
+                    print("GOAL " + as[7] + "\n");
+                    ha[9]++;
+                } else {
+                    print("SCORE " + bs[7] + "\n");
+                    ha[8]++;
+                }
+                // Bells in origninal
+                print("\n");
+                print("SCORE: ");
+                if (ha[8] <= ha[9]) {
+                    print(as[7] + ": " + ha[9] + "\t" + bs[7] + ": " + ha[8] + "\n");
+                } else {
+                    print(bs[7] + ": " + ha[8] + "\t" + as[7] + ": " + ha[9] + "\n");
+                }
+                if (c == 1) {
+                    print("GOAL SCORED BY: " + as[g] + "\n");
+                    if (g1 != 0) {
+                        if (g2 != 0) {
+                            print(" ASSISTED BY: " + as[g1] + " AND " + as[g2] + "\n");
+                        } else {
+                            print(" ASSISTED BY: " + as[g1] + "\n");
+                        }
+                    } else {
+                        print(" UNASSISTED.\n");
+                    }
+                    ta[g]++;
+                    t1[g1]++;
+                    t1[g2]++;
+                    // 1540
+                } else {
+                    print("GOAL SCORED BY: " + bs[g] + "\n");
+                    if (g1 != 0) {
+                        if (g2 != 0) {
+                            print(" ASSISTED BY: " + bs[g1] + " AND " + bs[g2] + "\n");
+                        } else {
+                            print(" ASSISTED BY: " + bs[g1] + "\n");
+                        }
+                    } else {
+                        print(" UNASSISTED.\n");
+                    }
+                    t2[g]++;
+                    t3[g1]++;
+                    t3[g2]++;
+                    // 1540
+                }
+            }
+        }
+        if (a != a1) {
+            s1 = Math.floor(6 * Math.random()) + 1;
+            if (c == 1) {
+                switch (s1) {
+                    case 1:
+                        print("KICK SAVE AND A BEAUTY BY " + bs[6] + "\n");
+                        print("CLEARED OUT BY " + bs[3] + "\n");
+                        l--;
+                        continue;
+                    case 2:
+                        print("WHAT A SPECTACULAR GLOVE SAVE BY " + bs[6] + "\n");
+                        print("AND " + bs[6] + " GOLFS IT INTO THE CROWD\n");
+                        break;
+                    case 3:
+                        print("SKATE SAVE ON A LOW STEAMER BY " + bs[6] + "\n");
+                        l--;
+                        continue;
+                    case 4:
+                        print("PAD SAVE BY " + bs[6] + " OFF THE STICK\n");
+                        print("OF " + as[g] + " AND " + bs[6] + " COVERS UP\n");
+                        break;
+                    case 5:
+                        print("WHISTLES ONE OVER THE HEAD OF " + bs[6] + "\n");
+                        l--;
+                        continue;
+                    case 6:
+                        print(bs[6] + " MAKES A FACE SAVE!! AND HE IS HURT\n");
+                        print("THE DEFENSEMAN " + bs[5] + " COVERS UP FOR HIM\n");
+                        break;
+                }
+            } else {
+                switch (s1) {
+                    case 1:
+                        print("STICK SAVE BY " + as[6] +"\n");
+                        print("AND CLEARED OUT BY " + as[4] + "\n");
+                        l--;
+                        continue;
+                    case 2:
+                        print("OH MY GOD!! " + bs[g] + " RATTLES ONE OFF THE POST\n");
+                        print("TO THE RIGHT OF " + as[6] + " AND " + as[6] + " COVERS ");
+                        print("ON THE LOOSE PUCK!\n");
+                        break;
+                    case 3:
+                        print("SKATE SAVE BY " + as[6] + "\n");
+                        print(as[6] + " WHACKS THE LOOSE PUCK INTO THE STANDS\n");
+                        break;
+                    case 4:
+                        print("STICK SAVE BY " + as[6] + " AND HE CLEARS IT OUT HIMSELF\n");
+                        l--;
+                        continue;
+                    case 5:
+                        print("KICKED OUT BY " + as[6] + "\n");
+                        print("AND IT REBOUNDS ALL THE WAY TO CENTER ICE\n");
+                        l--;
+                        continue;
+                    case 6:
+                        print("GLOVE SAVE " + as[6] + " AND HE HANGS ON\n");
+                        break;
+                }
+            }
+        }
+        print("AND WE'RE READY FOR THE FACE-OFF\n");
+    }
+    // Bells chime
+    print("THAT'S THE SIREN\n");
+    print("\n");
+    print(tab(15) + "FINAL SCORE:\n");
+    if (ha[8] <= ha[9]) {
+        print(as[7] + ": " + ha[9] + "\t" + bs[7] + ": " + ha[8] + "\n");
+    } else {
+        print(bs[7] + ": " + ha[8] + "\t" + as[7] + ": " + ha[9] + "\n");
+    }
+    print("\n");
+    print(tab(10) + "SCORING SUMMARY\n");
+    print("\n");
+    print(tab(25) + as[7] + "\n");
+    print("\tNAME\tGOALS\tASSISTS\n");
+    print("\t----\t-----\t-------\n");
+    for (i = 1; i <= 5; i++) {
+        print("\t" + as[i] + "\t" + ta[i] + "\t" + t1[i] + "\n");
+    }
+    print("\n");
+    print(tab(25) + bs[7] + "\n");
+    print("\tNAME\tGOALS\tASSISTS\n");
+    print("\t----\t-----\t-------\n");
+    for (t = 1; t <= 5; t++) {
+        print("\t" + bs[t] + "\t" + t2[t] + "\t" + t3[t] + "\n");
+    }
+    print("\n");
+    print("SHOTS ON NET\n");
+    print(as[7] + ": " + s2 + "\n");
+    print(bs[7] + ": " + s3 + "\n");
+}
+
+main();
diff --git a/25_Chief/pascal/README.md b/00_Alternate_Languages/49_Hockey/pascal/README.md
similarity index 100%
rename from 25_Chief/pascal/README.md
rename to 00_Alternate_Languages/49_Hockey/pascal/README.md
diff --git a/00_Alternate_Languages/49_Hockey/perl/README.md b/00_Alternate_Languages/49_Hockey/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/49_Hockey/python/README.md b/00_Alternate_Languages/49_Hockey/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/49_Hockey/ruby/README.md b/00_Alternate_Languages/49_Hockey/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/49_Hockey/vbnet/Hockey.sln b/00_Alternate_Languages/49_Hockey/vbnet/Hockey.sln
new file mode 100644
index 00000000..396cfe92
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/vbnet/Hockey.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Hockey", "Hockey.vbproj", "{9ED23BC7-7C12-4B48-8E85-F21E310813D5}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9ED23BC7-7C12-4B48-8E85-F21E310813D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9ED23BC7-7C12-4B48-8E85-F21E310813D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9ED23BC7-7C12-4B48-8E85-F21E310813D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9ED23BC7-7C12-4B48-8E85-F21E310813D5}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/49_Hockey/vbnet/Hockey.vbproj b/00_Alternate_Languages/49_Hockey/vbnet/Hockey.vbproj
new file mode 100644
index 00000000..59df31bf
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/vbnet/Hockey.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Hockey
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/49_Hockey/vbnet/README.md b/00_Alternate_Languages/49_Hockey/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/49_Hockey/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/50_Horserace/README.md b/00_Alternate_Languages/50_Horserace/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/50_Horserace/csharp/Horserace.csproj b/00_Alternate_Languages/50_Horserace/csharp/Horserace.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/csharp/Horserace.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/50_Horserace/csharp/Horserace.sln b/00_Alternate_Languages/50_Horserace/csharp/Horserace.sln
new file mode 100644
index 00000000..17d7fae3
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/csharp/Horserace.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Horserace", "Horserace.csproj", "{B1CD8505-43BA-4C2C-A458-54E14539DB35}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B1CD8505-43BA-4C2C-A458-54E14539DB35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B1CD8505-43BA-4C2C-A458-54E14539DB35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B1CD8505-43BA-4C2C-A458-54E14539DB35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B1CD8505-43BA-4C2C-A458-54E14539DB35}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/50_Horserace/csharp/README.md b/00_Alternate_Languages/50_Horserace/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/50_Horserace/horserace.bas b/00_Alternate_Languages/50_Horserace/horserace.bas
new file mode 100644
index 00000000..b777f883
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/horserace.bas
@@ -0,0 +1,130 @@
+100 PRINT TAB(31);"HORSERACE"
+110 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+120 PRINT:PRINT:PRINT
+210 DIM S(8)
+220 PRINT "WELCOME TO SOUTH PORTLAND HIGH RACETRACK"
+230 PRINT "                      ...OWNED BY LAURIE CHEVALIER"
+240 PRINT "DO YOU WANT DIRECTIONS";
+250 INPUT X$
+260 IF X$="NO" THEN 320
+270 PRINT"UP TO 10 MAY PLAY.  A TABLE OF ODDS WILL BE PRINTED.  YOU"
+280 PRINT"MAY BET ANY + AMOUNT UNDER 100000 ON ONE HORSE."
+290 PRINT "DURING THE RACE, A HORSE WILL BE SHOWN BY ITS"
+300 PRINT"NUMBER.  THE HORSES RACE DOWN THE PAPER!"
+310 PRINT
+320 PRINT "HOW MANY WANT TO BET";
+330 INPUT C
+340 PRINT "WHEN ? APPEARS,TYPE NAME"
+350 FOR A=1 TO C
+360 INPUT W$(A)
+370 NEXT A
+380 PRINT
+390 PRINT"HORSE",,"NUMBER","ODDS"
+400 PRINT
+410 FOR I=1 TO 8: S(I)=0: NEXT I
+420 LET R=0
+430 FOR A=1 TO 8
+440 LET D(A)=INT(10*RND(1)+1)
+450 NEXT A
+460 FOR A=1 TO 8
+470 LET R=R+D(A)
+480 NEXT A
+490 LET V$(1)="JOE MAW"
+500 LET V$(2)="L.B.J."
+510 LET V$(3)="MR.WASHBURN"
+520 LET V$(4)="MISS KAREN"
+530 LET V$(5)="JOLLY"
+540 LET V$(6)="HORSE"
+550 LET V$(7)="JELLY DO NOT"
+560 LET V$(8)="MIDNIGHT"
+570 FOR N=1 TO 8
+580 PRINT V$(N),,N,R/D(N);":1"
+590 NEXT N
+600 PRINT"--------------------------------------------------"
+610 PRINT "PLACE YOUR BETS...HORSE # THEN AMOUNT"
+620 FOR J=1 TO C
+630 PRINT W$(J);
+640 INPUT Q(J),P(J)
+650 IF P(J)<1 THEN 670
+660 IF P(J)<100000 THEN 690
+670 PRINT"  YOU CAN'T DO THAT!"
+680 GOTO 630
+690 NEXT J
+700 PRINT
+710 PRINT"1 2 3 4 5 6 7 8"
+720 PRINT"XXXXSTARTXXXX"
+730 FOR I=1 TO 8
+740 LET M=I
+750 LET M(I)=M
+760 LET Y(M(I))=INT(100*RND(1)+1)
+770 IF Y(M(I))<10 THEN 860
+780 LET S=INT(R/D(I)+.5)
+790 IF Y(M(I))27 THEN 1240
+1180 NEXT A
+1190 PRINT M(I);
+1200 NEXT I
+1210 FOR A=1 TO 28-T
+1220 PRINT
+1230 NEXT A
+1240 PRINT "XXXXFINISHXXXX";
+1242 PRINT
+1243 PRINT
+1244 PRINT "---------------------------------------------"
+1245 PRINT
+1250 IF T<28 THEN 720
+1270 PRINT "THE RACE RESULTS ARE:"
+1272 LET Z9=1
+1280 FOR I=8 TO 1 STEP-1
+1290 LET F=M(I)
+1300 PRINT
+1310 PRINT Z9;"PLACE HORSE NO.";F,"AT ";R/D(F);":1"
+1312 LET Z9=Z9+1
+1320  NEXT I
+1330 FOR J=1 TO C
+1340 IF Q(J)<>M(8) THEN 1370
+1350 LET N=Q(J)
+1355 PRINT
+1360 PRINT W$(J);" WINS $";(R/D(N))*P(J)
+1370 NEXT J
+1372 PRINT "DO YOU WANT TO BET ON THE NEXT RACE ?"
+1374 INPUT "YES OR NO"; O$
+1376 IF O$="YES" THEN 380
+1380 END
diff --git a/00_Alternate_Languages/50_Horserace/java/README.md b/00_Alternate_Languages/50_Horserace/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/50_Horserace/javascript/README.md b/00_Alternate_Languages/50_Horserace/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/50_Horserace/javascript/horserace.html b/00_Alternate_Languages/50_Horserace/javascript/horserace.html
new file mode 100644
index 00000000..2809ec39
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/javascript/horserace.html
@@ -0,0 +1,9 @@
+
+
+HORSERACE
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/50_Horserace/javascript/horserace.js b/00_Alternate_Languages/50_Horserace/javascript/horserace.js
new file mode 100644
index 00000000..39e12b0f
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/javascript/horserace.js
@@ -0,0 +1,213 @@
+// HORSERACE
+//
+// 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 = [];
+var ws = [];
+var da = [];
+var qa = [];
+var pa = [];
+var ma = [];
+var ya = [];
+var vs = [];
+
+// Main program
+async function main()
+{
+    print(tab(31) + "HORSERACE\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("WELCOME TO SOUTH PORTLAND HIGH RACETRACK\n");
+    print("                      ...OWNED BY LAURIE CHEVALIER\n");
+    print("DO YOU WANT DIRECTIONS");
+    str = await input();
+    if (str == "YES") {
+        print("UP TO 10 MAY PLAY.  A TABLE OF ODDS WILL BE PRINTED.  YOU\n");
+        print("MAY BET ANY + AMOUNT UNDER 100000 ON ONE HORSE.\n");
+        print("DURING THE RACE, A HORSE WILL BE SHOWN BY ITS\n");
+        print("NUMBER.  THE HORSES RACE DOWN THE PAPER!\n");
+        print("\n");
+    }
+    print("HOW MANY WANT TO BET");
+    c = parseInt(await input());
+    print("WHEN ? APPEARS,TYPE NAME\n");
+    for (a = 1; a <= c; a++) {
+        ws[a] = await input();
+    }
+    do {
+        print("\n");
+        print("HORSE\t\tNUMBERS\tODDS\n");
+        print("\n");
+        for (i = 1; i <= 8; i++) {
+            sa[i] = 0;
+        }
+        r = 0;
+        for (a = 1; a <= 8; a++) {
+            da[a] = Math.floor(10 * Math.random() + 1);
+        }
+        for (a = 1; a <= 8; a++) {
+            r = r + da[a];
+        }
+        vs[1] = "JOE MAN";
+        vs[2] = "L.B.J.";
+        vs[3] = "MR.WASHBURN";
+        vs[4] = "MISS KAREN";
+        vs[5] = "JOLLY";
+        vs[6] = "HORSE";
+        vs[7] = "JELLY DO NOT";
+        vs[8] = "MIDNIGHT";
+        for (n = 1; n <= 8; n++) {
+            print(vs[n] + "\t\t" + n + "\t" + (r / da[n]) + ":1\n");
+        }
+        print("--------------------------------------------------\n");
+        print("PLACE YOUR BETS...HORSE # THEN AMOUNT\n");
+        for (j = 1; j <= c; j++) {
+            while (1) {
+                print(ws[j]);
+                str = await input();
+                qa[j] = parseInt(str);
+                pa[j] = parseInt(str.substr(str.indexOf(",") + 1));
+                if (pa[j] < 1 || pa[j] >= 100000) {
+                    print("  YOU CAN'T DO THAT!\N");
+                } else {
+                    break;
+                }
+            }
+        }
+        print("\n");
+        print("1 2 3 4 5 6 7 8\n");
+        t = 0;
+        do {
+            print("XXXXSTARTXXXX\n");
+            for (i = 1; i <= 8; i++) {
+                m = i;
+                ma[i] = m;
+                ya[ma[i]] = Math.floor(100 * Math.random() + 1);
+                if (ya[ma[i]] < 10) {
+                    ya[ma[i]] = 1;
+                    continue;
+                }
+                s = Math.floor(r / da[i] + 0.5);
+                if (ya[ma[i]] < s + 17) {
+                    ya[ma[i]] = 2;
+                    continue;
+                }
+                if (ya[ma[i]] < s + 37) {
+                    ya[ma[i]] = 3;
+                    continue;
+                }
+                if (ya[ma[i]] < s + 57) {
+                    ya[ma[i]] = 4;
+                    continue;
+                }
+                if (ya[ma[i]] < s + 77) {
+                    ya[ma[i]] = 5;
+                    continue;
+                }
+                if (ya[ma[i]] < s + 92) {
+                    ya[ma[i]] = 6;
+                    continue;
+                }
+                ya[ma[i]] = 7;
+            }
+            m = i;
+            for (i = 1; i <= 8; i++) {
+                sa[ma[i]] = sa[ma[i]] + ya[ma[i]];
+            }
+            i = 1;
+            for (l = 1; l <= 8; l++) {
+                for (i = 1; i <= 8 - l; i++) {
+                    if (sa[ma[i]] < sa[ma[i + 1]])
+                        continue;
+                    h = ma[i];
+                    ma[i] = ma[i + 1];
+                    ma[i + 1] = h;
+                }
+            }
+            t = sa[ma[8]];
+            for (i = 1; i <= 8; i++) {
+                b = sa[ma[i]] - sa[ma[i - 1]];
+                if (b != 0) {
+                    for (a = 1; a <= b; a++) {
+                        print("\n");
+                        if (sa[ma[i]] > 27)
+                            break;
+                    }
+                    if (a <= b)
+                        break;
+                }
+                print(" " + ma[i] + " ");
+            }
+            for (a = 1; a < 28 - t; a++) {
+                print("\n");
+            }
+            print("XXXXFINISHXXXX\n");
+            print("\n");
+            print("\n");
+            print("---------------------------------------------\n");
+            print("\n");
+        } while (t < 28) ;
+        print("THE RACE RESULTS ARE:\n");
+        z9 = 1;
+        for (i = 8; i >= 1; i--) {
+            f = ma[i];
+            print("\n");
+            print("" + z9 + " PLACE HORSE NO. " + f + " AT " + (r / da[f]) + ":1\n");
+            z9++;
+        }
+        for (j = 1; j <= c; j++) {
+            if (qa[j] != ma[8])
+                continue;
+            n = qa[j];
+            print("\n");
+            print(ws[j] + " WINS $" + (r / da[n]) * pa[j] + "\n");
+        }
+        print("DO YOU WANT TO BET ON THE NEXT RACE ?\n");
+        print("YES OR NO");
+        str = await input();
+    } while (str == "YES") ;
+}
+
+main();
diff --git a/26_Chomp/pascal/README.md b/00_Alternate_Languages/50_Horserace/pascal/README.md
similarity index 100%
rename from 26_Chomp/pascal/README.md
rename to 00_Alternate_Languages/50_Horserace/pascal/README.md
diff --git a/00_Alternate_Languages/50_Horserace/perl/README.md b/00_Alternate_Languages/50_Horserace/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/50_Horserace/python/README.md b/00_Alternate_Languages/50_Horserace/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/50_Horserace/python/horserace.py b/00_Alternate_Languages/50_Horserace/python/horserace.py
new file mode 100644
index 00000000..428dbbcc
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/python/horserace.py
@@ -0,0 +1,279 @@
+import math
+import random
+import time
+
+
+def basic_print(*zones, **kwargs):
+    """Simulates the PRINT command from BASIC to some degree.
+    Supports `printing zones` if given multiple arguments."""
+
+    line = ""
+    if len(zones) == 1:
+        line = str(zones[0])
+    else:
+        line = "".join([f"{str(zone):<14}" for zone in zones])
+    identation = kwargs.get("indent", 0)
+    end = kwargs.get("end", "\n")
+    print(" " * identation + line, end=end)
+
+
+def basic_input(prompt, type_conversion=None):
+    """BASIC INPUT command with optional type conversion"""
+
+    while True:
+        try:
+            inp = input(f"{prompt}? ")
+            if type_conversion is not None:
+                inp = type_conversion(inp)
+            break
+        except ValueError:
+            basic_print("INVALID INPUT!")
+    return inp
+
+
+# horse names do not change over the program, therefore making it a global.
+# throught the game, the ordering of the horses is used to indentify them
+HORSE_NAMES = [
+    "JOE MAW",
+    "L.B.J.",
+    "MR.WASHBURN",
+    "MISS KAREN",
+    "JOLLY",
+    "HORSE",
+    "JELLY DO NOT",
+    "MIDNIGHT",
+]
+
+
+def introduction():
+    """Print the introduction, and optional the instructions"""
+
+    basic_print("HORSERACE", indent=31)
+    basic_print("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY", indent=15)
+    basic_print("\n\n")
+    basic_print("WELCOME TO SOUTH PORTLAND HIGH RACETRACK")
+    basic_print("                      ...OWNED BY LAURIE CHEVALIER")
+    y_n = basic_input("DO YOU WANT DIRECTIONS")
+
+    # if no instructions needed, return
+    if y_n.upper() == "NO":
+        return
+
+    basic_print("UP TO 10 MAY PLAY.  A TABLE OF ODDS WILL BE PRINTED.  YOU")
+    basic_print("MAY BET ANY + AMOUNT UNDER 100000 ON ONE HORSE.")
+    basic_print("DURING THE RACE, A HORSE WILL BE SHOWN BY ITS")
+    basic_print("NUMBER.  THE HORSES RACE DOWN THE PAPER!")
+    basic_print("")
+
+
+def setup_players():
+    """Gather the number of players and their names"""
+
+    # ensure we get an integer value from the user
+    number_of_players = basic_input("HOW MANY WANT TO BET", int)
+
+    # for each user query their name and return the list of names
+    player_names = []
+    basic_print("WHEN ? APPEARS,TYPE NAME")
+    for _ in range(number_of_players):
+        player_names.append(basic_input(""))
+    return player_names
+
+
+def setup_horses():
+    """Generates random odds for each horse. Returns a list of
+    odds, indexed by the order of the global HORSE_NAMES."""
+
+    odds = [random.randrange(1, 10) for _ in HORSE_NAMES]
+    total = sum(odds)
+
+    # rounding odds to two decimals for nicer output,
+    # this is not in the origin implementation
+    return [round(total / odd, 2) for odd in odds]
+
+
+def print_horse_odds(odds):
+    """Print the odds for each horse"""
+
+    basic_print("")
+    for i in range(len(HORSE_NAMES)):
+        basic_print(HORSE_NAMES[i], i, f"{odds[i]}:1")
+    basic_print("")
+
+
+def get_bets(player_names):
+    """For each player, get the number of the horse to bet on,
+    as well as the amount of money to bet"""
+
+    basic_print("--------------------------------------------------")
+    basic_print("PLACE YOUR BETS...HORSE # THEN AMOUNT")
+
+    bets = []
+    for name in player_names:
+        horse = basic_input(name, int)
+        amount = None
+        while amount is None:
+            amount = basic_input("", float)
+            if amount < 1 or amount >= 100000:
+                basic_print("  YOU CAN'T DO THAT!")
+                amount = None
+        bets.append((horse, amount))
+
+    basic_print("")
+
+    return bets
+
+
+def get_distance(odd):
+    """Advances a horse during one step of the racing simulation.
+    The amount travelled is random, but scaled by the odds of the horse"""
+
+    d = random.randrange(1, 100)
+    s = math.ceil(odd)
+    if d < 10:
+        return 1
+    elif d < s + 17:
+        return 2
+    elif d < s + 37:
+        return 3
+    elif d < s + 57:
+        return 4
+    elif d < s + 77:
+        return 5
+    elif d < s + 77:
+        return 5
+    elif d < s + 92:
+        return 6
+    else:
+        return 7
+
+
+def print_race_state(total_distance, race_pos):
+    """Outputs the current state/stop of the race.
+    Each horse is placed according to the distance they have travelled. In
+    case some horses travelled the same distance, their numbers are printed
+    on the same name"""
+
+    # we dont want to modify the `race_pos` list, since we need
+    # it later. Therefore we generating an interator from the list
+    race_pos_iter = iter(race_pos)
+
+    # race_pos is stored by last to first horse in the race.
+    # we get the next horse we need to print out
+    next_pos = next(race_pos_iter)
+
+    # start line
+    basic_print("XXXXSTARTXXXX")
+
+    # print all 28 lines/unit of the race course
+    for line in range(28):
+
+        # ensure we still have a horse to print and if so, check if the
+        # next horse to print is not the current line
+        # needs iteration, since multiple horses can share the same line
+        while next_pos is not None and line == total_distance[next_pos]:
+            basic_print(f"{next_pos} ", end="")
+            next_pos = next(race_pos_iter, None)
+        else:
+            # if no horses are left to print for this line, print a new line
+            basic_print("")
+
+    # finish line
+    basic_print("XXXXFINISHXXXX")
+
+
+def simulate_race(odds):
+    num_horses = len(HORSE_NAMES)
+
+    # in spirit of the original implementation, using two arrays to
+    # track the total distance travelled, and create an index from
+    # race position -> horse index
+    total_distance = [0] * num_horses
+
+    # race_pos maps from the position in the race, to the index of the horse
+    # it will later be sorted from last to first horse, based on the
+    # distance travelled by each horse.
+    # e.g. race_pos[0] => last horse
+    #      race_pos[-1] => winning horse
+    race_pos = list(range(num_horses))
+
+    basic_print("\n1 2 3 4 5 6 7 8")
+
+    while True:
+
+        # advance each horse by a random amount
+        for i in range(num_horses):
+            total_distance[i] += get_distance(odds[i])
+
+        # bubble sort race_pos based on total distance travelled
+        # in the original implementation, race_pos is reset for each
+        # simulation step, so we keep this behaviour here
+        race_pos = list(range(num_horses))
+        for line in range(num_horses):
+            for i in range(num_horses - 1 - line):
+                if total_distance[race_pos[i]] < total_distance[race_pos[i + 1]]:
+                    continue
+                race_pos[i], race_pos[i + 1] = race_pos[i + 1], race_pos[i]
+
+        # print current state of the race
+        print_race_state(total_distance, race_pos)
+
+        # goal line is defined as 28 units from start
+        # check if the winning horse is already over the finish line
+        if total_distance[race_pos[-1]] >= 28:
+            return race_pos
+
+        # this was not in the original BASIC implementation, but it makes the
+        # race visualization a nice animation (if the terminal size is set to 31 rows)
+        time.sleep(1)
+
+
+def print_race_results(race_positions, odds, bets, player_names):
+    """Print the race results, as well as the winnings of each player"""
+
+    # print the race positions first
+    basic_print("THE RACE RESULTS ARE:")
+    position = 1
+    for horse_idx in reversed(race_positions):
+        line = f"{position} PLACE HORSE NO. {horse_idx} AT {odds[horse_idx]}:1"
+        basic_print("")
+        basic_print(line)
+        position += 1
+
+    # followed by the amount the players won
+    winning_horse_idx = race_positions[-1]
+    for idx, name in enumerate(player_names):
+        (horse, amount) = bets[idx]
+        if horse == winning_horse_idx:
+            basic_print("")
+            basic_print(f"{name} WINS ${amount * odds[winning_horse_idx]}")
+
+
+def main_loop(player_names, horse_odds):
+    """Main game loop"""
+
+    while True:
+        print_horse_odds(horse_odds)
+        bets = get_bets(player_names)
+        final_race_positions = simulate_race(horse_odds)
+        print_race_results(final_race_positions, horse_odds, bets, player_names)
+
+        basic_print("DO YOU WANT TO BET ON THE NEXT RACE ?")
+        one_more = basic_input("YES OR NO")
+        if one_more.upper() != "YES":
+            break
+
+
+def main():
+    # introduction, player names and horse odds are only generated once
+    introduction()
+    player_names = setup_players()
+    horse_odds = setup_horses()
+
+    # main loop of the game, the player can play multiple races, with the
+    # same odds
+    main_loop(player_names, horse_odds)
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/50_Horserace/ruby/README.md b/00_Alternate_Languages/50_Horserace/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/50_Horserace/vbnet/Horserace.sln b/00_Alternate_Languages/50_Horserace/vbnet/Horserace.sln
new file mode 100644
index 00000000..63adf310
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/vbnet/Horserace.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Horserace", "Horserace.vbproj", "{B44BF36F-DF93-4374-A3A0-C6D447B4D0A7}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B44BF36F-DF93-4374-A3A0-C6D447B4D0A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B44BF36F-DF93-4374-A3A0-C6D447B4D0A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B44BF36F-DF93-4374-A3A0-C6D447B4D0A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B44BF36F-DF93-4374-A3A0-C6D447B4D0A7}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/50_Horserace/vbnet/Horserace.vbproj b/00_Alternate_Languages/50_Horserace/vbnet/Horserace.vbproj
new file mode 100644
index 00000000..245d9098
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/vbnet/Horserace.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Horserace
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/50_Horserace/vbnet/README.md b/00_Alternate_Languages/50_Horserace/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/50_Horserace/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/51_Hurkle/README.md b/00_Alternate_Languages/51_Hurkle/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/.gitignore b/00_Alternate_Languages/51_Hurkle/csharp/.gitignore
new file mode 100644
index 00000000..468a3976
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/.gitignore
@@ -0,0 +1,360 @@
+
+# Created by https://www.toptal.com/developers/gitignore/api/csharp
+# Edit at https://www.toptal.com/developers/gitignore?templates=csharp
+
+### Csharp ###
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*[.json, .xml, .info]
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# End of https://www.toptal.com/developers/gitignore/api/csharp
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/CardinalDirection.cs b/00_Alternate_Languages/51_Hurkle/csharp/CardinalDirection.cs
new file mode 100644
index 00000000..324edbd2
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/CardinalDirection.cs
@@ -0,0 +1,15 @@
+namespace hurkle
+{
+    internal enum CardinalDirection
+    {
+        None,
+        North,
+        NorthEast,
+        East,
+        SouthEast,
+        South,
+        SouthWest,
+        West,
+        NorthWest
+    }
+}
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/ConsoleHurkleView.cs b/00_Alternate_Languages/51_Hurkle/csharp/ConsoleHurkleView.cs
new file mode 100644
index 00000000..b587d12c
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/ConsoleHurkleView.cs
@@ -0,0 +1,67 @@
+using System;
+
+namespace hurkle
+{
+    internal class ConsoleHurkleView : IHurkleView
+    {
+        public GamePoint GetGuess(GuessViewModel guessViewModel)
+        {
+            Console.WriteLine($"GUESS #{guessViewModel.CurrentGuessNumber}");
+            var inputLine = Console.ReadLine();
+            var seperateStrings = inputLine.Split(',', 2, StringSplitOptions.TrimEntries);
+            var guessPoint = new GamePoint{
+                X = int.Parse(seperateStrings[0]),
+                Y = int.Parse(seperateStrings[1])
+            };
+
+            return guessPoint;
+        }
+
+        public void ShowDirection(FailedGuessViewModel failedGuessViewModel)
+        {
+            Console.Write("GO ");
+            switch(failedGuessViewModel.Direction)
+            {
+                case CardinalDirection.East:
+                    Console.WriteLine("EAST");
+                    break;
+                case CardinalDirection.North:
+                    Console.WriteLine("NORTH");
+                    break;
+                case CardinalDirection.South:
+                    Console.WriteLine("SOUTH");
+                    break;
+                case CardinalDirection.West:
+                    Console.WriteLine("WEST");
+                    break;
+                case CardinalDirection.NorthEast:
+                    Console.WriteLine("NORTHEAST");
+                    break;
+                case CardinalDirection.NorthWest:
+                    Console.WriteLine("NORTHWEST");
+                    break;
+                case CardinalDirection.SouthEast:
+                    Console.WriteLine("SOUTHEAST");
+                    break;
+                case CardinalDirection.SouthWest:
+                    Console.WriteLine("SOUTHWEST");
+                    break;
+            }
+
+            Console.WriteLine();
+        }
+
+        public void ShowLoss(LossViewModel lossViewModel)
+        {
+            Console.WriteLine();
+            Console.WriteLine($"SORRY, THAT'S {lossViewModel.MaxGuesses} GUESSES");
+            Console.WriteLine($"THE HURKLE IS AT {lossViewModel.HurkleLocation.X},{lossViewModel.HurkleLocation.Y}");
+        }
+
+        public void ShowVictory(VictoryViewModel victoryViewModel)
+        {
+            Console.WriteLine();
+            Console.WriteLine($"YOU FOUND HIM IN {victoryViewModel.CurrentGuessNumber} GUESSES!");
+        }
+    }
+}
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/FailedGuessViewModel.cs b/00_Alternate_Languages/51_Hurkle/csharp/FailedGuessViewModel.cs
new file mode 100644
index 00000000..541573e4
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/FailedGuessViewModel.cs
@@ -0,0 +1,7 @@
+namespace hurkle
+{
+    internal class FailedGuessViewModel
+    {
+        public CardinalDirection Direction { get; init; }
+    }
+}
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/GamePoint.cs b/00_Alternate_Languages/51_Hurkle/csharp/GamePoint.cs
new file mode 100644
index 00000000..7abde808
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/GamePoint.cs
@@ -0,0 +1,56 @@
+namespace hurkle
+{
+    internal class GamePoint
+    {
+        public int X {get;init;}
+        public int Y {get;init;}
+
+        public CardinalDirection GetDirectionTo(GamePoint target)
+        {
+            if(X == target.X)
+            {
+                if(Y > target.Y)
+                {
+                    return CardinalDirection.South;
+                }
+                else if(Y < target.Y)
+                {
+                    return CardinalDirection.North;
+                }
+                else
+                {
+                    return CardinalDirection.None;
+                }
+            }
+            else if(X > target.X)
+            {
+                if(Y == target.Y)
+                {
+                    return CardinalDirection.West;
+                }
+                else if(Y > target.Y)
+                {
+                    return CardinalDirection.SouthWest;
+                }
+                else
+                {
+                    return CardinalDirection.NorthWest;
+                }
+            }
+            else
+            {
+                if(Y == target.Y)
+                {
+                    return CardinalDirection.East;
+                }
+                else if(Y > target.Y)
+                {
+                    return CardinalDirection.SouthEast;
+                }
+                else{
+                    return CardinalDirection.NorthEast;
+                }
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/GuessViewModel.cs b/00_Alternate_Languages/51_Hurkle/csharp/GuessViewModel.cs
new file mode 100644
index 00000000..fe8524a9
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/GuessViewModel.cs
@@ -0,0 +1,7 @@
+namespace hurkle
+{
+    internal class GuessViewModel
+    {
+        public int CurrentGuessNumber {get;init;}
+    }
+}
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/Hurkle.csproj b/00_Alternate_Languages/51_Hurkle/csharp/Hurkle.csproj
new file mode 100644
index 00000000..20827042
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/Hurkle.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/Hurkle.sln b/00_Alternate_Languages/51_Hurkle/csharp/Hurkle.sln
new file mode 100644
index 00000000..d1a6fb25
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/Hurkle.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hurkle", "Hurkle.csproj", "{BE321D5B-93BD-4F91-A875-564DC9D4094F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BE321D5B-93BD-4F91-A875-564DC9D4094F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BE321D5B-93BD-4F91-A875-564DC9D4094F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BE321D5B-93BD-4F91-A875-564DC9D4094F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BE321D5B-93BD-4F91-A875-564DC9D4094F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {42DC6AE5-5127-4B1B-BD5E-F3B1CCDC3822}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/HurkleGame.cs b/00_Alternate_Languages/51_Hurkle/csharp/HurkleGame.cs
new file mode 100644
index 00000000..438676a8
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/HurkleGame.cs
@@ -0,0 +1,48 @@
+using System;
+
+namespace hurkle
+{
+    internal class HurkleGame
+    {
+        private readonly Random _random = new Random();
+        private readonly IHurkleView _view;
+        private readonly int guesses;
+        private readonly int gridSize;
+
+        public HurkleGame(int guesses, int gridSize, IHurkleView view)
+        {
+            _view = view;
+            this.guesses = guesses;
+            this.gridSize = gridSize;
+        }
+
+        public void PlayGame()
+        {
+            // BASIC program was generating a float between 0 and 1
+            // then multiplying by the size of the grid to to a number
+            // between 1 and 10. C# allows you to do that directly.
+            var hurklePoint = new GamePoint{
+                X = _random.Next(0, gridSize),
+                Y = _random.Next(0, gridSize)
+            };
+
+            for(var K=1;K<=guesses;K++)
+            {
+                var guessPoint = _view.GetGuess(new GuessViewModel{CurrentGuessNumber = K});
+
+                var direction = guessPoint.GetDirectionTo(hurklePoint);
+                switch(direction)
+                {
+                    case CardinalDirection.None:
+                        _view.ShowVictory(new VictoryViewModel{CurrentGuessNumber = K});
+                        return;
+                    default:
+                        _view.ShowDirection(new FailedGuessViewModel{Direction = direction});
+                        continue;
+                }
+            }
+
+            _view.ShowLoss(new LossViewModel{MaxGuesses = guesses, HurkleLocation = hurklePoint } );
+        }
+    }
+}
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/IHurkleView.cs b/00_Alternate_Languages/51_Hurkle/csharp/IHurkleView.cs
new file mode 100644
index 00000000..dbaf00f3
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/IHurkleView.cs
@@ -0,0 +1,10 @@
+namespace hurkle
+{
+    internal interface IHurkleView
+    {
+        GamePoint GetGuess(GuessViewModel guessViewModel);
+        void ShowVictory(VictoryViewModel victoryViewModel);
+        void ShowDirection(FailedGuessViewModel failedGuessViewModel);
+        void ShowLoss(LossViewModel lossViewModel);
+    }
+}
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/LossViewModel.cs b/00_Alternate_Languages/51_Hurkle/csharp/LossViewModel.cs
new file mode 100644
index 00000000..fe6eb1a9
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/LossViewModel.cs
@@ -0,0 +1,8 @@
+namespace hurkle
+{
+    internal class LossViewModel
+    {
+        public int MaxGuesses { get; init; }
+        public GamePoint HurkleLocation { get; init; }
+    }
+}
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/Program.cs b/00_Alternate_Languages/51_Hurkle/csharp/Program.cs
new file mode 100644
index 00000000..483aa2b0
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/Program.cs
@@ -0,0 +1,64 @@
+using System;
+
+namespace hurkle
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            /*
+            Original source transscription
+            10 PRINT TAB(33);"HURKLE"
+            20 PRINT TAB(15);"CREATIVE COMPUTING NORRISTOWN, NEW JERSEY"
+            30 PRINT;PRINT;PRINT
+            */
+            Console.WriteLine(new string(' ', 33) + @"HURKLE");
+            Console.WriteLine(new string(' ', 15) + @"CREATIVE COMPUTING NORRISTOWN, NEW JERSEY");
+            /*
+            110 N=5
+            120 G=10
+            */
+            var N=5;
+            var G=10;
+            /*
+            210 PRINT
+            220 PRINT "A HURKLE IS HIDING ON A";G;"BY";G;"GRID. HOMEBASE"
+            230 PRINT "ON THE GRID IS POINT 0,0 AND ANY GRIDPOINT IS A"
+            240 PRINT "PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. TRY TO"
+            250 PRINT "GUESS THE HURKLE'S GRIDPOINT. YOU GET";N;"TRIES."
+            260 PRINT "AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE"
+            270 PRINT "DIRECTION TO GO TO LOOK FOR THE HURKLE."
+            280 PRINT
+            */
+            // Using string formatting via the '$' string
+            Console.WriteLine();
+            Console.WriteLine($"A HURKLE IS HIDING ON A {G} BY {G} GRID. HOMEBASE");
+            Console.WriteLine(@"ON THE GRID IS POINT 0,0 AND ANY GRIDPOINT IS A");
+            Console.WriteLine(@"PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. TRY TO");
+            Console.WriteLine($"GUESS THE HURKLE'S GRIDPOINT. YOU GET {N} TRIES.");
+            Console.WriteLine(@"AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE");
+            Console.WriteLine(@"DIRECTION TO GO TO LOOK FOR THE HURKLE.");
+            Console.WriteLine();
+
+            var view = new ConsoleHurkleView();
+            var hurkle = new HurkleGame(N,G, view);
+            while(true)
+            {
+                hurkle.PlayGame();
+
+                Console.WriteLine("PLAY AGAIN? (Y)ES/(N)O");
+                var playAgainResponse = Console.ReadLine();
+                if(playAgainResponse.Trim().StartsWith("y", StringComparison.InvariantCultureIgnoreCase))
+                {
+                    Console.WriteLine();
+                    Console.WriteLine("LET'S PLAY AGAIN. HURKLE IS HIDING");
+                    Console.WriteLine();
+                }else{
+                    Console.WriteLine("THANKS FOR PLAYING!");
+                    break;
+                }
+
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/README.md b/00_Alternate_Languages/51_Hurkle/csharp/README.md
new file mode 100644
index 00000000..6973d578
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/README.md
@@ -0,0 +1,8 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
+
+This is demonstrating seperating the user interface from the application logic through the
+use of the View/ViewModel/Controller pattern.
+
+It also makes an effort to be relatively immutable.
diff --git a/00_Alternate_Languages/51_Hurkle/csharp/VictoryViewModel.cs b/00_Alternate_Languages/51_Hurkle/csharp/VictoryViewModel.cs
new file mode 100644
index 00000000..f19f6f86
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/csharp/VictoryViewModel.cs
@@ -0,0 +1,7 @@
+namespace hurkle
+{
+    internal class VictoryViewModel
+    {
+        public int CurrentGuessNumber {get; init;}
+    }
+}
diff --git a/00_Alternate_Languages/51_Hurkle/hurkle.bas b/00_Alternate_Languages/51_Hurkle/hurkle.bas
new file mode 100644
index 00000000..c758091c
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/hurkle.bas
@@ -0,0 +1,51 @@
+10 PRINT TAB(33);"HURKLE"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+110 N=5
+120 G=10
+210 PRINT
+220 PRINT "A HURKLE IS HIDING ON A";G;"BY";G;"GRID. HOMEBASE"
+230 PRINT "ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,"
+235 PRINT "AND ANY POINT ON THE GRID IS DESIGNATED BY A"
+240 PRINT "PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST"
+245 PRINT "NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER"
+246 PRINT "IS THE VERTICAL POSITION. YOU MUST TRY TO"
+250 PRINT "GUESS THE HURKLE'S GRIDPOINT. YOU GET";N;"TRIES."
+260 PRINT "AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE"
+270 PRINT "DIRECTION TO GO TO LOOK FOR THE HURKLE."
+280 PRINT
+285 A=INT(G*RND(1))
+286 B=INT(G*RND(1))
+310 FOR K=1 TO N
+320 PRINT "GUESS #";K;
+330 INPUT X,Y
+340 IF ABS(X-A)+ABS(Y-B)=0 THEN 500
+350 REM PRINT INFO
+360 GOSUB 610
+370 PRINT
+380 NEXT K
+410 PRINT
+420 PRINT "SORRY, THAT'S";N;"GUESSES."
+430 PRINT "THE HURKLE IS AT ";A;",";B
+440 PRINT
+450 PRINT "LET'S PLAY AGAIN, HURKLE IS HIDING."
+460 PRINT
+470 GOTO 285
+500 REM
+510 PRINT
+520 PRINT "YOU FOUND HIM IN";K;"GUESSES!"
+540 GOTO 440
+610 PRINT "GO ";
+620 IF Y=B THEN 670
+630 IF Y
+ * Based on the Basic game of Hurkle here
+ * https://github.com/coding-horror/basic-computer-games/blob/main/51%20Hurkle/hurkle.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. + */ +public class Hurkle { + + public static final int GRID_SIZE = 10; + public static final int MAX_GUESSES = 5; + + private enum GAME_STATE { + STARTING, + START_GAME, + GUESSING, + PLAY_AGAIN, + GAME_OVER + } + + private GAME_STATE gameState; + + // Used for keyboard input + private final Scanner kbScanner; + + private int guesses; + + // hurkle position + private int hurkleXPos; + private int hurkleYPos; + + // player guess + private int playerGuessXPos; + private int playerGuessYPos; + + public Hurkle() { + + gameState = GAME_STATE.STARTING; + + // Initialise kb scanner + kbScanner = new Scanner(System.in); + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + // Show an introduction the first time the game is played. + case STARTING: + intro(); + gameState = GAME_STATE.START_GAME; + break; + + // Start the game, set the number of players, names and round + case START_GAME: + + hurkleXPos = randomNumber(); + hurkleYPos = randomNumber(); + + guesses = 1; + gameState = GAME_STATE.GUESSING; + + break; + + // Guess an x,y position of the hurkle + case GUESSING: + String guess = displayTextAndGetInput("GUESS #" + guesses + "? "); + playerGuessXPos = getDelimitedValue(guess, 0); + playerGuessYPos = getDelimitedValue(guess, 1); + if (foundHurkle()) { + gameState = GAME_STATE.PLAY_AGAIN; + } else { + showDirectionOfHurkle(); + guesses++; + if (guesses > MAX_GUESSES) { + System.out.println("SORRY, THAT'S " + + MAX_GUESSES + " GUESSES."); + System.out.println("THE HURKLE IS AT " + + hurkleXPos + "," + hurkleYPos); + System.out.println(); + gameState = GAME_STATE.PLAY_AGAIN; + } + } + + break; + + case PLAY_AGAIN: + System.out.println("LET'S PLAY AGAIN, HURKLE IS HIDING."); + System.out.println(); + gameState = GAME_STATE.START_GAME; + break; + } + // Effectively an endless loop because the game never quits as per + // the original basic code. + } while (gameState != GAME_STATE.GAME_OVER); + } + + private void showDirectionOfHurkle() { + System.out.print("GO "); + if (playerGuessYPos == hurkleYPos) { + // don't print North or South because the player has chosen the + // same y grid pos as the hurkle + } else if (playerGuessYPos < hurkleYPos) { + System.out.print("NORTH"); + } else if (playerGuessYPos > hurkleYPos) { + System.out.print("SOUTH"); + } + + if (playerGuessXPos == hurkleXPos) { + // don't print East or West because the player has chosen the + // same x grid pos as the hurkle + } else if (playerGuessXPos < hurkleXPos) { + System.out.print("EAST"); + } else if (playerGuessXPos > hurkleXPos) { + System.out.print("WEST"); + } + System.out.println(); + } + + private boolean foundHurkle() { + if ((playerGuessXPos - hurkleXPos) + - (playerGuessYPos - hurkleYPos) == 0) { + System.out.println("YOU FOUND HIM IN " + guesses + " GUESSES."); + return true; + } + + return false; + } + + /** + * Display info about the game + */ + private void intro() { + System.out.println("HURKLE"); + System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("A HURKLE IS HIDING ON A " + GRID_SIZE + " BY " + + GRID_SIZE + " GRID. HOMEBASE"); + System.out.println("ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,"); + System.out.println("AND ANY POINT ON THE GRID IS DESIGNATED BY A"); + System.out.println("PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST"); + System.out.println("NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER"); + System.out.println("IS THE VERTICAL POSITION. YOU MUST TRY TO"); + System.out.println("GUESS THE HURKLE'S GRIDPOINT. YOU GET " + + MAX_GUESSES + " TRIES."); + System.out.println("AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE"); + System.out.println("DIRECTION TO GO TO LOOK FOR THE HURKLE."); + } + + /** + * Generate random number + * Used to create one part of an x,y grid position + * + * @return random number + */ + private int randomNumber() { + return (int) (Math.random() + * (GRID_SIZE) + 1); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + + /** + * Accepts a string delimited by comma's and returns the pos'th delimited + * value (starting at count 0). + * + * @param text - text with values separated by comma's + * @param pos - which position to return a value for + * @return the int representation of the value + */ + private int getDelimitedValue(String text, int pos) { + String[] tokens = text.split(","); + return Integer.parseInt(tokens[pos]); + } +} diff --git a/00_Alternate_Languages/51_Hurkle/java/src/HurkleGame.java b/00_Alternate_Languages/51_Hurkle/java/src/HurkleGame.java new file mode 100644 index 00000000..1b527398 --- /dev/null +++ b/00_Alternate_Languages/51_Hurkle/java/src/HurkleGame.java @@ -0,0 +1,7 @@ +public class HurkleGame { + + public static void main(String[] args) { + Hurkle hurkle = new Hurkle(); + hurkle.play(); + } +} diff --git a/00_Alternate_Languages/51_Hurkle/javascript/README.md b/00_Alternate_Languages/51_Hurkle/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/51_Hurkle/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/51_Hurkle/javascript/hurkle.html b/00_Alternate_Languages/51_Hurkle/javascript/hurkle.html new file mode 100644 index 00000000..8d2a5022 --- /dev/null +++ b/00_Alternate_Languages/51_Hurkle/javascript/hurkle.html @@ -0,0 +1,9 @@ + + +HURKLE + + +


+
+
+
diff --git a/00_Alternate_Languages/51_Hurkle/javascript/hurkle.js b/00_Alternate_Languages/51_Hurkle/javascript/hurkle.js
new file mode 100644
index 00000000..94d992a8
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/javascript/hurkle.js
@@ -0,0 +1,102 @@
+// BATNUM
+//
+// 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(33) + "HURKLE\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    n = 5;
+    g = 10;
+    print("\n");
+    print("A HURKLE IS HIDING ON A " + g + " BY " + g + " GRID. HOMEBASE\n");
+    print("ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,\n");
+    print("AND ANY POINT ON THE GRID IS DESIGNATED BY A\n");
+    print("PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST\n");
+    print("NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER\n");
+    print("IS THE VERTICAL POSITION. YOU MUST TRY TO\n");
+    print("GUESS THE HURKLE'S GRIDPOINT. YOU GET " + n + " TRIES.\n");
+    print("AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE\n");
+    print("DIRECTION TO GO TO LOOK FOR THE HURKLE.\n");
+    print("\n");
+    while (1) {
+        a = Math.floor(g * Math.random());
+        b = Math.floor(g * Math.random());
+        for (k = 1; k <= n; k++) {
+            print("GUESS #" + k + " ");
+            str = await input();
+            x = parseInt(str);
+            y = parseInt(str.substr(str.indexOf(",") + 1));
+            if (x == a && y == b) {
+                print("\n");
+                print("YOU FOUND HIM IN " + k + " GUESSES!\n");
+                break;
+            }
+            print("GO ");
+            if (y < b) {
+                print("NORTH");
+            } else if (y > b) {
+                print("SOUTH");
+            }
+            if (x < a) {
+                print("EAST\n");
+            } else {
+                print("WEST\n");
+            }
+        }
+        if (k > n) {
+            print("\n");
+            print("SORRY, THAT'S " + n + " GUESSES.\n");
+            print("THE HURKLE IS AT " + a + "," + b + "\n");
+        }
+        print("\n");
+        print("LET'S PLAY AGAIN, HURKLE IS HIDING.\n");
+        print("\n");
+    }
+}
+
+main();
diff --git a/27_Civil_War/pascal/README.md b/00_Alternate_Languages/51_Hurkle/pascal/README.md
similarity index 100%
rename from 27_Civil_War/pascal/README.md
rename to 00_Alternate_Languages/51_Hurkle/pascal/README.md
diff --git a/00_Alternate_Languages/51_Hurkle/perl/README.md b/00_Alternate_Languages/51_Hurkle/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/51_Hurkle/perl/hurkle.pl b/00_Alternate_Languages/51_Hurkle/perl/hurkle.pl
new file mode 100644
index 00000000..8ddadc22
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/perl/hurkle.pl
@@ -0,0 +1,84 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+# global variables
+
+my($GRID)  = 10;
+my($TRIES) = 5;
+
+
+# main program starts here
+
+# print instructions
+print <);
+            # Use a regex to attempt to parse out
+            # two integers separated by a comma.
+            if ($in =~ m{(\d+)\s*,\s*(\d+)}) {
+                $G1 = $1; $G2 = $2;
+                last CHECK;
+            }
+            # Input not accepted, please try again
+            print "Please enter two numbers separated by a comma ? ";
+        }
+
+        if (abs($H1 - $G1) + abs($H2 - $G2) != 0) {
+
+            # print directional info
+            printf("Go %s%s\n\n",
+                ($G2 == $H2 ? '' : $G2 < $H2 ? 'north' : 'south'),
+                ($G1 == $H1 ? '' : $G1 < $H1 ? 'east'  : 'west' ),
+            );
+        } else {
+            # win!
+            printf("\nYou found him in %d tries!\n", $i);
+            # move to the continue block
+            next PLAY;
+        }
+    } # tries loop
+
+    # No more guesses
+    printf("Sorry, that's %d guesses.\n", $TRIES);
+    printf("The Hurkle is at %d, %d\n", $H1, $H2);
+}
+
+# Execution comes here either from the "next PLAY"
+# statement, or by the PLAY block naturally ending
+# after the player has lost.
+continue {
+    print "\nLet's play again. Hurkle is hiding.\n\n";
+}
diff --git a/00_Alternate_Languages/51_Hurkle/python/README.md b/00_Alternate_Languages/51_Hurkle/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/51_Hurkle/python/hurkle.py b/00_Alternate_Languages/51_Hurkle/python/hurkle.py
new file mode 100644
index 00000000..62cffecb
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/python/hurkle.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+#
+# Ported to Python by @iamtraction
+
+from random import random
+
+
+def direction(A, B, X, Y):
+    """Prints the direction hint for finding the hurkle."""
+
+    print("GO ", end="")
+    if Y < B:
+        print("NORTH", end="")
+    elif Y > B:
+        print("SOUTH", end="")
+
+    if X < A:
+        print("EAST", end="")
+    elif X > A:
+        print("WEST", end="")
+
+    print()
+
+
+if __name__ == "__main__":
+    print(" " * 33 + "HURKLE")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+
+    print("\n\n\n")
+
+    N = 5
+    G = 10
+
+    print()
+    print("A HURKLE IS HIDING ON A", G, "BY", G, "GRID. HOMEBASE")
+    print("ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,")
+    print("AND ANY POINT ON THE GRID IS DESIGNATED BY A")
+    print("PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST")
+    print("NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER")
+    print("IS THE VERTICAL POSITION. YOU MUST TRY TO")
+    print("GUESS THE HURKLE'S GRIDPOINT. YOU GET", N, "TRIES.")
+    print("AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE")
+    print("DIRECTION TO GO TO LOOK FOR THE HURKLE.")
+    print()
+
+    while True:
+        A = int(G * random())
+        B = int(G * random())
+
+        for k in range(0, N):
+            print("\nGUESS #" + str(k))
+
+            # read coordinates in `X, Y` format, split the string
+            # at `,`, and then parse the coordinates to `int` and
+            # store them in `X` and `Y` respectively.
+            [X, Y] = [int(c) for c in input("X,Y? ").split(",")]
+
+            if abs(X - A) + abs(Y - B) == 0:
+                print("\nYOU FOUND HIM IN", k + 1, "GUESSES!")
+                break
+            else:
+                direction(A, B, X, Y)
+                continue
+
+        print("\n\nLET'S PLAY AGAIN, HURKLE IS HIDING.\n")
diff --git a/00_Alternate_Languages/51_Hurkle/ruby/README.md b/00_Alternate_Languages/51_Hurkle/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/51_Hurkle/ruby/hurkle.rb b/00_Alternate_Languages/51_Hurkle/ruby/hurkle.rb
new file mode 100644
index 00000000..39898805
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/ruby/hurkle.rb
@@ -0,0 +1,95 @@
+MAX_GUESSES = 5
+GRID_SIZE = 10
+
+class Point < Object
+  attr_accessor :x
+  attr_accessor :y
+
+  def initialize(text="")
+    x, y = text.split(",").map(&:strip)
+    @x = (x || rand(GRID_SIZE).floor).to_i
+    @y = (y || rand(GRID_SIZE).floor).to_i
+  end
+
+  def to_s
+    "#{@x}, #{@y}"
+  end
+
+  def ==(other_point)
+    @x == other_point.x && @y == other_point.y
+  end
+
+  def direction_to(other_point)
+    (  @y < other_point.y ? "NORTH" : "SOUTH" unless @y == other_point.y ).to_s +
+      (@x < other_point.x ? "EAST"  : "WEST"  unless @x == other_point.x ).to_s
+  end
+end
+
+def main
+  say_introduction
+
+  loop do
+    hurkle_point = Point.new
+    found = false
+    (1..MAX_GUESSES).each do |guess_num|
+      found = guess(hurkle_point, guess_num)
+      break if found
+    end
+    say_failure(hurkle_point) if not found
+    say_play_again
+  end
+
+end
+
+def say_introduction
+  puts " " * 33 + "HURKLE"
+  puts " " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+  3.times { puts }
+  puts
+  puts "A HURKLE IS HIDING ON A #{GRID_SIZE} BY #{GRID_SIZE} GRID. HOMEBASE"
+  puts "ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,"
+  puts "AND ANY POINT ON THE GRID IS DESIGNATED BY A"
+  puts "PAIR OF WHOLE NUMBERS SEPERATED BY A COMMA. THE FIRST"
+  puts "NUMBER IS THE HORIZONTAL POSITION AND THE SECOND NUMBER"
+  puts "IS THE VERTICAL POSITION. YOU MUST TRY TO"
+  puts "GUESS THE HURKLE'S GRIDPOINT. YOU GET #{MAX_GUESSES} TRIES."
+  puts "AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE"
+  puts "DIRECTION TO GO TO LOOK FOR THE HURKLE."
+  puts
+end
+
+def guess(hurkle_point, guess_num)
+  print "GUESS # #{guess_num} ? "
+  guess_point = Point.new(gets.chomp)
+  if guess_point == hurkle_point
+    say_success(guess_num)
+    true
+  else
+    say_where_to_go(hurkle_point, guess_point)
+    false
+  end
+end
+
+def say_success(guess_num)
+  puts
+  puts "YOU FOUND IT IN #{guess_num} GUESSES!"
+end
+
+def say_where_to_go(hurkle_point, guess_point)
+  puts "GO #{guess_point.direction_to(hurkle_point)}"
+  puts
+end
+
+def say_failure(hurkle_point)
+  puts
+  puts "SORRY, THAT'S " + MAX_GUESSES.to_s + " GUESSES."
+  puts "THE HURKLE IS AT #{hurkle_point}"
+end
+
+def say_play_again
+  puts
+  puts "LET'S PLAY AGAIN, HURKLE IS HIDING."
+  puts
+end
+
+main
diff --git a/00_Alternate_Languages/51_Hurkle/vbnet/Hurkle.sln b/00_Alternate_Languages/51_Hurkle/vbnet/Hurkle.sln
new file mode 100644
index 00000000..dda01502
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/vbnet/Hurkle.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Hurkle", "Hurkle.vbproj", "{63674AC0-0FE6-467F-B2D0-016105155ADE}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{63674AC0-0FE6-467F-B2D0-016105155ADE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{63674AC0-0FE6-467F-B2D0-016105155ADE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{63674AC0-0FE6-467F-B2D0-016105155ADE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{63674AC0-0FE6-467F-B2D0-016105155ADE}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/51_Hurkle/vbnet/Hurkle.vbproj b/00_Alternate_Languages/51_Hurkle/vbnet/Hurkle.vbproj
new file mode 100644
index 00000000..9d93e823
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/vbnet/Hurkle.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Hurkle
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/51_Hurkle/vbnet/README.md b/00_Alternate_Languages/51_Hurkle/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/51_Hurkle/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/52_Kinema/README.md b/00_Alternate_Languages/52_Kinema/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/52_Kinema/csharp/Kinema.csproj b/00_Alternate_Languages/52_Kinema/csharp/Kinema.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/csharp/Kinema.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/52_Kinema/csharp/Kinema.sln b/00_Alternate_Languages/52_Kinema/csharp/Kinema.sln
new file mode 100644
index 00000000..ddd98662
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/csharp/Kinema.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kinema", "Kinema.csproj", "{FD7FF20E-F7A8-4372-BF7C-6898BDEF53D7}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{FD7FF20E-F7A8-4372-BF7C-6898BDEF53D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FD7FF20E-F7A8-4372-BF7C-6898BDEF53D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FD7FF20E-F7A8-4372-BF7C-6898BDEF53D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FD7FF20E-F7A8-4372-BF7C-6898BDEF53D7}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/52_Kinema/csharp/README.md b/00_Alternate_Languages/52_Kinema/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/52_Kinema/java/README.md b/00_Alternate_Languages/52_Kinema/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/52_Kinema/java/src/Kinema.java b/00_Alternate_Languages/52_Kinema/java/src/Kinema.java
new file mode 100644
index 00000000..afbacbe8
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/java/src/Kinema.java
@@ -0,0 +1,176 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Kinema
+ * 

+ * Based on the Basic game of Kinema here + * https://github.com/coding-horror/basic-computer-games/blob/main/52%20Kinema/kinema.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. + */ +public class Kinema { + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + STARTUP, + INIT, + HOW_HIGH, + SECONDS_TILL_IT_RETURNS, + ITS_VELOCITY, + RESULTS, + GAME_OVER + } + + // Current game state + private GAME_STATE gameState; + + private int numberAnswersCorrect; + + // How many meters per second a ball is thrown + private int velocity; + + public Kinema() { + kbScanner = new Scanner(System.in); + + gameState = GAME_STATE.STARTUP; + } + + /** + * Main game loop + */ + public void play() { + + double playerAnswer; + double correctAnswer; + do { + switch (gameState) { + + case STARTUP: + intro(); + gameState = GAME_STATE.INIT; + break; + + case INIT: + numberAnswersCorrect = 0; + + // calculate a random velocity for the player to use in the calculations + velocity = 5 + (int) (35 * Math.random()); + System.out.println("A BALL IS THROWN UPWARDS AT " + velocity + " METERS PER SECOND."); + gameState = GAME_STATE.HOW_HIGH; + break; + + case HOW_HIGH: + + playerAnswer = displayTextAndGetNumber("HOW HIGH WILL IT GO (IN METERS)? "); + + // Calculate the correct answer to how high it will go + correctAnswer = 0.05 * Math.pow(velocity, 2); + if (calculate(playerAnswer, correctAnswer)) { + numberAnswersCorrect++; + } + gameState = GAME_STATE.ITS_VELOCITY; + break; + + case ITS_VELOCITY: + + playerAnswer = displayTextAndGetNumber("HOW LONG UNTIL IT RETURNS (IN SECONDS)? "); + + // Calculate current Answer for how long until it returns to the ground in seconds + correctAnswer = (double) velocity / 5; + if (calculate(playerAnswer, correctAnswer)) { + numberAnswersCorrect++; + } + gameState = GAME_STATE.SECONDS_TILL_IT_RETURNS; + break; + + case SECONDS_TILL_IT_RETURNS: + + // Calculate random number of seconds for 3rd question + double seconds = 1 + (Math.random() * (2 * velocity)) / 10; + + // Round to one decimal place. + double scale = Math.pow(10, 1); + seconds = Math.round(seconds * scale) / scale; + + playerAnswer = displayTextAndGetNumber("WHAT WILL ITS VELOCITY BE AFTER " + seconds + " SECONDS? "); + + // Calculate the velocity after the given number of seconds + correctAnswer = velocity - (10 * seconds); + if (calculate(playerAnswer, correctAnswer)) { + numberAnswersCorrect++; + } + gameState = GAME_STATE.RESULTS; + break; + + case RESULTS: + System.out.println(numberAnswersCorrect + " RIGHT OUT OF 3"); + if (numberAnswersCorrect > 1) { + System.out.println(" NOT BAD."); + } + gameState = GAME_STATE.STARTUP; + break; + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + private void intro() { + System.out.println(simulateTabs(33) + "KINEMA"); + System.out.println(simulateTabs(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + } + + private boolean calculate(double playerAnswer, double correctAnswer) { + + boolean gotItRight = false; + + if (Math.abs((playerAnswer - correctAnswer) / correctAnswer) < 0.15) { + System.out.println("CLOSE ENOUGH"); + gotItRight = true; + } else { + System.out.println("NOT EVEN CLOSE"); + } + System.out.println("CORRECT ANSWER IS " + correctAnswer); + System.out.println(); + + return gotItRight; + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to a Double + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private double displayTextAndGetNumber(String text) { + return Double.parseDouble(displayTextAndGetInput(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + + /** + * Simulate the old basic tab(xx) command which indented text by xx spaces. + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String simulateTabs(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + +} diff --git a/00_Alternate_Languages/52_Kinema/java/src/KinemaGame.java b/00_Alternate_Languages/52_Kinema/java/src/KinemaGame.java new file mode 100644 index 00000000..b84d0019 --- /dev/null +++ b/00_Alternate_Languages/52_Kinema/java/src/KinemaGame.java @@ -0,0 +1,7 @@ +public class KinemaGame { + public static void main(String[] args) { + + Kinema kinema = new Kinema(); + kinema.play(); + } +} diff --git a/00_Alternate_Languages/52_Kinema/javascript/README.md b/00_Alternate_Languages/52_Kinema/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/52_Kinema/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/52_Kinema/javascript/kinema.html b/00_Alternate_Languages/52_Kinema/javascript/kinema.html new file mode 100644 index 00000000..0e41284e --- /dev/null +++ b/00_Alternate_Languages/52_Kinema/javascript/kinema.html @@ -0,0 +1,9 @@ + + +KINEMA + + +


+
+
+
diff --git a/00_Alternate_Languages/52_Kinema/javascript/kinema.js b/00_Alternate_Languages/52_Kinema/javascript/kinema.js
new file mode 100644
index 00000000..91cd443b
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/javascript/kinema.js
@@ -0,0 +1,95 @@
+// KINEMA
+//
+// 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 q;
+
+function evaluate_answer(str, a)
+{
+    g = parseFloat(str);
+    if (Math.abs((g - a) / a) < 0.15) {
+        print("CLOSE ENOUGH.\n");
+        q++;
+    } else {
+        print("NOT EVEN CLOSE....\n");
+    }
+    print("CORRECT ANSWER IS " + a + "\n\n");
+}
+
+// Main program
+async function main()
+{
+    print(tab(33) + "KINEMA\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    while (1) {
+        print("\n");
+        print("\n");
+        q = 0;
+        v = 5 + Math.floor(35 * Math.random());
+        print("A BALL IS THROWN UPWARDS AT " + v + " METERS PER SECOND.\n");
+        print("\n");
+        a = 0.5 * Math.pow(v, 2);
+        print("HOW HIGH WILL IT GO (IN METERS)");
+        str = await input();
+        evaluate_answer(str, a);
+        a = v / 5;
+        print("HOW LONG UNTIL IT RETURNS (IN SECONDS)");
+        str = await input();
+        evaluate_answer(str, a);
+        t = 1 + Math.floor(2 * v * Math.random()) / 10;
+        a = v - 10 * t;
+        print("WHAT WILL ITS VELOCITY BE AFTER " + t + " SECONDS");
+        str = await input();
+        evaluate_answer(str, a);
+        print("\n");
+        print(q + " RIGHT OUT OF 3.");
+        if (q < 2)
+            continue;
+        print("  NOT BAD.\n");
+    }
+}
+
+main();
diff --git a/00_Alternate_Languages/52_Kinema/kinema.bas b/00_Alternate_Languages/52_Kinema/kinema.bas
new file mode 100644
index 00000000..2dbea7bd
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/kinema.bas
@@ -0,0 +1,34 @@
+10 PRINT TAB(33);"KINEMA"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT: PRINT: PRINT
+100 PRINT
+105 PRINT
+106 Q=0
+110 V=5+INT(35*RND(1))
+111 PRINT "A BALL IS THROWN UPWARDS AT";V;"METERS PER SECOND."
+112 PRINT
+115 A=.05*V^2
+116 PRINT "HOW HIGH WILL IT GO (IN METERS)";
+117 GOSUB 500
+120 A=V/5
+122 PRINT "HOW LONG UNTIL IT RETURNS (IN SECONDS)";
+124 GOSUB 500
+130 T=1+INT(2*V*RND(1))/10
+132 A=V-10*T
+134 PRINT "WHAT WILL ITS VELOCITY BE AFTER";T;"SECONDS";
+136 GOSUB 500
+140 PRINT
+150 PRINT Q;"RIGHT OUT OF 3.";
+160 IF Q<2 THEN 100
+170 PRINT "  NOT BAD."
+180 GOTO 100
+500 INPUT G
+502 IF ABS((G-A)/A)<.15 THEN 510
+504 PRINT "NOT EVEN CLOSE...."
+506 GOTO 512
+510 PRINT "CLOSE ENOUGH."
+511 Q=Q+1
+512 PRINT "CORRECT ANSWER IS ";A
+520 PRINT
+530 RETURN
+999 END
diff --git a/28_Combat/pascal/README.md b/00_Alternate_Languages/52_Kinema/pascal/README.md
similarity index 100%
rename from 28_Combat/pascal/README.md
rename to 00_Alternate_Languages/52_Kinema/pascal/README.md
diff --git a/00_Alternate_Languages/52_Kinema/perl/README.md b/00_Alternate_Languages/52_Kinema/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/52_Kinema/perl/kinema.pl b/00_Alternate_Languages/52_Kinema/perl/kinema.pl
new file mode 100644
index 00000000..ef607983
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/perl/kinema.pl
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 33 . "KINEMA\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+
+while (1) {
+	print "\n";
+	print "\n";
+	my $Q=0;
+	my $V=5+int(35*rand(1));
+	print "A BALL IS THROWN UPWARDS AT $V METERS PER SECOND.\n";
+	print "\n";
+
+	my $A=.05*$V^2;
+	print "HOW HIGH WILL IT GO (IN METERS)";
+	$Q+= &Input($A);
+
+	$A=$V/5;
+	print "HOW LONG UNTIL IT RETURNS (IN SECONDS)";
+	$Q+= &Input($A);
+
+	my $T=1+int(2*$V*rand(1))/10;
+	$A=$V-10*$T;
+	print "WHAT WILL ITS VELOCITY BE AFTER $T SECONDS";
+	$Q+= &Input($A);
+
+	print "\n";
+	print "$Q RIGHT OUT OF 3.";
+	if ($Q<2) { next; }
+	print " NOT BAD.\n";
+	}
+
+exit;
+
+
+#Line500:
+sub Input {
+	my ($A)= @_;
+	my $Point=0;
+	print "? "; chomp(my $G = );
+	if (abs(($G-$A)/$A)<.15) {
+		print "CLOSE ENOUGH.\n";
+		$Point=1;
+		} else {
+		print "NOT EVEN CLOSE....\n";
+		}
+	print "CORRECT ANSWER IS $A\n";
+	print "\n";
+	return $Point;
+	}
diff --git a/00_Alternate_Languages/52_Kinema/python/README.md b/00_Alternate_Languages/52_Kinema/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/52_Kinema/python/kinema.py b/00_Alternate_Languages/52_Kinema/python/kinema.py
new file mode 100644
index 00000000..347fff2a
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/python/kinema.py
@@ -0,0 +1,89 @@
+"""
+KINEMA
+
+A kinematics physics quiz.
+
+Ported by Dave LeCompte
+"""
+
+import random
+
+# We approximate gravity from 9.8 meters/second squared to 10, which
+# is only off by about 2%. 10 is also a lot easier for people to use
+# for mental math.
+
+g = 10
+
+# We only expect the student to get within this percentage of the
+# correct answer. This isn't rocket science.
+
+EXPECTED_ACCURACY_PERCENT = 15
+
+
+def print_with_tab(spaces_count, msg):
+    if spaces_count > 0:
+        spaces = " " * spaces_count
+    else:
+        spaces = ""
+    print(spaces + msg)
+
+
+def do_quiz():
+    print()
+    print()
+    num_questions_correct = 0
+
+    # pick random initial velocity
+    v0 = random.randint(5, 40)
+    print(f"A BALL IS THROWN UPWARDS AT {v0} METERS PER SECOND.")
+    print()
+
+    answer = v0**2 / (2 * g)
+    num_questions_correct += ask_player("HOW HIGH WILL IT GO (IN METERS)?", answer)
+
+    answer = 2 * v0 / g
+    num_questions_correct += ask_player(
+        "HOW LONG UNTIL IT RETURNS (IN SECONDS)?", answer
+    )
+
+    t = 1 + random.randint(0, 2 * v0) // g
+    answer = v0 - g * t
+    num_questions_correct += ask_player(
+        f"WHAT WILL ITS VELOCITY BE AFTER {t} SECONDS?", answer
+    )
+
+    print()
+    print(f"{num_questions_correct} right out of 3.")
+    if num_questions_correct >= 2:
+        print("  NOT BAD.")
+
+
+def ask_player(question, answer):
+    print(question)
+    player_answer = float(input())
+
+    accuracy_frac = EXPECTED_ACCURACY_PERCENT / 100.0
+    if abs((player_answer - answer) / answer) < accuracy_frac:
+        print("CLOSE ENOUGH.")
+        score = 1
+    else:
+        print("NOT EVEN CLOSE....")
+        score = 0
+    print(f"CORRECT ANSWER IS {answer}")
+    print()
+    return score
+
+
+def main():
+    print_with_tab(33, "KINEMA")
+    print_with_tab(15, "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+    while True:
+        do_quiz()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/52_Kinema/ruby/README.md b/00_Alternate_Languages/52_Kinema/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/52_Kinema/ruby/kinema.rb b/00_Alternate_Languages/52_Kinema/ruby/kinema.rb
new file mode 100644
index 00000000..27ed2aa2
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/ruby/kinema.rb
@@ -0,0 +1,45 @@
+#!/usr/bin/env ruby
+
+# Kinema
+# reinterpreted from BASIC by stephan.com
+
+EPSILON = 0.15
+
+def close?(guess, answer)
+  (guess-answer).abs < answer * EPSILON
+end
+
+def ask(text, answer)
+  puts text
+  guess = gets.strip.to_f
+  if close?(guess, answer)
+    puts 'Close enough'
+    @score += 1
+  else
+    puts 'Not even close....'
+  end
+
+  puts "Correct answer is #{answer}"
+end
+
+puts 'Kinema'.center(80)
+puts 'Adapted by stephan.com'.center(80)
+puts; puts; puts;
+
+loop do
+  puts; puts
+  @score = 0
+  v = 5 + rand(35)
+
+  puts "A ball is thrown upwards at #{v} meters per second"
+
+  ask 'How high will it go? (in meters)', 0.05 * v * v
+  ask 'How long until it returns? (in seconds)', v/5.0
+
+  t = 1 + rand(2*v)/10.0
+  ask "What will its velocity be after #{t} seconds?", v - 10 * t
+  puts
+  print "#{@score} right out of 3."
+  print " not bad" if @score > 1
+  puts
+end
diff --git a/00_Alternate_Languages/52_Kinema/vbnet/Kinema.sln b/00_Alternate_Languages/52_Kinema/vbnet/Kinema.sln
new file mode 100644
index 00000000..a669536c
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/vbnet/Kinema.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Kinema", "Kinema.vbproj", "{C929831F-0B1C-4EE4-9BAA-001BE5CCC2E2}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{C929831F-0B1C-4EE4-9BAA-001BE5CCC2E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C929831F-0B1C-4EE4-9BAA-001BE5CCC2E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C929831F-0B1C-4EE4-9BAA-001BE5CCC2E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C929831F-0B1C-4EE4-9BAA-001BE5CCC2E2}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/52_Kinema/vbnet/Kinema.vbproj b/00_Alternate_Languages/52_Kinema/vbnet/Kinema.vbproj
new file mode 100644
index 00000000..b779698b
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/vbnet/Kinema.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Kinema
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/52_Kinema/vbnet/README.md b/00_Alternate_Languages/52_Kinema/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/52_Kinema/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/53_King/README.md b/00_Alternate_Languages/53_King/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/53_King/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/53_King/csharp/King.csproj b/00_Alternate_Languages/53_King/csharp/King.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/53_King/csharp/King.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/53_King/csharp/King.sln b/00_Alternate_Languages/53_King/csharp/King.sln
new file mode 100644
index 00000000..94eb4d7d
--- /dev/null
+++ b/00_Alternate_Languages/53_King/csharp/King.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "King", "King.csproj", "{6CB6A32F-FFC7-4839-AAE2-4091D349BD34}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6CB6A32F-FFC7-4839-AAE2-4091D349BD34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6CB6A32F-FFC7-4839-AAE2-4091D349BD34}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6CB6A32F-FFC7-4839-AAE2-4091D349BD34}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6CB6A32F-FFC7-4839-AAE2-4091D349BD34}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/53_King/csharp/README.md b/00_Alternate_Languages/53_King/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/53_King/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/53_King/java/README.md b/00_Alternate_Languages/53_King/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/53_King/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/53_King/javascript/README.md b/00_Alternate_Languages/53_King/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/53_King/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/53_King/javascript/king.html b/00_Alternate_Languages/53_King/javascript/king.html
new file mode 100644
index 00000000..56b5e7e2
--- /dev/null
+++ b/00_Alternate_Languages/53_King/javascript/king.html
@@ -0,0 +1,9 @@
+
+
+KING
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/53_King/javascript/king.js b/00_Alternate_Languages/53_King/javascript/king.js
new file mode 100644
index 00000000..d8514a31
--- /dev/null
+++ b/00_Alternate_Languages/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();
diff --git a/00_Alternate_Languages/53_King/king.bas b/00_Alternate_Languages/53_King/king.bas
new file mode 100644
index 00000000..7352fa58
--- /dev/null
+++ b/00_Alternate_Languages/53_King/king.bas
@@ -0,0 +1,268 @@
+1 PRINT TAB(34);"KING"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+4 PRINT "DO YOU WANT INSTRUCTIONS";
+5 INPUT Z$
+6 N5=8
+10 IF LEFT$(Z$,1)="N" THEN 47
+11 IF Z$="AGAIN" THEN 1960
+12 PRINT:PRINT:PRINT
+20 PRINT "CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS"
+22 PRINT "DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR"
+24 PRINT "JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE"
+26 PRINT "MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY."
+28 PRINT "THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100"
+30 PRINT "RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES"
+32 PRINT "FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT"
+34 PRINT "FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND"
+36 PRINT "WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD"
+38 PRINT "TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT"
+40 PRINT "THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER"
+42 PRINT "SQUARE MILE TO PLANT."
+44 PRINT "YOUR GOAL IS TO COMPLETE YOUR";N5;"YEAR TERM OF OFFICE."
+46 PRINT "GOOD LUCK!"
+47 PRINT
+50 A=INT(60000+(1000*RND(1))-(1000*RND(1)))
+55 B=INT(500+(10*RND(1))-(10*RND(1)))
+65 D=2000
+100 W=INT(10*RND(1)+95)
+102 PRINT
+105 PRINT "YOU NOW HAVE ";A;" RALLODS IN THE TREASURY."
+110 PRINT INT(B);:PRINT "COUNTRYMEN, ";
+115 V9=INT(((RND(1)/2)*10+10))
+120 IF C=0 THEN 140
+130 PRINT INT(C);"FOREIGN WORKERS, ";
+140 PRINT "AND";INT(D);"SQ. MILES OF LAND."
+150 PRINT "THIS YEAR INDUSTRY WILL BUY LAND FOR";W;
+152 PRINT "RALLODS PER SQUARE MILE."
+155 PRINT "LAND CURRENTLY COSTS";V9;"RALLODS PER SQUARE MILE TO PLANT."
+162 PRINT
+200 PRINT "HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY";
+210 INPUT H
+215 IF H<0 THEN 200
+220 IF H<=D-1000 THEN 300
+230 PRINT "***  THINK AGAIN. YOU ONLY HAVE";D-1000;"SQUARE MILES OF FARM LAND."
+240 IF X<>0 THEN 200
+250 PRINT:PRINT "(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE"
+260 PRINT "FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,"
+270 PRINT "THICKER TOP SOIL, ETC.)"
+280 X=1
+299 GOTO 200
+300 D=INT(D-H)
+310 A=INT(A+(H*W))
+320 PRINT "HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN";
+340 INPUT I
+342 IF I<0 THEN 320
+350 IF I
0 THEN 1002 +602 IF I<>0 THEN 1002 +604 IF J<>0 THEN 1002 +606 IF K<>0 THEN 1002 +609 PRINT +612 PRINT "GOODBYE." +614 PRINT "(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER" +616 PRINT "'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START" +617 PRINT "OF THE GAME)." +618 STOP +1000 GOTO 600 +1002 PRINT +1003 PRINT +1010 A=INT(A-K) +1020 A4=A +1100 IF INT(I/100-B)>=0 THEN 1120 +1105 IF I/100<50 THEN 1700 +1110 PRINT INT(B-(I/100));"COUNTRYMEN DIED OF STARVATION" +1120 F1=INT(RND(1)*(2000-D)) +1122 IF K<25 THEN 1130 +1125 F1=INT(F1/(K/25)) +1130 IF F1<=0 THEN 1150 +1140 PRINT F1;"COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION" +1150 IF INT((I/100)-B)<0 THEN 1170 +1160 IF F1>0 THEN 1180 +1165 GOTO 1200 +1170 PRINT " YOU WERE FORCED TO SPEND";INT((F1+(B-(I/100)))*9); +1172 PRINT "RALLODS ON FUNERAL EXPENSES" +1174 B5=INT(F1+(B-(I/100))) +1175 A=INT(A-((F1+(B-(I/100)))*9)) +1176 GOTO 1185 +1180 PRINT " YOU WERE FORCED TO SPEND ";INT(F1*9);"RALLODS ON "; +1181 PRINT "FUNERAL EXPENSES." +1182 B5=F1 +1183 A=INT(A-(F1*9)) +1185 IF A>=0 THEN 1194 +1187 PRINT " INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD" +1189 D=INT(D+(A/W)) +1190 A=0 +1194 B=INT(B-B5) +1200 IF H=0 THEN 1250 +1220 C1=INT(H+(RND(1)*10)-(RND(1)*20)) +1224 IF C>0 THEN 1230 +1226 C1=C1+20 +1230 PRINT C1;"WORKERS CAME TO THE COUNTRY AND"; +1250 P1=INT(((I/100-B)/10)+(K/25)-((2000-D)/50)-(F1/2)) +1255 PRINT ABS(P1);"COUNTRYMEN "; +1260 IF P1<0 THEN 1275 +1265 PRINT "CAME TO"; +1270 GOTO 1280 +1275 PRINT "LEFT"; +1280 PRINT " THE ISLAND." +1290 B=INT(B+P1) +1292 C=INT(C+C1) +1305 U2=INT(((2000-D)*((RND(1)+1.5)/2))) +1310 IF C=0 THEN 1324 +1320 PRINT "OF ";INT(J);"SQ. MILES PLANTED,"; +1324 IF J>U2 THEN 1330 +1326 U2=J +1330 PRINT " YOU HARVESTED ";INT(J-U2);"SQ. MILES OF CROPS." +1340 IF U2=0 THEN 1370 +1344 IF T1>=2 THEN 1370 +1350 PRINT " (DUE TO "; +1355 IF T1=0 THEN 1365 +1360 PRINT "INCREASED "; +1365 PRINT "AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)" +1370 Q=INT((J-U2)*(W/2)) +1380 PRINT "MAKING";INT(Q);"RALLODS." +1390 A=INT(A+Q) +1400 V1=INT(((B-P1)*22)+(RND(1)*500)) +1405 V2=INT((2000-D)*15) +1410 PRINT " YOU MADE";ABS(INT(V1-V2));"RALLODS FROM TOURIST TRADE." +1420 IF V2=0 THEN 1450 +1425 IF V1-V2>=V3 THEN 1450 +1430 PRINT " DECREASE BECAUSE "; +1435 G1=10*RND(1) +1440 IF G1<=2 THEN 1460 +1442 IF G1<=4 THEN 1465 +1444 IF G1<=6 THEN 1470 +1446 IF G1<=8 THEN 1475 +1448 IF G1<=10 THEN 1480 +1450 V3=INT(A+V3) +1451 A=INT(A+V3) +1452 GOTO 1500 +1460 PRINT "FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION." +1462 GOTO 1450 +1465 PRINT "AIR POLLUTION IS KILLING GAME BIRD POPULATION." +1467 GOTO 1450 +1470 PRINT "MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION." +1472 GOTO 1450 +1475 PRINT "UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS." +1477 GOTO 1450 +1480 PRINT "HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT." +1482 GOTO 1450 +1500 IF B5>200 THEN 1600 +1505 IF B<343 THEN 1700 +1510 IF (A4/100)>5 THEN 1800 +1515 IF C>B THEN 1550 +1520 IF N5-1=X5 THEN 1900 +1545 GOTO 2000 +1550 PRINT +1552 PRINT +1560 PRINT "THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER" +1562 PRINT "OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND" +1564 PRINT "TAKEN OVER THE COUNTRY." +1570 IF RND(1)<=.5 THEN 1580 +1574 PRINT "YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW" +1576 PRINT "RESIDING IN PRISON." +1578 GOTO 1590 +1580 PRINT "YOU HAVE BEEN ASSASSINATED." +1590 PRINT +1592 PRINT +1596 STOP +1600 PRINT +1602 PRINT +1610 PRINT B5;"COUNTRYMEN DIED IN ONE YEAR!!!!!" +1615 PRINT "DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY" +1620 PRINT "BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU" +1622 M6=INT(RND(1)*10) +1625 IF M6<=3 THEN 1670 +1630 IF M6<=6 THEN 1680 +1635 IF M6<=10 THEN 1690 +1670 PRINT "ALSO HAD YOUR LEFT EYE GOUGED OUT!" +1672 GOTO 1590 +1680 PRINT "HAVE ALSO GAINED A VERY BAD REPUTATION." +1682 GOTO 1590 +1690 PRINT "HAVE ALSO BEEN DECLARED NATIONAL FINK." +1692 GOTO 1590 +1700 PRINT +1702 PRINT +1710 PRINT "OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU" +1715 PRINT "WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)" +1720 PRINT "HATE YOUR GUTS." +1730 GOTO 1570 +1800 IF B5-F1<2 THEN 1515 +1807 PRINT +1815 PRINT "MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID" +1820 PRINT "NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED" +1825 PRINT "OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE" +1830 PRINT "BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE." +1835 PRINT "THE CHOICE IS YOURS." +1840 PRINT "IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER" +1845 PRINT "BEFORE PROCEEDING." +1850 GOTO 1590 +1900 PRINT +1902 PRINT +1920 PRINT "CONGRATULATIONS!!!!!!!!!!!!!!!!!!" +1925 PRINT "YOU HAVE SUCCESFULLY COMPLETED YOUR";N5;"YEAR TERM" +1930 PRINT "OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT" +1935 PRINT "NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD" +1940 PRINT "LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT" +1945 PRINT "PLAYS THIS GAME." +1950 GOTO 1590 +1960 PRINT "HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED"; +1961 INPUT X5 +1962 IF X5<0 THEN 1590 +1963 IF X5<8 THEN 1969 +1965 PRINT " COME ON, YOUR TERM IN OFFICE IS ONLY";N5;"YEARS." +1967 GOTO 1960 +1969 PRINT "HOW MUCH DID YOU HAVE IN THE TREASURY"; +1970 INPUT A +1971 IF A<0 THEN 1590 +1975 PRINT "HOW MANY COUNTRYMEN"; +1976 INPUT B +1977 IF B<0 THEN 1590 +1980 PRINT "HOW MANY WORKERS"; +1981 INPUT C +1982 IF C<0 THEN 1590 +1990 PRINT "HOW MANY SQUARE MILES OF LAND"; +1991 INPUT D +1992 IF D<0 THEN 1590 +1993 IF D>2000 THEN 1996 +1994 IF D>1000 THEN 100 +1996 PRINT " COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND" +1997 PRINT " AND 10,000 SQ. MILES OF FOREST LAND." +1998 GOTO 1990 +2000 X5=X5+1 +2020 B5=0 +2040 GOTO 100 +2046 END diff --git a/00_Alternate_Languages/53_King/king_variable_update.bas b/00_Alternate_Languages/53_King/king_variable_update.bas new file mode 100644 index 00000000..7f88e101 --- /dev/null +++ b/00_Alternate_Languages/53_King/king_variable_update.bas @@ -0,0 +1,306 @@ +1 PRINT TAB(34);"KING" +2 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +3 PRINT:PRINT:PRINT +4 PRINT "DO YOU WANT INSTRUCTIONS"; +5 INPUT Z$ +6 YEARS_REQUIRED=8 +10 IF LEFT$(Z$,1)="N" THEN 47 + 11 IF Z$="AGAIN" THEN 1960 + 12 PRINT:PRINT:PRINT + 20 PRINT "CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS" + 22 PRINT "DETINU, RALLODS SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR" + 24 PRINT "JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE" + 26 PRINT "MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY." + 28 PRINT "THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100" + 30 PRINT "RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES" + 32 PRINT "FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT" + 34 PRINT "FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND" + 36 PRINT "WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD" + 38 PRINT "TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT" + 40 PRINT "THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER" + 42 PRINT "SQUARE MILE TO PLANT." + 44 PRINT "YOUR GOAL IS TO COMPLETE YOUR";YEARS_REQUIRED;"YEAR TERM OF OFFICE." + 46 PRINT "GOOD LUCK!" + +47 PRINT + +50 RALLODS=INT(60000+(1000*RND(1))-(1000*RND(1))) +55 COUNTRYMEN=INT(500+(10*RND(1))-(10*RND(1))) +65 LANDAREA=2000 +100 LANDPRICE=INT(10*RND(1)+95) +102 PRINT +105 PRINT "YOU NOW HAVE ";RALLODS;" RALLODS IN THE TREASURY." +110 PRINT INT(COUNTRYMEN);:PRINT "COUNTRYMEN, "; +115 COST_TO_PLANT=INT(((RND(1)/2)*10+10)) +120 IF FOREIGN_WORKERS=0 THEN 140 +130 PRINT INT(FOREIGN_WORKERS);"FOREIGN WORKERS, "; +140 PRINT "AND";INT(LANDAREA);"SQ. MILES OF LAND." +150 PRINT "THIS YEAR INDUSTRY WILL BUY LAND FOR";LANDPRICE; +152 PRINT "RALLODS PER SQUARE MILE." +155 PRINT "LAND CURRENTLY COSTS";COST_TO_PLANT;"RALLODS PER SQUARE MILE TO PLANT." +162 PRINT + +200 PRINT "HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY"; +210 INPUT SELL_TO_INDUSTRY +215 IF SELL_TO_INDUSTRY<0 THEN 200 +220 IF SELL_TO_INDUSTRY<=LANDAREA-1000 THEN 300 +230 PRINT "*** THINK AGAIN. YOU ONLY HAVE";LANDAREA-1000;"SQUARE MILES OF FARM LAND." + +240 IF EXPLANATION_GIVEN THEN 200 + 250 PRINT:PRINT "(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE" + 260 PRINT "FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES," + 270 PRINT "THICKER TOP SOIL, ETC.)" + 280 EXPLANATION_GIVEN=TRUE +299 GOTO 200 + +300 LANDAREA=INT(LANDAREA-SELL_TO_INDUSTRY) +310 RALLODS=INT(RALLODS+(SELL_TO_INDUSTRY*LANDPRICE)) +320 PRINT "HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN"; +340 INPUT WELFARE +342 IF WELFARE<0 THEN 320 +350 IF WELFARE0 THEN 1002 +602 IF WELFARE<>0 THEN 1002 +604 IF PLANTING_AREA<>0 THEN 1002 +606 IF MONEY_SPENT_ON_POLLUTION_CONTROL<>0 THEN 1002 + +609 PRINT +612 PRINT "GOODBYE." +614 PRINT "(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER" +616 PRINT "'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START" +617 PRINT "OF THE GAME)." +618 STOP + +1000 GOTO 600 + +1002 PRINT +1003 PRINT + +1010 RALLODS=INT(RALLODS-MONEY_SPENT_ON_POLLUTION_CONTROL) +1020 ORIGINAL_RALLODS=RALLODS + +1100 IF INT(WELFARE/100-COUNTRYMEN)>=0 THEN 1120 +1105 IF WELFARE/100<50 THEN 1700 +1110 PRINT INT(COUNTRYMEN-(WELFARE/100));"COUNTRYMEN DIED OF STARVATION" + +1120 POLLUTION_DEATHS=INT(RND(1)*(2000-LANDAREA)) +1122 IF MONEY_SPENT_ON_POLLUTION_CONTROL<25 THEN 1130 +1125 POLLUTION_DEATHS=INT(POLLUTION_DEATHS/(MONEY_SPENT_ON_POLLUTION_CONTROL/25)) + +1130 IF POLLUTION_DEATHS<=0 THEN 1150 +1140 PRINT POLLUTION_DEATHS;"COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION" + +1150 IF INT((WELFARE/100)-COUNTRYMEN)<0 THEN 1170 +1160 IF POLLUTION_DEATHS>0 THEN 1180 +1165 GOTO 1200 + +1170 PRINT " YOU WERE FORCED TO SPEND";INT((POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))*9); +1172 PRINT "RALLODS ON FUNERAL EXPENSES" +1174 DEATHS=INT(POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100))) +1175 RALLODS=INT(RALLODS-((POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))*9)) +1176 GOTO 1185 + +1180 PRINT " YOU WERE FORCED TO SPEND ";INT(POLLUTION_DEATHS*9);"RALLODS ON "; +1181 PRINT "FUNERAL EXPENSES." +1182 DEATHS=POLLUTION_DEATHS +1183 RALLODS=INT(RALLODS-(POLLUTION_DEATHS*9)) + +1185 IF RALLODS>=0 THEN 1194 +1187 PRINT " INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD" +1189 LANDAREA=INT(LANDAREA+(RALLODS/LANDPRICE)) +1190 RALLODS=0 + +1194 COUNTRYMEN=INT(COUNTRYMEN-DEATHS) + +1200 IF SELL_TO_INDUSTRY=0 THEN 1250 +1220 NEW_FOREIGNERS=INT(SELL_TO_INDUSTRY+(RND(1)*10)-(RND(1)*20)) +1224 IF FOREIGN_WORKERS>0 THEN 1230 +1226 NEW_FOREIGNERS=NEW_FOREIGNERS+20 + +1230 PRINT NEW_FOREIGNERS;"WORKERS CAME TO THE COUNTRY AND"; + +1250 IMMIGRATION=INT(((WELFARE/100-COUNTRYMEN)/10)+(MONEY_SPENT_ON_POLLUTION_CONTROL/25)-((2000-LANDAREA)/50)-(POLLUTION_DEATHS/2)) +1255 PRINT ABS(IMMIGRATION);"COUNTRYMEN "; +1260 IF IMMIGRATION<0 THEN 1275 +1265 PRINT "CAME TO"; +1270 GOTO 1280 +1275 PRINT "LEFT"; +1280 PRINT " THE ISLAND." +1290 COUNTRYMEN=INT(COUNTRYMEN+IMMIGRATION) + + +1292 FOREIGN_WORKERS=INT(FOREIGN_WORKERS+NEW_FOREIGNERS) + +1305 CROP_LOSS=INT(((2000-LANDAREA)*((RND(1)+1.5)/2))) +1310 IF FOREIGN_WORKERS=0 THEN 1324 +1320 PRINT "OF ";INT(PLANTING_AREA);"SQ. MILES PLANTED,"; +1324 IF PLANTING_AREA>CROP_LOSS THEN 1330 +1326 CROP_LOSS=PLANTING_AREA +1330 PRINT " YOU HARVESTED ";INT(PLANTING_AREA-CROP_LOSS);"SQ. MILES OF CROPS." +1340 IF CROP_LOSS=0 THEN 1370 +1344 IF T1>=2 THEN 1370 +1350 PRINT " (DUE TO "; +1355 IF T1=0 THEN 1365 +1360 PRINT "INCREASED "; +1365 PRINT "AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)" +1370 AGRICULTURAL_INCOME=INT((PLANTING_AREA-CROP_LOSS)*(LANDPRICE/2)) +1380 PRINT "MAKING";INT(AGRICULTURAL_INCOME);"RALLODS." +1390 RALLODS=INT(RALLODS+AGRICULTURAL_INCOME) + +REM I think tourism calculations are actually wrong in the original code! + +1400 V1=INT(((COUNTRYMEN-IMMIGRATION)*22)+(RND(1)*500)) +1405 V2=INT((2000-LANDAREA)*15) +1410 PRINT " YOU MADE";ABS(INT(V1-V2));"RALLODS FROM TOURIST TRADE." +1420 IF V2=0 THEN 1450 +1425 IF V1-V2>=V3 THEN 1450 +1430 PRINT " DECREASE BECAUSE "; +1435 G1=10*RND(1) +1440 IF G1<=2 THEN 1460 +1442 IF G1<=4 THEN 1465 +1444 IF G1<=6 THEN 1470 +1446 IF G1<=8 THEN 1475 +1448 IF G1<=10 THEN 1480 +1450 V3=INT(RALLODS+V3) +1451 RALLODS=INT(RALLODS+V3) +1452 GOTO 1500 +1460 PRINT "FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION." +1462 GOTO 1450 +1465 PRINT "AIR POLLUTION IS KILLING GAME BIRD POPULATION." +1467 GOTO 1450 +1470 PRINT "MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION." +1472 GOTO 1450 +1475 PRINT "UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS." +1477 GOTO 1450 +1480 PRINT "HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT." +1482 GOTO 1450 +1500 IF DEATHS>200 THEN 1600 +1505 IF COUNTRYMEN<343 THEN 1700 +1510 IF (ORIGINAL_RALLODS/100)>5 THEN 1800 +1515 IF FOREIGN_WORKERS>COUNTRYMEN THEN 1550 +1520 IF YEARS_REQUIRED-1=X5 THEN 1900 +1545 GOTO 2000 +1550 PRINT +1552 PRINT +1560 PRINT "THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER" +1562 PRINT "OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND" +1564 PRINT "TAKEN OVER THE COUNTRY." +1570 IF RND(1)<=.5 THEN 1580 +1574 PRINT "YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW" +1576 PRINT "RESIDING IN PRISON." +1578 GOTO 1590 +1580 PRINT "YOU HAVE BEEN ASSASSINATED." +1590 PRINT +1592 PRINT +1596 STOP +1600 PRINT +1602 PRINT +1610 PRINT DEATHS;"COUNTRYMEN DIED IN ONE YEAR!!!!!" +1615 PRINT "DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY" +1620 PRINT "BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU" +1622 M6=INT(RND(1)*10) +1625 IF M6<=3 THEN 1670 +1630 IF M6<=6 THEN 1680 +1635 IF M6<=10 THEN 1690 +1670 PRINT "ALSO HAD YOUR LEFT EYE GOUGED OUT!" +1672 GOTO 1590 +1680 PRINT "HAVE ALSO GAINED A VERY BAD REPUTATION." +1682 GOTO 1590 +1690 PRINT "HAVE ALSO BEEN DECLARED NATIONAL FINK." +1692 GOTO 1590 + +1700 PRINT +1702 PRINT +1710 PRINT "OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU" +1715 PRINT "WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)" +1720 PRINT "HATE YOUR GUTS." +1730 GOTO 1570 +1800 IF DEATHS-POLLUTION_DEATHS<2 THEN 1515 +1807 PRINT +1815 PRINT "MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID" +1820 PRINT "NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED" +1825 PRINT "OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE" +1830 PRINT "BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE." +1835 PRINT "THE CHOICE IS YOURS." +1840 PRINT "IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER" +1845 PRINT "BEFORE PROCEEDING." +1850 GOTO 1590 +1900 PRINT +1902 PRINT +1920 PRINT "CONGRATULATIONS!!!!!!!!!!!!!!!!!!" +1925 PRINT "YOU HAVE SUCCESFULLY COMPLETED YOUR";YEARS_REQUIRED;"YEAR TERM" +1930 PRINT "OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT" +1935 PRINT "NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD" +1940 PRINT "LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT" +1945 PRINT "PLAYS THIS GAME." +1950 GOTO 1590 + +1960 PRINT "HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED"; +1961 INPUT X5 +1962 IF X5<0 THEN 1590 +1963 IF X5<8 THEN 1969 +1965 PRINT " COME ON, YOUR TERM IN OFFICE IS ONLY";YEARS_REQUIRED;"YEARS." +1967 GOTO 1960 +1969 PRINT "HOW MUCH DID YOU HAVE IN THE TREASURY"; +1970 INPUT RALLODS +1971 IF RALLODS<0 THEN 1590 +1975 PRINT "HOW MANY COUNTRYMEN"; +1976 INPUT COUNTRYMEN +1977 IF COUNTRYMEN<0 THEN 1590 +1980 PRINT "HOW MANY WORKERS"; +1981 INPUT FOREIGN_WORKERS +1982 IF FOREIGN_WORKERS<0 THEN 1590 +1990 PRINT "HOW MANY SQUARE MILES OF LAND"; +1991 INPUT LANDAREA +1992 IF LANDAREA<0 THEN 1590 +1993 IF LANDAREA>2000 THEN 1996 +1994 IF LANDAREA>1000 THEN 100 +1996 PRINT " COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND" +1997 PRINT " AND 10,000 SQ. MILES OF FOREST LAND." +1998 GOTO 1990 + +2000 X5=X5+1 +2020 DEATHS=0 +2040 GOTO 100 +2046 END diff --git a/00_Alternate_Languages/53_King/kotlin/King.kt b/00_Alternate_Languages/53_King/kotlin/King.kt new file mode 100644 index 00000000..5947d278 --- /dev/null +++ b/00_Alternate_Languages/53_King/kotlin/King.kt @@ -0,0 +1,629 @@ +package king53 + +import kotlin.math.abs +import kotlin.random.Random +import kotlin.system.exitProcess + +lateinit var gameState: GameState +const val KEEP_ORIGINAL_BUGS = false +const val KEEP_ORIGINAL_SUICIDE_REFERENCE = false + +val rnd: Double get() = Random.nextDouble() +fun tab(i: Int) = " ".repeat(i) +class EndOfInputException : Throwable() + +fun main() { + header() + + print("DO YOU WANT INSTRUCTIONS? ") + readLine()?.apply { + gameState = if (startsWith("AGAIN")) loadOldGame() else GameState() + if (startsWith("Y")) instructions(gameState.yearsRequired) + } + ?: throw EndOfInputException() + + with(gameState) { + do { + + recalculateLandCost() + displayStatus() + inputLandSale() + performLandSale() + inputWelfare() + performWelfare() + inputPlantingArea() + performPlanting() + inputPollutionControl() + if (zeroInput()) { + displayExitMessage() + exitProcess(0) + } + val yearResult = simulateOneYear().also { + it.displayConsequences() + } + } while (yearResult == YearOutcome.ContinueNextYear) + } +} + +private fun header() { + println("${tab(34)}KING") + println("${tab(14)}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + println() + println() + println() +} + +fun instructions(yearsRequired: Int) { + println( + """ + + + CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS + DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR + JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE + MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY. + THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100 + RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES + FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT + FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND + WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD + TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT + THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER + SQUARE MILE TO PLANT. + YOUR GOAL IS TO COMPLETE YOUR $yearsRequired YEAR TERM OF OFFICE. + GOOD LUCK! + """.trimIndent() + ) +} + +fun loadOldGame(): GameState = GameState().apply { + + do { + var retry = false + print("HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED? ") + currentYear = validatedInput { it > 0 } + + if (currentYear >= yearsRequired) { + println(" COME ON, YOUR TERM IN OFFICE IS ONLY $yearsRequired YEARS.") + retry = true + } + + } while (retry) + + print("HOW MUCH DID YOU HAVE IN THE TREASURY? ") + rallods = validatedInput { it >= 0 } + + print("HOW MANY COUNTRYMEN? ") + countrymen = validatedInput { it >= 0 } + + print("HOW MANY WORKERS? ") + foreignWorkers = validatedInput { it >= 0 } + + do { + var retry = false + print("HOW MANY SQUARE MILES OF LAND? ") + landArea = validatedInput { it >= 0 } + + if (landArea > 2000 || landArea <= 1000) { + println(" COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND") + println(" AND 10,000 SQ. MILES OF FOREST LAND.") + retry = true + } + } while (retry) + +} + + +/** + * Possible outcomes for a year. + */ +sealed class YearOutcome { + + /** + * Display output for the end of the year, for each different possible + * year outcome. + */ + open fun displayConsequences() { + // Default display nothing + } + + fun finalFate() { + if (rnd < .5) { + println("YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW") + println("RESIDING IN PRISON.") + } else { + println("YOU HAVE BEEN ASSASSINATED.") + } + println() + println() + } + + object ContinueNextYear : YearOutcome() + + class Win(private val yearsRequired: Int) : YearOutcome() { + override fun displayConsequences() { + // The misspelling of "successfully" is in the original code. + println( + """ + + CONGRATULATIONS!!!!!!!!!!!!!!!!!! + YOU HAVE SUCCESFULLY COMPLETED YOUR $yearsRequired YEAR TERM + OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT + NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD + LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT + PLAYS THIS GAME. + + + """.trimIndent() + ) + } + } + + class ExtremeMismanagement(private val death: Int) : YearOutcome() { + override fun displayConsequences() { + println() + println("$death COUNTRYMEN DIED IN ONE YEAR!!!!!") + println("DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY") + println("BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU") + println( + when ((rnd * 10.0).toInt()) { + in 0..3 -> "ALSO HAD YOUR LEFT EYE GOUGED OUT!" + in 4..6 -> "HAVE ALSO GAINED A VERY BAD REPUTATION." + else -> "HAVE ALSO BEEN DECLARED NATIONAL FINK." + } + ) + } + } + + object TooManyPeopleDead : YearOutcome() { + // The mistyping of "population" is in the original game. + override fun displayConsequences() { + println( + """ + + + OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU + WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING) + HATE YOUR GUTS. + """.trimIndent() + ) + finalFate() + } + } + + object AntiImmigrationRevolution : YearOutcome() { + override fun displayConsequences() { + println( + """ + THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER + OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND + TAKEN OVER THE COUNTRY. + """.trimIndent() + ) + finalFate() + } + } + + object StarvationWithFullTreasury : YearOutcome() { + override fun displayConsequences() { + println( + if (KEEP_ORIGINAL_SUICIDE_REFERENCE) { + """ + MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID + NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED + OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE + BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE. + THE CHOICE IS YOURS. + IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER + BEFORE PROCEEDING. + """.trimIndent() + } else { + """ + MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID + NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED + OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE + BEEN FORCED TO RESIGN. + PLEASE TURN OFF YOUR COMPUTER AND SURRENDER IT TO + THE NEAREST POLICE STATION. + """.trimIndent() + } + ) + } + } + +} + +/** + * Record data, allow data input, and process the simulation for the game. + */ +class GameState(val yearsRequired: Int = 8) { + + /** + * The current year. Years start with zero, but we never + * output the current year. + */ + var currentYear = 0 + + /** + * Keep track of each year's crop loss, so we can report increases. + */ + private var lastYearsCropLoss: Int = 0 + + /** + * Number of countrymen who have died of either pollution + * or starvation this year. + * It costs 9 rallods to bury a body. + * If you lose 200 people in one year, you will throw an {@see ExtremeMismanagementException} + */ + private var death = 0 + + /** + * Last year's tourist numbers. Use this to check whether the number + * of tourists has gone up or down each year. + */ + private var tourists = 0 + + private var moneySpentOnPollutionControl = 0 + + private var moneySpentOnPlanting = 0 + /** + * Current stock of rallods. + * Player starts with between 59000 and 61000 rallods, but + * mostly distributed close to 60000. 75% of the time it's + * between 59500 and 60500. + */ + var rallods = (60000.0 + (1000.0 * rnd) - (1000.0 * rnd)).toInt() + + /** + * Population. + * Initial population is about 500. + * 75% of the time it's between 495 and 505. + */ + var countrymen = (500 + (10 * rnd) - (10 * rnd)).toInt() + + /** + * Land sale price is evenly between 95 and 104 rallods per + * square mile. + * Price doesn't change over the course of the game. + */ + private var landPrice = (10 * rnd + 95).toInt() + + private var plantingArea = 0 + + private var welfareThisYear = 0 + /** + * Land area in square miles. Arable land is 1000 square miles less. + * Almost all calculations use landArea-1000 because only arable + * land is of any use. + */ + var landArea = 2000 + + /** + * Number of foreigners brought in by companies to whom you + * have sold land. If this gets higher than your population, there will + * be a revolution. + */ + var foreignWorkers = 0 + + /** + * Planting cost is recalculated every year. + */ + private var costToPlant: Int = 1 + + /** + * There is a brief explanation of land selling only + * on the first turn. + */ + private var explanationOfSellingGiven = false + + private var sellThisYear: Int = 0 + + /** + * Planting cost is recalculated every year + * at between 10 and 14 rallods. + */ + fun recalculateLandCost() { + costToPlant = ((rnd / 2.0) * 10.0 + 10.0).toInt() + } + + /** + * Show the current status of the world. + */ + fun displayStatus() { + println() + println("YOU NOW HAVE $rallods RALLODS IN THE TREASURY.") + print("$countrymen COUNTRYMEN, ") + if (foreignWorkers != 0) { + println("$foreignWorkers FOREIGN WORKERS, ") + } + println("AND $landArea SQ. MILES OF LAND.") + println("THIS YEAR INDUSTRY WILL BUY LAND FOR $landPrice") + println("RALLODS PER SQUARE MILE.") + println("LAND CURRENTLY COSTS $costToPlant RALLODS PER SQUARE MILE TO PLANT.") + } + + fun displayExitMessage() { + println() + println("GOODBYE.") + println("(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER") + println("'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START") + println("OF THE GAME).") + } + + fun performLandSale() { + landArea -= sellThisYear + rallods += sellThisYear * landPrice + } + + fun performPlanting() { + rallods -= moneySpentOnPlanting + } + + fun performWelfare() { + rallods -= welfareThisYear + } + + /** + * Ask how much land we want to sell. Immediately get the money. + * The player has to do the calculations to work out how much + * money that makes. + */ + fun inputLandSale() { + do { + print("HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY? ") + sellThisYear = numberInput() + if (sellThisYear > landArea - 1000) { + println("*** THINK AGAIN. YOU ONLY HAVE ${landArea - 1000} SQUARE MILES OF FARM LAND.") + if (!explanationOfSellingGiven) { + println() + println("(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE") + println("FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,") + println("THICKER TOP SOIL, ETC.)") + explanationOfSellingGiven = true + } + } + } while (sellThisYear < 0 || sellThisYear > landArea - 1000) + } + + + /** + * Input the value of `welfareThisYear` + */ + fun inputWelfare() { + do { + var retry = false + print("HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN? ") + welfareThisYear = numberInput() + + if (welfareThisYear > rallods) { + println(" THINK AGAIN. YOU'VE ONLY $rallods RALLODS IN THE TREASURY") + retry = true + } + + if (welfareThisYear < 0) { + retry = true + } + } while (retry) + } + + /** + * Get the number of square miles to plant this year. + * Validate the response: + * Each countryman can only plant 2 square miles. + * You can only plant on arable land. + * You may not spend more on planting than your treasury. + */ + fun inputPlantingArea() { + if (welfareThisYear == rallods) { + plantingArea = 0 + } else { + do { + var retry = false + print("HOW MANY SQUARE MILES DO YOU WISH TO PLANT? ") + plantingArea = numberInput() + val moneySpentOnPlanting = plantingArea * costToPlant + + if (plantingArea < 0) { + retry = true + } else if (plantingArea >= 0 && plantingArea > countrymen * 2) { + println(" SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.") + retry = true + } else if (plantingArea > landArea - 1000) { + println(" SORRY, BUT YOU'VE ONLY ${landArea - 1000} SQ. MILES OF FARM LAND.") + retry = true + } else if (moneySpentOnPlanting > rallods) { + println(" THINK AGAIN. YOU'VE ONLY $rallods RALLODS LEFT IN THE TREASURY.") + retry = true + } + } while (retry) + } + + } + + /** + * Enter amount for pollution control. + * Validate that this does not exceed treasury. + */ + fun inputPollutionControl() { + do { + var retry = false + print("HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL? ") + moneySpentOnPollutionControl = numberInput() + + if (rallods < 0) { + retry = true + } else if (moneySpentOnPollutionControl > rallods) { + println(" THINK AGAIN. YOU ONLY HAVE $rallods RALLODS REMAINING.") + retry = true + } + + } while (retry) + } + + /** + * @return true if all data entered so far has been zero. + */ + fun zeroInput() = sellThisYear == 0 && + welfareThisYear == 0 && + plantingArea == 0 && + moneySpentOnPollutionControl == 0 + + fun simulateOneYear(): YearOutcome { + rallods -= moneySpentOnPollutionControl + val rallodsAfterPollutionControl = rallods + + var starvationDeaths = 0 + if (welfareThisYear / 100.0 - countrymen < 0) { + + /* + Wait, WHAT? + If you spend less than 5000 rallods on welfare, no matter the current size of the + population, then you will end the game, with the game claiming that too many + people have died, without showing exactly how many have died? + + https://github.com/coding-horror/basic-computer-games/blob/main/53_King/king.bas#:~:text=1105%20IF%20I/100%3C50%20THEN%201700 + */ + if (welfareThisYear / 100.0 < 50) + return YearOutcome.TooManyPeopleDead + + starvationDeaths = (countrymen - (welfareThisYear / 100.0)).toInt() + println("$starvationDeaths COUNTRYMEN DIED OF STARVATION") + } + + var pollutionDeaths = (rnd * (2000 - landArea)).toInt() + if (moneySpentOnPollutionControl >= 25) { + pollutionDeaths = (pollutionDeaths / (moneySpentOnPollutionControl / 25.0)).toInt() + } + + if (pollutionDeaths > 0) { + println("$pollutionDeaths COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION") + } + + death = pollutionDeaths + starvationDeaths + if (death > 0) { + println(" YOU WERE FORCED TO SPEND ${death * 9}") + println("RALLODS ON FUNERAL EXPENSES") + rallods -= death * 9 + } + + if (rallods < 0) { + println(" INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD") + landArea += rallods / landPrice + rallods = 1 + } + + countrymen -= death + + val newForeigners = + if (sellThisYear > 0) { + (sellThisYear + rnd * 10.0 + rnd * 20.0).toInt() + (if (foreignWorkers <= 0) 20 else 0) + } else 0 + + /* + Immigration is calculated as + One for every thousand rallods more welfare than strictly required + minus one for every 10 starvation deaths + plus One for every 25 rallods spent on pollution control + plus one for every 50 square miles of arable land + minus one for every 2 pollution deaths + */ + val immigration = ( + (welfareThisYear / 100.0 - countrymen) / 10.0 + + moneySpentOnPollutionControl / 25.0 - + (2000 - landArea) / 50.0 - + pollutionDeaths / 2.0 + ).toInt() + println( + "$newForeigners WORKERS CAME TO THE COUNTRY AND" + + " ${abs(immigration)} COUNTRYMEN ${if (immigration < 0) "LEFT" else "CAME TO"}" + + " THE ISLAND." + ) + + countrymen += immigration + foreignWorkers += newForeigners + + /* + Crop loss is between 75% and 125% of the land sold to industry, + due to the pollution that industry causes. + Money spent on pollution control reduces pollution deaths among + the population, but does not affect crop losses. + */ + var cropLoss = ((2000 - landArea) * (rnd + 1.5) / 2.0).toInt() + if (foreignWorkers > 0) + print("OF $plantingArea SQ. MILES PLANTED,") + if (plantingArea <= cropLoss) + cropLoss = plantingArea + val cropLossWorse = cropLoss > lastYearsCropLoss + lastYearsCropLoss = cropLoss + println(" YOU HARVESTED ${plantingArea - cropLoss} SQ. MILES OF CROPS.") + + if (cropLoss > 0) { + println(" (DUE TO ${if (cropLossWorse) "INCREASED " else ""}AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY)") + } + + val agriculturalIncome = ((plantingArea - cropLoss) * landPrice / 2.0).toInt() + println("MAKING $agriculturalIncome RALLODS.") + rallods += agriculturalIncome + + val v1 = (((countrymen - immigration) * 22.0) + rnd * 500).toInt() + val v2 = ((2000.0 - landArea) * 15.0).toInt() + println(" YOU MADE ${abs(v1 - v2)} RALLODS FROM TOURIST TRADE.") + if (v2 != 0 && v1 - v2 < tourists) { + print(" DECREASE BECAUSE ") + println( + when ((10 * rnd).toInt()) { + in 0..2 -> "FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION." + in 3..4 -> "AIR POLLUTION IS KILLING GAME BIRD POPULATION." + in 5..6 -> "MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION." + in 7..8 -> "UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS." + else -> "HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT." + } + ) + } + + /* + The original code was incorrect. + If v3 starts at 0, for example, our money doubles, when we + have already been told that "YOU MADE ${abs(v1 - v2)} RALLODS + FROM TOURIST TRADE" + + See the original code + 1450 V3=INT(A+V3) + 1451 A=INT(A+V3) + + https://github.com/coding-horror/basic-computer-games/blob/main/53_King/king.bas#:~:text=1450%20V3%3DINT,INT(A%2BV3) + */ + if (KEEP_ORIGINAL_BUGS) { + tourists += rallods + } else { + tourists = abs(v1 - v2) + } + rallods += tourists + + return if (death > 200) + YearOutcome.ExtremeMismanagement(death) + else if (countrymen < 343) + YearOutcome.TooManyPeopleDead + else if (rallodsAfterPollutionControl / 100 > 5 && death - pollutionDeaths >= 2) + YearOutcome.StarvationWithFullTreasury + else if (foreignWorkers > countrymen) + YearOutcome.AntiImmigrationRevolution + else { + if (currentYear++ > yearsRequired) + YearOutcome.Win(yearsRequired) + else + YearOutcome.ContinueNextYear + } + + } +} + +private fun numberInput() = try { + readLine()?.toInt() ?: throw EndOfInputException() +} catch (r: NumberFormatException) { + 0 +} + +class DataEntryValidationException : Throwable() +private fun validatedInput(predicate : (Int)->Boolean) = + numberInput().apply { if (!predicate(this)) throw DataEntryValidationException() } diff --git a/29_Craps/pascal/README.md b/00_Alternate_Languages/53_King/pascal/README.md similarity index 100% rename from 29_Craps/pascal/README.md rename to 00_Alternate_Languages/53_King/pascal/README.md diff --git a/00_Alternate_Languages/53_King/perl/README.md b/00_Alternate_Languages/53_King/perl/README.md new file mode 100644 index 00000000..e69c8b81 --- /dev/null +++ b/00_Alternate_Languages/53_King/perl/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Perl](https://www.perl.org/) diff --git a/00_Alternate_Languages/53_King/python/README.md b/00_Alternate_Languages/53_King/python/README.md new file mode 100644 index 00000000..781945ec --- /dev/null +++ b/00_Alternate_Languages/53_King/python/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Python](https://www.python.org/about/) diff --git a/00_Alternate_Languages/53_King/ruby/README.md b/00_Alternate_Languages/53_King/ruby/README.md new file mode 100644 index 00000000..fb32811e --- /dev/null +++ b/00_Alternate_Languages/53_King/ruby/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Ruby](https://www.ruby-lang.org/en/) diff --git a/00_Alternate_Languages/53_King/vbnet/King.sln b/00_Alternate_Languages/53_King/vbnet/King.sln new file mode 100644 index 00000000..c5bdb50c --- /dev/null +++ b/00_Alternate_Languages/53_King/vbnet/King.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "King", "King.vbproj", "{043D7CC7-1FFC-438E-BB00-31CB467BEB73}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {043D7CC7-1FFC-438E-BB00-31CB467BEB73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {043D7CC7-1FFC-438E-BB00-31CB467BEB73}.Debug|Any CPU.Build.0 = Debug|Any CPU + {043D7CC7-1FFC-438E-BB00-31CB467BEB73}.Release|Any CPU.ActiveCfg = Release|Any CPU + {043D7CC7-1FFC-438E-BB00-31CB467BEB73}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/00_Alternate_Languages/53_King/vbnet/King.vbproj b/00_Alternate_Languages/53_King/vbnet/King.vbproj new file mode 100644 index 00000000..62bef191 --- /dev/null +++ b/00_Alternate_Languages/53_King/vbnet/King.vbproj @@ -0,0 +1,8 @@ + + + Exe + King + net6.0 + 16.9 + + diff --git a/00_Alternate_Languages/53_King/vbnet/README.md b/00_Alternate_Languages/53_King/vbnet/README.md new file mode 100644 index 00000000..98b702c7 --- /dev/null +++ b/00_Alternate_Languages/53_King/vbnet/README.md @@ -0,0 +1,3 @@ +Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET) diff --git a/00_Alternate_Languages/54_Letter/README.md b/00_Alternate_Languages/54_Letter/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/54_Letter/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/54_Letter/csharp/Game.cs b/00_Alternate_Languages/54_Letter/csharp/Game.cs new file mode 100644 index 00000000..e7d525c9 --- /dev/null +++ b/00_Alternate_Languages/54_Letter/csharp/Game.cs @@ -0,0 +1,137 @@ +namespace Letter +{ + internal static class Game + { + /// + /// Maximum number of guesses. + /// Note the program doesn't enforce this - it just displays a message if this is exceeded. + /// + private const int MaximumGuesses = 5; + + /// + /// Main game loop. + /// + public static void Play() + { + DisplayIntroductionText(); + + // Keep playing forever, or until the user quits. + while (true) + { + PlayRound(); + } + } + + /// + /// Play a single round. + /// + internal static void PlayRound() + { + var gameState = new GameState(); + DisplayRoundIntroduction(); + + char letterInput = '\0'; // Set the initial character to something that's not A-Z. + while (letterInput != gameState.Letter) + { + letterInput = GetCharacterFromKeyboard(); + gameState.GuessesSoFar++; + DisplayGuessResult(gameState.Letter, letterInput); + } + DisplaySuccessMessage(gameState); + } + + /// + /// Display an introduction when the game loads. + /// + internal static void DisplayIntroductionText() + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine("LETTER"); + Console.WriteLine("Creative Computing, Morristown, New Jersey."); + Console.WriteLine(""); + + Console.ForegroundColor = ConsoleColor.DarkGreen; + Console.WriteLine("Letter Guessing Game"); + Console.WriteLine("I'll think of a letter of the alphabet, A to Z."); + Console.WriteLine("Try to guess my letter and I'll give you clues"); + Console.WriteLine("as to how close you're getting to my letter."); + Console.WriteLine(""); + + Console.ResetColor(); + } + + /// + /// Display introductionary text for each round. + /// + internal static void DisplayRoundIntroduction() + { + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine("O.K., I have a letter. Start guessing."); + + Console.ResetColor(); + } + + /// + /// Display text depending whether the guess is lower or higher. + /// + internal static void DisplayGuessResult(char letterToGuess, char letterInput) + { + Console.BackgroundColor = ConsoleColor.White; + Console.ForegroundColor = ConsoleColor.Black; + Console.Write(" " + letterInput + " "); + + Console.ResetColor(); + Console.ForegroundColor = ConsoleColor.Gray; + Console.Write(" "); + if (letterInput != letterToGuess) + { + if (letterInput > letterToGuess) + { + Console.WriteLine("Too high. Try a lower letter"); + } + else + { + Console.WriteLine("Too low. Try a higher letter"); + } + } + Console.ResetColor(); + } + + /// + /// Display success, and the number of guesses. + /// + internal static void DisplaySuccessMessage(GameState gameState) + { + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"You got it in {gameState.GuessesSoFar} guesses!!"); + if (gameState.GuessesSoFar > MaximumGuesses) + { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine($"But it shouldn't take more than {MaximumGuesses} guesses!"); + } + else + { + Console.WriteLine("Good job !!!!!"); + } + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine(""); + Console.WriteLine("Let's play again....."); + + Console.ResetColor(); + } + + /// + /// Get valid input from the keyboard: must be an alpha character. Converts to upper case if necessary. + /// + internal static char GetCharacterFromKeyboard() + { + char letterInput; + do + { + var keyPressed = Console.ReadKey(true); + letterInput = Char.ToUpper(keyPressed.KeyChar); // Convert to upper case immediately. + } while (!Char.IsLetter(letterInput)); // If the input is not a letter, wait for another letter to be pressed. + return letterInput; + } + } +} diff --git a/00_Alternate_Languages/54_Letter/csharp/GameState.cs b/00_Alternate_Languages/54_Letter/csharp/GameState.cs new file mode 100644 index 00000000..02aa38b1 --- /dev/null +++ b/00_Alternate_Languages/54_Letter/csharp/GameState.cs @@ -0,0 +1,37 @@ +namespace Letter +{ + /// + /// Holds the current state. + /// + internal class GameState + { + /// + /// Initialise the game state with a random letter. + /// + public GameState() + { + Letter = GetRandomLetter(); + GuessesSoFar = 0; + } + + /// + /// The letter that the user is guessing. + /// + public char Letter { get; set; } + + /// + /// The number of guesses the user has had so far. + /// + public int GuessesSoFar { get; set; } + + /// + /// Get a random character (A-Z) for the user to guess. + /// + internal static char GetRandomLetter() + { + var random = new Random(); + var randomNumber = random.Next(0, 26); + return (char)('A' + randomNumber); + } + } +} diff --git a/00_Alternate_Languages/54_Letter/csharp/Letter.csproj b/00_Alternate_Languages/54_Letter/csharp/Letter.csproj new file mode 100644 index 00000000..d3fe4757 --- /dev/null +++ b/00_Alternate_Languages/54_Letter/csharp/Letter.csproj @@ -0,0 +1,9 @@ + + + Exe + net6.0 + 10 + enable + enable + + diff --git a/00_Alternate_Languages/54_Letter/csharp/Letter.sln b/00_Alternate_Languages/54_Letter/csharp/Letter.sln new file mode 100644 index 00000000..3f567521 --- /dev/null +++ b/00_Alternate_Languages/54_Letter/csharp/Letter.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Letter", "Letter.csproj", "{8BE20DCF-A729-46ED-92EA-55866844EB93}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8BE20DCF-A729-46ED-92EA-55866844EB93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8BE20DCF-A729-46ED-92EA-55866844EB93}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8BE20DCF-A729-46ED-92EA-55866844EB93}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8BE20DCF-A729-46ED-92EA-55866844EB93}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/00_Alternate_Languages/54_Letter/csharp/Program.cs b/00_Alternate_Languages/54_Letter/csharp/Program.cs new file mode 100644 index 00000000..63bd4a12 --- /dev/null +++ b/00_Alternate_Languages/54_Letter/csharp/Program.cs @@ -0,0 +1,3 @@ +using Letter; + +Game.Play(); diff --git a/00_Alternate_Languages/54_Letter/csharp/README.md b/00_Alternate_Languages/54_Letter/csharp/README.md new file mode 100644 index 00000000..4daabb5c --- /dev/null +++ b/00_Alternate_Languages/54_Letter/csharp/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) diff --git a/00_Alternate_Languages/54_Letter/java/README.md b/00_Alternate_Languages/54_Letter/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/54_Letter/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/54_Letter/java/src/Letter.java b/00_Alternate_Languages/54_Letter/java/src/Letter.java new file mode 100644 index 00000000..ffe478cf --- /dev/null +++ b/00_Alternate_Languages/54_Letter/java/src/Letter.java @@ -0,0 +1,142 @@ +import java.awt.*; +import java.util.Arrays; +import java.util.Scanner; + +/** + * Game of Letter + *

+ * Based on the Basic game of Letter here + * https://github.com/coding-horror/basic-computer-games/blob/main/54%20Letter/letter.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. + */ +public class Letter { + + public static final int OPTIMAL_GUESSES = 5; + public static final int ASCII_A = 65; + public static final int ALL_LETTERS = 26; + + private enum GAME_STATE { + STARTUP, + INIT, + GUESSING, + RESULTS, + GAME_OVER + } + + // Used for keyboard input + private final Scanner kbScanner; + + // Current game state + private GAME_STATE gameState; + + // Players guess count; + private int playerGuesses; + + // Computers ascii code for a random letter between A..Z + private int computersLetter; + + public Letter() { + + gameState = GAME_STATE.STARTUP; + + // Initialise kb scanner + kbScanner = new Scanner(System.in); + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + // Show an introduction the first time the game is played. + case STARTUP: + intro(); + gameState = GAME_STATE.INIT; + break; + + case INIT: + playerGuesses = 0; + computersLetter = ASCII_A + (int) (Math.random() * ALL_LETTERS); + System.out.println("O.K., I HAVE A LETTER. START GUESSING."); + gameState = GAME_STATE.GUESSING; + break; + + // Player guesses the number until they get it or run out of guesses + case GUESSING: + String playerGuess = displayTextAndGetInput("WHAT IS YOUR GUESS? ").toUpperCase(); + + // Convert first character of input string to ascii + int toAscii = playerGuess.charAt(0); + playerGuesses++; + if (toAscii == computersLetter) { + gameState = GAME_STATE.RESULTS; + break; + } + + if (toAscii > computersLetter) { + System.out.println("TOO HIGH. TRY A LOWER LETTER."); + } else { + System.out.println("TOO LOW. TRY A HIGHER LETTER."); + } + break; + + // Play again, or exit game? + case RESULTS: + System.out.println(); + System.out.println("YOU GOT IT IN " + playerGuesses + " GUESSES!!"); + if (playerGuesses <= OPTIMAL_GUESSES) { + System.out.println("GOOD JOB !!!!!"); + // Original game beeped 15 tims if you guessed in the optimal guesses or less + // Changed this to do a single beep only + Toolkit.getDefaultToolkit().beep(); + } else { + // Took more than optimal number of guesses + System.out.println("BUT IT SHOULDN'T TAKE MORE THAN " + OPTIMAL_GUESSES + " GUESSES!"); + } + System.out.println(); + System.out.println("LET'S PLAN AGAIN....."); + gameState = GAME_STATE.INIT; + break; + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + public void intro() { + System.out.println(simulateTabs(33) + "LETTER"); + System.out.println(simulateTabs(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("LETTER GUESSING GAME"); + System.out.println(); + System.out.println("I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z."); + System.out.println("TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES"); + System.out.println("AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER."); + } + + /** + * Simulate the old basic tab(xx) command which indented text by xx spaces. + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String simulateTabs(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } +} diff --git a/00_Alternate_Languages/54_Letter/java/src/LetterGame.java b/00_Alternate_Languages/54_Letter/java/src/LetterGame.java new file mode 100644 index 00000000..fa023329 --- /dev/null +++ b/00_Alternate_Languages/54_Letter/java/src/LetterGame.java @@ -0,0 +1,8 @@ +public class LetterGame { + + public static void main(String[] args) { + + Letter letter = new Letter(); + letter.play(); + } +} diff --git a/00_Alternate_Languages/54_Letter/javascript/README.md b/00_Alternate_Languages/54_Letter/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/54_Letter/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/54_Letter/javascript/letter.html b/00_Alternate_Languages/54_Letter/javascript/letter.html new file mode 100644 index 00000000..744a5499 --- /dev/null +++ b/00_Alternate_Languages/54_Letter/javascript/letter.html @@ -0,0 +1,9 @@ + + +LETTER + + +


+
+
+
diff --git a/00_Alternate_Languages/54_Letter/javascript/letter.js b/00_Alternate_Languages/54_Letter/javascript/letter.js
new file mode 100644
index 00000000..9129c075
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/javascript/letter.js
@@ -0,0 +1,91 @@
+// LETTER
+//
+// 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(33) + "LETTER\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("LETTER GUESSING GAME\n");
+    print("\n");
+    print("I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\n");
+    print("TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\n");
+    print("AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\n");
+    while (1) {
+        l = 65 + Math.floor(26 * Math.random());
+        g = 0;
+        print("\n");
+        print("O.K., I HAVE A LETTER.  START GUESSING.\n");
+        while (1) {
+
+            print("\n");
+            print("WHAT IS YOUR GUESS");
+            g++;
+            str = await input();
+            a = str.charCodeAt(0);
+            print("\n");
+            if (a == l)
+                break;
+            if (a < l) {
+                print("TOO LOW.  TRY A HIGHER LETTER.\n");
+            } else {
+                print("TOO HIGH.  TRY A LOWER LETTER.\n");
+            }
+        }
+        print("\n");
+        print("YOU GOT IT IN " + g + " GUESSES!!\n");
+        if (g > 5) {
+            print("BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\n");
+        } else {
+            print("GOOD JOB !!!!!\n");
+        }
+        print("\n");
+        print("LET'S PLAY AGAIN.....");
+    }
+}
+
+main();
diff --git a/00_Alternate_Languages/54_Letter/letter.bas b/00_Alternate_Languages/54_Letter/letter.bas
new file mode 100644
index 00000000..ab3efe0c
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/letter.bas
@@ -0,0 +1,26 @@
+10 PRINT TAB(33);"LETTER"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+100 PRINT "LETTER GUESSING GAME": PRINT
+210 PRINT "I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z."
+220 PRINT "TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES"
+230 PRINT "AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER."
+310 L=65+INT(RND(1)*26)
+320 G=0
+340 PRINT: PRINT "O.K., I HAVE A LETTER.  START GUESSING."
+410 PRINT: PRINT "WHAT IS YOUR GUESS";
+420 G=G+1
+430 INPUT A$: A=ASC(A$): PRINT
+440 IF A=L THEN 500
+450 IF A>L THEN 480
+460 PRINT "TOO LOW.  TRY A HIGHER LETTER.": GOTO 410
+480 PRINT "TOO HIGH.  TRY A LOWER LETTER.": GOTO 410
+500 PRINT: PRINT "YOU GOT IT IN";G;"GUESSES!!"
+504 IF G<=5 THEN 508
+506 PRINT "BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!": GOTO 515
+508 PRINT "GOOD JOB !!!!!"
+510 FOR N=1 TO 15: PRINT CHR$(7);: NEXT N
+515 PRINT
+520 PRINT "LET'S PLAY AGAIN....."
+530 GOTO 310
+999 END
diff --git a/30_Cube/pascal/README.md b/00_Alternate_Languages/54_Letter/pascal/README.md
similarity index 100%
rename from 30_Cube/pascal/README.md
rename to 00_Alternate_Languages/54_Letter/pascal/README.md
diff --git a/00_Alternate_Languages/54_Letter/perl/README.md b/00_Alternate_Languages/54_Letter/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/54_Letter/perl/letter.pl b/00_Alternate_Languages/54_Letter/perl/letter.pl
new file mode 100644
index 00000000..56acf533
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/perl/letter.pl
@@ -0,0 +1,41 @@
+#!/usr/bin/perl
+use strict;
+
+print ' 'x33 . "LETTER\n";
+print ' 'x15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+
+print "LETTER GUESSING GAME\n\n";
+print "I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\n";
+print "TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\n";
+print "AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\n";
+
+while (1) {
+	my $letter = 65 + int(rand(26));
+	my $guesses = 0;
+	print "\nO.K., I HAVE A LETTER. START GUESSING.\n";
+
+	my $answer;
+	do {
+		print "\nWHAT IS YOUR GUESS? ";
+		$guesses++;
+		chomp($answer = );
+		$answer = ord($answer);
+		print "\n";
+		print "TOO LOW. TRY A HIGHER LETTER.\n" if $answer < $letter;
+		print "TOO HIGH. TRY A LOWER LETTER.\n" if $answer > $letter;
+	} until($answer eq $letter);
+
+	print "\nYOU GOT IT IN $guesses GUESSES!!\n";
+
+	if ($guesses <= 5) {
+		print "GOOD JOB !!!!!\n";
+		print chr(7) x 15; # ASCII Bell
+	} else {
+		print "BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\n";
+	}
+
+	print "\nLET'S PLAY AGAIN.....\n";
+}
+
+exit;
diff --git a/00_Alternate_Languages/54_Letter/python/README.md b/00_Alternate_Languages/54_Letter/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/54_Letter/python/letter.py b/00_Alternate_Languages/54_Letter/python/letter.py
new file mode 100644
index 00000000..d80b368a
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/python/letter.py
@@ -0,0 +1,83 @@
+"""
+LETTER
+
+A letter guessing game.
+
+Ported by Dave LeCompte
+"""
+
+import random
+
+# The original code printed character 7, the "BELL" character 15 times
+# when the player won. Many modern systems do not support this, and in
+# any case, it can quickly become annoying, so it is disabled here.
+
+BELLS_ON_SUCCESS = False
+
+
+def print_with_tab(space_count, msg):
+    if space_count > 0:
+        spaces = " " * space_count
+    else:
+        spaces = ""
+
+    print(spaces + msg)
+
+
+def print_instructions():
+    print("LETTER GUESSING GAME")
+    print()
+    print("I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.")
+    print("TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES")
+    print("AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.")
+
+
+def play_game():
+    target_value = random.randint(ord("A"), ord("Z"))
+    num_guesses = 0
+    print()
+    print("O.K., I HAVE A LETTER.  START GUESSING.")
+    print()
+    while True:
+        print("WHAT IS YOUR GUESS?")
+        num_guesses += 1
+        guess = ord(input())
+        print()
+        if guess == target_value:
+            print()
+            print(f"YOU GOT IT IN {num_guesses} GUESSES!!")
+            if num_guesses > 5:
+                print("BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!")
+                # goto 515
+            print("GOOD JOB !!!!!")
+
+            if BELLS_ON_SUCCESS:
+                bellStr = chr(7) * 15
+                print(bellStr)
+
+            print()
+            print("LET'S PLAY AGAIN.....")
+            return
+        elif guess > target_value:
+            print("TOO HIGH. TRY A LOWER LETTER.")
+            continue
+        else:
+            print("TOO LOW. TRY A HIGHER LETTER.")
+            continue
+
+
+def main():
+    print_with_tab(33, "LETTER")
+    print_with_tab(15, "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+    print_instructions()
+
+    while True:
+        play_game()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/54_Letter/ruby/README.md b/00_Alternate_Languages/54_Letter/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/54_Letter/ruby/letter.rb b/00_Alternate_Languages/54_Letter/ruby/letter.rb
new file mode 100644
index 00000000..c4c7a00c
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/ruby/letter.rb
@@ -0,0 +1,45 @@
+#!/usr/bin/env ruby
+
+# Kinema
+# reinterpreted from BASIC by stephan.com
+
+puts 'Letter'.center(80)
+puts 'Adapted by stephan.com'.center(80)
+puts "\n\n\n"
+
+puts "Letter guessing game\n\n"
+
+puts "I'll think of a letter of the alphabet, A to Z."
+puts "Try to guess my letter and I'll give you clues"
+puts "as to how close you're getting to my letter."
+
+def win(turns)
+  puts "\nyou got it in #{turns} guesses!!"
+  return puts "but it shouldn't take more than 5 guesses!" if turns > 5
+
+  puts "good job !!!!!\a\a\a"
+end
+
+def play
+  letter = ('A'..'Z').to_a.sample
+  guess = nil
+  turn = 0
+
+  puts "\nO.K., I have a letter.  Start guessing."
+
+  until guess == letter
+    puts "\nWhat is your guess?"
+
+    guess = gets.strip.chars.first.upcase
+    turn += 1
+
+    puts 'Too low.  Try a higher letter.' if guess < letter
+    puts 'Too high.  Try a lower letter.' if guess > letter
+  end
+  win(turn)
+end
+
+loop do
+  play
+  puts "\nlet's play again....."
+end
diff --git a/00_Alternate_Languages/54_Letter/vbnet/Letter.sln b/00_Alternate_Languages/54_Letter/vbnet/Letter.sln
new file mode 100644
index 00000000..e2896128
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/vbnet/Letter.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Letter", "Letter.vbproj", "{15392FFC-0EBB-4CA3-970F-8AC32DE84724}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{15392FFC-0EBB-4CA3-970F-8AC32DE84724}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{15392FFC-0EBB-4CA3-970F-8AC32DE84724}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{15392FFC-0EBB-4CA3-970F-8AC32DE84724}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{15392FFC-0EBB-4CA3-970F-8AC32DE84724}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/54_Letter/vbnet/Letter.vbproj b/00_Alternate_Languages/54_Letter/vbnet/Letter.vbproj
new file mode 100644
index 00000000..0c55e2e6
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/vbnet/Letter.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Letter
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/54_Letter/vbnet/README.md b/00_Alternate_Languages/54_Letter/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/54_Letter/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/55_Life/README.md b/00_Alternate_Languages/55_Life/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/55_Life/csharp/.gitignore b/00_Alternate_Languages/55_Life/csharp/.gitignore
new file mode 100644
index 00000000..e96e7522
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/csharp/.gitignore
@@ -0,0 +1,509 @@
+
+# Created by https://www.toptal.com/developers/gitignore/api/dotnetcore,rider,visualstudio,visualstudiocode
+# Edit at https://www.toptal.com/developers/gitignore?templates=dotnetcore,rider,visualstudio,visualstudiocode
+
+### DotnetCore ###
+# .NET Core build folders
+bin/
+obj/
+
+# Common node modules locations
+/node_modules
+/wwwroot/node_modules
+
+### Rider ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn.  Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### VisualStudioCode ###
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+!.vscode/*.code-snippets
+
+# Local History for Visual Studio Code
+.history/
+
+# Built Visual Studio Code Extensions
+*.vsix
+
+### VisualStudioCode Patch ###
+# Ignore all local history of files
+.history
+.ionide
+
+# Support for Project snippet scope
+
+### VisualStudio ###
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
+
+# User-specific files
+*.rsuser
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Mono auto generated files
+mono_crash.*
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+[Ll]ogs/
+
+# Visual Studio 2015/2017 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUnit
+*.VisualState.xml
+TestResult.xml
+nunit-*.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET Core
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
+*_i.c
+*_p.c
+*_h.h
+*.ilk
+*.meta
+*.obj
+*.iobj
+*.pch
+*.pdb
+*.ipdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*_wpftmp.csproj
+*.log
+*.tlog
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# Visual Studio Trace Files
+*.e2e
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# NuGet Symbol Packages
+*.snupkg
+# The packages folder can be ignored because of Package Restore
+**/[Pp]ackages/*
+# except build/, which is used as an MSBuild target.
+!**/[Pp]ackages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!?*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+orleans.codegen.cs
+
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
+
+# SQL Server files
+*.mdf
+*.ldf
+*.ndf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+node_modules/
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
+# Visual Studio 6 auto-generated project file (contains which files were open etc.)
+*.vbp
+
+# Visual Studio 6 workspace and project file (working project files containing files to include in project)
+*.dsw
+*.dsp
+
+# Visual Studio 6 technical files
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# Visual Studio History (VSHistory) files
+.vshistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+# VS Code files for those working on multiple tools
+*.code-workspace
+
+# Local History for Visual Studio Code
+
+# Windows Installer files from build outputs
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# JetBrains Rider
+*.sln.iml
+
+### VisualStudio Patch ###
+# Additional files built by Visual Studio
+
+# End of https://www.toptal.com/developers/gitignore/api/dotnetcore,rider,visualstudio,visualstudiocode
diff --git a/00_Alternate_Languages/55_Life/csharp/Life.csproj b/00_Alternate_Languages/55_Life/csharp/Life.csproj
new file mode 100644
index 00000000..7311ef16
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/csharp/Life.csproj
@@ -0,0 +1,9 @@
+
+
+    
+        Exe
+        net6.0
+        enable
+    
+
+
diff --git a/00_Alternate_Languages/55_Life/csharp/Life.sln b/00_Alternate_Languages/55_Life/csharp/Life.sln
new file mode 100644
index 00000000..1f6131b8
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/csharp/Life.sln
@@ -0,0 +1,16 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Life", "Life.csproj", "{28B02688-78D1-4B3E-B998-BCC78C292D03}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{28B02688-78D1-4B3E-B998-BCC78C292D03}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{28B02688-78D1-4B3E-B998-BCC78C292D03}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{28B02688-78D1-4B3E-B998-BCC78C292D03}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{28B02688-78D1-4B3E-B998-BCC78C292D03}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/55_Life/csharp/Program.cs b/00_Alternate_Languages/55_Life/csharp/Program.cs
new file mode 100644
index 00000000..0eadf0ea
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/csharp/Program.cs
@@ -0,0 +1,324 @@
+using System.Text;
+
+const int maxWidth = 70;
+const int maxHeight = 24;
+
+Console.WriteLine("ENTER YOUR PATTERN:");
+var pattern = new Pattern(ReadPattern(limitHeight: maxHeight).ToArray());
+
+var minX = 10 - pattern.Height / 2;
+var minY = 34 - pattern.Width / 2;
+var maxX = maxHeight - 1;
+var maxY = maxWidth - 1;
+
+var matrix = new Matrix(height: maxHeight, width: maxWidth);
+var simulation = InitializeSimulation(pattern, matrix);
+
+PrintHeader();
+ProcessSimulation();
+
+IEnumerable ReadPattern(int limitHeight)
+{
+    for (var i = 0; i < limitHeight; i++)
+    {
+        var input = Console.ReadLine();
+        if (input.ToUpper() == "DONE")
+        {
+            break;
+        }
+
+        // In the original version, BASIC would trim the spaces in the beginning of an input, so the original
+        // game allowed you to input an '.' before the spaces to circumvent this limitation. This behavior was
+        // kept for compatibility.
+        if (input.StartsWith('.'))
+            yield return input.Substring(1, input.Length - 1);
+
+        yield return input;
+    }
+}
+
+void PrintHeader()
+{
+    void PrintCentered(string text)
+    {
+        const int pageWidth = 64;
+
+        var spaceCount = (pageWidth - text.Length) / 2;
+        Console.Write(new string(' ', spaceCount));
+        Console.WriteLine(text);
+    }
+
+    PrintCentered("LIFE");
+    PrintCentered("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+    Console.WriteLine();
+    Console.WriteLine();
+    Console.WriteLine();
+}
+
+Simulation InitializeSimulation(Pattern pattern, Matrix matrixToInitialize) {
+    var newSimulation = new Simulation();
+
+    // transcribes the pattern to the middle of the simulation and counts initial population
+    for (var x = 0; x < pattern.Height; x++)
+    {
+        for (var y = 0; y < pattern.Width; y++)
+        {
+            if (pattern.Content[x][y] == ' ')
+                continue;
+
+            matrixToInitialize[minX + x, minY + y] = CellState.Stable;
+            newSimulation.IncreasePopulation();
+        }
+    }
+
+    return newSimulation;
+}
+
+TimeSpan GetPauseBetweenIterations()
+{
+    if (args.Length != 2) return TimeSpan.Zero;
+
+    var parameter = args[0].ToLower();
+    if (parameter.Contains("wait"))
+    {
+        var value = args[1];
+        if (int.TryParse(value, out var sleepMilliseconds))
+            return TimeSpan.FromMilliseconds(sleepMilliseconds);
+    }
+
+    return TimeSpan.Zero;
+}
+
+void ProcessSimulation()
+{
+    var pauseBetweenIterations = GetPauseBetweenIterations();
+    var isInvalid = false;
+
+    while (true)
+    {
+        var invalidText = isInvalid ? "INVALID!" : "";
+        Console.WriteLine($"GENERATION: {simulation.Generation}\tPOPULATION: {simulation.Population} {invalidText}");
+
+        simulation.StartNewGeneration();
+
+        var nextMinX = maxHeight - 1;
+        var nextMinY = maxWidth - 1;
+        var nextMaxX = 0;
+        var nextMaxY = 0;
+
+        var matrixOutput = new StringBuilder();
+
+        // prints the empty lines before search area
+        for (var x = 0; x < minX; x++)
+        {
+            matrixOutput.AppendLine();
+        }
+
+        // refreshes the matrix and updates search area
+        for (var x = minX; x <= maxX; x++)
+        {
+            var printedLine = Enumerable.Repeat(' ', maxWidth).ToList();
+            for (var y = minY; y <= maxY; y++)
+            {
+                if (matrix[x, y] == CellState.Dying)
+                {
+                    matrix[x, y] = CellState.Empty;
+                    continue;
+                }
+                if (matrix[x, y] == CellState.New)
+                {
+                    matrix[x, y] = CellState.Stable;
+                }
+                else if (matrix[x, y] != CellState.Stable)
+                {
+                    continue;
+                }
+
+                printedLine[y] = '*';
+
+                nextMinX = Math.Min(x, nextMinX);
+                nextMaxX = Math.Max(x, nextMaxX);
+                nextMinY = Math.Min(y, nextMinY);
+                nextMaxY = Math.Max(y, nextMaxY);
+            }
+
+            matrixOutput.AppendLine(string.Join(separator: null, values: printedLine));
+        }
+
+        // prints empty lines after search area
+        for (var x = maxX + 1; x < maxHeight; x++)
+        {
+            matrixOutput.AppendLine();
+        }
+        Console.Write(matrixOutput);
+
+        void UpdateSearchArea()
+        {
+            minX = nextMinX;
+            maxX = nextMaxX;
+            minY = nextMinY;
+            maxY = nextMaxY;
+
+            const int limitX = 21;
+            const int limitY = 67;
+
+            if (minX < 2)
+            {
+                minX = 2;
+                isInvalid = true;
+            }
+
+            if (maxX > limitX)
+            {
+                maxX = limitX;
+                isInvalid = true;
+            }
+
+            if (minY < 2)
+            {
+                minY = 2;
+                isInvalid = true;
+            }
+
+            if (maxY > limitY)
+            {
+                maxY = limitY;
+                isInvalid = true;
+            }
+        }
+        UpdateSearchArea();
+
+        for (var x = minX - 1; x <= maxX + 1; x++)
+        {
+            for (var y = minY - 1; y <= maxY + 1; y++)
+            {
+                int CountNeighbors()
+                {
+                    var neighbors = 0;
+                    for (var i = x - 1; i <= x + 1; i++)
+                    {
+                        for (var j = y - 1; j <= y + 1; j++)
+                        {
+                            if (matrix[i, j] == CellState.Stable || matrix[i, j] == CellState.Dying)
+                                neighbors++;
+                        }
+                    }
+
+                    return neighbors;
+                }
+
+                var neighbors = CountNeighbors();
+                if (matrix[x, y] == CellState.Empty)
+                {
+                    if (neighbors == 3)
+                    {
+                        matrix[x, y] = CellState.New;
+                        simulation.IncreasePopulation();
+                    }
+                }
+                else if (neighbors is < 3 or > 4)
+                {
+                    matrix[x, y] = CellState.Dying;
+                }
+                else
+                {
+                    simulation.IncreasePopulation();
+                }
+            }
+        }
+
+        // expands search area to accommodate new cells
+        minX--;
+        minY--;
+        maxX++;
+        maxY++;
+
+        if (pauseBetweenIterations > TimeSpan.Zero)
+            Thread.Sleep(pauseBetweenIterations);
+    }
+}
+
+public class Pattern
+{
+    public string[] Content { get; }
+    public int Height { get; }
+    public int Width { get; }
+
+    public Pattern(IReadOnlyCollection patternLines)
+    {
+        Height = patternLines.Count;
+        Width = patternLines.Max(x => x.Length);
+        Content = NormalizeWidth(patternLines);
+    }
+
+    private string[] NormalizeWidth(IReadOnlyCollection patternLines)
+    {
+        return patternLines
+            .Select(x => x.PadRight(Width, ' '))
+            .ToArray();
+    }
+}
+
+/// 
+/// Indicates the state of a given cell in the simulation.
+/// 
+internal enum CellState
+{
+    Empty = 0,
+    Stable = 1,
+    Dying = 2,
+    New = 3
+}
+
+public class Simulation
+{
+    public int Generation { get; private set; }
+
+    public int Population { get; private set; }
+
+    public void StartNewGeneration()
+    {
+        Generation++;
+        Population = 0;
+    }
+
+    public void IncreasePopulation()
+    {
+        Population++;
+    }
+}
+
+/// 
+/// This class was created to aid debugging, through the implementation of the ToString() method.
+/// 
+class Matrix
+{
+    private readonly CellState[,] _matrix;
+
+    public Matrix(int height, int width)
+    {
+        _matrix = new CellState[height, width];
+    }
+
+    public CellState this[int x, int y]
+    {
+        get => _matrix[x, y];
+        set => _matrix[x, y] = value;
+    }
+
+    public override string ToString()
+    {
+        var stringBuilder = new StringBuilder();
+        for (var x = 0; x < _matrix.GetLength(0); x++)
+        {
+            for (var y = 0; y < _matrix.GetLength(1); y++)
+            {
+                var character = _matrix[x, y] == 0 ? " ": ((int)_matrix[x, y]).ToString();
+                stringBuilder.Append(character);
+            }
+
+            stringBuilder.AppendLine();
+        }
+        return stringBuilder.ToString();
+    }
+}
diff --git a/00_Alternate_Languages/55_Life/csharp/README.md b/00_Alternate_Languages/55_Life/csharp/README.md
new file mode 100644
index 00000000..ee62b382
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/csharp/README.md
@@ -0,0 +1,71 @@
+# Life
+
+An implementation of John Conway's popular cellular automaton, also know as **Conway's Game of Life**. The original source was downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html).
+
+Ported by Dyego Alekssander Maas.
+
+## How to run
+
+This program requires you to install [.NET 6 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0). After installed, you just need to run `dotnet run` from this directory in the terminal.
+
+## Know more about Conway's Game of Life
+
+You can find more about Conway's Game of Life on this page of the [Cornell Math Explorers' Club](http://pi.math.cornell.edu/~lipa/mec/lesson6.html), alongside many examples of patterns you can try.
+
+### Optional parameters
+
+Optionally, you can run this program with the `--wait 1000` argument, the number being the time in milliseconds
+that the application will pause between each iteration. This is enables you to watch the simulation unfolding. By default, there is no pause between iterations.
+
+The complete command would be `dotnet run --wait 1000`.
+
+## Entering patterns
+
+Once running the game, you are expected to enter a pattern. This pattern consists of multiple lines of text with either **spaces** or **some character**, usually an asterisk (`*`).
+
+Spaces represent empty cells. Asterisks represent alive cells.
+
+After entering the pattern, you need to enter the word "DONE". It is not case sensitive. An example of pattern would be:
+
+```
+ *
+***
+DONE
+```
+
+### Some patterns you could try
+
+```
+ *
+***
+```
+
+```
+*
+***
+```
+
+```
+**
+**
+```
+
+```
+  *
+ *
+*
+```
+
+This one is known as **glider**:
+
+```
+***
+*
+ *
+```
+
+## Instructions to the port
+
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/55_Life/java/README.md b/00_Alternate_Languages/55_Life/java/README.md
new file mode 100644
index 00000000..687d300e
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/java/README.md
@@ -0,0 +1,19 @@
+# Game of Life - Java version
+
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
+
+## Requirements
+
+* Requires Java 17 (or later)
+
+## Notes
+
+The Java version of Game of Life tries to mimics the behaviour of the BASIC version.
+However, the Java code does not have much in common with the original.
+
+**Differences in behaviour:**
+* Input supports the ```.``` character, but it's optional.
+* Evaluation of ```DONE``` input string is case insensitive.
+* Run with the ```-s``` command line argument to halt the program after each generation, and continue when ```ENTER``` is pressed.
diff --git a/00_Alternate_Languages/55_Life/java/src/java/Life.java b/00_Alternate_Languages/55_Life/java/src/java/Life.java
new file mode 100644
index 00000000..2f5c184a
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/java/src/java/Life.java
@@ -0,0 +1,191 @@
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+/**
+ * The Game of Life class.
+ *
+ * Mimics the behaviour of the BASIC version, however the Java code does not have much in common with the original. + *
+ * Differences in behaviour: + *
    + *
  • Input supports the "." character, but it's optional.
  • + *
  • Input regarding the "DONE" string is case insensitive.
  • + *
+ */ +public class Life { + + private static final byte DEAD = 0; + private static final byte ALIVE = 1; + private static final String NEWLINE = "\n"; + + private final Scanner consoleReader = new Scanner(System.in); + + private final byte[][] matrix = new byte[21][67]; + private int generation = 0; + private int population = 0; + boolean stopAfterGen = false; + boolean invalid = false; + + /** + * Constructor. + * + * @param args the command line arguments + */ + public Life(String[] args) { + parse(args); + } + + private void parse(String[] args) { + for (String arg : args) { + if ("-s".equals(arg)) { + stopAfterGen = true; + break; + } + } + } + + /** + * Starts the game. + */ + public void start() { + printGameHeader(); + readPattern(); + while (true) { + printGeneration(); + advanceToNextGeneration(); + if (stopAfterGen) { + System.out.print("PRESS ENTER TO CONTINUE"); + consoleReader.nextLine(); + } + } + } + + private void advanceToNextGeneration() { + // store all cell transitions in a list, i.e. if a dead cell becomes alive, or a living cell dies + List transitions = new ArrayList<>(); + // there's still room for optimization: instead of iterating over all cells in the matrix, + // we could consider only the section containing the pattern(s), as in the BASIC version + for (int y = 0; y < matrix.length; y++) { + for (int x = 0; x < matrix[y].length; x++) { + int neighbours = countNeighbours(y, x); + if (matrix[y][x] == ALIVE) { + if (neighbours < 2 || neighbours > 3) { + transitions.add(new Transition(y, x, DEAD)); + population--; + } + } else { // cell is dead + if (neighbours == 3) { + if (x < 2 || x > 67 || y < 2 || y > 21) { + invalid = true; + } + transitions.add(new Transition(y, x, ALIVE)); + population++; + } + } + } + } + // apply all transitions to the matrix + transitions.forEach(t -> matrix[t.y()][t.x()] = t.newState()); + generation++; + } + + private int countNeighbours(int y, int x) { + int neighbours = 0; + for (int row = Math.max(y - 1, 0); row <= Math.min(y + 1, matrix.length - 1); row++) { + for (int col = Math.max(x - 1, 0); col <= Math.min(x + 1, matrix[row].length - 1); col++) { + if (row == y && col == x) { + continue; + } + if (matrix[row][col] == ALIVE) { + neighbours++; + } + } + } + return neighbours; + } + + private void readPattern() { + System.out.println("ENTER YOUR PATTERN:"); + List lines = new ArrayList<>(); + String line; + int maxLineLength = 0; + boolean reading = true; + while (reading) { + System.out.print("? "); + line = consoleReader.nextLine(); + if (line.equalsIgnoreCase("done")) { + reading = false; + } else { + // optional support for the '.' that is needed in the BASIC version + lines.add(line.replace('.', ' ')); + maxLineLength = Math.max(maxLineLength, line.length()); + } + } + fillMatrix(lines, maxLineLength); + } + + private void fillMatrix(List lines, int maxLineLength) { + float xMin = 33 - maxLineLength / 2f; + float yMin = 11 - lines.size() / 2f; + for (int y = 0; y < lines.size(); y++) { + String line = lines.get(y); + for (int x = 1; x <= line.length(); x++) { + if (line.charAt(x-1) == '*') { + matrix[floor(yMin + y)][floor(xMin + x)] = ALIVE; + population++; + } + } + } + } + + private int floor(float f) { + return (int) Math.floor(f); + } + + private void printGameHeader() { + printIndented(34, "LIFE"); + printIndented(15, "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(NEWLINE.repeat(3)); + } + + private void printIndented(int spaces, String str) { + System.out.println(" ".repeat(spaces) + str); + } + + private void printGeneration() { + printGenerationHeader(); + for (int y = 0; y < matrix.length; y++) { + for (int x = 0; x < matrix[y].length; x++) { + System.out.print(matrix[y][x] == 1 ? "*" : " "); + } + System.out.println(); + } + } + + private void printGenerationHeader() { + String invalidText = invalid ? "INVALID!" : ""; + System.out.printf("GENERATION: %-13d POPULATION: %d %s\n", generation, population, invalidText); + } + + /** + * Main method that starts the program. + * + * @param args the command line arguments: + *
-s: Stop after each generation (press enter to continue)
+ * @throws Exception if something goes wrong. + */ + public static void main(String[] args) throws Exception { + new Life(args).start(); + } + +} + +/** + * Represents a state change for a single cell within the matrix. + * + * @param y the y coordinate (row) of the cell + * @param x the x coordinate (column) of the cell + * @param newState the new state of the cell (either DEAD or ALIVE) + */ +record Transition(int y, int x, byte newState) { } diff --git a/00_Alternate_Languages/55_Life/javascript/README.md b/00_Alternate_Languages/55_Life/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/55_Life/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/55_Life/javascript/life.html b/00_Alternate_Languages/55_Life/javascript/life.html new file mode 100644 index 00000000..bebc6e82 --- /dev/null +++ b/00_Alternate_Languages/55_Life/javascript/life.html @@ -0,0 +1,9 @@ + + +LIFE + + +

+
+
+
diff --git a/00_Alternate_Languages/55_Life/javascript/life.js b/00_Alternate_Languages/55_Life/javascript/life.js
new file mode 100644
index 00000000..b4b0fe6b
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/javascript/life.js
@@ -0,0 +1,191 @@
+// LIFE
+//
+// 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 bs = [];
+var a = [];
+
+// Main program
+async function main()
+{
+    print(tab(34) + "LIFE\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("ENTER YOUR PATTERN:\n");
+    x1 = 1;
+    y1 = 1;
+    x2 = 24;
+    y2 = 70;
+    for (c = 1; c <= 24; c++) {
+        bs[c] = "";
+        a[c] = [];
+        for (d = 1; d <= 70; d++)
+            a[c][d] = 0;
+    }
+    c = 1;
+    while (1) {
+        bs[c] = await input();
+        if (bs[c] == "DONE") {
+            bs[c] = "";
+            break;
+        }
+        if (bs[c].substr(0, 1) == ".")
+            bs[c] = " " + bs[c].substr(1);
+        c++;
+    }
+    c--;
+    l = 0;
+    for (x = 1; x <= c - 1; x++) {
+        if (bs[x].length > l)
+            l = bs[x].length;
+    }
+    x1 = 11 - (c >> 1);
+    y1 = 33 - (l >> 1);
+    p = 0;
+    for (x = 1; x <= c; x++) {
+        for (y = 1; y <= bs[x].length; y++) {
+            if (bs[x][y - 1] != " ") {
+                a[x1 + x][y1 + y] = 1;
+                p++;
+            }
+        }
+    }
+    print("\n");
+    print("\n");
+    print("\n");
+    i9 = false;
+    g = 0;
+    while (g < 100) {
+        print("GENERATION: " + g + " POPULATION: " + p + " ");
+        if (i9)
+            print("INVALID!");
+        x3 = 24;
+        y3 = 70;
+        x4 = 1;
+        y4 = 1;
+        p = 0;
+        g++;
+        for (x = 1; x <= x1 - 1; x++)
+            print("\n");
+        for (x = x1; x <= x2; x++) {
+            print("\n");
+            str = "";
+            for (y = y1; y <= y2; y++) {
+                if (a[x][y] == 2) {
+                    a[x][y] = 0;
+                    continue;
+                } else if (a[x][y] == 3) {
+                    a[x][y] = 1;
+                } else if (a[x][y] != 1) {
+                    continue;
+                }
+                while (str.length < y)
+                    str += " ";
+                str += "*";
+                if (x < x3)
+                    x3 = x;
+                if (x > x4)
+                    x4 = x;
+                if (y < y3)
+                    y3 = y;
+                if (y > y4)
+                    y4 = y;
+            }
+            print(str);
+        }
+        for (x = x2 + 1; x <= 24; x++)
+            print("\n");
+        x1 = x3;
+        x2 = x4;
+        y1 = y3;
+        y2 = y4;
+        if (x1 < 3) {
+            x1 = 3;
+            i9 = true;
+        }
+        if (x2 > 22) {
+            x2 = 22;
+            i9 = true;
+        }
+        if (y1 < 3) {
+            y1 = 3;
+            i9 = true;
+        }
+        if (y2 > 68) {
+            y2 = 68;
+            i9 = true;
+        }
+        p = 0;
+        for (x = x1 - 1; x <= x2 + 1; x++) {
+            for (y = y1 - 1; y <= y2 + 1; y++) {
+                c = 0;
+                for (i = x - 1; i <= x + 1; i++) {
+                    for (j = y - 1; j <= y + 1; j++) {
+                        if (a[i][j] == 1 || a[i][j] == 2)
+                            c++;
+                    }
+                }
+                if (a[x][y] == 0) {
+                    if (c == 3) {
+                        a[x][y] = 3;
+                        p++;
+                    }
+                } else {
+                    if (c < 3 || c > 4) {
+                        a[x][y] = 2;
+                    } else {
+                        p++;
+                    }
+                }
+            }
+        }
+        x1--;
+        y1--;
+        x2++;
+        y2++;
+    }
+}
+
+main();
diff --git a/00_Alternate_Languages/55_Life/life.bas b/00_Alternate_Languages/55_Life/life.bas
new file mode 100644
index 00000000..71313579
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/life.bas
@@ -0,0 +1,66 @@
+2 PRINT TAB(34);"LIFE"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT: PRINT: PRINT
+8 PRINT "ENTER YOUR PATTERN:"
+9 X1=1: Y1=1: X2=24: Y2=70
+10 DIM A(24,70),B$(24)
+20 C=1
+30 INPUT B$(C)
+40 IF B$(C)="DONE" THEN B$(C)="": GOTO 80
+50 IF LEFT$(B$(C),1)="." THEN B$(C)=" "+RIGHT$(B$(C),LEN(B$(C))-1)
+60 C=C+1
+70 GOTO 30
+80 C=C-1: L=0
+90 FOR X=1 TO C-1
+100 IF LEN(B$(X))>L THEN L=LEN(B$(X))
+110 NEXT X
+120 X1=11-C/2
+130 Y1=33-L/2
+140 FOR X=1 TO C
+150 FOR Y=1 TO LEN(B$(X))
+160 IF MID$(B$(X),Y,1)<>" " THEN A(X1+X,Y1+Y)=1:P=P+1
+170 NEXT Y
+180 NEXT X
+200 PRINT:PRINT:PRINT
+210 PRINT "GENERATION:";G,"POPULATION:";P;: IF I9 THEN PRINT "INVALID!";
+215 X3=24:Y3=70:X4=1: Y4=1: P=0
+220 G=G+1
+225 FOR X=1 TO X1-1: PRINT: NEXT X
+230 FOR X=X1 TO X2
+240 PRINT
+250 FOR Y=Y1 TO Y2
+253 IF A(X,Y)=2 THEN A(X,Y)=0:GOTO 270
+256 IF A(X,Y)=3 THEN A(X,Y)=1:GOTO 261
+260 IF A(X,Y)<>1 THEN 270
+261 PRINT TAB(Y);"*";
+262 IF XX4 THEN X4=X
+266 IF YY4 THEN Y4=Y
+270 NEXT Y
+290 NEXT X
+295 FOR X=X2+1 TO 24: PRINT: NEXT X
+299 X1=X3: X2=X4: Y1=Y3: Y2=Y4
+301 IF X1<3 THEN X1=3:I9=-1
+303 IF X2>22 THEN X2=22:I9=-1
+305 IF Y1<3 THEN Y1=3:I9=-1
+307 IF Y2>68 THEN Y2=68:I9=-1
+309 P=0
+500 FOR X=X1-1 TO X2+1
+510 FOR Y=Y1-1 TO Y2+1
+520 C=0
+530 FOR I=X-1 TO X+1
+540 FOR J=Y-1 TO Y+1
+550 IF A(I,J)=1 OR A(I,J)=2 THEN C=C+1
+560 NEXT J
+570 NEXT I
+580 IF A(X,Y)=0 THEN 610
+590 IF C<3 OR C>4 THEN A(X,Y)=2: GOTO 600
+595 P=P+1
+600 GOTO 620
+610 IF C=3 THEN A(X,Y)=3:P=P+1
+620 NEXT Y
+630 NEXT X
+635 X1=X1-1:Y1=Y1-1:X2=X2+1:Y2=Y2+1
+640 GOTO 210
+650 END
diff --git a/31_Depth_Charge/pascal/README.md b/00_Alternate_Languages/55_Life/pascal/README.md
similarity index 100%
rename from 31_Depth_Charge/pascal/README.md
rename to 00_Alternate_Languages/55_Life/pascal/README.md
diff --git a/00_Alternate_Languages/55_Life/perl/README.md b/00_Alternate_Languages/55_Life/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/55_Life/perl/life.pl b/00_Alternate_Languages/55_Life/perl/life.pl
new file mode 100644
index 00000000..fccadc89
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/perl/life.pl
@@ -0,0 +1,93 @@
+#!/usr/bin/perl
+#use strict;
+
+print ' 'x 34 . "LIFE\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n"; print "\n"; print "\n";
+print "ENTER YOUR PATTERN; \n";
+$X1=1; $Y1=1; $X2=24; $Y2=70;
+@A;
+$C=1;
+
+@B;
+Line30:
+print "? "; chomp($B[$C] = uc());
+if ($B[$C] eq "DONE") { $B[$C]=""; goto Line80; }
+$B[$C]=~ s/\./ /g;
+$C=$C+1;
+goto Line30;
+
+
+Line80:
+
+$C=$C-1; $L=0; $G=0;
+for ($X=1; $X<=$C-1; $X++) {
+	if (length($B[$X])>$L) { $L=length($B[$X]); }
+	}
+
+$X1=11-$C/2;
+$Y1=33-$L/2;
+for ($X=1; $X<=$C; $X++) {
+	for ($Y=1; $Y<=length($B[$X]); $Y++) {
+		if (substr($B[$X],$Y-1,1) ne " ") { $A[$X1+$X][$Y1+$Y]=1; $P=$P+1; }
+		}
+	}
+print "\n"; print "\n"; print "\n";
+
+Line210:
+print "GENERATION: ".$G."\t\tPOPULATION: ".$P; if ($I9) { print "\tINVALID!"; }
+print "\n";
+$X3=24; $Y3=70; $X4=1; $Y4=1; $P=0;
+$G=$G+1;
+for ($X=1; $X<=$X1-1; $X++) { print "\n"; }
+for ($X=$X1; $X<=$X2; $X++) {
+	$Row= " "x 80;
+	for ($Y=$Y1; $Y<=$Y2; $Y++) {
+		if ($A[$X][$Y]==2) { $A[$X][$Y]=0; goto Line270; }
+		if ($A[$X][$Y]==3) { $A[$X][$Y]=1; goto Line261; }
+		if ($A[$X][$Y]!=1) { goto Line270; }
+
+		Line261:
+		substr($Row, $Y, 1, "*");
+		if ($X<$X3) { $X3=$X; }
+		if ($X>$X4) { $X4=$X; }
+		if ($Y<$Y3) { $Y3=$Y; }
+		if ($Y>$Y4) { $Y4=$Y; }
+
+		Line270:
+		}
+	print "$Row\n";
+	}
+
+for ($X=$X2+1; $X<=24; $X++) { print "\n"; }
+$X1=$X3; $X2=$X4; $Y1=$Y3; $Y2=$Y4;
+if ($X1<3) { $X1=3; $I9=-1; }
+if ($X2>22) { $X2=22; $I9=-1; }
+if ($Y1<3) { $Y1=3; $I9=-1; }
+if ($Y2>68) { $Y2=68; $I9=-1; }
+$P=0;
+
+for ($X=$X1-1; $X<=$X2+1; $X++) {
+	for ($Y=$Y1-1; $Y<=$Y2+1; $Y++) {
+		$C=0;
+		for ($I=$X-1; $I<=$X+1; $I++) {
+			for ($J=$Y-1; $J<=$Y+1; $J++) {
+				if ($A[$I][$J]==1 || $A[$I][$J]==2) { $C=$C+1; }
+				}
+			}
+		if ($A[$X][$Y]==0) { goto Line610; }
+		if ($C<3 || $C>4) { $A[$X][$Y]=2; goto Line600; }
+		$P=$P+1;
+
+		Line600:
+		goto Line620;
+
+		Line610:
+		if ($C==3) { $A[$X][$Y]=3; $P=$P+1; }
+
+		Line620:
+		}
+	}
+$X1=$X1-1; $Y1=$Y1-1; $X2=$X2+1; $Y2=$Y2+1;
+goto Line210;
+exit;
diff --git a/00_Alternate_Languages/55_Life/python/README.md b/00_Alternate_Languages/55_Life/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/55_Life/python/life.py b/00_Alternate_Languages/55_Life/python/life.py
new file mode 100644
index 00000000..71016871
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/python/life.py
@@ -0,0 +1,173 @@
+"""
+LIFE
+
+An implementation of John Conway's popular cellular automaton
+
+Ported by Dave LeCompte
+"""
+
+
+PAGE_WIDTH = 64
+
+MAX_WIDTH = 70
+MAX_HEIGHT = 24
+
+
+def print_centered(msg):
+    spaces = " " * ((PAGE_WIDTH - len(msg)) // 2)
+    print(spaces + msg)
+
+
+def print_header(title):
+    print_centered(title)
+    print_centered("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+
+def get_pattern():
+    print("ENTER YOUR PATTERN:")
+    c = 0
+
+    pattern = {}
+    while True:
+        line = input()
+        if line == "DONE":
+            return pattern
+
+        # BASIC input would strip of leading whitespace.
+        # Python input does not. The following allows you to start a
+        # line with a dot to disable the whitespace stripping. This is
+        # unnecessary for Python, but for historical accuracy, it's
+        # staying in.
+
+        if line[0] == ".":
+            line = " " + line[1:]
+        pattern[c] = line
+        c += 1
+
+
+def main():
+    print_header("LIFE")
+
+    pattern = get_pattern()
+
+    pattern_height = len(pattern)
+    pattern_width = 0
+    for line_num, line in pattern.items():
+        pattern_width = max(pattern_width, len(line))
+
+    min_x = 11 - pattern_height // 2
+    min_y = 33 - pattern_width // 2
+    max_x = MAX_HEIGHT - 1
+    max_y = MAX_WIDTH - 1
+
+    a = [[0 for y in range(MAX_WIDTH)] for x in range(MAX_HEIGHT)]
+    p = 0
+    g = 0
+    invalid = False
+
+    # line 140
+    # transcribe the input pattern into the active array
+    for x in range(0, pattern_height):
+        for y in range(0, len(pattern[x])):
+            if pattern[x][y] != " ":
+                a[min_x + x][min_y + y] = 1
+                p += 1
+
+    print()
+    print()
+    print()
+    while True:
+        if invalid:
+            inv_str = "INVALID!"
+        else:
+            inv_str = ""
+
+        print(f"GENERATION: {g}\tPOPULATION: {p} {inv_str}")
+
+        next_min_x = MAX_HEIGHT - 1
+        next_min_y = MAX_WIDTH - 1
+        next_max_x = 0
+        next_max_y = 0
+
+        p = 0
+        g += 1
+        for x in range(0, min_x):
+            print()
+
+        for x in range(min_x, max_x + 1):
+            print
+            line = [" "] * MAX_WIDTH
+            for y in range(min_y, max_y + 1):
+                if a[x][y] == 2:
+                    a[x][y] = 0
+                    continue
+                elif a[x][y] == 3:
+                    a[x][y] = 1
+                elif a[x][y] != 1:
+                    continue
+
+                # line 261
+                line[y] = "*"
+
+                next_min_x = min(x, next_min_x)
+                next_max_x = max(x, next_max_x)
+                next_min_y = min(y, next_min_y)
+                next_max_y = max(y, next_max_y)
+
+            print("".join(line))
+
+        # line 295
+        for x in range(max_x + 1, MAX_HEIGHT):
+            print()
+
+        print()
+
+        min_x = next_min_x
+        max_x = next_max_x
+        min_y = next_min_y
+        max_y = next_max_y
+
+        if min_x < 3:
+            min_x = 3
+            invalid = True
+        if max_x > 22:
+            max_x = 22
+            invalid = True
+        if min_y < 3:
+            min_y = 3
+            invalid = True
+        if max_y > 68:
+            max_y = 68
+            invalid = True
+
+        # line 309
+        p = 0
+
+        for x in range(min_x - 1, max_x + 2):
+            for y in range(min_y - 1, max_y + 2):
+                count = 0
+                for i in range(x - 1, x + 2):
+                    for j in range(y - 1, y + 2):
+                        if a[i][j] == 1 or a[i][j] == 2:
+                            count += 1
+                if a[x][y] == 0:
+                    if count == 3:
+                        a[x][y] = 3
+                        p += 1
+                elif (count < 3) or (count > 4):
+                    a[x][y] = 2
+                else:
+                    p += 1
+
+        # line 635
+        min_x = min_x - 1
+        min_y = min_y - 1
+        max_x = max_x + 1
+        max_y = max_y + 1
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/55_Life/ruby/README.md b/00_Alternate_Languages/55_Life/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/55_Life/ruby/life.rb b/00_Alternate_Languages/55_Life/ruby/life.rb
new file mode 100644
index 00000000..a8b46c72
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/ruby/life.rb
@@ -0,0 +1,160 @@
+#!ruby
+
+# The Pattern class encapsulates everything we would want to know about a
+# pattern in our Game of Life: its size, its current pattern of alive and
+# dead cells, which generation it's on and how long it can run, and how
+# to accept input for itself, print itself, and most importantly iterate
+# from one generation to the next.
+
+PATTERN_WIDTH = 80
+PATTERN_HEIGHT = 24
+
+class Pattern
+
+  # Begin with a totally empty/dead pattern of fixed size at generation 0.
+
+  def initialize(max_generations: 10)
+    @max_generations = max_generations
+    @generation = 0
+    @population = nil
+    @counter = Array.new(PATTERN_HEIGHT) { Array.new(PATTERN_WIDTH, 0) }
+    @invalid = false
+  end
+
+  # Take input from the console and enter it into the pattern.
+
+  def get_input
+    input = []
+    done = false
+
+    # Accept the input from the user on the console
+
+    loop do
+      print "? "
+      line = gets.chomp
+      break if line == 'DONE'
+      line.gsub!(/^\./, ' ')
+      input << line
+    end
+
+    # Emit some blank space
+    (1..10).each { puts }
+
+    # Center the input in the two-dimensional array
+    input_width = input.map { |line| line.length }.max
+    width_offset = ((PATTERN_WIDTH - input_width) / 2).floor
+    height_offset = ((PATTERN_HEIGHT - input.count) / 2).floor
+    # TODO emit error if width > PATTERN_WIDTH or line count > PATTERN_HEIGHT
+
+    # Start by setting each element to 0 if dead or a 1 if alive
+
+    input.each_index do |y|
+      line = input[y].ljust(input_width)
+      y_offset = y + height_offset
+      @counter[y_offset] = [
+        [0] * width_offset,
+        line.split("").map { |char| char == ' ' ? 0 : 1 },
+        [0] * PATTERN_WIDTH
+      ].flatten.take(PATTERN_WIDTH)
+    end
+
+    @population = @counter.flatten.sum
+  end
+
+  # Emit the pattern to the console.
+
+  def display
+    puts "GENERATION:#{@generation}\tPOPULATION:#{@population}"
+    puts "INVALID!"if @invalid
+
+    @counter.each do |row|
+      puts row.map { |cell| ((cell == 0 || cell == 2) ? ' ' : 'X') }.join('')
+    end
+  end
+
+  # Iterate from one generation to the next, returning true if the
+  # game of life should continue, and false if it should terminate.
+
+  def iterate
+    @generation = @generation + 1
+    return false if @generation > @max_generations
+
+    # Update the counter array with new values.
+    # First, change each 2 (dying) to a 0 (dead)
+    # and each 3 (born) to a 1 (alive)
+    @counter.map! { |row| row.map! { |cell| cell >= 2 ? cell-2 : cell } }
+
+    # Now for each cell, count its neighbors and update it
+
+    @population = 0
+    @counter.each_index do |rownum|
+      @counter[rownum].each_index do |colnum|
+        cell_value = @counter[rownum][colnum]
+
+        # If any cell on the border is set, our small algorithm is not
+        # smart enough to correctly check its neighbors, so sadly our
+        # pattern becomes invalid. We keep going though
+
+        @invalid = true if cell_value > 0 && (
+          rownum == 0 || rownum == PATTERN_HEIGHT-1 || colnum == 0 || colnum == PATTERN_WIDTH-1
+        )
+
+        # Count the cell's neighbors (not including itself)
+
+        neighbors = @counter[rownum-1..rownum+1].map { |row| row[colnum-1..colnum+1] }.flatten
+        neighbor_count = neighbors.inject(0) do |sum, value|
+          sum += (value == 1 || value == 2) ? 1 : 0
+        end
+        neighbor_count = neighbor_count - cell_value
+
+        # Update this cell based on its neighbor count, either leaving it
+        # as a 0 or 1, or setting it to 2 (dying) or 3 (being born)
+
+        if cell_value == 0
+          if neighbor_count == 3
+            cell_value = 3
+            @population = @population + 1
+          end
+        elsif neighbor_count < 2 || neighbor_count > 3
+          cell_value = 2
+        else
+          @population = @population + 1
+        end
+        @counter[rownum][colnum] = cell_value
+
+      end
+    end
+
+    # If every cell is dead, we are done. Otherwise, keep going up to the
+    # maximum number of generations
+
+    @population > 0
+  end
+
+end
+
+# The following program code makes use of the Pattern class to create,
+# iterate on, and display the Game of Life.
+
+def display_banner
+  puts " " * 34 + "LIFE"
+  puts " " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+  puts
+  puts "PLEASE ENTER YOUR STARTING PATTERN, USING SPACE FOR AN EMPTY CELL"
+  puts "AND AN 'X' FOR A FILLED CELL. YOUR PATTERN MAY BE UP TO #{PATTERN_HEIGHT} ROWS"
+  puts "OF UP TO #{PATTERN_WIDTH} COLUMNS EACH. TYPE 'DONE' WHEN DONE."
+  puts "ENTER YOUR PATTERN:"
+end
+
+def main
+
+  display_banner
+
+  pattern = Pattern.new
+  pattern.get_input
+  pattern.display
+  pattern.display while pattern.iterate
+
+end
+
+main
diff --git a/00_Alternate_Languages/55_Life/vbnet/Life.sln b/00_Alternate_Languages/55_Life/vbnet/Life.sln
new file mode 100644
index 00000000..8feae175
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/vbnet/Life.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Life", "Life.vbproj", "{05455AEE-3BE0-4DDD-A59E-89F862EF68AE}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{05455AEE-3BE0-4DDD-A59E-89F862EF68AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{05455AEE-3BE0-4DDD-A59E-89F862EF68AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{05455AEE-3BE0-4DDD-A59E-89F862EF68AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{05455AEE-3BE0-4DDD-A59E-89F862EF68AE}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/55_Life/vbnet/Life.vbproj b/00_Alternate_Languages/55_Life/vbnet/Life.vbproj
new file mode 100644
index 00000000..5d62487f
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/vbnet/Life.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Life
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/55_Life/vbnet/README.md b/00_Alternate_Languages/55_Life/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/55_Life/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/56_Life_for_Two/README.md b/00_Alternate_Languages/56_Life_for_Two/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/56_Life_for_Two/csharp/LifeforTwo.csproj b/00_Alternate_Languages/56_Life_for_Two/csharp/LifeforTwo.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/csharp/LifeforTwo.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/56_Life_for_Two/csharp/LifeforTwo.sln b/00_Alternate_Languages/56_Life_for_Two/csharp/LifeforTwo.sln
new file mode 100644
index 00000000..7a5585cb
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/csharp/LifeforTwo.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LifeforTwo", "LifeforTwo.csproj", "{B2BFE429-A4BC-4CEA-881E-32382182EA32}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B2BFE429-A4BC-4CEA-881E-32382182EA32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B2BFE429-A4BC-4CEA-881E-32382182EA32}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B2BFE429-A4BC-4CEA-881E-32382182EA32}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B2BFE429-A4BC-4CEA-881E-32382182EA32}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/56_Life_for_Two/csharp/README.md b/00_Alternate_Languages/56_Life_for_Two/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/56_Life_for_Two/java/README.md b/00_Alternate_Languages/56_Life_for_Two/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/56_Life_for_Two/javascript/README.md b/00_Alternate_Languages/56_Life_for_Two/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/56_Life_for_Two/javascript/lifefortwo.html b/00_Alternate_Languages/56_Life_for_Two/javascript/lifefortwo.html
new file mode 100644
index 00000000..fbd70636
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/javascript/lifefortwo.html
@@ -0,0 +1,9 @@
+
+
+LIFE FOR TWO
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/56_Life_for_Two/javascript/lifefortwo.js b/00_Alternate_Languages/56_Life_for_Two/javascript/lifefortwo.js
new file mode 100644
index 00000000..a38a0af8
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/javascript/lifefortwo.js
@@ -0,0 +1,209 @@
+// LIFE FOR TWO
+//
+// 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 na = [];
+var ka = [, 3,102,103,120,130,121,112,111,12,
+          21,30,1020,1030,1011,1021,1003,1002,1012];
+var aa = [,-1,0,1,0,0,-1,0,1,-1,-1,1,-1,-1,1,1,1];
+var xa = [];
+var ya = [];
+var j;
+var k;
+var m2;
+var m3;
+
+function show_data()
+{
+    k = 0;
+    m2 = 0;
+    m3 = 0;
+    for (j = 0; j <= 6; j++) {
+        print("\n");
+        for (k = 0; k <= 6; k++) {
+            if (j == 0 || j == 6) {
+                if (k == 6)
+                    print(" 0 ");
+                else
+                    print(" " + k + " ");
+            } else if (k == 0 || k == 6) {
+                if (j == 6)
+                    print(" 0\n");
+                else
+                    print(" " + j + " ");
+            } else {
+                if (na[j][k] >= 3) {
+                    for (o1 = 1; o1 <= 18; o1++) {
+                        if (na[j][k] == ka[o1])
+                            break;
+                    }
+                    if (o1 <= 18) {
+                        if (o1 <= 9) {
+                            na[j][k] = 100;
+                            m2++;
+                            print(" * ");
+                        } else {
+                            na[j][k] = 1000;
+                            m3++;
+                            print(" # ");
+                        }
+                    } else {
+                        na[j][k] = 0;
+                        print("   ");
+                    }
+                } else {
+                    na[j][k] = 0;
+                    print("   ");
+                }
+            }
+        }
+    }
+}
+
+function process_board()
+{
+    for (j = 1; j <= 5; j++) {
+        for (k = 1; k <= 5; k++) {
+            if (na[j][k] > 99) {
+                b = 1;
+                if (na[j][k] > 999)
+                    b = 10;
+                for (o1 = 1; o1 <= 15; o1 += 2) {
+                    na[j + aa[o1]][k + aa[o1 + 1]] = na[j + aa[o1]][k + aa[o1 + 1]] + b;
+                }
+            }
+        }
+    }
+    show_data();
+}
+
+// Main program
+async function main()
+{
+    print(tab(33) + "LIFE2\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print(tab(10) + "U.B. LIFE GAME\n");
+    m2 = 0;
+    m3 = 0;
+    for (j = 0; j <= 6; j++) {
+        na[j] = [];
+        for (k = 0; k <= 6; k++)
+            na[j][k] = 0;
+    }
+    for (b = 1; b <= 2; b++) {
+        p1 = (b == 2) ? 30 : 3;
+        print("\n");
+        print("PLAYER " + b + " - 3 LIVE PIECES.\n");
+        for (k1 = 1; k1 <= 3; k1++) {
+            while (1) {
+                print("X,Y\n");
+                str = await input();
+                ya[b] = parseInt(str);
+                xa[b] = parseInt(str.substr(str.indexOf(",") + 1));
+                if (xa[b] > 0 && xa[b] < 6 && ya[b] > 0 && ya[b] < 5 && na[xa[b]][ya[b]] == 0)
+                    break;
+                print("ILLEGAL COORDS. RETYPE\n");
+            }
+            if (b != 1) {
+                if (xa[1] == xa[2] && ya[1] == ya[2]) {
+                    print("SAME COORD.  SET TO 0\n");
+                    na[xa[b] + 1][ya[b] + 1] = 0;
+                    b = 99;
+                }
+            }
+            na[xa[b]][ya[b]] = p1;
+        }
+    }
+    show_data();
+    while (1) {
+        print("\n");
+        process_board();
+        if (m2 == 0 && m3 == 0) {
+            print("\n");
+            print("A DRAW\n");
+            break;
+        }
+        if (m3 == 0) {
+            print("\n");
+            print("PLAYER 1 IS THE WINNER\n");
+            break;
+        }
+        if (m2 == 0) {
+            print("\n");
+            print("PLAYER 2 IS THE WINNER\n");
+            break;
+        }
+        for (b = 1; b <= 2; b++) {
+            print("\n");
+            print("\n");
+            print("PLAYER " + b + " ");
+            while (1) {
+                print("X,Y\n");
+                str = await input();
+                ya[b] = parseInt(str);
+                xa[b] = parseInt(str.substr(str.indexOf(",") + 1));
+                if (xa[b] > 0 && xa[b] < 6 && ya[b] > 0 && ya[b] < 5 && na[xa[b]][ya[b]] == 0)
+                    break;
+                print("ILLEGAL COORDS. RETYPE\n");
+            }
+            if (b != 1) {
+                if (xa[1] == xa[2] && ya[1] == ya[2]) {
+                    print("SAME COORD.  SET TO 0\n");
+                    na[xa[b] + 1][ya[b] + 1] = 0;
+                    b = 99;
+                }
+            }
+            if (b == 99)
+                break;
+        }
+        if (b <= 2) {
+            na[x[1]][y[1]] = 100;
+            na[x[2]][y[2]] = 1000;
+        }
+    }
+}
+
+main();
diff --git a/00_Alternate_Languages/56_Life_for_Two/lifefortwo.bas b/00_Alternate_Languages/56_Life_for_Two/lifefortwo.bas
new file mode 100644
index 00000000..e970ef6d
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/lifefortwo.bas
@@ -0,0 +1,83 @@
+2 PRINT TAB(33);"LIFE2"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT: PRINT: PRINT
+7 DIM N(6,6),K(18),A(16),X(2),Y(2)
+8 DATA 3,102,103,120,130,121,112,111,12
+9 DATA 21,30,1020,1030,1011,1021,1003,1002,1012
+10 FOR M=1 TO 18: READ K(M): NEXT M
+13 DATA -1,0,1,0,0,-1,0,1,-1,-1,1,-1,-1,1,1,1
+14 FOR O1= 1 TO 16: READ A(O1): NEXT O1
+20 GOTO 500
+50 FOR J=1 TO 5
+51 FOR K=1 TO 5
+55 IF N(J,K)>99 THEN GOSUB 200
+60 NEXT K
+65 NEXT J
+90 K=0: M2=0: M3=0
+99 FOR J=0 TO 6: PRINT
+100 FOR K=0 TO 6
+101 IF J<>0 THEN IF J<>6 THEN 105
+102 IF K=6 THEN PRINT 0;: GOTO 125
+103 PRINT K;: GOTO 120
+105 IF K<>0 THEN IF K<>6 THEN 110
+106 IF J=6 THEN PRINT 0: GOTO 126
+107 PRINT J;: GOTO 120
+110 GOSUB 300
+120 NEXT K
+125 NEXT J
+126 RETURN
+200 B=1: IF N(J,K)>999 THEN B=10
+220 FOR O1= 1 TO 15 STEP 2
+230 N(J+A(O1),K+A(O1+1))=N(J+A(O1),K+A(O1+1))+B
+231 NEXT O1
+239 RETURN
+300 IF N(J,K)<3 THEN 399
+305 FOR O1=1 TO 18
+310 IF N(J,K)=K(O1) THEN 350
+315 NEXT O1
+320 GOTO 399
+350 IF O1>9 THEN 360
+351 N(J,K)=100: M2=M2+1: PRINT " * ";
+355 RETURN
+360 N(J,K)=1000: M3=M3+1: PRINT " # ";
+365 RETURN
+399 N(J,K)=0: PRINT "   ";: RETURN
+500 PRINT TAB(10);"U.B. LIFE GAME"
+505 M2=0: M3=0
+510 FOR J=1 TO 5
+511 FOR K=1 TO 5
+515 N(J,K)=0
+516 NEXT K
+517 NEXT J
+519 FOR B=1 TO 2: P1=3: IF B=2 THEN P1=30
+520 PRINT:PRINT "PLAYER";B;" - 3 LIVE PIECES."
+535 FOR K1=1 TO 3: GOSUB 700
+540 N(X(B),Y(B))=P1: NEXT K1
+542 NEXT B
+559 GOSUB 90
+560 PRINT: GOSUB 50
+570 IF M2=0 THEN IF M3=0 THEN 574
+571 IF M3=0 THEN B=1: GOTO 575
+572 IF M2=0 THEN B=2: GOTO 575
+573 GOTO 580
+574 PRINT: PRINT "A DRAW":GOTO 800
+575 PRINT: PRINT "PLAYER";B;"IS THE WINNER":GOTO 800
+580 FOR B=1 TO 2: PRINT: PRINT: PRINT "PLAYER";B;: GOSUB 700
+581 IF B=99 THEN 560
+582 NEXT B
+586 N(X(1),Y(1))=100: N(X(2),Y(2))=1000
+596 GOTO 560
+700 PRINT "X,Y":PRINT"XXXXXX";CHR$(13);"$$$$$$";CHR$(13);"&&&&&&";
+701 PRINT CHR$(13);: INPUT Y(B),X(B)
+705 IF X(B)<=5 THEN IF X(B)>0 THEN 708
+706 GOTO 750
+708 IF Y(B)<=5 THEN IF Y(B)>0 THEN 715
+710 GOTO 750
+715 IF N(X(B),Y(B))<>0 THEN 750
+720 IF B=1 THEN RETURN
+725 IF X(1)=X(2) THEN IF Y(1)=Y(2) THEN 740
+730 RETURN
+740 PRINT "SAME COORD.  SET TO 0"
+741 N(X(B)+1,Y(B)+1)=0: B=99: RETURN
+750 PRINT "ILLEGAL COORDS. RETYPE": GOTO 700
+999 END
diff --git a/32_Diamond/pascal/README.md b/00_Alternate_Languages/56_Life_for_Two/pascal/README.md
similarity index 100%
rename from 32_Diamond/pascal/README.md
rename to 00_Alternate_Languages/56_Life_for_Two/pascal/README.md
diff --git a/00_Alternate_Languages/56_Life_for_Two/perl/README.md b/00_Alternate_Languages/56_Life_for_Two/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/56_Life_for_Two/python/README.md b/00_Alternate_Languages/56_Life_for_Two/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/56_Life_for_Two/ruby/README.md b/00_Alternate_Languages/56_Life_for_Two/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/56_Life_for_Two/vbnet/LifeforTwo.sln b/00_Alternate_Languages/56_Life_for_Two/vbnet/LifeforTwo.sln
new file mode 100644
index 00000000..2d5167d3
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/vbnet/LifeforTwo.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "LifeforTwo", "LifeforTwo.vbproj", "{571A55BD-86BA-4DD2-9769-B258E7654586}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{571A55BD-86BA-4DD2-9769-B258E7654586}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{571A55BD-86BA-4DD2-9769-B258E7654586}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{571A55BD-86BA-4DD2-9769-B258E7654586}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{571A55BD-86BA-4DD2-9769-B258E7654586}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/56_Life_for_Two/vbnet/LifeforTwo.vbproj b/00_Alternate_Languages/56_Life_for_Two/vbnet/LifeforTwo.vbproj
new file mode 100644
index 00000000..31087af1
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/vbnet/LifeforTwo.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    LifeforTwo
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/56_Life_for_Two/vbnet/README.md b/00_Alternate_Languages/56_Life_for_Two/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/56_Life_for_Two/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/57_Literature_Quiz/README.md b/00_Alternate_Languages/57_Literature_Quiz/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/57_Literature_Quiz/csharp/LiteratureQuiz.csproj b/00_Alternate_Languages/57_Literature_Quiz/csharp/LiteratureQuiz.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/csharp/LiteratureQuiz.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/57_Literature_Quiz/csharp/LiteratureQuiz.sln b/00_Alternate_Languages/57_Literature_Quiz/csharp/LiteratureQuiz.sln
new file mode 100644
index 00000000..8ba67c92
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/csharp/LiteratureQuiz.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LiteratureQuiz", "LiteratureQuiz.csproj", "{1B77EECB-5ECC-41E5-BD12-519CA4C745AE}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{1B77EECB-5ECC-41E5-BD12-519CA4C745AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1B77EECB-5ECC-41E5-BD12-519CA4C745AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1B77EECB-5ECC-41E5-BD12-519CA4C745AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1B77EECB-5ECC-41E5-BD12-519CA4C745AE}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/57_Literature_Quiz/csharp/README.md b/00_Alternate_Languages/57_Literature_Quiz/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/57_Literature_Quiz/csharp/litquiz.cs b/00_Alternate_Languages/57_Literature_Quiz/csharp/litquiz.cs
new file mode 100644
index 00000000..c2f07a2a
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/csharp/litquiz.cs
@@ -0,0 +1,155 @@
+using System;
+
+namespace litquiz
+{
+    class litquiz
+    {
+        public static int Score = 0;
+
+
+        public static void Main(string[] args)
+        {
+
+            //Print the title and intro
+
+            Console.WriteLine("                         LITERATURE QUIZ");
+            Console.WriteLine("               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE");
+            Console.WriteLine();
+            Console.WriteLine("THIS IS A MULTIPLE-CHOICE QUIZ");
+            Console.WriteLine("TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.");
+            Console.WriteLine();
+            Console.WriteLine("GOOD LUCK!");
+            Console.WriteLine();
+            Console.WriteLine();
+            One();
+
+
+
+        }
+
+        public static void One() {
+            Console.WriteLine("IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT");
+            Console.WriteLine("1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO");
+
+            string answerOne;
+            answerOne = Console.ReadLine();
+
+            if(answerOne == "4")
+            {
+                Console.WriteLine("VERY GOOD! HERE'S ANOTHER.");
+                Score = Score + 1;
+                Two();
+            }
+            else
+            {
+                Console.WriteLine("SORRY...FIGARO WAS HIS NAME.");
+                Two();
+            }
+
+        }
+
+        public static void Two()
+        {
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?");
+            Console.WriteLine("1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S");
+
+            string answerTwo;
+            answerTwo = Console.ReadLine();
+
+            if(answerTwo == "2")
+            {
+                Console.WriteLine("PRETTY GOOD!");
+                Score = Score + 1;
+                Three();
+            }
+            else
+            {
+                Console.WriteLine("TOO BAD...IT WAS ELMER FUDD'S GARDEN.");
+                Three();
+            }
+        }
+
+        public static void Three()
+        {
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED");
+            Console.WriteLine("1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO");
+
+            string answerThree;
+            answerThree = Console.ReadLine();
+
+            if(answerThree == "4")
+            {
+                Console.WriteLine("YEA!  YOU'RE A REAL LITERATURE GIANT.");
+                Score = Score + 1;
+                Four();
+            }
+            else
+            {
+                Console.WriteLine("BACK TO THE BOOKS,...TOTO WAS HIS NAME.");
+                Four();
+            }
+
+
+
+
+        }
+
+        public static void Four()
+        {
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE");
+            Console.WriteLine("1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY");
+
+            string answerFour;
+            answerFour = Console.ReadLine();
+
+            if(answerFour == "3")
+            {
+                Console.WriteLine("GOOD MEMORY!");
+                Score = Score + 1;
+                End();
+            }
+            else
+            {
+                Console.WriteLine("OH, COME ON NOW...IT WAS SNOW WHITE.");
+                End();
+            }
+
+        }
+
+        public static void End()
+        {
+            Console.WriteLine();
+            Console.WriteLine();
+            if(Score == 4)
+            {
+                Console.WriteLine("WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY");
+                Console.WriteLine("YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE");
+                Console.WriteLine("LITERATURE (HA, HA, HA)");
+                return;
+            }
+            else if(Score < 2)
+            {
+                Console.WriteLine("UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO");
+                Console.WriteLine("NURSERY SCHOOL FOR YOU, MY FRIEND.");
+                return;
+            }
+            else
+            {
+                Console.WriteLine("NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME");
+                Console.WriteLine("READING THE NURSERY GREATS.");
+                return;
+            }
+        }
+
+	}
+}
diff --git a/00_Alternate_Languages/57_Literature_Quiz/java/README.md b/00_Alternate_Languages/57_Literature_Quiz/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/57_Literature_Quiz/java/src/LiteratureQuiz.java b/00_Alternate_Languages/57_Literature_Quiz/java/src/LiteratureQuiz.java
new file mode 100644
index 00000000..20331b1a
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/java/src/LiteratureQuiz.java
@@ -0,0 +1,176 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Literature Quiz
+ * 

+ * Based on the Basic game of Literature Quiz here + * https://github.com/coding-horror/basic-computer-games/blob/main/57%20Literature%20Quiz/litquiz.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. + */ +public class LiteratureQuiz { + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + STARTUP, + QUESTIONS, + RESULTS, + GAME_OVER + } + + // Current game state + private GAME_STATE gameState; + // Players correct answers + private int correctAnswers; + + public LiteratureQuiz() { + + gameState = GAME_STATE.STARTUP; + + // Initialise kb scanner + kbScanner = new Scanner(System.in); + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + // Show an introduction the first time the game is played. + case STARTUP: + intro(); + correctAnswers = 0; + gameState = GAME_STATE.QUESTIONS; + break; + + // Ask the player four questions + case QUESTIONS: + + // Question 1 + System.out.println("IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT"); + int question1Answer = displayTextAndGetNumber("1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO ? "); + if (question1Answer == 3) { + System.out.println("VERY GOOD! HERE'S ANOTHER."); + correctAnswers++; + } else { + System.out.println("SORRY...FIGARO WAS HIS NAME."); + } + + System.out.println(); + + // Question 2 + System.out.println("FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?"); + int question2Answer = displayTextAndGetNumber("1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S ? "); + if (question2Answer == 2) { + System.out.println("PRETTY GOOD!"); + correctAnswers++; + } else { + System.out.println("TOO BAD...IT WAS ELMER FUDD'S GARDEN."); + } + + System.out.println(); + + // Question 3 + System.out.println("IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED"); + int question3Answer = displayTextAndGetNumber("1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO ? "); + if (question3Answer == 4) { + System.out.println("YEA! YOU'RE A REAL LITERATURE GIANT."); + correctAnswers++; + } else { + System.out.println("BACK TO THE BOOKS,...TOTO WAS HIS NAME."); + } + + System.out.println(); + + // Question 4 + System.out.println("WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE"); + int question4Answer = displayTextAndGetNumber("1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY ? "); + if (question4Answer == 3) { + System.out.println("GOOD MEMORY!"); + correctAnswers++; + } else { + System.out.println("OH, COME ON NOW...IT WAS SNOW WHITE."); + } + + System.out.println(); + gameState = GAME_STATE.RESULTS; + break; + + // How did the player do? + case RESULTS: + if (correctAnswers == 4) { + // All correct + System.out.println("WOW! THAT'S SUPER! YOU REALLY KNOW YOUR NURSERY"); + System.out.println("YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE"); + System.out.println("LITERATURE (HA, HA, HA)"); + // one or none correct + } else if (correctAnswers < 2) { + System.out.println("UGH. THAT WAS DEFINITELY NOT TOO SWIFT. BACK TO"); + System.out.println("NURSERY SCHOOL FOR YOU, MY FRIEND."); + // two or three correct + } else { + System.out.println("NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME"); + System.out.println("READING THE NURSERY GREATS."); + } + gameState = GAME_STATE.GAME_OVER; + break; + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + public void intro() { + System.out.println(simulateTabs(25) + "LITERATURE QUIZ"); + System.out.println(simulateTabs(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("LITERATURE QUIZ"); + System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE."); + System.out.println("THIS IS A MULTIPLE-CHOICE QUIZ."); + System.out.println("TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK."); + System.out.println(); + System.out.println("GOOD LUCK!"); + System.out.println(); + } + + /** + * Simulate the old basic tab(xx) command which indented text by xx spaces. + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String simulateTabs(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to an Integer + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private int displayTextAndGetNumber(String text) { + return Integer.parseInt(displayTextAndGetInput(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } +} diff --git a/00_Alternate_Languages/57_Literature_Quiz/java/src/LiteratureQuizGame.java b/00_Alternate_Languages/57_Literature_Quiz/java/src/LiteratureQuizGame.java new file mode 100644 index 00000000..3f7d9fd4 --- /dev/null +++ b/00_Alternate_Languages/57_Literature_Quiz/java/src/LiteratureQuizGame.java @@ -0,0 +1,8 @@ +public class LiteratureQuizGame { + + public static void main(String[] args) { + + LiteratureQuiz literatureQuiz = new LiteratureQuiz(); + literatureQuiz.play(); + } +} diff --git a/00_Alternate_Languages/57_Literature_Quiz/javascript/README.md b/00_Alternate_Languages/57_Literature_Quiz/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/57_Literature_Quiz/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/57_Literature_Quiz/javascript/litquiz.html b/00_Alternate_Languages/57_Literature_Quiz/javascript/litquiz.html new file mode 100644 index 00000000..e4aae4c3 --- /dev/null +++ b/00_Alternate_Languages/57_Literature_Quiz/javascript/litquiz.html @@ -0,0 +1,9 @@ + + +LITERATURE QUIZ + + +


+
+
+
diff --git a/00_Alternate_Languages/57_Literature_Quiz/javascript/litquiz.js b/00_Alternate_Languages/57_Literature_Quiz/javascript/litquiz.js
new file mode 100644
index 00000000..f652cdf3
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/javascript/litquiz.js
@@ -0,0 +1,119 @@
+// LITQUIZ
+//
+// 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(25) + "LITERATURE QUIZ\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    r = 0;
+    print("TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\n");
+    print("\n");
+    print("THIS IS A MULTIPLE-CHOICE QUIZ.\n");
+    print("TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\n");
+    print("\n");
+    print("GOOD LUCK!\n");
+    print("\n");
+    print("\n");
+    print("IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT\n");
+    print("1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO\n");
+    a = parseInt(await input());
+    if (a == 3) {
+        print("VERY GOOD!  HERE'S ANOTHER.\n");
+        r++;
+    } else {
+        print("SORRY...FIGARO WAS HIS NAME.\n");
+    }
+    print("\n");
+    print("\n");
+    print("FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\n");
+    print("1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S\n");
+    a = parseInt(await input());
+    if (a == 2) {
+        print("PRETTY GOOD!\n");
+        r++;
+    } else {
+        print("TOO BAD...IT WAS ELMER FUDD'S GARDEN.\n");
+    }
+    print("\n");
+    print("\n");
+    print("IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED\n");
+    print("1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO\n");
+    a = parseInt(await input());
+    if (a == 4) {
+        print("YEA!  YOU'RE A REAL LITERATURE GIANT.\n");
+        r++;
+    } else {
+        print("BACK TO THE BOOKS,...TOTO WAS HIS NAME.\n");
+    }
+    print("\n");
+    print("\n");
+    print("WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE\n");
+    print("1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY\n");
+    a = parseInt(await input());
+    if (a == 3) {
+        print("GOOD MEMORY!\n");
+        r++;
+    } else {
+        print("OH, COME ON NOW...IT WAS SNOW WHITE.\n");
+    }
+    print("\n");
+    print("\n");
+    if (r == 4) {
+        print("WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY\n");
+        print("YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\n");
+        print("LITERATURE (HA, HA, HA)\n");
+    } else if (r < 2) {
+        print("UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO\n");
+        print("NURSERY SCHOOL FOR YOU, MY FRIEND.\n");
+    } else {
+        print("NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\n");
+        print("READING THE NURSERY GREATS.\n");
+    }
+}
+
+main();
diff --git a/00_Alternate_Languages/57_Literature_Quiz/litquiz.bas b/00_Alternate_Languages/57_Literature_Quiz/litquiz.bas
new file mode 100644
index 00000000..fe731b2c
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/litquiz.bas
@@ -0,0 +1,49 @@
+1 PRINT TAB(25);"LITERATURE QUIZ"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+5 R=0
+10 PRINT "TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE."
+12 PRINT: PRINT "THIS IS A MULTIPLE-CHOICE QUIZ."
+13 PRINT "TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK."
+15 PRINT: PRINT "GOOD LUCK!": PRINT: PRINT
+40 PRINT "IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT"
+42 PRINT "1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO";
+43 INPUT A: IF A=3 THEN 46
+44 PRINT "SORRY...FIGARO WAS HIS NAME.": GOTO 50
+46 PRINT "VERY GOOD!  HERE'S ANOTHER."
+47 R=R+1
+50 PRINT: PRINT
+51 PRINT "FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?"
+52 PRINT "1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S";
+53 INPUT A: IF A=2 THEN 56
+54 PRINT "TOO BAD...IT WAS ELMER FUDD'S GARDEN.": GOTO 60
+56 PRINT "PRETTY GOOD!"
+57 R=R+1
+60 PRINT: PRINT
+61 PRINT "IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED"
+62 PRINT "1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO";
+63 INPUT A: IF A=4 THEN 66
+64 PRINT "BACK TO THE BOOKS,...TOTO WAS HIS NAME.": GOTO 70
+66 PRINT "YEA!  YOU'RE A REAL LITERATURE GIANT."
+67 R=R+1
+70 PRINT:PRINT
+71 PRINT "WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE"
+72 PRINT "1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY";
+73 INPUT A: IF A=3 THEN 76
+74 PRINT "OH, COME ON NOW...IT WAS SNOW WHITE."
+75 GOTO 80
+76 PRINT "GOOD MEMORY!"
+77 R=R+1
+80 PRINT:PRINT
+85 IF R=4 THEN 100
+90 IF R<2 THEN 200
+92 PRINT "NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME"
+94 PRINT "READING THE NURSERY GREATS."
+96 STOP
+100 PRINT "WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY"
+110 PRINT "YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE"
+120 PRINT "LITERATURE (HA, HA, HA)"
+130 STOP
+200 PRINT "UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO"
+205 PRINT "NURSERY SCHOOL FOR YOU, MY FRIEND."
+999 END
diff --git a/33_Dice/pascal/README.md b/00_Alternate_Languages/57_Literature_Quiz/pascal/README.md
similarity index 100%
rename from 33_Dice/pascal/README.md
rename to 00_Alternate_Languages/57_Literature_Quiz/pascal/README.md
diff --git a/00_Alternate_Languages/57_Literature_Quiz/perl/README.md b/00_Alternate_Languages/57_Literature_Quiz/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/57_Literature_Quiz/perl/litquiz.pl b/00_Alternate_Languages/57_Literature_Quiz/perl/litquiz.pl
new file mode 100644
index 00000000..eed03506
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/perl/litquiz.pl
@@ -0,0 +1,80 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 25 . "LITERATURE QUIZ\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n"; print "\n"; print "\n";
+print "TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.\n";
+print "\n"; print "THIS IS A MULTIPLE-CHOICE QUIZ.\n";
+print "TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.\n";
+print "\n"; print "GOOD LUCK!\n";
+my $R=0;
+
+
+print "\n"; print "\n";
+print "IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT\n";
+print "1)TIGGER, 2)CICERO, 3)FIGARO, 4)GUIPETTO";
+print "? "; chomp(my $A = );
+
+if ($A eq 3) {
+	$R++;
+	print "VERY GOOD! HERE'S ANOTHER.\n";
+	} else {
+	print "SORRY...FIGARO WAS HIS NAME.\n";
+	}
+
+
+print "\n"; print "\n";
+print "FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?\n";
+print "1)MR. NIXON'S, 2)ELMER FUDD'S, 3)CLEM JUDD'S, 4)STROMBOLI'S";
+print "? "; chomp($A = );
+
+if ($A eq 2) {
+	print "PRETTY GOOD!\n";
+	$R=$R+1;
+	} else {
+	print "TOO BAD...IT WAS ELMER FUDD'S GARDEN.\n";
+	}
+
+
+print "\n"; print "\n";
+print "IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED\n";
+print "1)CICERO, 2)TRIXIA, 3)KING, 4)TOTO";
+print "? "; chomp($A = );
+if ($A eq 4) {
+	print "YEA! YOU'RE A REAL LITERATURE GIANT.\n";
+	$R=$R+1;
+	} else {
+	print "BACK TO THE BOOKS,...TOTO WAS HIS NAME.\n";
+	}
+
+
+print "\n"; print "\n";
+print "WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE\n";
+print "1)SLEEPING BEAUTY, 2)CINDERELLA, 3)SNOW WHITE, 4)WENDY";
+print "? "; chomp($A = );
+if ($A eq 3) {
+	print "GOOD MEMORY!\n";
+	$R=$R+1;
+	} else {
+	print "OH, COME ON NOW...IT WAS SNOW WHITE.\n";
+	}
+
+
+print "\n"; print "\n";
+if ($R eq 4) {
+	print "WOW! THAT'S SUPER! YOU REALLY KNOW YOUR NURSERY\n";
+	print "YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE\n";
+	print "LITERATURE (HA, HA, HA)\n";
+	exit
+	}
+if ($R<2) {
+	print "UGH. THAT WAS DEFINITELY NOT TOO SWIFT. BACK TO\n";
+	print "NURSERY SCHOOL FOR YOU, MY FRIEND.\n";
+	exit;
+	}
+
+print "NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME\n";
+print "READING THE NURSERY GREATS.\n";
+exit;
diff --git a/00_Alternate_Languages/57_Literature_Quiz/python/README.md b/00_Alternate_Languages/57_Literature_Quiz/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/57_Literature_Quiz/python/litquiz.py b/00_Alternate_Languages/57_Literature_Quiz/python/litquiz.py
new file mode 100644
index 00000000..b5b9d1c5
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/python/litquiz.py
@@ -0,0 +1,117 @@
+"""
+LITQUIZ
+
+A children's literature quiz
+
+Ported by Dave LeCompte
+"""
+
+PAGE_WIDTH = 64
+
+
+class Question:
+    def __init__(
+        self, question, answer_list, correct_number, incorrect_message, correct_message
+    ):
+        self.question = question
+        self.answer_list = answer_list
+        self.correct_number = correct_number
+        self.incorrect_message = incorrect_message
+        self.correct_message = correct_message
+
+    def ask(self):
+        print(self.question)
+
+        options = [f"{i+1}){self.answer_list[i]}" for i in range(len(self.answer_list))]
+        print(", ".join(options))
+
+        response = int(input())
+
+        if response == self.correct_number:
+            print(self.correct_message)
+            return True
+        else:
+            print(self.incorrect_message)
+            return False
+
+
+questions = [
+    Question(
+        "IN PINOCCHIO, WHAT WAS THE NAME OF THE CAT?",
+        ["TIGGER", "CICERO", "FIGARO", "GUIPETTO"],
+        3,
+        "SORRY...FIGARO WAS HIS NAME.",
+        "VERY GOOD!  HERE'S ANOTHER.",
+    ),
+    Question(
+        "FROM WHOSE GARDEN DID BUGS BUNNY STEAL THE CARROTS?",
+        ["MR. NIXON'S", "ELMER FUDD'S", "CLEM JUDD'S", "STROMBOLI'S"],
+        2,
+        "TOO BAD...IT WAS ELMER FUDD'S GARDEN.",
+        "PRETTY GOOD!",
+    ),
+    Question(
+        "IN THE WIZARD OF OS, DOROTHY'S DOG WAS NAMED?",
+        ["CICERO", "TRIXIA", "KING", "TOTO"],
+        4,
+        "BACK TO THE BOOKS,...TOTO WAS HIS NAME.",
+        "YEA!  YOU'RE A REAL LITERATURE GIANT.",
+    ),
+    Question(
+        "WHO WAS THE FAIR MAIDEN WHO ATE THE POISON APPLE?",
+        ["SLEEPING BEAUTY", "CINDERELLA", "SNOW WHITE", "WENDY"],
+        3,
+        "OH, COME ON NOW...IT WAS SNOW WHITE.",
+        "GOOD MEMORY!",
+    ),
+]
+
+
+def print_centered(msg):
+    spaces = " " * ((64 - len(msg)) // 2)
+
+    print(spaces + msg)
+
+
+def print_instructions():
+    print("TEST YOUR KNOWLEDGE OF CHILDREN'S LITERATURE.")
+    print()
+    print("THIS IS A MULTIPLE-CHOICE QUIZ.")
+    print("TYPE A 1, 2, 3, OR 4 AFTER THE QUESTION MARK.")
+    print()
+    print("GOOD LUCK!")
+    print()
+    print()
+
+
+def main():
+    print_centered("LITERATURE QUIZ")
+    print_centered("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+    print_instructions()
+
+    score = 0
+
+    for q in questions:
+        if q.ask():
+            score += 1
+        print()
+        print()
+
+    if score == len(questions):
+        print("WOW!  THAT'S SUPER!  YOU REALLY KNOW YOUR NURSERY")
+        print("YOUR NEXT QUIZ WILL BE ON 2ND CENTURY CHINESE")
+        print("LITERATURE (HA, HA, HA)")
+    elif score < len(questions) / 2:
+        print("UGH.  THAT WAS DEFINITELY NOT TOO SWIFT.  BACK TO")
+        print("NURSERY SCHOOL FOR YOU, MY FRIEND.")
+    else:
+        print("NOT BAD, BUT YOU MIGHT SPEND A LITTLE MORE TIME")
+        print("READING THE NURSERY GREATS.")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/57_Literature_Quiz/ruby/README.md b/00_Alternate_Languages/57_Literature_Quiz/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/57_Literature_Quiz/vbnet/LiteratureQuiz.sln b/00_Alternate_Languages/57_Literature_Quiz/vbnet/LiteratureQuiz.sln
new file mode 100644
index 00000000..67ca803d
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/vbnet/LiteratureQuiz.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "LiteratureQuiz", "LiteratureQuiz.vbproj", "{7897F5C5-055B-449D-9BD5-1F631DA87D06}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{7897F5C5-055B-449D-9BD5-1F631DA87D06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7897F5C5-055B-449D-9BD5-1F631DA87D06}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7897F5C5-055B-449D-9BD5-1F631DA87D06}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7897F5C5-055B-449D-9BD5-1F631DA87D06}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/57_Literature_Quiz/vbnet/LiteratureQuiz.vbproj b/00_Alternate_Languages/57_Literature_Quiz/vbnet/LiteratureQuiz.vbproj
new file mode 100644
index 00000000..32c35664
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/vbnet/LiteratureQuiz.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    LiteratureQuiz
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/57_Literature_Quiz/vbnet/README.md b/00_Alternate_Languages/57_Literature_Quiz/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/57_Literature_Quiz/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/58_Love/README.md b/00_Alternate_Languages/58_Love/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/58_Love/csharp/Input.cs b/00_Alternate_Languages/58_Love/csharp/Input.cs
new file mode 100644
index 00000000..030e3ead
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/csharp/Input.cs
@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+
+namespace Love
+{
+    // Provides input methods which emulate the BASIC interpreter's keyboard input routines
+    internal static class Input
+    {
+        private static void Prompt(string text = "") => Console.Write($"{text}? ");
+
+        public static string ReadLine(string prompt)
+        {
+            Prompt(prompt);
+            var values = ReadStrings();
+
+            if (values.Length > 1)
+            {
+                Console.WriteLine("!Extra input ingored");
+            }
+
+            return values[0];
+        }
+
+        private static string[] ReadStrings() => Console.ReadLine().Split(',', StringSplitOptions.TrimEntries);
+    }
+}
diff --git a/00_Alternate_Languages/58_Love/csharp/Love.csproj b/00_Alternate_Languages/58_Love/csharp/Love.csproj
new file mode 100644
index 00000000..fc2efa30
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/csharp/Love.csproj
@@ -0,0 +1,11 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+  
+    
+  
+
diff --git a/00_Alternate_Languages/58_Love/csharp/Love.sln b/00_Alternate_Languages/58_Love/csharp/Love.sln
new file mode 100644
index 00000000..813af0f2
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/csharp/Love.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Love", "Love.csproj", "{1C02A3CA-615B-42CF-B696-4514770CA67F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{1C02A3CA-615B-42CF-B696-4514770CA67F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1C02A3CA-615B-42CF-B696-4514770CA67F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1C02A3CA-615B-42CF-B696-4514770CA67F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1C02A3CA-615B-42CF-B696-4514770CA67F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {F9C55508-108B-4EA1-ADD7-4BA8EC915E68}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/58_Love/csharp/LovePattern.cs b/00_Alternate_Languages/58_Love/csharp/LovePattern.cs
new file mode 100644
index 00000000..4c24ed84
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/csharp/LovePattern.cs
@@ -0,0 +1,57 @@
+using System.IO;
+
+namespace Love
+{
+    internal class LovePattern
+    {
+        private readonly int[] _segmentLengths = new[] {
+            60, 1, 12, 26, 9, 12, 3, 8, 24, 17, 8, 4, 6, 23, 21, 6, 4, 6, 22, 12, 5,
+            6, 5, 4, 6, 21, 11, 8, 6, 4, 4, 6, 21, 10, 10, 5, 4, 4, 6, 21, 9, 11, 5,
+            4, 4, 6, 21, 8, 11, 6, 4, 4, 6, 21, 7, 11, 7, 4, 4, 6, 21, 6, 11, 8, 4,
+            4, 6, 19, 1, 1, 5, 11, 9, 4, 4, 6, 19, 1, 1, 5, 10, 10, 4, 4, 6, 18, 2,
+            1, 6, 8, 11, 4, 4, 6, 17, 3, 1, 7, 5, 13, 4, 4, 6, 15, 5, 2, 23, 5, 1,
+            29, 5, 17, 8, 1, 29, 9, 9, 12, 1, 13, 5, 40, 1, 1, 13, 5, 40, 1, 4, 6,
+            13, 3, 10, 6, 12, 5, 1, 5, 6, 11, 3, 11, 6, 14, 3, 1, 5, 6, 11, 3, 11,
+            6, 15, 2, 1, 6, 6, 9, 3, 12, 6, 16, 1, 1, 6, 6, 9, 3, 12, 6, 7, 1, 10,
+            7, 6, 7, 3, 13, 6, 6, 2, 10, 7, 6, 7, 3, 13, 14, 10, 8, 6, 5, 3, 14, 6,
+            6, 2, 10, 8, 6, 5, 3, 14, 6, 7, 1, 10, 9, 6, 3, 3, 15, 6, 16, 1, 1, 9,
+            6, 3, 3, 15, 6, 15, 2, 1, 10, 6, 1, 3, 16, 6, 14, 3, 1, 10, 10, 16, 6,
+            12, 5, 1, 11, 8, 13, 27, 1, 11, 8, 13, 27, 1, 60
+        };
+
+        public int LineLength => 60;
+
+        internal void Write(SourceCharacters source, Stream destination)
+        {
+            using var writer = new StreamWriter(destination);
+
+            WritePadding(writer);
+
+            var lineLength = 0;
+
+            foreach (var segmentLength in _segmentLengths)
+            {
+                foreach (var character in source.GetCharacters(segmentLength))
+                {
+                    writer.Write(character);
+                }
+                lineLength += segmentLength;
+                if (lineLength >= LineLength)
+                {
+                    writer.WriteLine();
+                    lineLength = 0;
+                }
+            }
+
+            WritePadding(writer);
+        }
+
+        private void WritePadding(StreamWriter writer)
+        {
+            for (int i = 0; i < 10; i++)
+            {
+                writer.WriteLine();
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/58_Love/csharp/Program.cs b/00_Alternate_Languages/58_Love/csharp/Program.cs
new file mode 100644
index 00000000..a9784466
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/csharp/Program.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Reflection;
+
+namespace Love
+{
+    internal class Program
+    {
+        static void Main(string[] args)
+        {
+            DisplayIntro();
+
+            var message = Input.ReadLine("Your message, please");
+            var pattern = new LovePattern();
+
+            var source = new SourceCharacters(pattern.LineLength, message);
+
+            using var destination = Console.OpenStandardOutput();
+
+            pattern.Write(source, destination);
+        }
+
+        private static void DisplayIntro()
+        {
+            using var stream = Assembly.GetExecutingAssembly()
+                .GetManifestResourceStream("Love.Strings.Intro.txt");
+            using var stdout = Console.OpenStandardOutput();
+
+            stream.CopyTo(stdout);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/58_Love/csharp/README.md b/00_Alternate_Languages/58_Love/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/58_Love/csharp/SourceCharacters.cs b/00_Alternate_Languages/58_Love/csharp/SourceCharacters.cs
new file mode 100644
index 00000000..64716f9c
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/csharp/SourceCharacters.cs
@@ -0,0 +1,38 @@
+using System;
+
+namespace Love
+{
+    internal class SourceCharacters
+    {
+        private readonly int _lineLength;
+        private readonly char[][] _chars;
+        private int _currentRow;
+        private int _currentIndex;
+
+        public SourceCharacters(int lineLength, string message)
+        {
+            _lineLength = lineLength;
+            _chars = new[] { new char[lineLength], new char[lineLength] };
+
+            for (int i = 0; i < lineLength; i++)
+            {
+                _chars[0][i] = message[i % message.Length];
+                _chars[1][i] = ' ';
+            }
+        }
+
+        public ReadOnlySpan GetCharacters(int count)
+        {
+            var span = new ReadOnlySpan(_chars[_currentRow], _currentIndex, count);
+
+            _currentRow = 1 - _currentRow;
+            _currentIndex += count;
+            if (_currentIndex >= _lineLength)
+            {
+                _currentIndex = _currentRow = 0;
+            }
+
+            return span;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/58_Love/csharp/Strings/Intro.txt b/00_Alternate_Languages/58_Love/csharp/Strings/Intro.txt
new file mode 100644
index 00000000..cc10189e
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/csharp/Strings/Intro.txt
@@ -0,0 +1,9 @@
+                                 Love
+               Creative Computing  Morristown, New Jersey
+
+
+
+A tribute to the great American artist, Robert Indiana.
+His greatest work will be reproduced with a message of
+your choice up to 60 characters.  If you can't think of
+a message, simply type the word 'LOVE'
diff --git a/00_Alternate_Languages/58_Love/java/README.md b/00_Alternate_Languages/58_Love/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/58_Love/java/src/Love.java b/00_Alternate_Languages/58_Love/java/src/Love.java
new file mode 100644
index 00000000..da8385aa
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/java/src/Love.java
@@ -0,0 +1,170 @@
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Love
+ * 

+ * Based on the Basic game of Love here + * https://github.com/coding-horror/basic-computer-games/blob/main/58%20Love/love.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. + */ + +public class Love { + + // This is actually defined in the data, but made it a const for readability + public static final int ROW_LENGTH = 60; + + // Contains the data to draw the picture + private final ArrayList data; + + // Used for keyboard input + private final Scanner kbScanner; + + public Love() { + data = storeData(); + kbScanner = new Scanner(System.in); + } + + /** + * Show an intro, accept a message, then draw the picture. + */ + public void process() { + intro(); + + int rowLength = data.get(0); + + String message = displayTextAndGetInput("YOUR MESSAGE, PLEASE "); + + // ensure the string is at least 60 characters + while (message.length() < rowLength) { + message += message; + } + + // chop of any extra characters so its exactly ROW_LENGTH in length + if (message.length() > ROW_LENGTH) { + message = message.substring(0, ROW_LENGTH); + } + + // Print header + System.out.println(message); + + int pos = 1; // don't read row length which is value in first element position + + int runningLineTotal = 0; + StringBuilder lineText = new StringBuilder(); + boolean outputChars = true; + while (true) { + int charsOrSpacesLength = data.get(pos); + if (charsOrSpacesLength == ROW_LENGTH) { + // EOF, so exit + break; + } + if (outputChars) { + // add characters from message string for charsOrSpacesLength characters + for (int i = 0; i < charsOrSpacesLength; i++) { + lineText.append(message.charAt(i + runningLineTotal)); + // switch to spaces which will be in the next element of the arraylist + outputChars = false; + } + } else { + // add charsOrSpacesLength spaces to the string + lineText.append(addSpaces(charsOrSpacesLength)); + // Switch to chars to output on next loop + outputChars = true; + } + + // We need to know when to print the string out + runningLineTotal += charsOrSpacesLength; + + // Are we at end of line? If so print and reset for next line + if (runningLineTotal >= ROW_LENGTH) { + System.out.println(lineText); + lineText = new StringBuilder(); + runningLineTotal = 0; + outputChars = true; + } + + // Move to next arraylist element + pos++; + } + + // Print footer + System.out.println(message); + + } + + private void intro() { + System.out.println(addSpaces(33) + "LOVE"); + System.out.println(addSpaces(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA."); + System.out.println("HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF"); + System.out.println("YOUR CHOICE UP TO 60 CHARACTERS. IF YOU CAN'T THINK OF"); + System.out.println("A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'"); + System.out.println(); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.nextLine(); + } + + /** + * Return a string of x spaces + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String addSpaces(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + + /** + * Original Basic program had the data in DATA format. We're importing all the data into an array for ease of + * processing. + * Format of data is + * FIRST int of data is 60, which is the number of characters per line. + * LAST int of data is same as FIRST above. + * Then the data alternates between how many characters to print and how many spaces to print + * You need to keep a running total of the count of ints read and once this hits 60, its time to + * print and then reset count to zero. + * + * @return ArrayList of type Integer containing the data + */ + private ArrayList storeData() { + + ArrayList theData = new ArrayList<>(); + + theData.addAll(Arrays.asList(60, 1, 12, 26, 9, 12, 3, 8, 24, 17, 8, 4, 6, 23, 21, 6, 4, 6, 22, 12, 5, 6, 5)); + theData.addAll(Arrays.asList(4, 6, 21, 11, 8, 6, 4, 4, 6, 21, 10, 10, 5, 4, 4, 6, 21, 9, 11, 5, 4)); + theData.addAll(Arrays.asList(4, 6, 21, 8, 11, 6, 4, 4, 6, 21, 7, 11, 7, 4, 4, 6, 21, 6, 11, 8, 4)); + theData.addAll(Arrays.asList(4, 6, 19, 1, 1, 5, 11, 9, 4, 4, 6, 19, 1, 1, 5, 10, 10, 4, 4, 6, 18, 2, 1, 6, 8, 11, 4)); + theData.addAll(Arrays.asList(4, 6, 17, 3, 1, 7, 5, 13, 4, 4, 6, 15, 5, 2, 23, 5, 1, 29, 5, 17, 8)); + theData.addAll(Arrays.asList(1, 29, 9, 9, 12, 1, 13, 5, 40, 1, 1, 13, 5, 40, 1, 4, 6, 13, 3, 10, 6, 12, 5, 1)); + theData.addAll(Arrays.asList(5, 6, 11, 3, 11, 6, 14, 3, 1, 5, 6, 11, 3, 11, 6, 15, 2, 1)); + theData.addAll(Arrays.asList(6, 6, 9, 3, 12, 6, 16, 1, 1, 6, 6, 9, 3, 12, 6, 7, 1, 10)); + theData.addAll(Arrays.asList(7, 6, 7, 3, 13, 6, 6, 2, 10, 7, 6, 7, 3, 13, 14, 10, 8, 6, 5, 3, 14, 6, 6, 2, 10)); + theData.addAll(Arrays.asList(8, 6, 5, 3, 14, 6, 7, 1, 10, 9, 6, 3, 3, 15, 6, 16, 1, 1)); + theData.addAll(Arrays.asList(9, 6, 3, 3, 15, 6, 15, 2, 1, 10, 6, 1, 3, 16, 6, 14, 3, 1, 10, 10, 16, 6, 12, 5, 1)); + theData.addAll(Arrays.asList(11, 8, 13, 27, 1, 11, 8, 13, 27, 1, 60)); + + return theData; + } + + public static void main(String[] args) { + + Love love = new Love(); + love.process(); + } +} diff --git a/00_Alternate_Languages/58_Love/javascript/README.md b/00_Alternate_Languages/58_Love/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/58_Love/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/58_Love/javascript/love.html b/00_Alternate_Languages/58_Love/javascript/love.html new file mode 100644 index 00000000..ede593e8 --- /dev/null +++ b/00_Alternate_Languages/58_Love/javascript/love.html @@ -0,0 +1,9 @@ + + +LOVE + + +


+
+
+
diff --git a/00_Alternate_Languages/58_Love/javascript/love.js b/00_Alternate_Languages/58_Love/javascript/love.js
new file mode 100644
index 00000000..6a99e72f
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/javascript/love.js
@@ -0,0 +1,105 @@
+// LOVE
+//
+// 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 data = [60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5,
+            4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4,
+            4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4,
+            4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4,
+            4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8,
+            1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1,
+            5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1,
+            6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10,
+            7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10,
+            8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1,
+            9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1,
+            11,8,13,27,1,11,8,13,27,1,60];
+
+// Main program
+async function main()
+{
+    print(tab(33) + "LOVE\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.\n");
+    print("HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF\n");
+    print("YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF\n");
+    print("A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'\n");
+    print("\n");
+    print("YOUR MESSAGE, PLEASE");
+    str = await input();
+    l = str.length;
+    ts = [];
+    for (i = 1; i <= 10; i++)
+        print("\n");
+    ts = "";
+    do {
+        ts += str;
+    } while (ts.length < 60) ;
+    pos = 0;
+    c = 0;
+    while (++c < 37) {
+        a1 = 1;
+        p = 1;
+        print("\n");
+        do {
+            a = data[pos++];
+            a1 += a;
+            if (p != 1) {
+                for (i = 1; i <= a; i++)
+                    print(" ");
+                p = 1;
+            } else {
+                for (i = a1 - a; i <= a1 - 1; i++)
+                    print(ts[i]);
+                p = 0;
+            }
+        } while (a1 <= 60) ;
+    }
+    for (i = 1; i <= 10; i++)
+        print("\n");
+}
+
+main();
diff --git a/00_Alternate_Languages/58_Love/love.bas b/00_Alternate_Languages/58_Love/love.bas
new file mode 100644
index 00000000..c53d2ae3
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/love.bas
@@ -0,0 +1,34 @@
+2 PRINT TAB(33);"LOVE"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT: PRINT: PRINT
+20 PRINT "A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA."
+30 PRINT "HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF"
+40 PRINT "YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF"
+50 PRINT "A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'": PRINT
+60 INPUT "YOUR MESSAGE, PLEASE";A$: L=LEN(A$)
+70 DIM T$(120): FOR I=1 TO 10: PRINT: NEXT I
+100 FOR J=0 TO INT(60/L)
+110 FOR I=1 TO L
+120 T$(J*L+I)=MID$(A$,I,1)
+130 NEXT I: NEXT J
+140 C=0
+200 A1=1: P=1: C=C+1: IF C=37 THEN 999
+205 PRINT
+210 READ A: A1=A1+A: IF P=1 THEN 300
+240 FOR I=1 TO A: PRINT " ";: NEXT I: P=1: GOTO 400
+300 FOR I=A1-A TO A1-1: PRINT T$(I);: NEXT I: P=0
+400 IF A1>60 THEN 200
+410 GOTO 210
+600 DATA 60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5
+610 DATA 4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4
+620 DATA 4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4
+630 DATA 4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4
+640 DATA 4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8
+650 DATA 1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1
+660 DATA 5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1
+670 DATA 6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10
+680 DATA 7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10
+690 DATA 8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1
+700 DATA 9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1
+710 DATA 11,8,13,27,1,11,8,13,27,1,60
+999 FOR I=1 TO 10: PRINT: NEXT I: END
diff --git a/34_Digits/pascal/README.md b/00_Alternate_Languages/58_Love/pascal/README.md
similarity index 100%
rename from 34_Digits/pascal/README.md
rename to 00_Alternate_Languages/58_Love/pascal/README.md
diff --git a/00_Alternate_Languages/58_Love/perl/README.md b/00_Alternate_Languages/58_Love/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/58_Love/perl/love.pl b/00_Alternate_Languages/58_Love/perl/love.pl
new file mode 100644
index 00000000..31127e05
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/perl/love.pl
@@ -0,0 +1,52 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 33 . "LOVE\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+print "A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.\n";
+print "HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF\n";
+print "YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF\n";
+print "A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'\n"; print "\n";
+print "YOUR MESSAGE, PLEASE? "; chomp(my $A = );
+my $L= length($A);
+
+
+#Original logic too fuzzy, remaked.
+my $Width= 60;
+my $Text= substr($A x ($Width/$L+1), 0, $Width);
+for (my $I=1; $I<10; $I++) { print "\n"; }
+
+my @Data= (
+	60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5,
+	4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4,
+	4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4,
+	4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4,
+	4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8,
+	1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1,
+	5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1,
+	6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10,
+	7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10,
+	8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1,
+	9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1,
+	11,8,13,27,1,11,8,13,27,1,60
+	);
+
+
+my $Pos=0;
+my $Toggle=1;
+foreach my $Size (@Data) {
+	my $Chunk= $Toggle ? substr($Text, $Pos, $Size) : " " x $Size;
+	print $Chunk;
+	$Pos+= $Size;
+	$Toggle= !$Toggle;
+	if ($Pos>= $Width) {
+		print "\n";
+		$Toggle=1;
+		$Pos=0;
+		}
+	}
+
+for (my $I=1; $I<10; $I++) { print "\n"; }
+exit;
diff --git a/00_Alternate_Languages/58_Love/python/README.md b/00_Alternate_Languages/58_Love/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/58_Love/python/love.py b/00_Alternate_Languages/58_Love/python/love.py
new file mode 100644
index 00000000..a2fc0777
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/python/love.py
@@ -0,0 +1,152 @@
+######################################################################
+#
+# LOVE
+#
+# From: BASIC Computer Games (1978)
+#       Edited by David H. Ahl
+#
+# "This program is designed to reproduce Robert Indiana's great art
+#  work 'Love' with a message of your choice up to 60 characters long.
+#
+# "The [DATA variable is] an alternating count of the number
+#  of characters and blanks which form the design.  These data give
+#  the correct proportions for a standard 10 character per inch
+#  Teletype or line printer.
+#
+# "The LOVE program was created by David Ahl."
+#
+#
+# Python port by Jeff Jetton, 2019
+#
+######################################################################
+
+
+# Image data. Each top-level element is a row. Each row element
+# contains alternating character and blank run lengths.
+DATA = [
+    [
+        60,
+    ],
+    [1, 12, 26, 9, 12],
+    [3, 8, 24, 17, 8],
+    [4, 6, 23, 21, 6],
+    [4, 6, 22, 12, 5, 6, 5],
+    [4, 6, 21, 11, 8, 6, 4],
+    [4, 6, 21, 10, 10, 5, 4],
+    [4, 6, 21, 9, 11, 5, 4],
+    [4, 6, 21, 8, 11, 6, 4],
+    [4, 6, 21, 7, 11, 7, 4],
+    [4, 6, 21, 6, 11, 8, 4],
+    [4, 6, 19, 1, 1, 5, 11, 9, 4],
+    [4, 6, 19, 1, 1, 5, 10, 10, 4],
+    [4, 6, 18, 2, 1, 6, 8, 11, 4],
+    [4, 6, 17, 3, 1, 7, 5, 13, 4],
+    [4, 6, 15, 5, 2, 23, 5],
+    [1, 29, 5, 17, 8],
+    [1, 29, 9, 9, 12],
+    [1, 13, 5, 40, 1],
+    [1, 13, 5, 40, 1],
+    [4, 6, 13, 3, 10, 6, 12, 5, 1],
+    [5, 6, 11, 3, 11, 6, 14, 3, 1],
+    [5, 6, 11, 3, 11, 6, 15, 2, 1],
+    [6, 6, 9, 3, 12, 6, 16, 1, 1],
+    [6, 6, 9, 3, 12, 6, 7, 1, 10],
+    [7, 6, 7, 3, 13, 6, 6, 2, 10],
+    [7, 6, 7, 3, 13, 14, 10],
+    [8, 6, 5, 3, 14, 6, 6, 2, 10],
+    [8, 6, 5, 3, 14, 6, 7, 1, 10],
+    [9, 6, 3, 3, 15, 6, 16, 1, 1],
+    [9, 6, 3, 3, 15, 6, 15, 2, 1],
+    [10, 6, 1, 3, 16, 6, 14, 3, 1],
+    [10, 10, 16, 6, 12, 5, 1],
+    [11, 8, 13, 27, 1],
+    [11, 8, 13, 27, 1],
+    [
+        60,
+    ],
+]
+
+
+# Assume that the total length of the first element
+# is the line length used by every row
+ROW_LEN = sum(DATA[0])
+
+# Display intro text
+print("\n                  Love")
+print("Creative Computing  Morristown, New Jersey")
+print("\n\n")
+print("A tribute to the great American artist, Robert Indiana.")
+print("His great work will be reproduced with a message of")
+print("your choice up to 60 characters.  If you can't think of")
+print("a message, simple type the word 'love'\n")  # (sic)
+
+# Get message from user
+message = input("Your message, please? ")
+if message == "":
+    message = "LOVE"
+
+# Repeat the message until we get at least one line's worth
+while len(message) < ROW_LEN:
+    message += message
+
+# Display image
+print("\n" * 9)
+for row in DATA:
+    print_message = True
+    position = 0
+    line_text = ""
+    for length in row:
+        if print_message:
+            text = message[position : (position + length)]
+            print_message = False
+        else:
+            text = " " * length
+            print_message = True
+        line_text += text
+        position += length
+    print(line_text)
+
+print("")
+
+
+######################################################################
+#
+# Porting Notes
+#
+#   Not too different from the original, logic-wise. The image was
+#   originally encoded as a series of BASIC "DATA" lines. Here,
+#   we've converted it to a more Pythonic nested list structure.
+#   Other changes include reducing some of the vertical spacing
+#   (since we'll probably be showing this on a screen rather than
+#   the sort of tractor-feed printer the program was written for)
+#   and having the message default to LOVE when no input is given.
+#
+#   This program uses a simple version of run-length encoding to
+#   compress a 60 x 36 image (2,160 characters) into just 252 DATA
+#   values.  That's about an 8.5-to-1 data compression ratio,
+#   which is pretty good!
+#
+#
+# Ideas for Modifications
+#
+#   Process the user's message input to remove spaces and change
+#   to uppercase.
+#
+#   Encode other images in a similar fashion and let the user choose
+#   which one they'd like to use to display their message.
+#
+#   To help with the above step, create a program that reads in a
+#   text file of any sort of similar character/space art and produces
+#   the Python code to initialize the correct nested list of values.
+#
+#   For example, if the input file were:
+#
+#     *****
+#     *  **
+#     **  *
+#
+#   Your program would output:
+#
+#    ((5, ), (1, 1, 2), (2, 1, 1))
+#
+######################################################################
diff --git a/00_Alternate_Languages/58_Love/ruby/README.md b/00_Alternate_Languages/58_Love/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/58_Love/ruby/love.rb b/00_Alternate_Languages/58_Love/ruby/love.rb
new file mode 100644
index 00000000..3717a14b
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/ruby/love.rb
@@ -0,0 +1,43 @@
+data = [60, 1, 12, 26, 9, 12, 3, 8, 24, 17, 8, 4, 6, 23, 21, 6, 4, 6, 22, 12, 5, 6, 5,
+        4, 6, 21, 11, 8, 6, 4, 4, 6, 21, 10, 10, 5, 4, 4, 6, 21, 9, 11, 5, 4, 4, 6, 21,
+        8, 11, 6, 4, 4, 6, 21, 7, 11, 7, 4, 4, 6, 21, 6, 11, 8, 4, 4, 6, 19, 1, 1, 5,
+        11, 9, 4, 4, 6, 19, 1, 1, 5, 10, 10, 4, 4, 6, 18, 2, 1, 6, 8, 11, 4, 4, 6, 17,
+        3, 1, 7, 5, 13, 4, 4, 6, 15, 5, 2, 23, 5, 1, 29, 5, 17, 8, 1, 29, 9, 9, 12, 1,
+        13, 5, 40, 1, 1, 13, 5, 40, 1, 4, 6, 13, 3, 10, 6, 12, 5, 1, 5, 6, 11, 3, 11,
+        6, 14, 3, 1, 5, 6, 11, 3, 11, 6, 15, 2, 1, 6, 6, 9, 3, 12, 6, 16, 1, 1, 6, 6,
+        9, 3, 12, 6, 7, 1, 10, 7, 6, 7, 3, 13, 6, 6, 2, 10, 7, 6, 7, 3, 13, 14, 10, 8,
+        6, 5, 3, 14, 6, 6, 2, 10, 8, 6, 5, 3, 14, 6, 7, 1, 10, 9, 6, 3, 3, 15, 6, 16, 1,
+        1, 9, 6, 3, 3, 15, 6, 15, 2, 1, 10, 6, 1, 3, 16, 6, 14, 3, 1, 10, 10, 16, 6, 12,
+        5, 1, 11, 8, 13, 27, 1, 11, 8, 13, 27, 1, 60]
+
+puts 'LOVE'.center(60)
+puts 'stephan.com'.center(60)
+puts "\n\n"
+
+puts <<~EOLOVE
+  A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.
+  HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF
+  YOUR CHOICE UP TO 60 CHARACTERS.  IF YOU CAN'T THINK OF
+  A MESSAGE, SIMPLY TYPE THE WORD 'LOVE'\n
+EOLOVE
+
+message = gets.strip
+message = 'love' if message.empty?
+l = message.length
+
+until data.empty?
+  puts
+  col = 0
+  p = true
+  while col < 60
+    run = data.shift
+
+    if p
+      run.times { |i| print message[(col + i) % l] }
+    else
+      print ' ' * run
+    end
+    p = !p
+    col += run
+  end
+end
diff --git a/00_Alternate_Languages/58_Love/vbnet/Love.sln b/00_Alternate_Languages/58_Love/vbnet/Love.sln
new file mode 100644
index 00000000..44ae6e7f
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/vbnet/Love.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Love", "Love.vbproj", "{440AD3C3-D842-4717-BB4D-C54463F59ECA}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{440AD3C3-D842-4717-BB4D-C54463F59ECA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{440AD3C3-D842-4717-BB4D-C54463F59ECA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{440AD3C3-D842-4717-BB4D-C54463F59ECA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{440AD3C3-D842-4717-BB4D-C54463F59ECA}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/58_Love/vbnet/Love.vbproj b/00_Alternate_Languages/58_Love/vbnet/Love.vbproj
new file mode 100644
index 00000000..444df2a3
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/vbnet/Love.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Love
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/58_Love/vbnet/README.md b/00_Alternate_Languages/58_Love/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/58_Love/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/csharp/LunarLEMRocket.csproj b/00_Alternate_Languages/59_Lunar_LEM_Rocket/csharp/LunarLEMRocket.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/csharp/LunarLEMRocket.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/csharp/LunarLEMRocket.sln b/00_Alternate_Languages/59_Lunar_LEM_Rocket/csharp/LunarLEMRocket.sln
new file mode 100644
index 00000000..4f74244d
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/csharp/LunarLEMRocket.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LunarLEMRocket", "LunarLEMRocket.csproj", "{12D3D8F6-5468-49BD-BDD6-E9B4D5954496}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{12D3D8F6-5468-49BD-BDD6-E9B4D5954496}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{12D3D8F6-5468-49BD-BDD6-E9B4D5954496}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{12D3D8F6-5468-49BD-BDD6-E9B4D5954496}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{12D3D8F6-5468-49BD-BDD6-E9B4D5954496}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/csharp/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/java/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lem.html b/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lem.html
new file mode 100644
index 00000000..717ae005
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lem.html
@@ -0,0 +1,9 @@
+
+
+LEM
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lem.js b/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lem.js
new file mode 100644
index 00000000..68bab1cf
--- /dev/null
+++ b/00_Alternate_Languages/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 APPROPRIATE NUMBER");
+        }
+        while (1) {
+            k = parseInt(await input());
+            if (k == 0 || k == 1)
+                break;
+            print("ENTER THE APPROPRIATE 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/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lunar.html b/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lunar.html
new file mode 100644
index 00000000..cdcabc2d
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lunar.html
@@ -0,0 +1,9 @@
+
+
+LUNAR
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lunar.js b/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lunar.js
new file mode 100644
index 00000000..69306aa2
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/javascript/lunar.js
@@ -0,0 +1,191 @@
+// LUNAR
+//
+// 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 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()
+{
+    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(33) + "LUNAR\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    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) {
+        print("\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(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) {
+                if (m - n < 1e-3)
+                    break;
+                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 (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;
+            }
+        }
+        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("SORRY THERE WERE NO SURVIVORS. YOU BLEW IT!\n");
+            print("IN FACT, YOU BLASTED A NEW LUNAR CRATER " + (w * 0.227) + " FEET DEEP!\n");
+        }
+        print("\n");
+        print("\n");
+        print("\n");
+        print("TRY AGAIN??\n");
+    }
+}
+
+main();
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/lem.bas b/00_Alternate_Languages/59_Lunar_LEM_Rocket/lem.bas
new file mode 100644
index 00000000..eece9cc1
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/lem.bas
@@ -0,0 +1,246 @@
+2 PRINT TAB(34);"LEM"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+7 REM ROCKT2 IS AN INTERACTIVE GAME THAT SIMULATES A LUNAR
+8 REM LANDING IS SIMILAR TO THAT OF THE APOLLO PROGRAM.
+9 REM THERE IS ABSOLUTELY NO CHANCE INVOLVED
+10 Z$="GO"
+15 B1=1
+20 M=17.95
+25 F1=5.25
+30 N=7.5
+35 R0=926
+40 V0=1.29
+45 T=0
+50 H0=60
+55 R=R0+H0
+60 A=-3.425
+65 R1=0
+70 A1=8.84361E-04
+75 R3=0
+80 A3=0
+85 M1=7.45
+90 M0=M1
+95 B=750
+100 T1=0
+105 F=0
+110 P=0
+115 N=1
+120 M2=0
+125 S=0
+130 C=0
+135 IF Z$="YES" THEN 1150
+140 PRINT
+145 PRINT "LUNAR LANDING SIMULATION"
+150 PRINT
+155 PRINT "HAVE YOU FLOWN AN APOLLO/LEM MISSION BEFORE";
+160 PRINT " (YES OR NO)";
+165 INPUT Q$
+170 IF Q$="YES" THEN 190
+175 IF Q$="NO" THEN 205
+180 PRINT "JUST ANSWER THE QUESTION, PLEASE, ";
+185 GOTO 160
+190 PRINT
+195 PRINT "INPUT MEASUREMENT OPTION NUMBER";
+200 GOTO 225
+205 PRINT
+210 PRINT "WHICH SYSTEM OF MEASUREMENT DO YOU PREFER?"
+215 PRINT " 1=METRIC     0=ENGLISH"
+220 PRINT "ENTER THE APPROPRIATE NUMBER";
+225 INPUT K
+230 PRINT
+235 IF K=0 THEN 280
+240 IF K=1 THEN 250
+245 GOTO 220
+250 Z=1852.8
+255 M$="METERS"
+260 G3=3.6
+265 N$=" KILOMETERS"
+270 G5=1000
+275 GOTO 305
+280 Z=6080
+285 M$="FEET"
+290 G3=.592
+295 N$="N.MILES"
+300 G5=Z
+305 IF B1=3 THEN 670
+310 IF Q$="YES" THEN 485
+315 PRINT
+320 PRINT "  YOU ARE ON A LUNAR LANDING MISSION.  AS THE PILOT OF"
+325 PRINT "THE LUNAR EXCURSION MODULE, YOU WILL BE EXPECTED TO"
+330 PRINT "GIVE CERTAIN COMMANDS TO THE MODULE NAVIGATION SYSTEM."
+335 PRINT "THE ON-BOARD COMPUTER WILL GIVE A RUNNING ACCOUNT"
+340 PRINT "OF INFORMATION NEEDED TO NAVIGATE THE SHIP."
+345 PRINT
+350 PRINT
+355 PRINT "THE ATTITUDE ANGLE CALLED FOR IS DESCRIBED AS FOLLOWS."
+360 PRINT "+ OR -180 DEGREES IS DIRECTLY AWAY FROM THE MOON"
+365 PRINT "-90 DEGREES IS ON A TANGENT IN THE DIRECTION OF ORBIT"
+370 PRINT "+90 DEGREES IS ON A TANGENT FROM THE DIRECTION OF ORBIT"
+375 PRINT "0 (ZERO) DEGREES IS DIRECTLY TOWARD THE MOON"
+380 PRINT
+385 PRINT TAB(30);"-180|+180"
+390 PRINT TAB(34);"^"
+395 PRINT TAB(27);"-90 < -+- > +90"
+400 PRINT TAB(34);"!"
+405 PRINT TAB(34);"0"
+410 PRINT TAB(21);"<<<< DIRECTION OF ORBIT <<<<"
+415 PRINT
+420 PRINT TAB(20);"------ SURFACE OF MOON ------"
+425 PRINT
+430 PRINT
+435 PRINT "ALL ANGLES BETWEEN -180 AND +180 DEGREES ARE ACCEPTED."
+440 PRINT
+445 PRINT "1 FUEL UNIT = 1 SEC. AT MAX THRUST"
+450 PRINT "ANY DISCREPANCIES ARE ACCOUNTED FOR IN THE USE OF FUEL"
+455 PRINT "FOR AN ATTITUDE CHANGE."
+460 PRINT "AVAILABLE ENGINE POWER: 0 (ZERO) AND ANY VALUE BETWEEN"
+465 PRINT "10 AND 100 PERCENT."
+470 PRINT
+475 PRINT"NEGATIVE THRUST OR TIME IS PROHIBITED."
+480 PRINT
+485 PRINT
+490 PRINT "INPUT: TIME INTERVAL IN SECONDS ------ (T)"
+495 PRINT "       PERCENTAGE OF THRUST ---------- (P)"
+500 PRINT "       ATTITUDE ANGLE IN DEGREES ----- (A)"
+505 PRINT
+510 IF Q$="YES" THEN 535
+515 PRINT "FOR EXAMPLE:"
+520 PRINT "T,P,A? 10,65,-60"
+525 PRINT "TO ABORT THE MISSION AT ANY TIME, ENTER 0,0,0"
+530 PRINT
+535 PRINT "OUTPUT: TOTAL TIME IN ELAPSED SECONDS"
+540 PRINT "        HEIGHT IN ";M$
+545 PRINT "        DISTANCE FROM LANDING SITE IN ";M$
+550 PRINT "        VERTICAL VELOCITY IN ";M$;"/SECOND"
+555 PRINT "        HORIZONTAL VELOCITY IN ";M$;"/SECOND"
+560 PRINT "        FUEL UNITS REMAINING"
+565 PRINT
+570 GOTO 670
+575 PRINT
+580 PRINT "T,P,A";
+585 INPUT T1,F,P
+590 F=F/100
+595 IF T1<0 THEN 905
+600 IF T1=0 THEN 1090
+605 IF ABS(F-.05)>1 THEN 945
+610 IF ABS(F-.05)<.05 THEN 945
+615 IF ABS(P)>180 THEN 925
+620 N=20
+625 IF T1<400 THEN 635
+630 N=T1/20
+635 T1=T1/N
+640 P=P*3.14159/180
+645 S=SIN(P)
+650 C=COS(P)
+655 M2=M0*T1*F/B
+660 R3=-.5*R0*((V0/R)^2)+R*A1*A1
+665 A3=-2*R1*A1/R
+670 FOR I=1 TO N
+675 IF M1=0 THEN 715
+680 M1=M1-M2
+685 IF M1>0 THEN 725
+690 F=F*(1+M1/M2)
+695 M2=M1+M2
+700 PRINT "YOU ARE OUT OF FUEL."
+705 M1=0
+710 GOTO 725
+715 F=0
+720 M2=0
+725 M=M-.5*M2
+730 R4=R3
+735 R3=-.5*R0*((V0/R)^2)+R*A1*A1
+740 R2=(3*R3-R4)/2+.00526*F1*F*C/M
+745 A4=A3
+750 A3=-2*R1*A1/R
+755 A2=(3*A3-A4)/2+.0056*F1*F*S/(M*R)
+760 X=R1*T1+.5*R2*T1*T1
+765 R=R+X
+770 H0=H0+X
+775 R1=R1+R2*T1
+780 A=A+A1*T1+.5*A2*T1*T1
+785 A1=A1+A2*T1
+790 M=M-.5*M2
+795 T=T+T1
+800 IF H0<3.287828E-04 THEN 810
+805 NEXT I
+810 H=H0*Z
+815 H1=R1*Z
+820 D=R0*A*Z
+825 D1=R*A1*Z
+830 T2=M1*B/M0
+835 PRINT " ";T;TAB(10);H;TAB(23);D;
+840 PRINT TAB(37);H1;TAB(49);D1;TAB(60);T2
+845 IF H0<3.287828E-04 THEN 880
+850 IF R0*A>164.474 THEN 1050
+855 IF M1>0 THEN 580
+860 T1=20
+865 F=0
+870 P=0
+875 GOTO 620
+880 IF R1<-8.21957E-04 THEN 1020
+885 IF ABS(R*A1)>4.93174E-04 THEN 1020
+890 IF H0<-3.287828E-04 THEN 1020
+895 IF ABS(D)>10*Z THEN 1065
+900 GOTO 995
+905 PRINT
+910 PRINT "THIS SPACECRAFT IS NOT ABLE TO VIOLATE THE SPACE-";
+915 PRINT "TIME CONTINUUM."
+920 GOTO 575
+925 PRINT
+930 PRINT "IF YOU WANT TO SPIN AROUND, GO OUTSIDE THE MODULE"
+935 PRINT "FOR AN E.V.A."
+940 GOTO 575
+945 PRINT
+950 PRINT "IMPOSSIBLE THRUST VALUE ";
+955 IF F<0 THEN 985
+960 IF F-.05<.05 THEN 975
+965 PRINT "TOO LARGE"
+970 GOTO 575
+975 PRINT "TOO SMALL"
+980 GOTO 575
+985 PRINT "NEGATIVE"
+990 GOTO 575
+995 PRINT
+1000 PRINT "TRANQUILITY BASE HERE -- THE EAGLE HAS LANDED."
+1005 PRINT "CONGRATULATIONS -- THERE WAS NO SPACECRAFT DAMAGE."
+1010 PRINT "YOU MAY NOW PROCEED WITH SURFACE EXPLORATION."
+1015 GOTO 1100
+1020 PRINT
+1025 PRINT "CRASH !!!!!!!!!!!!!!!!"
+1030 PRINT "YOUR IMPACT CREATED A CRATER";ABS(H);M$;" DEEP."
+1035 X1=SQR(D1*D1+H1*H1)*G3
+1040 PRINT "AT CONTACT YOU WERE TRAVELING";X1;N$;"/HR"
+1045 GOTO 1100
+1050 PRINT
+1055 PRINT "YOU HAVE BEEN LOST IN SPACE WITH NO HOPE OF RECOVERY."
+1060 GOTO 1100
+1065 PRINT "YOU ARE DOWN SAFELY - "
+1075 PRINT
+1080 PRINT "BUT MISSED THE LANDING SITE BY";ABS(D/G5);N$;"."
+1085 GOTO 1100
+1090 PRINT
+1095 PRINT "MISSION ABENDED"
+1100 PRINT
+1105 PRINT "DO YOU WANT TO TRY IT AGAIN (YES/NO)?"
+1110 INPUT Z$
+1115 IF Z$="YES" THEN 20
+1120 IF Z$="NO" THEN 1130
+1125 GOTO 1105
+1130 PRINT
+1135 PRINT "TOO BAD, THE SPACE PROGRAM HATES TO LOSE EXPERIENCED"
+1140 PRINT "ASTRONAUTS."
+1145 STOP
+1150 PRINT
+1155 PRINT "OK, DO YOU WANT THE COMPLETE INSTRUCTIONS OR THE INPUT -"
+1160 PRINT "OUTPUT STATEMENTS?"
+1165 PRINT "1=COMPLETE INSTRUCTIONS"
+1170 PRINT "2=INPUT-OUTPUT STATEMENTS"
+1175 PRINT "3=NEITHER"
+1180 INPUT B1
+1185 Q$="NO"
+1190 IF B1=1 THEN 205
+1195 Q$="YES"
+1200 IF B1=2 THEN 190
+1205 IF B1=3 THEN 190
+1210 GOTO 1165
+1215 END
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/lunar.bas b/00_Alternate_Languages/59_Lunar_LEM_Rocket/lunar.bas
new file mode 100644
index 00000000..b1203718
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/lunar.bas
@@ -0,0 +1,48 @@
+10 PRINT TAB(33);"LUNAR"
+20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
+25 PRINT:PRINT:PRINT
+30 PRINT "THIS IS A COMPUTER SIMULATION OF AN APOLLO LUNAR"
+40 PRINT "LANDING CAPSULE.": PRINT: PRINT
+50 PRINT "THE ON-BOARD COMPUTER HAS FAILED (IT WAS MADE BY"
+60 PRINT "XEROX) SO YOU HAVE TO LAND THE CAPSULE MANUALLY."
+70 PRINT: PRINT "SET BURN RATE OF RETRO ROCKETS TO ANY VALUE BETWEEN"
+80 PRINT "0 (FREE FALL) AND 200 (MAXIMUM BURN) POUNDS PER SECOND."
+90 PRINT "SET NEW BURN RATE EVERY 10 SECONDS.": PRINT
+100 PRINT "CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,500 LBS."
+110 PRINT: PRINT: PRINT: PRINT "GOOD LUCK"
+120 L=0
+130 PRINT: PRINT "SEC","MI + FT","MPH","LB FUEL","BURN RATE":PRINT
+140 A=120:V=1:M=33000:N=16500:G=1E-03:Z=1.8
+150 PRINT L,INT(A);INT(5280*(A-INT(A))),3600*V,M-N,:INPUT K:T=10
+160 IF M-N<1E-03 THEN 240
+170 IF T<1E-03 THEN 150
+180 S=T: IF M>=N+S*K THEN 200
+190 S=(M-N)/K
+200 GOSUB 420: IF I<=0 THEN 340
+210 IF V<=0 THEN 230
+220 IF J<0 THEN 370
+230 GOSUB 330: GOTO 160
+240 PRINT "FUEL OUT AT";L;"SECONDS":S=(-V+SQR(V*V+2*A*G))/G
+250 V=V+G*S: L=L+S
+260 W=3600*V: PRINT "ON MOON AT";L;"SECONDS - IMPACT VELOCITY";W;"MPH"
+274 IF W<=1.2 THEN PRINT "PERFECT LANDING!": GOTO 440
+280 IF W<=10 THEN PRINT "GOOD LANDING (COULD BE BETTER)":GOTO 440
+282 IF W>60 THEN 300
+284 PRINT "CRAFT DAMAGE... YOU'RE STRANDED HERE UNTIL A RESCUE"
+286 PRINT "PARTY ARRIVES. HOPE YOU HAVE ENOUGH OXYGEN!"
+288 GOTO 440
+300 PRINT "SORRY THERE WERE NO SURVIVORS. YOU BLEW IT!"
+310 PRINT "IN FACT, YOU BLASTED A NEW LUNAR CRATER";W*.227;"FEET DEEP!"
+320 GOTO 440
+330 L=L+S: T=T-S: M=M-S*K: A=I: V=J: RETURN
+340 IF S<5E-03 THEN 260
+350 D=V+SQR(V*V+2*A*(G-Z*K/M)):S=2*A/D
+360 GOSUB 420: GOSUB 330: GOTO 340
+370 W=(1-M*G/(Z*K))/2: S=M*V/(Z*K*(W+SQR(W*W+V/Z)))+.05:GOSUB 420
+380 IF I<=0 THEN 340
+390 GOSUB 330: IF J>0 THEN 160
+400 IF V>0 THEN 370
+410 GOTO 160
+420 Q=S*K/M: J=V+G*S+Z*(-Q-Q*Q/2-Q^3/3-Q^4/4-Q^5/5)
+430 I=A-G*S*S/2-V*S+Z*S*(Q/2+Q^2/6+Q^3/12+Q^4/20+Q^5/30):RETURN
+440 PRINT:PRINT:PRINT:PRINT "TRY AGAIN??": GOTO 70
diff --git a/35_Even_Wins/pascal/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/pascal/README.md
similarity index 100%
rename from 35_Even_Wins/pascal/README.md
rename to 00_Alternate_Languages/59_Lunar_LEM_Rocket/pascal/README.md
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/perl/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/python/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/python/lunar.py b/00_Alternate_Languages/59_Lunar_LEM_Rocket/python/lunar.py
new file mode 100644
index 00000000..bbbaf69a
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/python/lunar.py
@@ -0,0 +1,358 @@
+"""
+LUNAR
+
+Lunar landing simulation
+
+Ported by Dave LeCompte
+"""
+
+import collections
+import math
+
+PAGE_WIDTH = 64
+
+COLUMN_WIDTH = 2
+SECONDS_WIDTH = 4
+MPH_WIDTH = 6
+ALT_MI_WIDTH = 6
+ALT_FT_WIDTH = 4
+MPH_WIDTH = 6
+FUEL_WIDTH = 8
+BURN_WIDTH = 10
+
+SECONDS_LEFT = 0
+SECONDS_RIGHT = SECONDS_LEFT + SECONDS_WIDTH
+ALT_LEFT = SECONDS_RIGHT + COLUMN_WIDTH
+ALT_MI_RIGHT = ALT_LEFT + ALT_MI_WIDTH
+ALT_FT_RIGHT = ALT_MI_RIGHT + COLUMN_WIDTH + ALT_FT_WIDTH
+MPH_LEFT = ALT_FT_RIGHT + COLUMN_WIDTH
+MPH_RIGHT = MPH_LEFT + MPH_WIDTH
+FUEL_LEFT = MPH_RIGHT + COLUMN_WIDTH
+FUEL_RIGHT = FUEL_LEFT + FUEL_WIDTH
+BURN_LEFT = FUEL_RIGHT + COLUMN_WIDTH
+BURN_RIGHT = BURN_LEFT + BURN_WIDTH
+
+PhysicalState = collections.namedtuple("PhysicalState", ["velocity", "altitude"])
+
+
+def print_centered(msg):
+    spaces = " " * ((PAGE_WIDTH - len(msg)) // 2)
+    print(spaces + msg)
+
+
+def print_header(title):
+    print_centered(title)
+    print_centered("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+
+def add_rjust(line, s, pos):
+    # adds a new field to a line right justified to end at pos
+
+    s = str(s)
+    slen = len(s)
+    if len(line) + slen > pos:
+        new_len = pos - slen
+        line = line[:new_len]
+    if len(line) + slen < pos:
+        spaces = " " * (pos - slen - len(line))
+        line = line + spaces
+    return line + s
+
+
+def add_ljust(line, s, pos):
+    # adds a new field to a line left justified starting at pos
+
+    s = str(s)
+    if len(line) > pos:
+        line = line[:pos]
+    if len(line) < pos:
+        spaces = " " * (pos - len(line))
+        line = line + spaces
+    return line + s
+
+
+def print_instructions():
+    # Somebody had a bad experience with Xerox.
+
+    print("THIS IS A COMPUTER SIMULATION OF AN APOLLO LUNAR")
+    print("LANDING CAPSULE.")
+    print()
+    print()
+    print("THE ON-BOARD COMPUTER HAS FAILED (IT WAS MADE BY")
+    print("XEROX) SO YOU HAVE TO LAND THE CAPSULE MANUALLY.")
+    print()
+
+
+def print_intro():
+    print("SET BURN RATE OF RETRO ROCKETS TO ANY VALUE BETWEEN")
+    print("0 (FREE FALL) AND 200 (MAXIMUM BURN) POUNDS PER SECOND.")
+    print("SET NEW BURN RATE EVERY 10 SECONDS.")
+    print()
+    print("CAPSULE WEIGHT 32,500 LBS; FUEL WEIGHT 16,500 LBS.")
+    print()
+    print()
+    print()
+    print("GOOD LUCK")
+    print()
+
+
+def show_landing(sim_clock, capsule):
+    w = 3600 * capsule.v
+    print(
+        f"ON MOON AT {sim_clock.elapsed_time:.2f} SECONDS - IMPACT VELOCITY {w:.2f} MPH"
+    )
+    if w < 1.2:
+        print("PERFECT LANDING!")
+    elif w < 10:
+        print("GOOD LANDING (COULD BE BETTER)")
+    elif w <= 60:
+        print("CRAFT DAMAGE... YOU'RE STRANDED HERE UNTIL A RESCUE")
+        print("PARTY ARRIVES. HOPE YOU HAVE ENOUGH OXYGEN!")
+    else:
+        print("SORRY THERE WERE NO SURVIVORS. YOU BLEW IT!")
+        print(f"IN FACT, YOU BLASTED A NEW LUNAR CRATER {w*.227:.2f} FEET DEEP!")
+    end_sim()
+
+
+def show_out_of_fuel(sim_clock, capsule):
+    print(f"FUEL OUT AT {sim_clock.elapsed_time} SECONDS")
+    delta_t = (
+        -capsule.v + math.sqrt(capsule.v**2 + 2 * capsule.a * capsule.g)
+    ) / capsule.g
+    capsule.v += capsule.g * delta_t
+    sim_clock.advance(delta_t)
+    show_landing(sim_clock, capsule)
+
+
+def format_line_for_report(t, miles, feet, velocity, fuel, burn_rate, is_header):
+    line = add_rjust("", t, SECONDS_RIGHT)
+    line = add_rjust(line, miles, ALT_MI_RIGHT)
+    line = add_rjust(line, feet, ALT_FT_RIGHT)
+    line = add_rjust(line, velocity, MPH_RIGHT)
+    line = add_rjust(line, fuel, FUEL_RIGHT)
+    if is_header:
+        line = add_rjust(line, burn_rate, BURN_RIGHT)
+    else:
+        line = add_ljust(line, burn_rate, BURN_LEFT)
+    return line
+
+
+class Capsule:
+    def __init__(
+        self,
+        altitude=120,
+        velocity=1,
+        mass_with_fuel=33000,
+        mass_without_fuel=16500,
+        g=1e-3,
+        z=1.8,
+    ):
+        self.a = altitude  # in miles above the surface
+        self.v = velocity  # downward
+        self.m = mass_with_fuel
+        self.n = mass_without_fuel
+        self.g = g
+        self.z = z
+        self.fuel_per_second = 0
+
+    def remaining_fuel(self):
+        return self.m - self.n
+
+    def is_out_of_fuel(self):
+        return self.remaining_fuel() < 1e-3
+
+    def update_state(self, sim_clock, delta_t, new_state):
+        sim_clock.advance(delta_t)
+        self.m = self.m - delta_t * self.fuel_per_second
+        self.a = new_state.altitude
+        self.v = new_state.velocity
+
+    def fuel_time_remaining(self):
+        # extrapolates out how many seconds we have at the current fuel burn rate
+        assert self.fuel_per_second > 0
+        return self.remaining_fuel() / self.fuel_per_second
+
+    def predict_motion(self, delta_t):
+        # Perform an Euler's Method numerical integration of the equations of motion.
+
+        q = delta_t * self.fuel_per_second / self.m
+
+        # new velocity
+        new_velocity = (
+            self.v
+            + self.g * delta_t
+            + self.z * (-q - q**2 / 2 - q**3 / 3 - q**4 / 4 - q**5 / 5)
+        )
+
+        # new altitude
+        new_altitude = (
+            self.a
+            - self.g * delta_t**2 / 2
+            - self.v * delta_t
+            + self.z
+            * delta_t
+            * (q / 2 + q**2 / 6 + q**3 / 12 + q**4 / 20 + q**5 / 30)
+        )
+
+        return PhysicalState(altitude=new_altitude, velocity=new_velocity)
+
+    def make_state_display_string(self, sim_clock):
+        seconds = sim_clock.elapsed_time
+        miles = int(self.a)
+        feet = int(5280 * (self.a - miles))
+        velocity = int(3600 * self.v)
+        fuel = int(self.remaining_fuel())
+        burn_rate = " ? "
+
+        return format_line_for_report(
+            seconds, miles, feet, velocity, fuel, burn_rate, False
+        )
+
+    def prompt_for_burn(self, sim_clock):
+        msg = self.make_state_display_string(sim_clock)
+
+        self.fuel_per_second = float(input(msg))
+        sim_clock.time_until_next_prompt = 10
+
+
+class SimulationClock:
+    def __init__(self, elapsed_time, time_until_next_prompt):
+        self.elapsed_time = elapsed_time
+        self.time_until_next_prompt = time_until_next_prompt
+
+    def time_for_prompt(self):
+        return self.time_until_next_prompt < 1e-3
+
+    def advance(self, delta_t):
+        self.elapsed_time += delta_t
+        self.time_until_next_prompt -= delta_t
+
+
+def process_final_tick(delta_t, sim_clock, capsule):
+    # When we extrapolated our position based on our velocity
+    # and delta_t, we overshot the surface. For better
+    # accuracy, we will back up and do shorter time advances.
+
+    while True:
+        if delta_t < 5e-3:
+            show_landing(sim_clock, capsule)
+            return
+        # line 35
+        average_vel = (
+            capsule.v
+            + math.sqrt(
+                capsule.v**2
+                + 2
+                * capsule.a
+                * (capsule.g - capsule.z * capsule.fuel_per_second / capsule.m)
+            )
+        ) / 2
+        delta_t = capsule.a / average_vel
+        new_state = capsule.predict_motion(delta_t)
+        capsule.update_state(sim_clock, delta_t, new_state)
+
+
+def handle_flyaway(sim_clock, capsule):
+    """
+    The user has started flying away from the moon. Since this is a
+    lunar LANDING simulation, we wait until the capsule's velocity is
+    positive (downward) before prompting for more input.
+
+    Returns True if landed, False if simulation should continue.
+    """
+
+    while True:
+        w = (1 - capsule.m * capsule.g / (capsule.z * capsule.fuel_per_second)) / 2
+        delta_t = (
+            capsule.m
+            * capsule.v
+            / (
+                capsule.z
+                * capsule.fuel_per_second
+                * math.sqrt(w**2 + capsule.v / capsule.z)
+            )
+        ) + 0.05
+
+        new_state = capsule.predict_motion(delta_t)
+
+        if new_state.altitude <= 0:
+            # have landed
+            return True
+
+        capsule.update_state(sim_clock, delta_t, new_state)
+
+        if (new_state.velocity > 0) or (capsule.v <= 0):
+            # return to normal sim
+            return False
+
+
+def end_sim():
+    print()
+    print()
+    print()
+    print("TRY AGAIN??")
+    print()
+    print()
+    print()
+
+
+def run_simulation():
+    print()
+    print(
+        format_line_for_report("SEC", "MI", "FT", "MPH", "LB FUEL", "BURN RATE", True)
+    )
+
+    sim_clock = SimulationClock(0, 10)
+    capsule = Capsule()
+
+    capsule.prompt_for_burn(sim_clock)
+
+    while True:
+        if capsule.is_out_of_fuel():
+            show_out_of_fuel(sim_clock, capsule)
+            return
+
+        if sim_clock.time_for_prompt():
+            capsule.prompt_for_burn(sim_clock)
+            continue
+
+        # clock advance is the shorter of the time to the next prompt,
+        # or when we run out of fuel.
+        if capsule.fuel_per_second > 0:
+            delta_t = min(
+                sim_clock.time_until_next_prompt, capsule.fuel_time_remaining()
+            )
+        else:
+            delta_t = sim_clock.time_until_next_prompt
+
+        new_state = capsule.predict_motion(delta_t)
+
+        if new_state.altitude <= 0:
+            process_final_tick(delta_t, sim_clock, capsule)
+            return
+
+        if capsule.v > 0 and new_state.velocity < 0:
+            # moving away from the moon
+
+            landed = handle_flyaway(sim_clock, capsule)
+            if landed:
+                process_final_tick(delta_t, sim_clock, capsule)
+                return
+
+        else:
+            capsule.update_state(sim_clock, delta_t, new_state)
+
+
+def main():
+    print_header("LUNAR")
+    print_instructions()
+    while True:
+        print_intro()
+        run_simulation()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/rocket.bas b/00_Alternate_Languages/59_Lunar_LEM_Rocket/rocket.bas
new file mode 100644
index 00000000..efcd22fb
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/rocket.bas
@@ -0,0 +1,71 @@
+10 PRINT TAB(30); "ROCKET"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+70 PRINT "LUNAR LANDING SIMULATION"
+80 PRINT "----- ------- ----------": PRINT
+100 INPUT "DO YOU WANT INSTRUCTIONS (YES OR NO)";A$
+110 IF A$="NO" THEN 390
+160 PRINT
+200 PRINT"YOU ARE LANDING ON THE MOON AND AND HAVE TAKEN OVER MANUAL"
+210 PRINT"CONTROL 1000 FEET ABOVE A GOOD LANDING SPOT. YOU HAVE A DOWN-"
+220 PRINT"WARD VELOCITY OF 50 FEET/SEC. 150 UNITS OF FUEL REMAIN."
+225 PRINT
+230 PRINT"HERE ARE THE RULES THAT GOVERN YOUR APOLLO SPACE-CRAFT:": PRINT
+240 PRINT"(1) AFTER EACH SECOND THE HEIGHT, VELOCITY, AND REMAINING FUEL"
+250 PRINT"    WILL BE REPORTED VIA DIGBY YOUR ON-BOARD COMPUTER."
+260 PRINT"(2) AFTER THE REPORT A '?' WILL APPEAR. ENTER THE NUMBER"
+270 PRINT"    OF UNITS OF FUEL YOU WISH TO BURN DURING THE NEXT"
+280 PRINT"    SECOND. EACH UNIT OF FUEL WILL SLOW YOUR DESCENT BY"
+290 PRINT"    1 FOOT/SEC."
+310 PRINT"(3) THE MAXIMUM THRUST OF YOUR ENGINE IS 30 FEET/SEC/SEC"
+320 PRINT"    OR 30 UNITS OF FUEL PER SECOND."
+330 PRINT"(4) WHEN YOU CONTACT THE LUNAR SURFACE. YOUR DESCENT ENGINE"
+340 PRINT"    WILL AUTOMATICALLY SHUT DOWN AND YOU WILL BE GIVEN A"
+350 PRINT"    REPORT OF YOUR LANDING SPEED AND REMAINING FUEL."
+360 PRINT"(5) IF YOU RUN OUT OF FUEL THE '?' WILL NO LONGER APPEAR"
+370 PRINT"    BUT YOUR SECOND BY SECOND REPORT WILL CONTINUE UNTIL"
+380 PRINT"    YOU CONTACT THE LUNAR SURFACE.":PRINT
+390 PRINT"BEGINNING LANDING PROCEDURE..........":PRINT
+400 PRINT"G O O D  L U C K ! ! !"
+420 PRINT:PRINT
+430 PRINT"SEC  FEET      SPEED     FUEL     PLOT OF DISTANCE"
+450 PRINT
+455 T=0:H=1000:V=50:F=150
+490 PRINT T;TAB(6);H;TAB(16);V;TAB(26);F;TAB(35);"I";TAB(H/15);"*"
+500 INPUT B
+510 IF B<0 THEN 650
+520 IF B>30 THEN B=30
+530 IF B>F THEN B=F
+540 V1=V-B+5
+560 F=F-B
+570 H=H- .5*(V+V1)
+580 IF H<=0 THEN 670
+590 T=T+1
+600 V=V1
+610 IF F>0 THEN 490
+615 IF B=0 THEN 640
+620 PRINT"**** OUT OF FUEL ****"
+640 PRINT T;TAB(4);H;TAB(12);V;TAB(20);F;TAB(29);"I";TAB(H/12+29);"*"
+650 B=0
+660 GOTO 540
+670 PRINT"***** CONTACT *****"
+680 H=H+ .5*(V1+V)
+690 IF B=5 THEN 720
+700 D=(-V+SQR(V*V+H*(10-2*B)))/(5-B)
+710 GOTO 730
+720 D=H/V
+730 V1=V+(5-B)*D
+760 PRINT"TOUCHDOWN AT";T+D;"SECONDS."
+770 PRINT"LANDING VELOCITY=";V1;"FEET/SEC."
+780 PRINT F;"UNITS OF FUEL REMAINING."
+790 IF V1<>0 THEN 810
+800 PRINT"CONGRATULATIONS! A PERFECT LANDING!!"
+805 PRINT"YOUR LICENSE WILL BE RENEWED.......LATER."
+810 IF ABS(V1)<2 THEN 840
+820 PRINT"***** SORRY, BUT YOU BLEW IT!!!!"
+830 PRINT"APPROPRIATE CONDOLENCES WILL BE SENT TO YOUR NEXT OF KIN."
+840 PRINT:PRINT:PRINT
+850 INPUT "ANOTHER MISSION";A$
+860 IF A$="YES" THEN 390
+870 PRINT: PRINT "CONTROL OUT.": PRINT
+999 END
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/ruby/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/rust/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/rust/README.md
new file mode 100644
index 00000000..158d6cb1
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/rust/README.md
@@ -0,0 +1,11 @@
+README.md
+
+Original source downloaded from Vintage Basic
+
+This folder for chapter #59 contains three different games.  Three folders here contain the three games:
+
+ - Rocket
+ - LEM
+ - lunar
+
+Conversion to [Rust](https://www.rust-lang.org)
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/rust/rocket/src/main.rs b/00_Alternate_Languages/59_Lunar_LEM_Rocket/rust/rocket/src/main.rs
new file mode 100644
index 00000000..bd4685c6
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/rust/rocket/src/main.rs
@@ -0,0 +1,107 @@
+//Goal of this port is to keep Basic lang idioms where possible. Gotta have those single letter capital variables!
+use num_integer::{sqrt};
+use std::io::{self, Write};
+use text_io::{read, try_read};
+#[allow(non_snake_case)]
+fn main() {
+    println!("{:>30}", "ROCKET");
+    println!("{:>15}", "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+    println!();println!();println!();
+    println!("LUNAR LANDING SIMULATION");
+    println!("----- ------- ----------");println!();
+    let A= input("DO YOU WANT INSTRUCTIONS (YES OR NO) ");
+    if !(A=="NO") {
+        println!();
+        println!("YOU ARE LANDING ON THE MOON AND AND HAVE TAKEN OVER MANUAL");
+        println!("CONTROL 1000 FEET ABOVE A GOOD LANDING SPOT. YOU HAVE A DOWN-");
+        println!("WARD VELOCITY OF 50 FEET/SEC. 150 UNITS OF FUEL REMAIN.");
+        println!();
+        println!("HERE ARE THE RULES THAT GOVERN YOUR APOLLO SPACE-CRAFT:"); println!();
+        println!("(1) AFTER EACH SECOND THE HEIGHT, VELOCITY, AND REMAINING FUEL");
+        println!("    WILL BE REPORTED VIA DIGBY YOUR ON-BOARD COMPUTER.");
+        println!("(2) AFTER THE REPORT A '?' WILL APPEAR. ENTER THE NUMBER");
+        println!("    OF UNITS OF FUEL YOU WISH TO BURN DURING THE NEXT");
+        println!("    SECOND. EACH UNIT OF FUEL WILL SLOW YOUR DESCENT BY");
+        println!("    1 FOOT/SEC.");
+        println!("(3) THE MAXIMUM THRUST OF YOUR ENGINE IS 30 FEET/SEC/SEC");
+        println!("    OR 30 UNITS OF FUEL PER SECOND.");
+        println!("(4) WHEN YOU CONTACT THE LUNAR SURFACE. YOUR DESCENT ENGINE");
+        println!("    WILL AUTOMATICALLY SHUT DOWN AND YOU WILL BE GIVEN A");
+        println!("    REPORT OF YOUR LANDING SPEED AND REMAINING FUEL.");
+        println!("(5) IF YOU RUN OUT OF FUEL THE '?' WILL NO LONGER APPEAR");
+        println!("    BUT YOUR SECOND BY SECOND REPORT WILL CONTINUE UNTIL");
+        println!("    YOU CONTACT THE LUNAR SURFACE.");println!();
+    }
+    loop {
+        println!("BEGINNING LANDING PROCEDURE..........");println!();
+        println!("G O O D  L U C K ! ! !");
+        println!();println!();
+        println!("SEC  FEET      SPEED     FUEL     PLOT OF DISTANCE");
+        println!();
+        let mut T=0;let mut H:i32=1000;let mut V=50;let mut F=150;
+        let D:i32; let mut V1:i32; let mut B:i32;
+        'falling: loop {
+            println!(" {:<4}{:<11}{:<10}{:<8}I{capsule:>high$}", T,H,V,F,high=(H/15) as usize,capsule="*");
+            B = input_int("");
+            if B<0 { B=0 }
+            else { if B>30 { B=30 } }
+            if B>F { B=F }
+            'nofuel: loop {
+                V1=V-B+5;
+                F=F-B;
+                H=H- (V+V1)/2;
+                if  H<=0 { break 'falling}
+                T=T+1;
+                V=V1;
+                if F>0 { break 'nofuel }
+                if B!=0 {
+                    println!("**** OUT OF FUEL ****");
+                }
+                println!(" {:<4}{:<11}{:<10}{:<8}I{capsule:>high$}", T,H,V,F,high=(H/12+29) as usize,capsule="*");
+                B=0;
+            }
+        }
+        H=H+ (V1+V)/2;
+        if B==5 {
+            D=H/V;
+        } else {
+            D=(-V+sqrt(V*V+H*(10-2*B)))/(5-B);
+            V1=V+(5-B)*D;
+        }
+        println!("***** CONTACT *****");
+        println!("TOUCHDOWN AT {} SECONDS.",T+D);
+        println!("LANDING VELOCITY={} FEET/SEC.",V1);
+        println!("{} UNITS OF FUEL REMAINING.", F);
+        if V1==0 {
+            println!("CONGRATULATIONS! A PERFECT LANDING!!");
+            println!("YOUR LICENSE WILL BE RENEWED.......LATER.");
+        }
+        if V1.abs()>=2 {
+            println!("***** SORRY, BUT YOU BLEW IT!!!!");
+            println!("APPROPRIATE CONDOLENCES WILL BE SENT TO YOUR NEXT OF KIN.");
+        }
+        println!();println!();println!();
+        let A = input("ANOTHER MISSION");
+        if !(A=="YES") { break };
+    }
+    println!();println!( "CONTROL OUT.");println!();
+}
+
+
+fn input(prompt:&str) -> String {
+    loop {
+        print!("{} ? ",prompt);io::stdout().flush().unwrap();
+        let innn:String=read!("{}\n");
+        let out:String = innn.trim().to_string();
+        if out!="" {return out}
+    }
+}
+fn input_int(prompt:&str) -> i32 {
+    loop {
+        print!("{} ? ",prompt);io::stdout().flush().unwrap();
+        match try_read!() {
+            Ok(n) => return n,
+            Err(_) => println!("Enter a number 0-30"),
+        }
+    }
+}
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/vbnet/LunarLEMRocket.sln b/00_Alternate_Languages/59_Lunar_LEM_Rocket/vbnet/LunarLEMRocket.sln
new file mode 100644
index 00000000..a77348e6
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/vbnet/LunarLEMRocket.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "LunarLEMRocket", "LunarLEMRocket.vbproj", "{6145C5DF-CFFB-42B8-9025-913D9D4A8B10}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6145C5DF-CFFB-42B8-9025-913D9D4A8B10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6145C5DF-CFFB-42B8-9025-913D9D4A8B10}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6145C5DF-CFFB-42B8-9025-913D9D4A8B10}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6145C5DF-CFFB-42B8-9025-913D9D4A8B10}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/vbnet/LunarLEMRocket.vbproj b/00_Alternate_Languages/59_Lunar_LEM_Rocket/vbnet/LunarLEMRocket.vbproj
new file mode 100644
index 00000000..553bdcd5
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/vbnet/LunarLEMRocket.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    LunarLEMRocket
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/59_Lunar_LEM_Rocket/vbnet/README.md b/00_Alternate_Languages/59_Lunar_LEM_Rocket/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/59_Lunar_LEM_Rocket/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/60_Mastermind/README.md b/00_Alternate_Languages/60_Mastermind/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/Code.cs b/00_Alternate_Languages/60_Mastermind/csharp/Code.cs
new file mode 100644
index 00000000..f8189c48
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/Code.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Game
+{
+    /// 
+    /// Represents a secret code in the game.
+    /// 
+    public class Code
+    {
+        private readonly int[] m_colors;
+
+        /// 
+        /// Initializes a new instance of the Code class from the given set
+        /// of positions.
+        /// 
+        /// 
+        /// Contains the color for each position.
+        /// 
+        public Code(IEnumerable colors)
+        {
+            m_colors = colors.ToArray();
+            if (m_colors.Length == 0)
+                throw new ArgumentException("A code must contain at least one position");
+        }
+
+        /// 
+        /// Compares this code with the given code.
+        /// 
+        /// 
+        /// The code to compare.
+        /// 
+        /// 
+        /// A number of black pegs and a number of white pegs.  The number
+        /// of black pegs is the number of positions that contain the same
+        /// color in both codes.  The number of white pegs is the number of
+        /// colors that appear in both codes, but in the wrong positions.
+        /// 
+        public (int blacks, int whites) Compare(Code other)
+        {
+            // What follows is the O(N^2) from the original BASIC program
+            // (where N is the number of positions in the code).  Note that
+            // there is an O(N) algorithm.  (Finding it is left as an
+            // exercise for the reader.)
+            if (other.m_colors.Length != m_colors.Length)
+                throw new ArgumentException("Only codes of the same length can be compared");
+
+            // Keeps track of which positions in the other code have already
+            // been marked as exact or close matches.
+            var consumed = new bool[m_colors.Length];
+
+            var blacks = 0;
+            var whites = 0;
+
+            for (var i = 0; i < m_colors.Length; ++i)
+            {
+                if (m_colors[i] == other.m_colors[i])
+                {
+                    ++blacks;
+                    consumed[i] = true;
+                }
+                else
+                {
+                    // Check if the current color appears elsewhere in the
+                    // other code.  We must be careful not to consider
+                    // positions that are also exact matches.
+                    for (var j = 0; j < m_colors.Length; ++j)
+                    {
+                        if (!consumed[j] &&
+                            m_colors[i] == other.m_colors[j] &&
+                            m_colors[j] != other.m_colors[j])
+                        {
+                            ++whites;
+                            consumed[j] = true;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            return (blacks, whites);
+        }
+
+        /// 
+        /// Gets a string representation of the code.
+        /// 
+        public override string ToString() =>
+            new (m_colors.Select(index => Colors.List[index].ShortName).ToArray());
+    }
+}
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/CodeFactory.cs b/00_Alternate_Languages/60_Mastermind/csharp/CodeFactory.cs
new file mode 100644
index 00000000..f1d0cb98
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/CodeFactory.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Game
+{
+    /// 
+    /// Provides methods for generating codes with a given number of positions
+    /// and colors.
+    /// 
+    public class CodeFactory
+    {
+        /// 
+        /// Gets the number of colors in codes generated by this factory.
+        /// 
+        public int Colors { get; }
+
+        /// 
+        /// Gets the number of positions in codes generated by this factory.
+        /// 
+        public int Positions { get; }
+
+        /// 
+        /// Gets the number of distinct codes that this factory can
+        /// generate.
+        /// 
+        public int Possibilities { get; }
+
+        /// 
+        /// Initializes a new instance of the CodeFactory class.
+        /// 
+        /// 
+        /// The number of positions.
+        /// 
+        /// 
+        /// The number of colors.
+        /// 
+        public CodeFactory(int positions, int colors)
+        {
+            if (positions < 1)
+                throw new ArgumentException("A code must contain at least one position");
+
+            if (colors < 1)
+                throw new ArgumentException("A code must contain at least one color");
+
+            if (colors > Game.Colors.List.Length)
+                throw new ArgumentException($"A code can contain no more than {Game.Colors.List.Length} colors");
+
+            Positions     = positions;
+            Colors        = colors;
+            Possibilities = (int)Math.Pow(colors, positions);
+        }
+
+        /// 
+        /// Creates a specified code.
+        /// 
+        /// 
+        /// The number of the code to create from 0 to Possibilities - 1.
+        /// 
+        public Code Create(int number) =>
+            EnumerateCodes().Skip(number).First();
+
+        /// 
+        /// Creates a random code using the provided random number generator.
+        /// 
+        /// 
+        /// The random number generator.
+        /// 
+        public Code Create(Random random) =>
+            Create(random.Next(Possibilities));
+
+        /// 
+        /// Generates a collection of codes containing every code that this
+        /// factory can create exactly once.
+        /// 
+        public IEnumerable EnumerateCodes()
+        {
+            var current = new int[Positions];
+            var position = default(int);
+
+            do
+            {
+                yield return new Code(current);
+
+                position = 0;
+                while (position < Positions && ++current[position] == Colors)
+                    current[position++] = 0;
+            }
+            while (position < Positions);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/ColorInfo.cs b/00_Alternate_Languages/60_Mastermind/csharp/ColorInfo.cs
new file mode 100644
index 00000000..b05b8fa9
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/ColorInfo.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace Game
+{
+    /// 
+    /// Stores information about a color.
+    /// 
+    public record ColorInfo
+    {
+        /// 
+        /// Gets a single character that represents the color.
+        /// 
+        public char ShortName { get; init; }
+
+        /// 
+        /// Gets the color's full name.
+        /// 
+        public string LongName { get; init; } = String.Empty;
+    }
+}
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/Colors.cs b/00_Alternate_Languages/60_Mastermind/csharp/Colors.cs
new file mode 100644
index 00000000..6901633c
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/Colors.cs
@@ -0,0 +1,20 @@
+namespace Game
+{
+    /// 
+    /// Provides information about the colors that can be used in codes.
+    /// 
+    public static class Colors
+    {
+        public static readonly ColorInfo[] List = new[]
+        {
+            new ColorInfo { ShortName = 'B', LongName = "BLACK"  },
+            new ColorInfo { ShortName = 'W', LongName = "WHITE"  },
+            new ColorInfo { ShortName = 'R', LongName = "RED"    },
+            new ColorInfo { ShortName = 'G', LongName = "GREEN"  },
+            new ColorInfo { ShortName = 'O', LongName = "ORANGE" },
+            new ColorInfo { ShortName = 'Y', LongName = "YELLOW" },
+            new ColorInfo { ShortName = 'P', LongName = "PURPLE" },
+            new ColorInfo { ShortName = 'T', LongName = "TAN"    }
+        };
+    }
+}
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/Command.cs b/00_Alternate_Languages/60_Mastermind/csharp/Command.cs
new file mode 100644
index 00000000..5df3201a
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/Command.cs
@@ -0,0 +1,13 @@
+namespace Game
+{
+    /// 
+    /// Enumerates the different commands that the user can issue during
+    /// the game.
+    /// 
+    public enum Command
+    {
+        MakeGuess,
+        ShowBoard,
+        Quit
+    }
+}
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/Controller.cs b/00_Alternate_Languages/60_Mastermind/csharp/Controller.cs
new file mode 100644
index 00000000..85a41f9f
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/Controller.cs
@@ -0,0 +1,175 @@
+using System;
+using System.Collections.Immutable;
+using System.Linq;
+
+namespace Game
+{
+    /// 
+    /// Contains functions for getting input from the end user.
+    /// 
+    public static class Controller
+    {
+        /// 
+        /// Maps the letters for each color to the integer value representing
+        /// that color.
+        /// 
+        /// 
+        /// We derive this map from the Colors list rather than defining the
+        /// entries directly in order to keep all color related information
+        /// in one place.  (This makes it easier to change the color options
+        /// later.)
+        /// 
+        private static ImmutableDictionary ColorsByKey = Colors.List
+            .Select((info, index) => (key: info.ShortName, index))
+            .ToImmutableDictionary(entry => entry.key, entry => entry.index);
+
+        /// 
+        /// Gets the number of colors to use in the secret code.
+        /// 
+        public static int GetNumberOfColors()
+        {
+            var maximumColors = Colors.List.Length;
+            var colors = 0;
+
+            while (colors < 1 || colors > maximumColors)
+            {
+                colors = GetInteger(View.PromptNumberOfColors);
+                if (colors > maximumColors)
+                    View.NotifyTooManyColors(maximumColors);
+            }
+
+            return colors;
+        }
+
+        /// 
+        /// Gets the number of positions in the secret code.
+        /// 
+        /// 
+        public static int GetNumberOfPositions()
+        {
+            // Note: We should probably ensure that the user enters a sane
+            //  number of positions here.  (Things go south pretty quickly
+            //  with a large number of positions.)  But since the original
+            //  program did not, neither will we.
+            return GetInteger(View.PromptNumberOfPositions);
+        }
+
+        /// 
+        /// Gets the number of rounds to play.
+        /// 
+        public static int GetNumberOfRounds()
+        {
+            // Note: Silly numbers of rounds (like 0, or a negative number)
+            //  are harmless, but it would still make sense to validate.
+            return GetInteger(View.PromptNumberOfRounds);
+        }
+
+        /// 
+        /// Gets a command from the user.
+        /// 
+        /// 
+        /// The current move number.
+        /// 
+        /// 
+        /// The number of code positions.
+        /// 
+        /// 
+        /// The maximum number of code colors.
+        /// 
+        /// 
+        /// The entered command and guess (if applicable).
+        /// 
+        public static (Command command, Code? guess) GetCommand(int moveNumber, int positions, int colors)
+        {
+            while (true)
+            {
+                View.PromptGuess (moveNumber);
+
+                var input = Console.ReadLine();
+                if (input is null)
+                    Environment.Exit(0);
+
+                switch (input.ToUpperInvariant())
+                {
+                    case "BOARD":
+                        return (Command.ShowBoard, null);
+                    case "QUIT":
+                        return (Command.Quit, null);
+                    default:
+                        if (input.Length != positions)
+                            View.NotifyBadNumberOfPositions();
+                        else
+                        if (input.FindFirstIndex(c => !TranslateColor(c).HasValue) is int invalidPosition)
+                            View.NotifyInvalidColor(input[invalidPosition]);
+                        else
+                            return (Command.MakeGuess, new Code(input.Select(c => TranslateColor(c)!.Value)));
+
+                        break;
+                }
+            }
+        }
+
+        /// 
+        /// Waits until the user indicates that he or she is ready to continue.
+        /// 
+        public static void WaitUntilReady()
+        {
+            View.PromptReady();
+            var input = Console.ReadLine();
+            if (input is null)
+                Environment.Exit(0);
+        }
+
+        /// 
+        /// Gets the number of blacks and whites for the given code from the
+        /// user.
+        /// 
+        public static (int blacks, int whites) GetBlacksWhites(Code code)
+        {
+            while (true)
+            {
+                View.PromptBlacksWhites(code);
+
+                var input = Console.ReadLine();
+                if (input is null)
+                    Environment.Exit(0);
+
+                var parts = input.Split(',');
+
+                if (parts.Length != 2)
+                    View.PromptTwoValues();
+                else
+                if (!Int32.TryParse(parts[0], out var blacks) || !Int32.TryParse(parts[1], out var whites))
+                    View.PromptValidInteger();
+                else
+                    return (blacks, whites);
+            }
+        }
+
+        /// 
+        /// Gets an integer value from the user.
+        /// 
+        private static int GetInteger(Action prompt)
+        {
+            while (true)
+            {
+                prompt();
+
+                var input = Console.ReadLine();
+                if (input is null)
+                    Environment.Exit(0);
+
+                if (Int32.TryParse(input, out var result))
+                    return result;
+                else
+                    View.PromptValidInteger();
+            }
+        }
+
+        /// 
+        /// Translates the given character into the corresponding color.
+        /// 
+        private static int? TranslateColor(char c) =>
+            ColorsByKey.TryGetValue(c, out var index) ? index : null;
+    }
+}
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/EnumerableExtensions.cs b/00_Alternate_Languages/60_Mastermind/csharp/EnumerableExtensions.cs
new file mode 100644
index 00000000..3bd6cf96
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/EnumerableExtensions.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Game
+{
+    /// 
+    /// Provides additional methods for the 
+    /// interface.
+    /// 
+    public static class EnumerableExtensions
+    {
+        /// 
+        /// Cycles through the integer values in the range [0, count).
+        /// 
+        /// 
+        /// The first value to return.
+        /// 
+        /// 
+        /// The number of values to return.
+        /// 
+        public static IEnumerable Cycle(int start, int count)
+        {
+            if (count < 1)
+                throw new ArgumentException("count must be at least 1");
+
+            if (start < 0 || start >= count)
+                throw new ArgumentException("start must be in the range [0, count)");
+
+            for (var i = start; i < count; ++i)
+                yield return i;
+
+            for (var i = 0; i < start; ++i)
+                yield return i;
+        }
+
+        /// 
+        /// Finds the index of the first item in the given sequence that
+        /// satisfies the given predicate.
+        /// 
+        /// 
+        /// The type of elements in the sequence.
+        /// 
+        /// 
+        /// The source sequence.
+        /// 
+        /// 
+        /// The predicate function.
+        /// 
+        /// 
+        /// The index of the first element in the source sequence for which
+        /// predicate(element) is true.  If there is no such element, return
+        /// is null.
+        /// 
+        public static int? FindFirstIndex(this IEnumerable source, Func predicate) =>
+            source.Select((element, index) => predicate(element) ? index : default(int?))
+                .FirstOrDefault(index => index.HasValue);
+
+        /// 
+        /// Returns the first item in the given sequence that matches the
+        /// given predicate.
+        /// 
+        /// 
+        /// The type of elements in the sequence.
+        /// 
+        /// 
+        /// The source sequence.
+        /// 
+        /// 
+        /// The predicate to check against each element.
+        /// 
+        /// 
+        /// The value to return if no elements match the predicate.
+        /// 
+        /// 
+        /// The first item in the source sequence that matches the given
+        /// predicate, or the provided default value if none do.
+        /// 
+        public static T FirstOrDefault(this IEnumerable source, Func predicate, T defaultValue)
+        {
+            foreach (var element in source)
+                if (predicate(element))
+                    return element;
+
+            return defaultValue;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/Mastermind.csproj b/00_Alternate_Languages/60_Mastermind/csharp/Mastermind.csproj
new file mode 100644
index 00000000..849a99d4
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/Mastermind.csproj
@@ -0,0 +1,7 @@
+
+  
+    Exe
+    net5.0
+    enable
+  
+
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/Mastermind.sln b/00_Alternate_Languages/60_Mastermind/csharp/Mastermind.sln
new file mode 100644
index 00000000..0da53b6d
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/Mastermind.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mastermind", "Mastermind.csproj", "{AEC839CD-C6D3-4476-AA85-79B160AF78BE}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{AEC839CD-C6D3-4476-AA85-79B160AF78BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AEC839CD-C6D3-4476-AA85-79B160AF78BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AEC839CD-C6D3-4476-AA85-79B160AF78BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AEC839CD-C6D3-4476-AA85-79B160AF78BE}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {1BDFBEE6-8345-438C-8FCE-B2C9394CC080}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/Program.cs b/00_Alternate_Languages/60_Mastermind/csharp/Program.cs
new file mode 100644
index 00000000..596b552d
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/Program.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Game
+{
+    // MASTERMIND II
+    // STEVE NORTH
+    // CREATIVE COMPUTING
+    // PO BOX 789-M MORRISTOWN NEW JERSEY 07960
+    class Program
+    {
+        public const int MaximumGuesses = 10;
+
+        static void Main()
+        {
+            var (codeFactory, rounds) = StartGame();
+
+            var random        = new Random();
+            var humanScore    = 0;
+            var computerScore = 0;
+
+            for (var round = 1; round <= rounds; ++round)
+            {
+                View.ShowStartOfRound(round);
+
+                if (!HumanTakesTurn())
+                    return;
+
+                while (!ComputerTakesTurn())
+                    View.ShowInconsistentInformation();
+            }
+
+            View.ShowScores(humanScore, computerScore, isFinal: true);
+
+            /// 
+            /// Gets the game start parameters from the user.
+            /// 
+            (CodeFactory codeFactory, int rounds) StartGame()
+            {
+                View.ShowBanner();
+
+                var colors    = Controller.GetNumberOfColors();
+                var positions = Controller.GetNumberOfPositions();
+                var rounds    = Controller.GetNumberOfRounds();
+
+                var codeFactory = new CodeFactory(positions, colors);
+
+                View.ShowTotalPossibilities(codeFactory.Possibilities);
+                View.ShowColorTable(codeFactory.Colors);
+
+                return (codeFactory, rounds);
+            }
+
+            /// 
+            /// Executes the human's turn.
+            /// 
+            /// 
+            /// True if thue human completed his or her turn and false if
+            /// he or she quit the game.
+            /// 
+            bool HumanTakesTurn()
+            {
+                // Store a history of the human's guesses (used for the show
+                // board command below).
+                var history     = new List();
+                var code        = codeFactory.Create(random);
+                var guessNumber = default(int);
+
+                for (guessNumber = 1; guessNumber <= MaximumGuesses; ++guessNumber)
+                {
+                    var guess = default(Code);
+
+                    while (guess is null)
+                    {
+                        switch (Controller.GetCommand(guessNumber, codeFactory.Positions, codeFactory.Colors))
+                        {
+                            case (Command.MakeGuess, Code input):
+                                guess = input;
+                                break;
+                            case (Command.ShowBoard, _):
+                                View.ShowBoard(history);
+                                break;
+                            case (Command.Quit, _):
+                                View.ShowQuitGame(code);
+                                return false;
+                        }
+                    }
+
+                    var (blacks, whites) = code.Compare(guess);
+                    if (blacks == codeFactory.Positions)
+                        break;
+
+                    View.ShowResults(blacks, whites);
+
+                    history.Add(new TurnResult(guess, blacks, whites));
+                }
+
+                if (guessNumber <= MaximumGuesses)
+                    View.ShowHumanGuessedCode(guessNumber);
+                else
+                    View.ShowHumanFailedToGuessCode(code);
+
+                humanScore += guessNumber;
+
+                View.ShowScores(humanScore, computerScore, isFinal: false);
+                return true;
+            }
+
+            /// 
+            /// Executes the computers turn.
+            /// 
+            /// 
+            /// True if the computer completes its turn successfully and false
+            /// if it does not (due to human error).
+            /// 
+            bool ComputerTakesTurn()
+            {
+                var isCandidate = new bool[codeFactory.Possibilities];
+                var guessNumber = default(int);
+
+                Array.Fill(isCandidate, true);
+
+                View.ShowComputerStartTurn();
+                Controller.WaitUntilReady();
+
+                for (guessNumber = 1; guessNumber <= MaximumGuesses; ++guessNumber)
+                {
+                    // Starting with a random code, cycle through codes until
+                    // we find one that is still a candidate solution.  If
+                    // there are no remaining candidates, then it implies that
+                    // the user made an error in one or more responses.
+                    var codeNumber = EnumerableExtensions.Cycle(random.Next(codeFactory.Possibilities), codeFactory.Possibilities)
+                        .FirstOrDefault(i => isCandidate[i], -1);
+
+                    if (codeNumber < 0)
+                        return false;
+
+                    var guess = codeFactory.Create(codeNumber);
+
+                    var (blacks, whites) = Controller.GetBlacksWhites(guess);
+                    if (blacks == codeFactory.Positions)
+                        break;
+
+                    // Mark codes which are no longer potential solutions.  We
+                    // know that the current guess yields the above number of
+                    // blacks and whites when compared to the solution, so any
+                    // code that yields a different number of blacks or whites
+                    // can't be the answer.
+                    foreach (var (candidate, index) in codeFactory.EnumerateCodes().Select((candidate, index) => (candidate, index)))
+                    {
+                        if (isCandidate[index])
+                        {
+                            var (candidateBlacks, candidateWhites) = guess.Compare(candidate);
+                            if (blacks > candidateBlacks || whites > candidateWhites)
+                                isCandidate[index] = false;
+                        }
+                    }
+                }
+
+                if (guessNumber <= MaximumGuesses)
+                    View.ShowComputerGuessedCode(guessNumber);
+                else
+                    View.ShowComputerFailedToGuessCode();
+
+                computerScore += guessNumber;
+                View.ShowScores(humanScore, computerScore, isFinal: false);
+
+                return true;
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/README.md b/00_Alternate_Languages/60_Mastermind/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/TurnResult.cs b/00_Alternate_Languages/60_Mastermind/csharp/TurnResult.cs
new file mode 100644
index 00000000..b854e92f
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/TurnResult.cs
@@ -0,0 +1,38 @@
+namespace Game
+{
+    /// 
+    /// Stores the result of a player's turn.
+    /// 
+    public record TurnResult
+    {
+        /// 
+        /// Gets the code guessed by the player.
+        /// 
+        public Code Guess { get; }
+
+        /// 
+        /// Gets the number of black pegs resulting from the guess.
+        /// 
+        public int Blacks { get; }
+
+        /// 
+        /// Gets the number of white pegs resulting from the guess.
+        /// 
+        public int Whites { get; }
+
+        /// 
+        /// Initializes a new instance of the TurnResult record.
+        /// 
+        /// 
+        /// The player's guess.
+        /// 
+        /// 
+        /// The number of black pegs.
+        /// 
+        /// 
+        /// The number of white pegs.
+        /// 
+        public TurnResult(Code guess, int blacks, int whites) =>
+            (Guess, Blacks, Whites) = (guess, blacks, whites);
+    }
+}
diff --git a/00_Alternate_Languages/60_Mastermind/csharp/View.cs b/00_Alternate_Languages/60_Mastermind/csharp/View.cs
new file mode 100644
index 00000000..ea8bd898
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/csharp/View.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Game
+{
+    /// 
+    /// Contains functions for displaying information to the end user.
+    /// 
+    public static class View
+    {
+        public static void ShowBanner()
+        {
+            Console.WriteLine("                              MASTERMIND");
+            Console.WriteLine("               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+        }
+
+        public static void ShowTotalPossibilities(int possibilities)
+        {
+            Console.WriteLine($"TOTAL POSSIBILITIES = {possibilities}");
+            Console.WriteLine();
+        }
+
+        public static void ShowColorTable(int numberOfColors)
+        {
+            Console.WriteLine();
+            Console.WriteLine("COLOR     LETTER");
+            Console.WriteLine("=====     ======");
+
+            foreach (var color in Colors.List.Take(numberOfColors))
+                Console.WriteLine($"{color.LongName,-13}{color.ShortName}");
+
+            Console.WriteLine();
+        }
+
+        public static void ShowStartOfRound(int roundNumber)
+        {
+            Console.WriteLine();
+            Console.WriteLine($"ROUND NUMBER {roundNumber} ----");
+            Console.WriteLine();
+            Console.WriteLine("GUESS MY COMBINATION.");
+            Console.WriteLine();
+        }
+
+        public static void ShowBoard(IEnumerable history)
+        {
+            Console.WriteLine();
+            Console.WriteLine("BOARD");
+            Console.WriteLine("MOVE     GUESS          BLACK     WHITE");
+
+            var moveNumber = 0;
+            foreach (var result in history)
+                Console.WriteLine($"{++moveNumber,-9}{result.Guess,-16}{result.Blacks,-10}{result.Whites}");
+
+            Console.WriteLine();
+        }
+
+        public static void ShowQuitGame(Code code)
+        {
+            Console.WriteLine($"QUITTER!  MY COMBINATION WAS: {code}");
+            Console.WriteLine("GOOD BYE");
+        }
+
+        public static void ShowResults(int blacks, int whites)
+        {
+            Console.WriteLine($"YOU HAVE  {blacks}  BLACKS AND  {whites}  WHITES.");
+        }
+
+        public static void ShowHumanGuessedCode(int guessNumber)
+        {
+            Console.WriteLine($"YOU GUESSED IT IN  {guessNumber}  MOVES!");
+        }
+
+        public static void ShowHumanFailedToGuessCode(Code code)
+        {
+            // Note: The original code did not print out the combination, but
+            // this appears to be a bug.
+            Console.WriteLine("YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!");
+            Console.WriteLine($"THE ACTUAL COMBINATION WAS: {code}");
+        }
+
+        public static void ShowScores(int humanScore, int computerScore, bool isFinal)
+        {
+            if (isFinal)
+            {
+                Console.WriteLine("GAME OVER");
+                Console.WriteLine("FINAL SCORE:");
+            }
+            else
+                Console.WriteLine("SCORE:");
+
+            Console.WriteLine($"     COMPUTER  {computerScore}");
+            Console.WriteLine($"     HUMAN     {humanScore}");
+            Console.WriteLine();
+        }
+
+        public static void ShowComputerStartTurn()
+        {
+            Console.WriteLine("NOW I GUESS.  THINK OF A COMBINATION.");
+        }
+
+        public static void ShowInconsistentInformation()
+        {
+            Console.WriteLine("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.");
+            Console.WriteLine("TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.");
+        }
+
+        public static void ShowComputerGuessedCode(int guessNumber)
+        {
+            Console.WriteLine($"I GOT IT IN  {guessNumber}  MOVES!");
+        }
+
+        public static void ShowComputerFailedToGuessCode()
+        {
+            Console.WriteLine("I USED UP ALL MY MOVES!");
+            Console.WriteLine("I GUESS MY CPU IS JUST HAVING AN OFF DAY.");
+        }
+
+        public static void PromptNumberOfColors()
+        {
+            Console.Write("NUMBER OF COLORS? ");
+        }
+
+        public static void PromptNumberOfPositions()
+        {
+            Console.Write("NUMBER OF POSITIONS? ");
+        }
+
+        public static void PromptNumberOfRounds()
+        {
+            Console.Write("NUMBER OF ROUNDS? ");
+        }
+
+        public static void PromptGuess(int moveNumber)
+        {
+            Console.Write($"MOVE #  {moveNumber}  GUESS ? ");
+        }
+
+        public static void PromptReady()
+        {
+            Console.Write("HIT RETURN WHEN READY ? ");
+        }
+
+        public static void PromptBlacksWhites(Code code)
+        {
+            Console.Write($"MY GUESS IS: {code}");
+            Console.Write("  BLACKS, WHITES ? ");
+        }
+
+        public static void PromptTwoValues()
+        {
+            Console.WriteLine("PLEASE ENTER TWO VALUES, SEPARATED BY A COMMA");
+        }
+
+        public static void PromptValidInteger()
+        {
+            Console.WriteLine("PLEASE ENTER AN INTEGER VALUE");
+        }
+
+        public static void NotifyBadNumberOfPositions()
+        {
+            Console.WriteLine("BAD NUMBER OF POSITIONS");
+        }
+
+        public static void NotifyInvalidColor(char colorKey)
+        {
+            Console.WriteLine($"'{colorKey}' IS UNRECOGNIZED.");
+        }
+
+        public static void NotifyTooManyColors(int maxColors)
+        {
+            Console.WriteLine($"NO MORE THAN {maxColors}, PLEASE!");
+        }
+    }
+}
diff --git a/00_Alternate_Languages/60_Mastermind/java/README.md b/00_Alternate_Languages/60_Mastermind/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/60_Mastermind/javascript/README.md b/00_Alternate_Languages/60_Mastermind/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/60_Mastermind/javascript/mastermind.html b/00_Alternate_Languages/60_Mastermind/javascript/mastermind.html
new file mode 100644
index 00000000..e1835c05
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/javascript/mastermind.html
@@ -0,0 +1,9 @@
+
+
+MASTERMIND
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/60_Mastermind/javascript/mastermind.js b/00_Alternate_Languages/60_Mastermind/javascript/mastermind.js
new file mode 100644
index 00000000..5c91575b
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/javascript/mastermind.js
@@ -0,0 +1,363 @@
+// MASTERMIND
+//
+// 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 p9;
+var c9;
+var b;
+var w;
+var f;
+var m;
+
+var qa;
+var sa;
+var ss;
+var as;
+var gs;
+var hs;
+
+function initialize_qa()
+{
+    for (s = 1; s <= p9; s++)
+        qa[s] = 0;
+}
+
+function increment_qa()
+{
+    if (qa[1] <= 0) {
+        // If zero, this is our firt increment: make all ones
+        for (s = 1; s <= p9; s++)
+            qa[s] = 1;
+    } else {
+        q = 1;
+        while (1) {
+            qa[q] = qa[q] + 1;
+            if (qa[q] <= c9)
+                return;
+            qa[q] = 1;
+            q++;
+        }
+    }
+}
+
+function convert_qa()
+{
+    for (s = 1; s <= p9; s++) {
+        as[s] = ls.substr(qa[s] - 1, 1);
+    }
+}
+
+function get_number()
+{
+    b = 0;
+    w = 0;
+    f = 0;
+    for (s = 1; s <= p9; s++) {
+        if (gs[s] == as[s]) {
+            b++;
+            gs[s] = String.fromCharCode(f);
+            as[s] = String.fromCharCode(f + 1);
+            f += 2;
+        } else {
+            for (t = 1; t <= p9; t++) {
+                if (gs[s] == as[t] && gs[t] != as[t]) {
+                    w++;
+                    as[t] = String.fromCharCode(f);
+                    gs[s] = String.fromCharCode(f + 1);
+                    f += 2;
+                    break;
+                }
+            }
+        }
+    }
+}
+
+function convert_qa_hs()
+{
+    for (s = 1; s <= p9; s++) {
+        hs[s] = ls.substr(qa[s] - 1, 1);
+    }
+}
+
+function copy_hs()
+{
+    for (s = 1; s <= p9; s++) {
+        gs[s] = hs[s];
+    }
+}
+
+function board_printout()
+{
+    print("\n");
+    print("BOARD\n");
+    print("MOVE     GUESS          BLACK     WHITE\n");
+    for (z = 1; z <= m - 1; z++) {
+        str = " " + z + " ";
+        while (str.length < 9)
+            str += " ";
+        str += ss[z];
+        while (str.length < 25)
+            str += " ";
+        str += sa[z][1];
+        while (str.length < 35)
+            str += " ";
+        str += sa[z][2];
+        print(str + "\n");
+    }
+    print("\n");
+}
+
+function quit()
+{
+    print("QUITTER!  MY COMBINATION WAS: ");
+    convert_qa();
+    for (x = 1; x <= p9; x++) {
+        print(as[x]);
+    }
+    print("\n");
+    print("GOOD BYE\n");
+}
+
+function show_score()
+{
+    print("SCORE:\n");
+    show_points();
+}
+
+function show_points()
+{
+    print("     COMPUTER " + c + "\n");
+    print("     HUMAN    " + h + "\n");
+    print("\n");
+}
+
+var color = ["BLACK", "WHITE", "RED", "GREEN",
+             "ORANGE", "YELLOW", "PURPLE", "TAN"];
+
+// Main program
+async function main()
+{
+    print(tab(30) + "MASTERMIND\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    //
+    //  MASTERMIND II
+    //  STEVE NORTH
+    //  CREATIVE COMPUTING
+    //  PO BOX 789-M MORRISTOWN NEW JERSEY 07960
+    //
+    //
+    while (1) {
+        print("NUMBER OF COLORS");
+        c9 = parseInt(await input());
+        if (c9 <= 8)
+            break;
+        print("NO MORE THAN 8, PLEASE!\n");
+    }
+    print("NUMBER OF POSITIONS");
+    p9 = parseInt(await input());
+    print("NUMBER OF ROUNDS");
+    r9 = parseInt(await input());
+    p = Math.pow(c9, p9);
+    print("TOTAL POSSIBILITIES = " + p + "\n");
+    h = 0;
+    c = 0;
+    qa = [];
+    sa = [];
+    ss = [];
+    as = [];
+    gs = [];
+    ia = [];
+    hs = [];
+    ls = "BWRGOYPT";
+    print("\n");
+    print("\n");
+    print("COLOR    LETTER\n");
+    print("=====    ======\n");
+    for (x = 1; x <= c9; x++) {
+        str = color[x - 1];
+        while (str.length < 13)
+            str += " ";
+        str += ls.substr(x - 1, 1);
+        print(str + "\n");
+    }
+    print("\n");
+    for (r = 1; r <= r9; r++) {
+        print("\n");
+        print("ROUND NUMBER " + r + " ----\n");
+        print("\n");
+        print("GUESS MY COMBINATION.\n");
+        print("\n");
+        // Get a combination
+        a = Math.floor(p * Math.random() + 1);
+        initialize_qa();
+        for (x = 1; x <= a; x++) {
+            increment_qa();
+        }
+        for (m = 1; m <= 10; m++) {
+            while (1) {
+                print("MOVE # " + m + " GUESS ");
+                str = await input();
+                if (str == "BOARD") {
+                    board_printout();
+                } else if (str == "QUIT") {
+                    quit();
+                    return;
+                } else if (str.length != p9) {
+                    print("BAD NUMBER OF POSITIONS.\n");
+                } else {
+                    // Unpack str into gs(1-p9)
+                    for (x = 1; x <= p9; x++) {
+                        y = ls.indexOf(str.substr(x - 1, 1));
+                        if (y < 0) {
+                            print("'" + str.substr(x - 1, 1) + "' IS UNRECOGNIZED.\n");
+                            break;
+                        }
+                        gs[x] = str.substr(x - 1, 1);
+                    }
+                    if (x > p9)
+                        break;
+                }
+            }
+            // Now we convert qa(1-p9) into as(1-p9) [ACTUAL GUESS]
+            convert_qa();
+            // And get number of blacks and white
+            get_number();
+            if (b == p9) {
+                print("YOU GUESSED IT IN " + m + " MOVES!\n");
+                break;
+            }
+            //tell human results
+            print("YOU HAVE " + b + " BLACKS AND " + w + " WHITES.")
+            // Save all this stuff for board printout later
+            ss[m] = str;
+            sa[m] = [];
+            sa[m][1] = b;
+            sa[m][2] = w;
+        }
+        if (m > 10) {
+            print("YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!\n");
+        }
+        h += m;
+        show_score();
+
+        //
+        // Now computer guesses
+        //
+        for (x = 1; x <= p; x++)
+            ia[x] = 1;
+        print("NOW I GUESS.  THINK OF A COMBINATION.\n");
+        print("HIT RETURN WHEN READY:");
+        str = await input();
+        for (m = 1; m <= 10; m++) {
+            initialize_qa();
+            // Find a guess
+            g = Math.floor(p * Math.random() + 1);
+            if (ia[g] != 1) {
+                for (x = g; x <= p; x++) {
+                    if (ia[x] == 1)
+                        break;
+                }
+                if (x > p) {
+                    for (x = 1; x <= g; x++) {
+                        if (ia[x] == 1)
+                            break;
+                    }
+                    if (x > g) {
+                        print("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\n");
+                        print("TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\n");
+                        for (x = 1; x <= p; x++)
+                            ia[x] = 1;
+                        print("NOW I GUESS.  THINK OF A COMBINATION.\n");
+                        print("HIT RETURN WHEN READY:");
+                        str = await input();
+                        m = 0;
+                        continue;
+                    }
+                }
+                g = x;
+            }
+            // Now we convert guess #g into gs
+            for (x = 1; x <= g; x++) {
+                increment_qa();
+            }
+            convert_qa_hs();
+            print("MY GUESS IS: ");
+            for (x = 1; x <= p9; x++) {
+                print(hs[x]);
+            }
+            print("  BLACKS, WHITES ");
+            str = await input();
+            b1 = parseInt(str);
+            w1 = parseInt(str.substr(str.indexOf(",") + 1));
+            if (b1 == p9) {
+                print("I GOT IT IN " + m + " MOVES!\n");
+                break;
+            }
+            initialize_qa();
+            for (x = 1; x <= p; x++) {
+                increment_qa();
+                if (ia[x] != 0) {
+                    copy_hs();
+                    convert_qa();
+                    get_number();
+                    if (b1 > b || w1 > w)
+                        ia[x] = 0;
+                }
+            }
+        }
+        if (m > 10) {
+            print("I USED UP ALL MY MOVES!\n");
+            print("I GUESS MY CPU I JUST HAVING AN OFF DAY.\n");
+        }
+        c += m;
+        show_score();
+    }
+    print("GAME OVER\n");
+    print("FINAL SCORE:\n");
+    show_points();
+}
+
+main();
diff --git a/00_Alternate_Languages/60_Mastermind/mastermind.bas b/00_Alternate_Languages/60_Mastermind/mastermind.bas
new file mode 100644
index 00000000..215cdd18
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/mastermind.bas
@@ -0,0 +1,232 @@
+2 PRINT TAB(30);"MASTERMIND"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT: PRINT: PRINT
+10 REM
+20 REM     MASTERMIND II
+30 REM     STEVE NORTH
+40 REM     CREATIVE COMPUTING
+50 REM     PO BOX 789-M MORRISTOWN NEW JERSEY 07960
+60 REM
+70 REM
+80 INPUT "NUMBER OF COLORS";C9
+90 IF C9>8 THEN PRINT "NO MORE THAN 8, PLEASE!":GOTO 80
+100 INPUT "NUMBER OF POSITIONS";P9
+110 INPUT "NUMBER OF ROUNDS";R9
+120 P=C9^P9
+130 PRINT "TOTAL POSSIBILITIES =";P
+140 H=0:C=0
+150 DIM Q(P9),S(10,2),S$(10),A$(P9),G$(P9),I(P),H$(P9)
+160 L$="BWRGOYPT"
+170 PRINT
+180 PRINT
+190 PRINT "COLOR     LETTER"
+200 PRINT "=====     ======"
+210 FOR X=1 TO C9
+220 READ X$
+230 PRINT X$;TAB(13);MID$(L$,X,1)
+240 NEXT X
+250 PRINT
+260 FOR R=1 TO R9
+270 PRINT
+280 PRINT "ROUND NUMBER";R;"----"
+290 PRINT
+300 PRINT "GUESS MY COMBINATION.":PRINT
+310 REM     GET A COMBINATION
+320 A=INT(P*RND(1)+1)
+330 GOSUB 3000
+340 FOR X=1 TO A
+350 GOSUB 3500
+360 NEXT X
+370 FOR M=1 TO 10
+380 PRINT "MOVE # ";M;" GUESS ";:INPUT X$
+390 IF X$="BOARD" THEN 2000
+400 IF X$="QUIT" THEN 2500
+410 IF LEN(X$)<>P9 THEN PRINT "BAD NUMBER OF POSITIONS.":GOTO 380
+420 REM     UNPACK X$ INTO G$(1-P9)
+430 FOR X=1 TO P9
+440 FOR Y=1 TO C9
+450 IF MID$(X$,X,1)=MID$(L$,Y,1) THEN 480
+460 NEXT Y
+470 PRINT "'"; MID$(X$,X,1); "' IS UNRECOGNIZED.":GOTO 380
+480 G$(X)=MID$(X$,X,1)
+490 NEXT X
+500 REM     NOW WE CONVERT Q(1-P9) INTO A$(1-P9) [ACTUAL GUESS]
+510 GOSUB 4000
+520 REM     AND GET NUMBER OF BLACKS AND WHITES
+530 GOSUB 4500
+540 IF B=P9 THEN 630
+550 REM     TELL HUMAN RESULTS
+560 PRINT "YOU HAVE ";B;" BLACKS AND ";W;" WHITES."
+570 REM     SAVE ALL THIS STUFF FOR BOARD PRINTOUT LATER
+580 S$(M)=X$
+590 S(M,1)=B
+600 S(M,2)=W
+610 NEXT M
+620 PRINT "YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!":GOTO 640
+622 GOSUB 4000
+623 PRINT "THE ACTUAL COMBINATION WAS: ";
+624 FOR X=1 TO P9
+625 PRINT A$(X);
+626 NEXT X
+627 PRINT
+630 PRINT "YOU GUESSED IT IN ";M;" MOVES!"
+640 H=H+M
+650 GOSUB 5000
+660 REM
+670 REM     NOW COMPUTER GUESSES
+680 REM
+690 FOR X=1 TO P
+700 I(X)=1
+710 NEXT X
+720 PRINT "NOW I GUESS.  THINK OF A COMBINATION."
+730 INPUT "HIT RETURN WHEN READY:";X$
+740 FOR M=1 TO 10
+750 GOSUB 3000
+760 REM     FIND A GUESS
+770 G=INT(P*RND(1)+1)
+780 IF I(G)=1 THEN 890
+790 FOR X=G TO P
+800 IF I(X)=1 THEN 880
+810 NEXT X
+820 FOR X=1 TO G
+830 IF I(X)=1 THEN 880
+840 NEXT X
+850 PRINT "YOU HAVE GIVEN ME INCONSISTENT INFORMATION."
+860 PRINT "TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL."
+870 GOTO 660
+880 G=X
+890 REM     NOW WE CONVERT GUESS #G INTO G$
+900 FOR X=1 TO G
+910 GOSUB 3500
+920 NEXT X
+930 GOSUB 6000
+940 PRINT "MY GUESS IS: ";
+950 FOR X=1 TO P9
+960 PRINT H$(X);
+970 NEXT X
+980 INPUT "  BLACKS, WHITES ";B1,W1
+990 IF B1=P9 THEN 1120
+1000 GOSUB 3000
+1010 FOR X=1 TO P
+1020 GOSUB 3500
+1030 IF I(X)=0 THEN 1070
+1035 GOSUB 6500
+1040 GOSUB 4000
+1050 GOSUB 4500
+1060 IF B1>B OR W1>W THEN I(X)=0
+1070 NEXT X
+1080 NEXT M
+1090 PRINT "I USED UP ALL MY MOVES!"
+1100 PRINT "I GUESS MY CPU IS JUST HAVING AN OFF DAY."
+1110 GOTO 1130
+1120 PRINT "I GOT IT IN ";M;" MOVES!"
+1130 C=C+M
+1140 GOSUB 5000
+1150 NEXT R
+1160 PRINT "GAME OVER"
+1170 PRINT "FINAL SCORE:"
+1180 GOSUB 5040
+1190 STOP
+2000 REM
+2010 REM     BOARD PRINTOUT ROUTINE
+2020 REM
+2025 PRINT
+2030 PRINT "BOARD"
+2040 PRINT "MOVE     GUESS          BLACK     WHITE"
+2050 FOR Z=1 TO M-1
+2060 PRINT Z;TAB(9);S$(Z);TAB(25);S(Z,1);TAB(35);S(Z,2)
+2070 NEXT Z
+2075 PRINT
+2080 GOTO 380
+2500 REM
+2510 REM     QUIT ROUTINE
+2520 REM
+2530 PRINT "QUITTER!  MY COMBINATION WAS: ";
+2535 GOSUB 4000
+2540 FOR X=1 TO P9
+2550 PRINT A$(X);
+2560 NEXT X
+2565 PRINT
+2570 PRINT "GOOD BYE"
+2580 STOP
+3000 REM
+3010 REM     INITIALIZE Q(1-P9) TO ZEROS
+3020 REM
+3030 FOR S=1 TO P9
+3040 Q(S)=0
+3050 NEXT S
+3060 RETURN
+3500 REM
+3510 REM     INCREMENT Q(1-P9)
+3520 REM
+3522 IF Q(1)>0 THEN 3530
+3524 REM  IF ZERO, THIS IS OUR FIRST INCREMENT: MAKE ALL ONES
+3526 FOR S=1 TO P9
+3527 Q(S)=1
+3528 NEXT S
+3529 RETURN
+3530 Q=1
+3540 Q(Q)=Q(Q)+1
+3550 IF Q(Q)<=C9 THEN RETURN
+3560 Q(Q)=1
+3570 Q=Q+1
+3580 GOTO 3540
+4000 REM
+4010 REM     CONVERT Q(1-P9) TO A$(1-P9)
+4020 REM
+4030 FOR S=1 TO P9
+4040 A$(S)=MID$(L$,Q(S),1)
+4050 NEXT S
+4060 RETURN
+4500 REM
+4510 REM     GET NUMBER OF BLACKS (B) AND WHITES (W)
+4520 REM     MASHES G$ AND A$ IN THE PROCESS
+4530 REM
+4540 B=0:W=0:F=0
+4550 FOR S=1 TO P9
+4560 IF G$(S)<>A$(S) THEN 4620
+4570 B=B+1
+4580 G$(S)=CHR$(F)
+4590 A$(S)=CHR$(F+1)
+4600 F=F+2
+4610 GOTO 4660
+4620 FOR T=1 TO P9
+4630 IF G$(S)<>A$(T) THEN 4650
+4640 IF G$(T)=A$(T) THEN 4650
+4645 W=W+1:A$(T)=CHR$(F):G$(S)=CHR$(F+1):F=F+2:GOTO 4660
+4650 NEXT T
+4660 NEXT S
+4670 RETURN
+5000 REM
+5010 REM     PRINT SCORE
+5020 REM
+5030 PRINT "SCORE:"
+5040 PRINT "     COMPUTER ";C
+5050 PRINT "     HUMAN    ";H
+5060 PRINT
+5070 RETURN
+5500 REM
+5510 REM     CONVERT Q(1-P9) INTO G$(1-P9)
+5520 REM
+5530 FOR S=1 TO P9
+5540 G$(S)=MID$(L$,Q(S),1)
+5550 NEXT S
+5560 RETURN
+6000 REM
+6010 REM     CONVERT Q(1-P9) TO H$(1-P9)
+6020 REM
+6030 FOR S=1 TO P9
+6040 H$(S)=MID$(L$,Q(S),1)
+6050 NEXT S
+6060 RETURN
+6500 REM
+6510 REM     COPY H$ INTO G$
+6520 REM
+6530 FOR S=1 TO P9
+6540 G$(S)=H$(S)
+6550 NEXT S
+6560 RETURN
+8000 REM     PROGRAM DATA FOR COLOR NAMES
+8010 DATA BLACK,WHITE,RED,GREEN,ORANGE,YELLOW,PURPLE,TAN
+9998 REM   ...WE'RE SORRY BUT IT'S TIME TO GO...
+9999 END
diff --git a/36_Flip_Flop/pascal/README.md b/00_Alternate_Languages/60_Mastermind/pascal/README.md
similarity index 100%
rename from 36_Flip_Flop/pascal/README.md
rename to 00_Alternate_Languages/60_Mastermind/pascal/README.md
diff --git a/00_Alternate_Languages/60_Mastermind/perl/README.md b/00_Alternate_Languages/60_Mastermind/perl/README.md
new file mode 100644
index 00000000..67786f32
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/perl/README.md
@@ -0,0 +1,7 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
+
+This is pretty much a re-implementation of the BASIC, taking advantage
+of Perl's array functionality and working directly with the alphabetic
+color codes.
diff --git a/00_Alternate_Languages/60_Mastermind/perl/mastermind.pl b/00_Alternate_Languages/60_Mastermind/perl/mastermind.pl
new file mode 100644
index 00000000..87364852
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/perl/mastermind.pl
@@ -0,0 +1,419 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'state' and 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use List::Util qw{ min sum };   # Convenient list utilities
+use Term::ReadLine;     # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+use constant MAX_GUESSES    => 10;
+
+print <<'EOD';
+                               MASTERMIND
+               Creative Computing  Morristown, New Jersey
+
+
+EOD
+
+=begin comment
+
+     MASTERMIND II
+     STEVE NORTH
+     CREATIVE COMPUTING
+     PO BOX 789-M MORRISTOWN NEW JERSEY 07960
+
+=end comment
+
+=cut
+
+# NOTE that mixed-case 'my' variables are 'global' in the sense that
+# they are used in subroutines, but not passed to them.
+
+say '';
+
+my $number_of_colors = get_input(
+    'Number of colors [1-8]: ',
+    sub { m/ \A [1-8] \z /smx },
+    "No more than 8, please!\n",
+);
+
+say '';
+
+my $Number_of_Positions = get_input(
+    'Number of positions: ',
+    sub { m/ \A [0-9]+ \z /smx && $ARG },
+    "A positive number, please\n",
+);
+
+say '';
+
+my $number_of_rounds = get_input(
+    'Number of rounds: ',
+    sub { m/ \A [0-9]+ \z /smx && $ARG },
+    "A positive number, please\n",
+);
+
+my $P = $number_of_colors ** $Number_of_Positions;
+say 'Total possibilities = ', $P;
+
+my @colors = ( qw{
+    Black White Red Green Orange Yellow Purple Tan
+})[ 0 .. $number_of_colors - 1 ];
+my @Color_Codes = map { uc substr $ARG, 0, 1 } @colors;
+
+print <<'EOD';
+
+
+Color        Letter
+=====        ======
+EOD
+
+foreach my $inx ( 0 .. $#colors ) {
+    printf "%-13s%s\n", $colors[$inx], $Color_Codes[$inx];
+}
+
+say '';
+
+my $computer_score = 0;  # Computer score
+my $human_score = 0;  # Human score
+
+foreach my $round_number ( 1 .. $number_of_rounds ) {
+
+    print <<"EOD";
+
+Round number $round_number ----
+
+Guess my combination.
+
+EOD
+
+    $human_score += human_guesses( $Number_of_Positions );
+
+    print_score( $computer_score, $human_score );
+
+    $computer_score += computer_guesses();
+
+    print_score( $computer_score, $human_score );
+
+}
+
+# Make a $pattern into a hash with one key for each possible color. The
+# value for each color is the number of times it appears in the pattern.
+sub hashify_pattern {
+    my $pattern = uc $ARG[0];
+    my %p = map { $ARG => 0 } @Color_Codes;
+    $p{$ARG}++ for split qr//, $pattern;
+    return \%p;
+}
+
+# Given a $pattern, a $guess at that pattern, and $black and $white
+# scores, return a true value if the $black and $white scores of the
+# $guess are those supplied as arguments; otherwise return a false
+# value. This is used by computer_guesses() to eliminate possibilities.
+sub analyze_black_white {
+    my ( $pattern, $guess, $black, $white ) = @ARG;
+    my $info = analyze_guess( $pattern, $guess );
+    return $info->{black} == $black && $info->{white} == $white;
+}
+
+# Given a $pattern and a $guess at that pattern, return a reference to a
+# hash with the following keys:
+#  {guess} is the guess;
+#  {black} is the black score of the guess
+#  {white} is the white score of the guess
+sub analyze_guess {
+    my ( $pattern, $guess ) = @ARG;
+    my $pattern_hash = hashify_pattern( $pattern );
+    my $guess_hash = hashify_pattern( $guess );
+    my $white = sum(
+        map { min( $pattern_hash->{$ARG}, $guess_hash->{$ARG} ) } @Color_Codes,
+    );
+    my $black = 0;
+    foreach my $inx ( 0 .. length( $pattern ) - 1 ) {
+        if ( substr( $pattern, $inx, 1 ) eq substr( $guess, $inx, 1 ) )
+        {
+            $black++;
+            --$white;
+        }
+    }
+    return +{
+        guess   => $guess,
+        black   => $black,
+        white   => $white,
+    }
+}
+
+# Used by the computer to guess the human's choice. The return is the
+# number of guesses the computer took. The return is the maximum plus
+# one if the computer failed to guess.
+sub computer_guesses {
+
+    print <<'EOD';
+
+Now I guess. Think of a combination.
+EOD
+    get_input(
+        'Hit  when ready:',
+    );
+
+    # Generate all possible permutations.
+    my @possible;
+    foreach my $permutation ( 0 .. @Color_Codes ** $Number_of_Positions - 1 ) {
+        my $guess;
+        for ( 1 .. $Number_of_Positions ) {
+            my $inx = $permutation % @Color_Codes;
+            $guess .= $Color_Codes[ $inx ];
+            $permutation = int( $permutation / @Color_Codes );
+        }
+        push @possible, $guess;
+    }
+
+    # Guess ...
+    foreach my $guess_num ( 1 .. MAX_GUESSES ) {
+
+        # Guess a possible permutation at random, removing it from the
+        # list.
+        my $guess = splice @possible, int rand @possible, 1;
+        say 'My guess is: ', $guess;
+
+        # Find out its black/white score.
+        my ( $black, $white ) = split qr< , >smx, get_input(
+            'Blacks, Whites: ',
+            sub { m/ \A [0-9]+ , [0-9]+ \z /smx },
+            "Please enter two unsigned integers\n",
+        );
+
+        # If it's all black, the computer wins.
+        if ( $black == $Number_of_Positions ) {
+            say "I got it in $guess_num moves!";
+            return $guess_num;
+        }
+
+        # Eliminate all possible permutations that give the black/white
+        # score that our guess got. If there are any left, take another
+        # guess.
+        next if @possible = grep { analyze_black_white( $ARG, $guess, $black,
+            $white ) } @possible;
+
+        # There were no permutations left. Complain.
+        print <<'EOD';
+You have given me inconsistent information.
+Try again, and this time please be more careful.
+EOD
+
+        goto &computer_guesses; # Tail-call ourselves to try again.
+    }
+
+    print <<'EOD';
+I used up all my moves!
+I guess my CPU is just having an off day.
+EOD
+
+    return MAX_GUESSES + 1;
+}
+
+# Used to generate a pattern and process the human's guesses. The return
+# is the number of guesses the human took. The return is the maximum
+# plus one if the human failed to guess.
+sub human_guesses {
+
+    my @saved_moves;  # Saved moves
+    my $pattern = uc join '',
+        map { $Color_Codes[ rand @Color_Codes ] } 1 .. $Number_of_Positions;
+
+    foreach my $guess_num ( 1 .. MAX_GUESSES ) {
+
+        my $guess = uc get_input(
+            "Move # $guess_num guess: ",
+            sub {
+
+                # If the user entered 'quit', bail out.
+                if ( m/ \A quit \z /smxi ) {
+                    die "Quitter!  My combination was $pattern\n\nGood bye\n";
+                }
+
+                # If the user entered 'board', display the board so far.
+                # We return success to prevent the warning message, but
+                # we also clear $ARG. The caller's caller sees this and
+                # re-queries.
+                if ( m/ \A board \z /smxi ) {
+                    print <<'EOD';
+
+Board
+Move     Guess          Black     White
+EOD
+                    my $number = 1;
+                    foreach my $item ( @saved_moves ) {
+                        printf "%4d     %-13s  %3d       %3d\n", $number++,
+                        @{ $item }{ qw{ guess black white } };
+                    }
+                    return undef;   # Validation failure, but suppress warning.
+                }
+
+                # End of special-case code. Below here we are dealing
+                # with guess input.
+
+                # The length of the input must equal the number of
+                # positions.
+                if ( $Number_of_Positions != length ) {
+                    warn "Bad number of positions\n";
+                    return 0;
+                }
+
+                # The input may contain only valid color codes.
+                state $invalid_color = do { # Evaluated only once
+                    local $LIST_SEPARATOR = '';
+                    qr< [^@Color_Codes] >smxi;
+                };
+                if ( m/ ( $invalid_color ) /smxi ) {
+                    warn "'$1' is unrecognized.\n";
+                    return 0;
+                }
+
+                # We're good.
+                return 1;
+            },
+             "Please enter 'board', 'quit', or any $Number_of_Positions of @{[
+                 join ', ', map { qq<'$ARG'> } @Color_Codes ]}.\n",
+        );
+
+        my $rslt = analyze_guess( $pattern, $guess );
+
+        push @saved_moves, $rslt;
+
+        if ( $rslt->{black} == $Number_of_Positions ) {
+            say "You guessed it in $guess_num moves.";
+            return $guess_num;
+        }
+
+        say "You have $rslt->{black} blacks and $rslt->{white} whites.";
+
+    }
+
+    print <<"EOD";
+You ran out of moves.  That's all you get.
+
+The actual combination was: $pattern
+EOD
+
+    return MAX_GUESSES + 1;
+}
+
+# Print the $computer and $human score
+sub print_score {
+    my ( $computer, $human ) = @ARG;
+    print <<"EOD";
+Score:
+     Computer: $computer
+        Human: $human
+EOD
+    return;
+}
+
+# Get input from the user. The arguments are:
+# * The prompt
+# * A reference to validation code. This code receives the response in
+#   $ARG and returns true for a valid response.
+# * A warning to print if the response is not valid. This must end in a
+#   return. It is suppressed if the validation code returned undef.
+# The first valid response is returned. An end-of-file terminates the
+# script.
+sub get_input {
+    my ( $prompt, $validate, $warning ) = @ARG;
+
+    # If no validator is passed, default to one that always returns
+    # true.
+    $validate ||= sub { 1 };
+
+    # Create the readline object. The 'state' causes the variable to be
+    # initialized only once, no matter how many times this subroutine is
+    # called. The do { ... } is a compound statement used because we
+    # need to tweak the created object before we store it.
+    state $term = do {
+        my $obj = Term::ReadLine->new( 'reverse' );
+        $obj->ornaments( 0 );
+        $obj;
+    };
+
+    while ( 1 ) {   # Iterate indefinitely
+
+        # Read the input into the topic variable, localized to prevent
+        # Spooky Action at a Distance. We exit on undef, which signals
+        # end-of-file.
+        exit unless defined( local $ARG = $term->readline( $prompt ) );
+
+        # Return the input if it is valid.
+        return $ARG if my $rslt = $validate->();
+
+        # Issue the warning, and go around the merry-go-round again.
+        warn $warning if defined $rslt;
+    }
+}
+
+# NOTE the following is unused, but left in place in case someone wants
+# to add a 'Do you want instructions?'
+#
+# Get a yes-or-no answer. The argument is the prompt, which will have
+# '? [y/n]: ' appended. The donkey work is done by get_input(), which is
+# requested to validate the response as beginning with 'y' or 'n',
+# case-insensitive. The return is a true value for 'y' and a false value
+# for 'n'.
+sub get_yes_no {
+    my ( $prompt ) = @ARG;
+    state $map_answer = {
+        n   => 0,
+        y   => 1,
+    };
+    my $resp = lc get_input(
+        "$prompt? [y/n]: ",
+        sub { m/ \A [yn] /smxi },
+        "Please respond 'y' or 'n'\n",
+    );
+    return $map_answer->{ substr $resp, 0, 1 };
+}
+
+__END__
+
+=head1 TITLE
+
+mastermind - Play the game 'Mastermind' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ mastermind.pl
+
+=head1 DETAILS
+
+This Perl script is a port of mastermind, which is the 60th
+entry in Basic Computer Games.
+
+This is pretty much a re-implementation of the BASIC, taking advantage
+of Perl's array functionality and working directly with the alphabetic
+color codes.
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :
diff --git a/00_Alternate_Languages/60_Mastermind/python/README.md b/00_Alternate_Languages/60_Mastermind/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/60_Mastermind/python/mastermind.py b/00_Alternate_Languages/60_Mastermind/python/mastermind.py
new file mode 100644
index 00000000..b7fcf641
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/python/mastermind.py
@@ -0,0 +1,259 @@
+import random
+import sys
+
+
+def main():
+
+    global colors, color_letters, num_positions, num_colors, human_score, computer_score
+    colors = ["BLACK", "WHITE", "RED", "GREEN", "ORANGE", "YELLOW", "PURPLE", "TAN"]
+    color_letters = "BWRGOYPT"
+
+    num_colors = 100
+    human_score = 0
+    computer_score = 0
+
+    # get user inputs for game conditions
+    print("Mastermind")
+    print("Creative Computing Morristown, New Jersey")
+    while num_colors > 8:
+        num_colors = int(input("Number of colors (max 8): "))  # C9 in BASIC
+    num_positions = int(input("Number of positions: "))  # P9 in BASIC
+    num_rounds = int(input("Number of rounds: "))  # R9 in BASIC
+    possibilities = num_colors**num_positions
+    all_possibilities = [1] * possibilities
+
+    print(f"Number of possibilities {possibilities}")
+    print("Color\tLetter")
+    print("=====\t======")
+    for element in range(0, num_colors):
+        print(f"{colors[element]}\t{colors[element][0]}")
+
+    current_round = 1
+
+    while current_round <= num_rounds:
+        print(f"Round number {current_round}")
+        num_moves = 1
+        guesses = []
+        turn_over = False
+        print("Guess my combination ...")
+        answer = int(possibilities * random.random())
+        numeric_answer = [-1] * num_positions
+        for i in range(0, answer):
+            numeric_answer = get_possibility(numeric_answer)
+        # human_readable_answer = make_human_readable(numeric_answer)
+        while num_moves < 10 and not turn_over:
+            print(f"Move # {num_moves} Guess : ")
+            user_command = input("Guess ")
+            if user_command == "BOARD":
+                print_board(guesses)  # 2000
+            elif user_command == "QUIT":  # 2500
+                human_readable_answer = make_human_readable(numeric_answer)
+                print(f"QUITTER! MY COMBINATION WAS: {human_readable_answer}")
+                print("GOOD BYE")
+                quit()
+            elif len(user_command) != num_positions:  # 410
+                print("BAD NUMBER OF POSITIONS")
+            else:
+                invalid_letters = get_invalid_letters(user_command)
+                if invalid_letters > "":
+                    print(f"INVALID GUESS: {invalid_letters}")
+                else:
+                    guess_results = compare_two_positions(
+                        user_command, make_human_readable(numeric_answer)
+                    )
+                    print(f"Results: {guess_results}")
+                    if guess_results[1] == num_positions:  # correct guess
+                        turn_over = True
+                        print(f"You guessed it in {num_moves} moves!")
+                        human_score = human_score + num_moves
+                        print_score()
+                    else:
+                        print(
+                            "You have {} blacks and {} whites".format(
+                                guess_results[1], guess_results[2]
+                            )
+                        )
+                        num_moves = num_moves + 1
+                        guesses.append(guess_results)
+        if not turn_over:  # RAN OUT OF MOVES
+            print("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!")
+            print(
+                "THE ACTUAL COMBINATION WAS: {}".format(
+                    make_human_readable(numeric_answer)
+                )
+            )
+            human_score = human_score + num_moves
+            print_score()
+
+        # COMPUTER TURN
+        guesses = []
+        turn_over = False
+        inconsistent_information = False
+        while not turn_over and not inconsistent_information:
+            all_possibilities = [1] * possibilities
+            num_moves = 1
+            inconsistent_information = False
+            print("NOW I GUESS. THINK OF A COMBINATION.")
+            input("HIT RETURN WHEN READY: ")
+            while num_moves < 10 and not turn_over and not inconsistent_information:
+                found_guess = False
+                computer_guess = int(possibilities * random.random())
+                if (
+                    all_possibilities[computer_guess] == 1
+                ):  # random guess is possible, use it
+                    found_guess = True
+                    guess = computer_guess
+                else:
+                    for i in range(computer_guess, possibilities):
+                        if all_possibilities[i] == 1:
+                            found_guess = True
+                            guess = i
+                            break
+                    if not found_guess:
+                        for i in range(0, computer_guess):
+                            if all_possibilities[i] == 1:
+                                found_guess = True
+                                guess = i
+                                break
+                if not found_guess:  # inconsistent info from user
+                    print("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.")
+                    print("TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.")
+                    turn_over = True
+                    inconsistent_information = True
+                else:
+                    numeric_guess = [-1] * num_positions
+                    for i in range(0, guess):
+                        numeric_guess = get_possibility(numeric_guess)
+                    human_readable_guess = make_human_readable(numeric_guess)
+                    print(f"My guess is: {human_readable_guess}")
+                    blacks, whites = input("ENTER BLACKS, WHITES (e.g. 1,2): ").split(
+                        ","
+                    )
+                    blacks = int(blacks)
+                    whites = int(whites)
+                    if blacks == num_positions:  # Correct guess
+                        print(f"I GOT IT IN {num_moves} MOVES")
+                        turn_over = True
+                        computer_score = computer_score + num_moves
+                        print_score()
+                    else:
+                        num_moves += 1
+                        for i in range(0, possibilities):
+                            if all_possibilities[i] == 0:  # already ruled out
+                                continue
+                            numeric_possibility = [-1] * num_positions
+                            for j in range(0, i):
+                                numeric_possibility = get_possibility(
+                                    numeric_possibility
+                                )
+                            human_readable_possibility = make_human_readable(
+                                numeric_possibility
+                            )  # 4000
+                            comparison = compare_two_positions(
+                                human_readable_possibility, human_readable_guess
+                            )
+                            print(comparison)
+                            if (blacks > comparison[1]) or (whites > comparison[2]):
+                                all_possibilities[i] = 0
+            if not turn_over:  # COMPUTER DID NOT GUESS
+                print("I USED UP ALL MY MOVES!")
+                print("I GUESS MY CPU IS JUST HAVING AN OFF DAY.")
+                computer_score = computer_score + num_moves
+                print_score()
+        current_round += 1
+    print_score(is_final_score=True)
+    sys.exit()
+
+
+# 470
+def get_invalid_letters(user_command):
+    """Makes sure player input consists of valid colors for selected game configuration."""
+    valid_colors = color_letters[:num_colors]
+    invalid_letters = ""
+    for letter in user_command:
+        if letter not in valid_colors:
+            invalid_letters = invalid_letters + letter
+    return invalid_letters
+
+
+# 2000
+def print_board(guesses):
+    """Prints previous guesses within the round."""
+    print("Board")
+    print("Move\tGuess\tBlack White")
+    for idx, guess in enumerate(guesses):
+        print(f"{idx + 1}\t{guess[0]}\t{guess[1]}     {guess[2]}")
+
+
+# 3500
+# Easily the place for most optimization, since they generate every possibility
+# every time when checking for potential solutions
+# From the original article:
+#    "We did try a version that kept an actual list of all possible combinations
+#    (as a string array), which was significantly faster than this versionn but
+#    which ate tremendous amounts of memory."
+def get_possibility(possibility):
+    # print(possibility)
+    if possibility[0] > -1:  # 3530
+        current_position = 0  # Python arrays are zero-indexed
+        while True:
+            if possibility[current_position] < num_colors - 1:  # zero-index again
+                possibility[current_position] += 1
+                return possibility
+            else:
+                possibility[current_position] = 0
+                current_position += 1
+    else:  # 3524
+        possibility = [0] * num_positions
+    return possibility
+
+
+# 4500
+def compare_two_positions(guess, answer):
+    """Returns blacks (correct color and position) and whites (correct color only) for candidate position (guess) versus reference position (answer)."""
+    increment = 0
+    blacks = 0
+    whites = 0
+    initial_guess = guess
+    for pos in range(0, num_positions):
+        if guess[pos] != answer[pos]:
+            for pos2 in range(0, num_positions):
+                if not (
+                    guess[pos] != answer[pos2] or guess[pos2] == answer[pos2]
+                ):  # correct color but not correct place
+                    whites = whites + 1
+                    answer = answer[:pos2] + chr(increment) + answer[pos2 + 1 :]
+                    guess = guess[:pos] + chr(increment + 1) + guess[pos + 1 :]
+                    increment = increment + 2
+        else:  # correct color and placement
+            blacks = blacks + 1
+            # THIS IS DEVIOUSLY CLEVER
+            guess = guess[:pos] + chr(increment + 1) + guess[pos + 1 :]
+            answer = answer[:pos] + chr(increment) + answer[pos + 1 :]
+            increment = increment + 2
+    return [initial_guess, blacks, whites]
+
+
+# 5000 + logic from 1160
+def print_score(is_final_score=False):
+    """Prints score after each turn ends, including final score at end of game."""
+    if is_final_score:
+        print("GAME OVER")
+        print("FINAL SCORE:")
+    else:
+        print("SCORE:")
+    print(f"     COMPUTER {computer_score}")
+    print(f"     HUMAN    {human_score}")
+
+
+# 4000, 5500, 6000 subroutines are all identical
+def make_human_readable(num):
+    """Make the numeric representation of a position human readable."""
+    retval = ""
+    for i in range(0, len(num)):
+        retval = retval + color_letters[int(num[i])]
+    return retval
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/60_Mastermind/ruby/README.md b/00_Alternate_Languages/60_Mastermind/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/60_Mastermind/rust/README.md b/00_Alternate_Languages/60_Mastermind/rust/README.md
new file mode 100644
index 00000000..7e85f9a1
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/rust/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)
diff --git a/00_Alternate_Languages/60_Mastermind/rust/src/main.rs b/00_Alternate_Languages/60_Mastermind/rust/src/main.rs
new file mode 100644
index 00000000..5bef7f97
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/rust/src/main.rs
@@ -0,0 +1,421 @@
+use rand::{Rng, prelude::{thread_rng, ThreadRng}};
+use std::{io, fmt::Display, str::FromStr};
+
+//DATA
+const COLORS: [&str;8] = ["Black ", "White ","Red ","Green ","Orange ","Yellow ", "Purple ", "Tan "]; //all available colors
+const LETTERS: &str = "BWRGOYPT"; //letters representing the above colors
+
+struct CODE {
+    code: Vec, //maybe use a char array later, idk
+
+}
+impl CODE {
+    /**
+     * create generic, empty code
+     */
+    fn new() -> CODE {
+        return CODE{code: Vec::new()};
+    }
+    /**
+     * generates and returns a random CODE with the given parameters
+     */
+    fn new_random(rng: &mut ThreadRng, num_colors: usize, num_positions: usize) -> CODE {
+        //data
+        let mut code = CODE{code: Vec::new()};
+        //generate random combination of colors
+        for _i in 0..num_positions {
+            code.code.push(rng.gen_range(0..num_colors));
+        }
+        return code;
+    }
+    /**
+     * converts input_int from base 10 to base num_colors to generate the code
+     * input_int must be between 0 and num_colors.pow(num_positions)
+     */
+    fn new_from_int(mut input_int: usize, num_colors: usize, num_positions: usize) -> CODE {
+        //DATA
+        let mut converted_number:Vec<_> = Vec::new();
+        assert!(2 <= num_colors && num_colors <= 36); //if num_colors is outside of this range, things break later on
+
+        //convert input_int into a code by effectively converting input_int from base 10 to base n where n is num_colors, uses some fancy stuff to do this
+        loop {
+            converted_number.push(std::char::from_digit((input_int % num_colors) as u32, num_colors as u32).unwrap()); //
+            input_int /= num_colors;
+            if input_int == 0 {break}
+        }
+
+        while converted_number.len() < num_positions {converted_number.push('0');} // fill remaining space with zero's
+        let converted_number: Vec<_> = converted_number.iter().rev().map(|e| e.to_digit(num_colors as u32).unwrap() as usize).collect(); //reverse the vector and convert it to integers
+        return CODE{code: converted_number};
+    }
+    /**
+     * returns a code parsed from the passed string
+     */
+    fn new_from_string(input_string: String, num_colors: usize) -> Option {
+        let valid_chars = &LETTERS[0..num_colors];
+        //DATA
+        let new_code = CODE{
+            code:
+            input_string.to_ascii_uppercase().chars() //get an iterator with all the chars in input string converted to uppercase
+            .filter( |c| { valid_chars.contains(*c)}) //remove chars that aren't in LETTERS
+            .map( |x| -> usize {valid_chars.find(x).expect("invalid character")})//convert all the chars into usizes representing their index in LETTERS
+            .collect() //wrap this iterator up into a vector
+        };
+        //if code is empty, return None, otherwise return Some(code)
+        if new_code.code.is_empty() {return None;}
+        else {return Some(new_code);}
+    }
+
+    /**
+     * returns a string containing the code represented as characters
+     */
+    fn _as_human_readible_chars(&self) -> String {
+        return self.code.iter().map(|i|->char{LETTERS.chars().nth(*i).expect("index out of bounds")}).collect();
+    }
+    /**
+     * returns a string containing the code represented as words
+     */
+    fn _as_human_readible_words(&self) -> String {
+        return self.code.iter().map(|i|->&str{COLORS.iter().nth(*i).expect("index out of bounds")}).collect();
+    }
+}
+struct GUESS {
+    code: CODE,
+    blacks: usize,
+    whites: usize,
+}
+impl GUESS {
+    /**
+     * create a new guess, and evaluate it
+     */
+    fn new(code: CODE) -> GUESS {
+        return GUESS{code:code, blacks:0,whites:0 };
+    }
+
+    /**
+     * evaulates itself for the number of black and white pegs it should have for a given answer
+     */
+    fn evaluate(&mut self, answer:&CODE) {
+        //data
+        let mut consumed = vec![false;answer.code.len()];
+
+        if self.code.code.len() != answer.code.len() {
+            panic!("only codes of the same length can be compared");
+        }
+
+        for i in 0..answer.code.len() {
+            if self.code.code[i] == answer.code[i] { //correct value correct place
+                self.blacks += 1;
+                consumed[i] = true;
+            }
+            else {
+                //check for correct value incorrect place, don't count positions that are already exact matches
+                for j in 0..answer.code.len() {
+                    if !consumed[j] && self.code.code[i] == answer.code[j] && self.code.code[j] != answer.code[j] {
+                        self.whites += 1;
+                        consumed[j] = true;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
+
+fn main() {
+    //DATA
+    let mut rng = thread_rng();
+    let num_colors: usize;
+    let num_positions: usize;
+    let num_rounds: usize;
+    let num_guesses: usize;
+    let total_posibilities: usize;
+
+    let mut human_score: usize = 0;
+    let mut computer_score: usize = 0;
+
+    //print welcome message
+    welcome();
+
+    //ask user for a number of colors, positions, and rounds
+    num_colors = get_number_from_user_input("NUMBER OF COLORS", "", 1, COLORS.len());
+    num_positions = get_number_from_user_input("NUMBER OF POSITIONS", "", 2, 10);
+    num_rounds = get_number_from_user_input("NUMBER OF ROUNDS", "", 1, 10);
+    num_guesses = get_number_from_user_input("NUMBER OF GUESSES", "", 10, 0);
+
+
+    //print number of posibilities
+    total_posibilities = num_colors.pow(num_positions as u32);
+    println!("\nTOTAL POSSIBILITIES = {}\n", total_posibilities);
+
+    //print color letter table
+    print_color_letter_table(num_colors);
+
+    //game loop
+    for round_num in 1..=num_rounds {
+        //data
+        let mut num_moves: usize = 1;
+        let mut answer: CODE;
+        let mut guess: GUESS;
+        let mut guesses: Vec = Vec::new();
+        let mut all_possibilities = vec![true; total_posibilities];
+
+
+        //print round number
+        println!("\n\nROUND NUMBER: {}", round_num);
+
+        //human player is code-breaker, computer is code-maker
+        //generate a combination
+        answer = CODE::new_random(&mut rng, num_colors, num_positions);
+        //println!("CODE: {:?}", answer._as_human_readible_chars()); //this is for troubleshooting, prints the code converted back into characters
+
+        //round loop
+        loop {
+            //loop condition
+            if num_moves > num_guesses {
+                println!("YOU RAN OUT OF MOVES!  THAT'S ALL YOU GET!");
+                println!("THE ACTUAL COMBINATION WAS: {}", answer._as_human_readible_chars());
+                human_score += num_moves;
+                print_scores(human_score,computer_score);
+                break;
+            }
+
+            //input loop
+            guess = GUESS::new(loop {
+                println!("\nMOVE # {} GUESS: ", num_moves);
+
+                //get player move
+                let mut raw_input = String::new(); //temp variable to store user input
+                io::stdin().read_line(&mut raw_input).expect("CANNOT READ INPUT!"); //read user input from standard input and store it to raw_input
+
+                //attempt to parse input
+                if raw_input.trim().eq_ignore_ascii_case("board") {
+                    //print the board state
+                    print_board(&guesses);
+                    continue; //run loop again
+                }
+                else if raw_input.trim().eq_ignore_ascii_case("quit") {
+                    //quit the game
+                    println!("QUITTER!  MY COMBINATION WAS: {}\nGOOD BYE", answer._as_human_readible_words());
+                    return; //exit the game
+                }
+                else {
+                    //parse input for a code
+                    match CODE::new_from_string(raw_input, num_colors) {
+                        Some(code) => {
+                            //ensure code is correct length
+                            if code.code.len() != num_positions { // if not
+                                println!("BAD NUMBER OF POSITIONS.");
+                                continue; //run loop again
+                            }
+                            else {break code;}//break with the code
+                        },
+                        None => continue, //run loop again
+                    }
+                }
+            });
+
+            //evaluate guess
+            guess.evaluate(&answer);
+            let blacks = guess.blacks;
+            let whites = guess.whites;
+            //add guess to the list of guesses
+            guesses.push(guess);
+
+            //tell human the results
+            if blacks >= num_positions { //guessed it correctly
+                println!("YOU GUESSED IT IN {} MOVES!", num_moves);
+                human_score += num_moves;
+                print_scores(human_score,computer_score);
+                break; //break from loop
+            } else { //didn't
+                println!("YOU HAVE {} BLACKS AND {} WHITES.", blacks, whites);
+                //increment moves
+                num_moves += 1;
+            }
+        }
+
+        //computer is code-breaker, human player is code-maker
+        println!("\nNOW I GUESS.  THINK OF A COMBINATION.\nHIT RETURN WHEN READY: ");
+        //prompt user to give a valid combination #730
+        //input loop
+        answer = loop {
+            let mut raw_input = String::new(); //temp variable to store user input
+            io::stdin().read_line(&mut raw_input).expect("CANNOT READ INPUT!"); //read user input from standard input and store it to raw_input
+
+            //attempt to create a code from the user input, if successful break the loop returning the code
+            if let Some(code) = CODE::new_from_string(raw_input, num_colors) {
+                if code.code.len() == num_positions {break code;} //exit loop with code
+                else {println!("CODE MUST HAVE {} POSITIONS", num_positions);continue;} //tell them to try again
+            }
+
+            println!("INVALID CODE.  TRY AGAIN"); //if unsuccessful, this is printed and the loop runs again
+        };
+
+        //reset some things in preparation for computer play
+        guesses.clear();
+        num_moves = 0;
+        //let num_colors = *answer.code.iter().max().unwrap(); //figure out the number of colors from the code | Commented bc we're enforcing that the computer cracks the same size code as the human
+        //let num_positions = answer.code.len(); //figure out the number of positions from the code | Commented bc we're enforcing that the computer cracks the same size code as the human
+
+        //round loop
+        loop {
+            //loop condition
+            if num_moves > num_guesses {
+                println!("I USED UP ALL MY MOVES!");
+                println!("I GUESS MY CPU IS JUST HAVING AN OFF DAY.");
+                computer_score += num_moves;
+                print_scores(human_score,computer_score);
+                break;
+            }
+
+            //randomly generate a guess //770
+            let mut guess_int = rng.gen_range(0..total_posibilities);
+            guess = GUESS::new(CODE::new());
+            //if it's possible, use it //780
+            if all_possibilities[guess_int] {
+                guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess
+            }
+            else {//if it's not possible:
+                //  search all possibilities after guess, use first valid one //790
+                for g in guess_int..total_posibilities {
+                    if all_possibilities[g] {
+                        guess_int=g;
+                        guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess
+                        break;
+                    }
+                }
+                //if none was found
+                //  search all possibilities before guess, use first valid one //820
+                if guess.code.code.is_empty() {
+                    for g in (0..guess_int).rev() {
+                        if all_possibilities[g] {
+                            guess_int=g;
+                            guess = GUESS::new(CODE::new_from_int(guess_int, num_colors, num_positions)); //create guess
+                            break;
+                        }
+                    }
+                }
+                // if none where found, tell the user and start over #850
+                if guess.code.code.is_empty() {
+                    println!("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.");
+                    println!("PLAY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.");
+                    return; //exit game
+                };
+            }
+
+            //convert guess into something readible #890
+            //print it #940
+            println!("MY GUESS IS: {}", guess.code._as_human_readible_chars());
+            //ask user for feedback, #980
+            let blacks=get_number_from_user_input("BLACKS: ", "", 0, num_positions);
+            let whites=get_number_from_user_input("WHITES: ", "", 0, num_positions);
+
+            //if we got it, end #990
+            if blacks >= num_positions { //guessed it correctly
+                println!("I GOT IT IN {} MOVES!", num_moves);
+                computer_score += num_moves;
+                print_scores(human_score,computer_score);
+                break; //break from loop
+            } else { //didn't
+                all_possibilities[guess_int] = false;
+                //if we didn't, eliminate the combinations that don't work
+                //we know the number of black and white pegs for a valid answer, so eleminate all that get different amounts
+                all_possibilities.iter_mut().enumerate().for_each(|b| {
+                    if *b.1 { //filter out ones we already know aren't possible
+                        let mut tmp_guess = GUESS::new(CODE::new_from_int(b.0, num_colors, num_positions));
+                        tmp_guess.evaluate(&answer);
+                        if blacks > tmp_guess.blacks || whites > tmp_guess.whites { //if number of blacks/whites is different, set it to false
+                            *b.1 = false;
+                        }
+                    }
+                });
+
+                //increment moves
+                num_moves += 1;
+            }
+
+
+        }
+
+    }
+}
+
+/**
+ * print the welcome message
+ */
+fn welcome() {
+    println!("
+                             MASTERMIND
+              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+
+
+    ");
+}
+
+/**
+ * print scores
+ */
+fn print_scores(human_score:usize, computer_score:usize) {
+    println!("SCORE\n\tCOMPUTER: {}\n\tHUMAN: {}", computer_score, human_score);
+}
+
+/**
+ * print the color - letter table
+ * only prints the first num_colors pairs
+ */
+fn print_color_letter_table(num_colors: usize) {
+    println!("COLOR\tLETTER");
+    println!("=====\t======");
+    for i in 0..num_colors {
+        println!("{}\t{}", COLORS[i], &LETTERS[i..i+1]);
+    }
+}
+
+fn print_board(guesses: &Vec) {
+    println!("BOARD");
+    println!("MOVE\tGUESS\t\tBLACK\tWhite");
+    for guess in guesses.iter().enumerate() {
+        println!("{}\t{}\t\t{}\t{}", guess.0,guess.1.code._as_human_readible_chars(),guess.1.blacks,guess.1.whites);
+    }
+
+}
+
+/**
+ * gets a number from user input
+ * pass an empty &str for error_message if you don't want one printed
+ * pass a min lower  than the max to have minimun and maximun bounds
+ * pass a min higher than the max to only have a minumum bound
+ * pass a min equal   to  the max to only have a maximun bound
+ */
+fn get_number_from_user_input(prompt: &str, error_message: &str, min:T, max:T) -> T {
+    //DATA
+    let mut raw_input = String::new(); // temporary variable for user input that can be parsed later
+
+    //input loop
+    return loop {
+
+        //print prompt
+        println!("{}", prompt);
+        //read user input from standard input, and store it to raw_input
+        raw_input.clear(); //clear input
+        io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!");
+
+        //from input, try to read a number
+        if let Ok(i) = raw_input.trim().parse() {
+            //what bounds must the input fall into
+            if min < max {  //have a min and max bound: [min,max]
+                if i >= min && i <= max {//is input valid, within bounds
+                    break i; //exit the loop with the value i, returning it
+                } else {println!("ONLY BETWEEN {} AND {}, PLEASE!", min, max);} //print error message specific to this case
+            } else if min > max { //only a min bound: [min, infinity)
+                if i >= min {break i;} else {println!("NO LESS THAN {}, PLEASE!", min);}
+            } else { //only a max bound: (-infinity, max]
+                if i <= max {break i;} else {println!("NO MORE THAN {}, PLEASE!", max);}
+            }
+            continue; //continue to the next loop iteration
+        };
+        //this is only reached if a number couldn't be parsed from the input
+        if !error_message.is_empty() {println!("{}",error_message);} //if they gave an error message to use, print it
+    };
+}
diff --git a/00_Alternate_Languages/60_Mastermind/vbnet/Mastermind.sln b/00_Alternate_Languages/60_Mastermind/vbnet/Mastermind.sln
new file mode 100644
index 00000000..5ea0a369
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/vbnet/Mastermind.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Mastermind", "Mastermind.vbproj", "{B32A8054-8790-4810-93A8-CD0C740CEBD5}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B32A8054-8790-4810-93A8-CD0C740CEBD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B32A8054-8790-4810-93A8-CD0C740CEBD5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B32A8054-8790-4810-93A8-CD0C740CEBD5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B32A8054-8790-4810-93A8-CD0C740CEBD5}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/60_Mastermind/vbnet/Mastermind.vbproj b/00_Alternate_Languages/60_Mastermind/vbnet/Mastermind.vbproj
new file mode 100644
index 00000000..dc0b7890
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/vbnet/Mastermind.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Mastermind
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/60_Mastermind/vbnet/README.md b/00_Alternate_Languages/60_Mastermind/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/60_Mastermind/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/61_Math_Dice/README.md b/00_Alternate_Languages/61_Math_Dice/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/61_Math_Dice/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/61_Math_Dice/mathdice.bas b/00_Alternate_Languages/61_Math_Dice/mathdice.bas
new file mode 100644
index 00000000..a62a7d8c
--- /dev/null
+++ b/00_Alternate_Languages/61_Math_Dice/mathdice.bas
@@ -0,0 +1,60 @@
+10 PRINT TAB(31);"MATH DICE"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+40 PRINT "THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE."
+50 PRINT "WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION"
+60 PRINT "MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY."
+70 PRINT "TO CONCLUDE THE LESSON, TYPE CONTROL-C AS YOUR ANSWER."
+80 PRINT
+90 PRINT
+100 N=N+1
+110 D=INT(6*RND(1)+1)
+120 PRINT" ----- "
+130 IF D=1 THEN 200
+140 IF D=2 THEN 180
+150 IF D=3 THEN 180
+160 PRINT "I * * I"
+170 GOTO 210
+180 PRINT "I *   I"
+190 GOTO 210
+200 PRINT "I     I"
+210 IF D=2 THEN 260
+220 IF D=4 THEN 260
+230 IF D=6 THEN 270
+240 PRINT "I  *  I"
+250 GOTO 280
+260 PRINT "I     I"
+265 GOTO 280
+270 PRINT "I * * I"
+280 IF D=1 THEN 350
+290 IF D=2 THEN 330
+300 IF D=3 THEN 330
+310 PRINT "I * * I"
+320 GOTO 360
+330 PRINT "I   * I"
+340 GOTO 360
+350 PRINT "I     I"
+360 PRINT " ----- "
+370 PRINT
+375 IF N=2 THEN 500
+380 PRINT "   +"
+381 PRINT
+400 A=D
+410 GOTO 100
+500 T=D+A
+510 PRINT "      =";
+520 INPUT T1
+530 IF T1=T THEN 590
+540 PRINT "NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER."
+541 PRINT "      =";
+550 INPUT T2
+560 IF T2=T THEN 590
+570 PRINT "NO, THE ANSWER IS";T
+580 GOTO 600
+590 PRINT "RIGHT!"
+600 PRINT
+601 PRINT "THE DICE ROLL AGAIN..."
+610 PRINT
+615 N=0
+620 GOTO 100
+999 END
diff --git a/61_Math_Dice/pascal/README.md b/00_Alternate_Languages/61_Math_Dice/pascal/README.md
similarity index 100%
rename from 61_Math_Dice/pascal/README.md
rename to 00_Alternate_Languages/61_Math_Dice/pascal/README.md
diff --git a/61_Math_Dice/pascal/mathdice.pas b/00_Alternate_Languages/61_Math_Dice/pascal/mathdice.pas
similarity index 100%
rename from 61_Math_Dice/pascal/mathdice.pas
rename to 00_Alternate_Languages/61_Math_Dice/pascal/mathdice.pas
diff --git a/00_Alternate_Languages/62_Mugwump/README.md b/00_Alternate_Languages/62_Mugwump/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/Game.cs b/00_Alternate_Languages/62_Mugwump/csharp/Game.cs
new file mode 100644
index 00000000..bf72d44e
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/Game.cs
@@ -0,0 +1,36 @@
+using System;
+using System.Linq;
+
+namespace Mugwump
+{
+    internal class Game
+    {
+        private readonly Grid _grid;
+
+        private Game(Random random)
+        {
+            _grid = new Grid(Enumerable.Range(1, 4).Select(id => new Mugwump(id, random.Next(10), random.Next(10))));
+        }
+
+        public static void Play(Random random) => new Game(random).Play();
+
+        private void Play()
+        {
+            for (int turn = 1; turn <= 10; turn++)
+            {
+                var guess = Input.ReadGuess($"Turn no. {turn} -- what is your guess");
+
+                if (_grid.Check(guess))
+                {
+                    Console.WriteLine();
+                    Console.WriteLine($"You got them all in {turn} turns!");
+                    return;
+                }
+            }
+
+            Console.WriteLine();
+            Console.WriteLine("Sorry, that's 10 tries.  Here is where they're hiding:");
+            _grid.Reveal();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/Grid.cs b/00_Alternate_Languages/62_Mugwump/csharp/Grid.cs
new file mode 100644
index 00000000..dd89c638
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/Grid.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Mugwump
+{
+    internal class Grid
+    {
+        private readonly List _mugwumps;
+
+        public Grid(IEnumerable mugwumps)
+        {
+            _mugwumps = mugwumps.ToList();
+        }
+
+        public bool Check(Position guess)
+        {
+            foreach (var mugwump in _mugwumps.ToList())
+            {
+                var (found, distance) = mugwump.FindFrom(guess);
+
+                Console.WriteLine(found ? $"You have found {mugwump}" : $"You are {distance} units from {mugwump}");
+                if (found)
+                {
+                    _mugwumps.Remove(mugwump);
+                }
+            }
+
+            return _mugwumps.Count == 0;
+        }
+
+        public void Reveal()
+        {
+            foreach (var mugwump in _mugwumps.ToList())
+            {
+                Console.WriteLine(mugwump.Reveal());
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/Input.cs b/00_Alternate_Languages/62_Mugwump/csharp/Input.cs
new file mode 100644
index 00000000..97222c3e
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/Input.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+
+namespace Mugwump
+{
+    // Provides input methods which emulate the BASIC interpreter's keyboard input routines
+    internal static class Input
+    {
+        internal static Position ReadGuess(string prompt)
+        {
+            Console.WriteLine();
+            Console.WriteLine();
+            var input = ReadNumbers(prompt, 2);
+            return new Position(input[0], input[1]);
+        }
+
+        private static void Prompt(string text = "") => Console.Write($"{text}? ");
+
+        private static List ReadNumbers(string prompt, int requiredCount)
+        {
+            var numbers = new List();
+
+            while (!TryReadNumbers(prompt, requiredCount, numbers))
+            {
+                prompt = "";
+            }
+
+            return numbers;
+        }
+
+        private static bool TryReadNumbers(string prompt, int requiredCount, List numbers)
+        {
+            Prompt(prompt);
+            var inputValues = ReadStrings();
+
+            foreach (var value in inputValues)
+            {
+                if (numbers.Count == requiredCount)
+                {
+                    Console.WriteLine("!Extra input ingored");
+                    return true;
+                }
+
+                if (!TryParseNumber(value, out var number))
+                {
+                    return false;
+                }
+
+                numbers.Add(number);
+            }
+
+            return numbers.Count == requiredCount || TryReadNumbers("?", requiredCount, numbers);
+        }
+
+        private static string[] ReadStrings() => Console.ReadLine().Split(',', StringSplitOptions.TrimEntries);
+
+        private static bool TryParseNumber(string text, out float number)
+        {
+            if (float.TryParse(text, out number)) { return true; }
+
+            Console.WriteLine("!Number expected - retry input line");
+            number = default;
+            return false;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/Mugwump.cs b/00_Alternate_Languages/62_Mugwump/csharp/Mugwump.cs
new file mode 100644
index 00000000..bd117c63
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/Mugwump.cs
@@ -0,0 +1,20 @@
+namespace Mugwump
+{
+    internal class Mugwump
+    {
+        private readonly int _id;
+        private readonly Position _position;
+
+        public Mugwump(int id, int x, int y)
+        {
+            _id = id;
+            _position = new Position(x, y);
+        }
+
+        public (bool, Distance) FindFrom(Position guess) => (guess == _position, guess - _position);
+
+        public string Reveal() => $"{this} is at {_position}";
+
+        public override string ToString() => $"Mugwump {_id}";
+    }
+}
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/Mugwump.csproj b/00_Alternate_Languages/62_Mugwump/csharp/Mugwump.csproj
new file mode 100644
index 00000000..fc2efa30
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/Mugwump.csproj
@@ -0,0 +1,11 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+  
+    
+  
+
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/Mugwump.sln b/00_Alternate_Languages/62_Mugwump/csharp/Mugwump.sln
new file mode 100644
index 00000000..ab99858a
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/Mugwump.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Mugwump", "Mugwump.csproj", "{DB23BDB0-10A4-4771-B942-E646A1A5C416}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{DB23BDB0-10A4-4771-B942-E646A1A5C416}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DB23BDB0-10A4-4771-B942-E646A1A5C416}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DB23BDB0-10A4-4771-B942-E646A1A5C416}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DB23BDB0-10A4-4771-B942-E646A1A5C416}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {1FE34948-9066-4F57-A4C1-423293A430C5}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/Offset.cs b/00_Alternate_Languages/62_Mugwump/csharp/Offset.cs
new file mode 100644
index 00000000..c62e3862
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/Offset.cs
@@ -0,0 +1,16 @@
+using System;
+
+namespace Mugwump
+{
+    internal class Distance
+    {
+        private readonly float _value;
+
+        public Distance(float deltaX, float deltaY)
+        {
+            _value = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY);
+        }
+
+        public override string ToString() => $"{_value:0.0}";
+    }
+}
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/Position.cs b/00_Alternate_Languages/62_Mugwump/csharp/Position.cs
new file mode 100644
index 00000000..6005ae8b
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/Position.cs
@@ -0,0 +1,9 @@
+namespace Mugwump
+{
+    internal record Position(float X, float Y)
+    {
+        public override string ToString() => $"( {X} , {Y} )";
+
+        public static Distance operator -(Position p1, Position p2) => new(p1.X - p2.X, p1.Y - p2.Y);
+    }
+}
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/Program.cs b/00_Alternate_Languages/62_Mugwump/csharp/Program.cs
new file mode 100644
index 00000000..6121b81d
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/Program.cs
@@ -0,0 +1,33 @@
+using System;
+using System.Reflection;
+
+namespace Mugwump
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            DisplayIntro();
+
+            var random = new Random();
+
+            while (true)
+            {
+                Game.Play(random);
+
+                Console.WriteLine();
+                Console.WriteLine("That was fun! Let's play again.......");
+                Console.WriteLine("Four more mugwumps are now in hiding.");
+            }
+        }
+
+        private static void DisplayIntro()
+        {
+            using var stream = Assembly.GetExecutingAssembly()
+                .GetManifestResourceStream("Mugwump.Strings.Intro.txt");
+            using var stdout = Console.OpenStandardOutput();
+
+            stream.CopyTo(stdout);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/README.md b/00_Alternate_Languages/62_Mugwump/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/62_Mugwump/csharp/Strings/Intro.txt b/00_Alternate_Languages/62_Mugwump/csharp/Strings/Intro.txt
new file mode 100644
index 00000000..ea46087a
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/csharp/Strings/Intro.txt
@@ -0,0 +1,14 @@
+                                 Mugwump
+               Creative Computing  Morristown, New Jersey
+
+
+
+The object of this game is to find four mugwumps
+hidden on a 10 by 10 grid.  Homebase is position 0,0.
+Any guess you make must be two numbers with each
+number between 0 and 9, inclusive.  First number
+is distance to right of homebase and second number
+is distance above homebase.
+
+You get 10 tries.  After each try, I will tell
+you how far you are from each wugwump.
diff --git a/00_Alternate_Languages/62_Mugwump/java/README.md b/00_Alternate_Languages/62_Mugwump/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/62_Mugwump/java/src/Mugwump.java b/00_Alternate_Languages/62_Mugwump/java/src/Mugwump.java
new file mode 100644
index 00000000..a35ce845
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/java/src/Mugwump.java
@@ -0,0 +1,186 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Mugwump
+ * 

+ * Based on the Basic game of Mugwump here + * https://github.com/coding-horror/basic-computer-games/blob/main/62%20Mugwump/mugwump.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. + */ + +public class Mugwump { + + public static final int NUMBER_OF_MUGWUMPS = 4; + + public static final int MAX_TURNS = 10; + + public static final int FOUND = -1; + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + INIT, + GAME_START, + PLAY_TURN + } + + // Current game state + private GAME_STATE gameState; + + int[][] mugwumpLocations; + + int turn; + + public Mugwump() { + kbScanner = new Scanner(System.in); + gameState = GAME_STATE.INIT; + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + case INIT: + intro(); + gameState = GAME_STATE.GAME_START; + + break; + + case GAME_START: + + turn = 0; + + // initialise all array elements with 0 + mugwumpLocations = new int[NUMBER_OF_MUGWUMPS][2]; + + // Place 4 mugwumps + for (int i = 0; i < NUMBER_OF_MUGWUMPS; i++) { + for (int j = 0; j < 2; j++) { + mugwumpLocations[i][j] = (int) (Math.random() * 10); + } + } + gameState = GAME_STATE.PLAY_TURN; + break; + + case PLAY_TURN: + turn++; + String locations = displayTextAndGetInput("TURN NO." + turn + " -- WHAT IS YOUR GUESS? "); + int distanceRightGuess = getDelimitedValue(locations, 0); + int distanceUpGuess = getDelimitedValue(locations, 1); + + int numberFound = 0; + for (int i = 0; i < NUMBER_OF_MUGWUMPS; i++) { + + if (mugwumpLocations[i][0] == FOUND) { + numberFound++; + } + + int right = mugwumpLocations[i][0]; + int up = mugwumpLocations[i][1]; + + if (right == distanceRightGuess && up == distanceUpGuess) { + if (right != FOUND) { + System.out.println("YOU HAVE FOUND MUGWUMP " + (i + 1)); + mugwumpLocations[i][0] = FOUND; + } + numberFound++; + } else { + // Not found so show distance + if (mugwumpLocations[i][0] != FOUND) { + double distance = Math.sqrt((Math.pow(right - distanceRightGuess, 2.0d)) + + (Math.pow(up - distanceUpGuess, 2.0d))); + + System.out.println("YOU ARE " + (int) ((distance * 10) / 10) + " UNITS FROM MUGWUMP"); + } + } + } + + if (numberFound == NUMBER_OF_MUGWUMPS) { + System.out.println("YOU GOT THEM ALL IN " + turn + " TURNS!"); + gameState = GAME_STATE.GAME_START; + } else if (turn >= MAX_TURNS) { + System.out.println("SORRY, THAT'S " + MAX_TURNS + " TRIES. HERE IS WHERE THEY'RE HIDING"); + for (int i = 0; i < NUMBER_OF_MUGWUMPS; i++) { + if (mugwumpLocations[i][0] != FOUND) { + System.out.println("MUGWUMP " + (i + 1) + " IS AT (" + + mugwumpLocations[i][0] + "," + mugwumpLocations[i][1] + ")"); + } + } + gameState = GAME_STATE.GAME_START; + } + + // Game ended? + if (gameState != GAME_STATE.PLAY_TURN) { + System.out.println("THAT WAS FUN! LET'S PLAY AGAIN......."); + System.out.println("FOUR MORE MUGWUMPS ARE NOW IN HIDING."); + } + } + // Infinite loop - based on original basic version + } while (true); + } + + private void intro() { + System.out.println(addSpaces(33) + "MUGWUMP"); + System.out.println(addSpaces(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS"); + System.out.println("HIDDEN ON A 10 BY 10 GRID. HOMEBASE IS POSITION 0,0."); + System.out.println("ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH"); + System.out.println("NUMBER BETWEEN 0 AND 9, INCLUSIVE. FIRST NUMBER"); + System.out.println("IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER"); + System.out.println("IS DISTANCE ABOVE HOMEBASE."); + System.out.println(); + System.out.println("YOU GET 10 TRIES. AFTER EACH TRY, I WILL TELL"); + System.out.println("YOU HOW FAR YOU ARE FROM EACH MUGWUMP."); + } + + /** + * Accepts a string delimited by comma's and returns the pos'th delimited + * value (starting at count 0). + * + * @param text - text with values separated by comma's + * @param pos - which position to return a value for + * @return the int representation of the value + */ + private int getDelimitedValue(String text, int pos) { + String[] tokens = text.split(","); + return Integer.parseInt(tokens[pos]); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.nextLine(); + } + + /** + * Return a string of x spaces + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String addSpaces(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + + public static void main(String[] args) { + + Mugwump mugwump = new Mugwump(); + mugwump.play(); + } +} diff --git a/00_Alternate_Languages/62_Mugwump/javascript/README.md b/00_Alternate_Languages/62_Mugwump/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/62_Mugwump/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/62_Mugwump/javascript/mugwump.html b/00_Alternate_Languages/62_Mugwump/javascript/mugwump.html new file mode 100644 index 00000000..1d590487 --- /dev/null +++ b/00_Alternate_Languages/62_Mugwump/javascript/mugwump.html @@ -0,0 +1,9 @@ + + +MUGWUMP + + +


+
+
+
diff --git a/00_Alternate_Languages/62_Mugwump/javascript/mugwump.js b/00_Alternate_Languages/62_Mugwump/javascript/mugwump.js
new file mode 100644
index 00000000..6ae35a87
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/javascript/mugwump.js
@@ -0,0 +1,117 @@
+// MUGWUMP
+//
+// 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 p = [];
+
+// Main program
+async function main()
+{
+    print(tab(33) + "MUGWUMP\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    // Courtesy People's Computer Company
+    print("THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS\n");
+    print("HIDDEN ON A 10 BY 10 GRID.  HOMEBASE IS POSITION 0,0.\n");
+    print("ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH\n");
+    print("NUMBER BETWEEN 0 AND 9, INCLUSIVE.  FIRST NUMBER\n");
+    print("IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER\n");
+    print("IS DISTANCE ABOVE HOMEBASE.\n");
+    print("\n");
+    print("YOU GET 10 TRIES.  AFTER EACH TRY, I WILL TELL\n");
+    print("YOU HOW FAR YOU ARE FROM EACH MUGWUMP.\n");
+    print("\n");
+    while (1) {
+        for (i = 1; i <= 4; i++) {
+            p[i] = [];
+            for (j = 1; j <= 2; j++) {
+                p[i][j] = Math.floor(10 * Math.random());
+            }
+        }
+        t = 0;
+        do {
+            t++;
+            print("\n");
+            print("\n");
+            print("TURN NO. " + t + " -- WHAT IS YOUR GUESS");
+            str = await input();
+            m = parseInt(str);
+            n = parseInt(str.substr(str.indexOf(",") + 1));
+            for (i = 1; i <= 4; i++) {
+                if (p[i][1] == -1)
+                    continue;
+                if (p[i][1] == m && p[i][2] == n) {
+                    p[i][1] = -1;
+                    print("YOU HAVE FOUND MUGWUMP " + i + "\n");
+                } else {
+                    d = Math.sqrt(Math.pow(p[i][1] - m, 2) + Math.pow(p[i][2] - n, 2));
+                    print("YOU ARE " + Math.floor(d * 10) / 10 + " UNITS FROM MUGWUMP " + i + "\n");
+                }
+            }
+            for (j = 1; j <= 4; j++) {
+                if (p[j][1] != -1)
+                    break;
+            }
+            if (j > 4) {
+                print("\n");
+                print("YOU GOT THEM ALL IN " + t + " TURNS!\n");
+                break;
+            }
+        } while (t < 10) ;
+        if (t == 10) {
+            print("\n");
+            print("SORRY, THAT'S 10 TRIES.  HERE IS WHERE THEY'RE HIDING:\n");
+            for (i = 1; i <= 4; i++) {
+                if (p[i][1] != -1)
+                    print("MUGWUMP " + i + " IS AT (" + p[i][1] + "," + p[i][2] + ")\n");
+            }
+        }
+        print("\n");
+        print("THAT WAS FUN! LET'S PLAY AGAIN.......\n");
+        print("FOUR MORE MUGWUMPS ARE NOW IN HIDING.\n");
+    }
+}
+
+main();
diff --git a/00_Alternate_Languages/62_Mugwump/mugwump.bas b/00_Alternate_Languages/62_Mugwump/mugwump.bas
new file mode 100644
index 00000000..e238486d
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/mugwump.bas
@@ -0,0 +1,56 @@
+1 PRINT TAB(33);"MUGWUMP"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+4 REM     COURTESY PEOPLE'S COMPUTER COMPANY
+10 DIM P(4,2)
+20 PRINT "THE OBJECT OF THIS GAME IS TO FIND FOUR MUGWUMPS"
+30 PRINT "HIDDEN ON A 10 BY 10 GRID.  HOMEBASE IS POSITION 0,0."
+40 PRINT "ANY GUESS YOU MAKE MUST BE TWO NUMBERS WITH EACH"
+50 PRINT "NUMBER BETWEEN 0 AND 9, INCLUSIVE.  FIRST NUMBER"
+60 PRINT "IS DISTANCE TO RIGHT OF HOMEBASE AND SECOND NUMBER"
+70 PRINT "IS DISTANCE ABOVE HOMEBASE."
+80 PRINT
+90 PRINT "YOU GET 10 TRIES.  AFTER EACH TRY, I WILL TELL"
+100 PRINT "YOU HOW FAR YOU ARE FROM EACH MUGWUMP."
+110 PRINT
+240 GOSUB 1000
+250 T=0
+260 T=T+1
+270 PRINT
+275 PRINT
+290 PRINT "TURN NO.";T;"-- WHAT IS YOUR GUESS";
+300 INPUT M,N
+310 FOR I=1 TO 4
+320 IF P(I,1)=-1 THEN 400
+330 IF P(I,1)<>M THEN 380
+340 IF P(I,2)<>N THEN 380
+350 P(I,1)=-1
+360 PRINT "YOU HAVE FOUND MUGWUMP";I
+370 GOTO 400
+380 D=SQR((P(I,1)-M)^2+(P(I,2)-N)^2)
+390 PRINT "YOU ARE";(INT(D*10))/10;"UNITS FROM MUGWUMP";I
+400 NEXT I
+410 FOR J=1 TO 4
+420 IF P(J,1)<>-1 THEN 470
+430 NEXT J
+440 PRINT
+450 PRINT "YOU GOT THEM ALL IN";T;"TURNS!"
+460 GOTO 580
+470 IF T<10 THEN 260
+480 PRINT
+490 PRINT "SORRY, THAT'S 10 TRIES.  HERE IS WHERE THEY'RE HIDING:"
+540 FOR I=1 TO 4
+550 IF P(I,1)=-1 THEN 570
+560 PRINT "MUGWUMP";I;"IS AT (";P(I,1);",";P(I,2);")"
+570 NEXT I
+580 PRINT
+600 PRINT "THAT WAS FUN! LET'S PLAY AGAIN......."
+610 PRINT "FOUR MORE MUGWUMPS ARE NOW IN HIDING."
+630 GOTO 240
+1000 FOR J=1 TO 2
+1010 FOR I=1 TO 4
+1020 P(I,J)=INT(10*RND(1))
+1030 NEXT I
+1040 NEXT J
+1050 RETURN
+1099 END
diff --git a/37_Football/pascal/README.md b/00_Alternate_Languages/62_Mugwump/pascal/README.md
similarity index 100%
rename from 37_Football/pascal/README.md
rename to 00_Alternate_Languages/62_Mugwump/pascal/README.md
diff --git a/00_Alternate_Languages/62_Mugwump/perl/README.md b/00_Alternate_Languages/62_Mugwump/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/62_Mugwump/perl/mugwump.pl b/00_Alternate_Languages/62_Mugwump/perl/mugwump.pl
new file mode 100644
index 00000000..13a50bff
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/perl/mugwump.pl
@@ -0,0 +1,95 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+# global variables defined here
+my(@MUGWUMP) = ();
+
+# subroutines defined here
+
+# init_mugwump: pick the random places for the Mugwumps
+sub init_mugwump() {
+    @MUGWUMP = ();
+    for (1 .. 4) {
+        push @MUGWUMP, [ int(rand 10), int(rand 10) ];
+    }
+}
+
+
+# main code starts here
+
+# print introductory text
+print <);
+        my($M,$N) = split(/,/,$in);
+        $M = int($M);
+        $N = int($N);
+
+        for my $i (0 .. $#MUGWUMP) {
+            # -1 indicates a Mugwump that was already found
+            next if $MUGWUMP[$i]->[0] == -1;
+
+            if ($MUGWUMP[$i]->[0] == $M && $MUGWUMP[$i]->[1] == $N) {
+                $MUGWUMP[$i]->[0] = -1;
+                printf("You have found Mugwump %d\n", $i+1);
+            } else {
+                my $d = sqrt(($MUGWUMP[$i]->[0] - $M) ** 2 + ($MUGWUMP[$i]->[1] - $N) ** 2);
+                printf("You are %.1f units away from Mugwump %d\n", $d, $i+1);
+            }
+        }
+
+        # If a Mugwump still has not been found,
+        # go to the next turn
+        for my $j (0 .. $#MUGWUMP) {
+            if ($MUGWUMP[$j]->[0] != -1) {
+                next TURN;
+            }
+        }
+        # You win!
+        printf("You got all of them in %d %s!\n\n", $turn, ($turn == 1 ? 'turn' : 'turns'));
+        # Pass execution down to the continue block
+        next PLAY;
+
+    } # end of TURN loop
+
+    print "\nSorry, that's 10 tries.  Here's where they're hiding:\n";
+    for my $i (0 .. $#MUGWUMP) {
+        printf("Mugwump %d is at (%d, %d)\n", $i+1, $MUGWUMP[$i]->[0], $MUGWUMP[$i]->[1])
+            if $MUGWUMP[$i]->[0] != -1;
+    }
+}
+continue {
+    print "\nThat was fun! Let's play again.......\n";
+    print "Four more Mugwumps are now in hiding.\n\n";
+}
diff --git a/00_Alternate_Languages/62_Mugwump/python/README.md b/00_Alternate_Languages/62_Mugwump/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/62_Mugwump/python/mugwump.py b/00_Alternate_Languages/62_Mugwump/python/mugwump.py
new file mode 100644
index 00000000..c5722407
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/python/mugwump.py
@@ -0,0 +1,82 @@
+from math import sqrt
+from random import randint
+
+
+def introduction():
+    print(
+        """The object of this game is to find 4 mugwumps
+hidden on a 10*10 grid.  Homebase is position 0,0.
+Any guess you make must be two numbers with each
+number between 0 and 9 inclusive.  First number
+is distance to right of homebase, and second number
+is the distance above homebase."""
+    )
+
+    print(
+        """You get 10 tries.  After each try, I will tell
+you how far you are from each mugwump."""
+    )
+
+
+def generate_mugwumps(n=4):
+    mugwumps = []
+    for _ in range(n):
+        current = [randint(0, 9), randint(0, 9)]
+        mugwumps.append(current)
+    return mugwumps
+
+
+def reveal_mugwumps(mugwumps):
+    print("Sorry, that's 10 tries.  Here's where they're hiding.")
+    for idx, mugwump in enumerate(mugwumps, 1):
+        if mugwump[0] != -1:
+            print(f"Mugwump {idx} is at {mugwump[0]},{mugwump[1]}")
+
+
+def calculate_distance(guess, mugwump):
+    d = sqrt(((mugwump[0] - guess[0]) ** 2) + ((mugwump[1] - guess[1]) ** 2))
+    return d
+
+
+def play_again():
+    print("THAT WAS FUN! LET'S PLAY AGAIN.......")
+    choice = input("Press Enter to play again, any other key then Enter to quit.")
+    if choice == "":
+        print("Four more mugwumps are now in hiding.")
+    else:
+        exit()
+
+
+def play_round():
+    mugwumps = generate_mugwumps()
+    turns = 1
+    score = 0
+    while turns <= 10 and score != 4:
+        m = -1
+        while m == -1:
+            try:
+                m, n = map(int, input(f"Turn {turns} - what is your guess? ").split())
+            except ValueError:
+                m = -1
+        for idx, mugwump in enumerate(mugwumps):
+            if m == mugwump[0] and n == mugwump[1]:
+                print(f"You found mugwump {idx + 1}")
+                mugwumps[idx][0] = -1
+                score += 1
+            if mugwump[0] == -1:
+                continue
+            print(
+                f"You are {calculate_distance((m, n), mugwump):.1f} units from mugwump {idx + 1}"
+            )
+        turns += 1
+    if score == 4:
+        print(f"Well done! You got them all in {turns} turns.")
+    else:
+        reveal_mugwumps(mugwumps)
+
+
+if __name__ == "__main__":
+    introduction()
+    while True:
+        play_round()
+        play_again()
diff --git a/00_Alternate_Languages/62_Mugwump/ruby/README.md b/00_Alternate_Languages/62_Mugwump/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/62_Mugwump/vbnet/Mugwump.sln b/00_Alternate_Languages/62_Mugwump/vbnet/Mugwump.sln
new file mode 100644
index 00000000..49f0dd09
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/vbnet/Mugwump.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Mugwump", "Mugwump.vbproj", "{5A0B0AE7-4148-42CB-8010-5A0683E3CF3A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{5A0B0AE7-4148-42CB-8010-5A0683E3CF3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5A0B0AE7-4148-42CB-8010-5A0683E3CF3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5A0B0AE7-4148-42CB-8010-5A0683E3CF3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5A0B0AE7-4148-42CB-8010-5A0683E3CF3A}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/62_Mugwump/vbnet/Mugwump.vbproj b/00_Alternate_Languages/62_Mugwump/vbnet/Mugwump.vbproj
new file mode 100644
index 00000000..50f8a0a1
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/vbnet/Mugwump.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Mugwump
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/62_Mugwump/vbnet/README.md b/00_Alternate_Languages/62_Mugwump/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/62_Mugwump/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/63_Name/README.md b/00_Alternate_Languages/63_Name/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/63_Name/csharp/Name.csproj b/00_Alternate_Languages/63_Name/csharp/Name.csproj
new file mode 100644
index 00000000..c73e0d16
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/csharp/Name.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    netcoreapp3.1
+  
+
+
diff --git a/00_Alternate_Languages/63_Name/csharp/Name.sln b/00_Alternate_Languages/63_Name/csharp/Name.sln
new file mode 100644
index 00000000..931d9288
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/csharp/Name.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("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Name", "Name.csproj", "{B63B5D5C-C5E0-4EFE-9EF4-292915DCC22D}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B63B5D5C-C5E0-4EFE-9EF4-292915DCC22D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B63B5D5C-C5E0-4EFE-9EF4-292915DCC22D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B63B5D5C-C5E0-4EFE-9EF4-292915DCC22D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B63B5D5C-C5E0-4EFE-9EF4-292915DCC22D}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {FCD5BEAE-D35E-49A7-B8F3-B8B3F4A8C624}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/63_Name/csharp/Program.cs b/00_Alternate_Languages/63_Name/csharp/Program.cs
new file mode 100644
index 00000000..a9c817f3
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/csharp/Program.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Name
+{
+    public class Program
+    {
+        static void Main(string[] args)
+        {
+            Console.WriteLine("NAME".CentreAlign());
+            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".CentreAlign());
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("HELLO.");
+            Console.WriteLine("MY NAME IS CREATIVE COMPUTER.");
+            Console.Write("WHAT'S YOUR NAME (FIRST AND LAST? ");
+            var name = Console.ReadLine();
+            Console.WriteLine();
+            Console.WriteLine($"THANK YOU, {name.Reverse()}.");
+            Console.WriteLine("OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART");
+            Console.WriteLine("COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!");
+            Console.WriteLine();
+            Console.WriteLine("BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.");
+            Console.WriteLine($"LET'S PUT THEM IN ORDER LIKE THIS: {name.Sort()}");
+            Console.WriteLine();
+            Console.Write("DON'T YOU LIKE THAT BETTER? ");
+            var like = Console.ReadLine();
+            Console.WriteLine();
+
+            if (like.ToUpperInvariant() == "YES")
+            {
+                Console.WriteLine("I KNEW YOU'D AGREE!!");
+            }
+            else
+            {
+                Console.WriteLine("I'M SORRY YOU DON'T LIKE IT THAT WAY.");
+            }
+
+            Console.WriteLine();
+            Console.WriteLine($"I REALLY ENJOYED MEETING YOU {name}.");
+            Console.WriteLine("HAVE A NICE DAY!");
+        }
+    }
+}
diff --git a/00_Alternate_Languages/63_Name/csharp/README.md b/00_Alternate_Languages/63_Name/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/63_Name/csharp/StringExtensions.cs b/00_Alternate_Languages/63_Name/csharp/StringExtensions.cs
new file mode 100644
index 00000000..8003fa38
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/csharp/StringExtensions.cs
@@ -0,0 +1,41 @@
+using System;
+
+namespace Name
+{
+    public static class StringExtensions
+    {
+        private const int ConsoleWidth = 120; // default console width
+
+        public static string CentreAlign(this string value)
+        {
+            int spaces = ConsoleWidth - value.Length;
+            int leftPadding = spaces / 2 + value.Length;
+
+            return value.PadLeft(leftPadding).PadRight(ConsoleWidth);
+        }
+
+        public static string Reverse(this string value)
+        {
+            if (value is null)
+            {
+                return null;
+            }
+
+            char[] characterArray = value.ToCharArray();
+            Array.Reverse(characterArray);
+            return new String(characterArray);
+        }
+
+        public static string Sort(this string value)
+        {
+            if (value is null)
+            {
+                return null;
+            }
+
+            char[] characters = value.ToCharArray();
+            Array.Sort(characters);
+            return new string(characters);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/63_Name/java/Name.java b/00_Alternate_Languages/63_Name/java/Name.java
new file mode 100644
index 00000000..7b67f489
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/java/Name.java
@@ -0,0 +1,55 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+public class Name {
+
+    public static void printempty() { System.out.println(" "); }
+
+    public static void print(String toprint) { System.out.println(toprint); }
+
+    public static void main(String[] args) {
+        print("                                          NAME");
+        print("                         CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+        printempty();
+        printempty();
+        print("HELLO.");
+        print("MY NAME iS CREATIVE COMPUTER.");
+        print("WHATS YOUR NAME? (FIRST AND LAST)");
+
+        Scanner namesc = new Scanner(System.in);
+        String name = namesc.nextLine();
+
+        String namereversed = new StringBuilder(name).reverse().toString();
+
+        char namesorted[] = name.toCharArray();
+        Arrays.sort(namesorted);
+
+        printempty();
+        print("THANK YOU, " + namereversed);
+        printempty();
+        print("OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART");
+        print("COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!");
+        printempty();
+        printempty();
+        print("BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.");
+
+        print("LET'S PUT THEM IN ORDER LIKE THIS: " + new String(namesorted));
+        printempty();
+        printempty();
+
+        print("DON'T YOU LIKE THAT BETTER?");
+        printempty();
+
+        Scanner agreementsc = new Scanner(System.in);
+        String agreement = agreementsc.nextLine();
+
+        if (agreement.equalsIgnoreCase("yes")) {
+            print("I KNEW YOU'D AGREE!!");
+        } else {
+            print("I'M SORRY YOU DON'T LIKE IT THAT WAY.");
+            printempty();
+            print("I REALLY ENJOYED MEETING YOU, " + name);
+            print("HAVE A NICE DAY!");
+        }
+    }
+}
diff --git a/00_Alternate_Languages/63_Name/java/README.md b/00_Alternate_Languages/63_Name/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/63_Name/javascript/README.md b/00_Alternate_Languages/63_Name/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/63_Name/javascript/name.html b/00_Alternate_Languages/63_Name/javascript/name.html
new file mode 100644
index 00000000..bed003f4
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/javascript/name.html
@@ -0,0 +1,9 @@
+
+
+NAME
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/63_Name/javascript/name.js b/00_Alternate_Languages/63_Name/javascript/name.js
new file mode 100644
index 00000000..3c376f59
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/javascript/name.js
@@ -0,0 +1,93 @@
+// NAME
+//
+// 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 str;
+var b;
+
+// Main program
+async function main()
+{
+    print(tab(34) + "NAME\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("HELLO.\n");
+    print("MY NAME IS CREATIVE COMPUTER.\n");
+    print("WHAT'S YOUR NAME (FIRST AND LAST)");
+    str = await input();
+    l = str.length;
+    print("\n");
+    print("THANK YOU, ");
+    for (i = l; i >= 1; i--)
+        print(str[i - 1]);
+    print(".\n");
+    print("OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART\n");
+    print("COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\n");
+    print("\n");
+    print("BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\n");
+    print("LET'S PUT THEM IN ORDER LIKE THIS: ");
+    b = [];
+    for (i = 1; i <= l; i++)
+        b[i - 1] = str.charCodeAt(i - 1);
+    b.sort();
+    for (i = 1; i <= l; i++)
+        print(String.fromCharCode(b[i - 1]));
+    print("\n");
+    print("\n");
+    print("DON'T YOU LIKE THAT BETTER");
+    ds = await input();
+    if (ds == "YES") {
+        print("\n");
+        print("I KNEW YOU'D AGREE!!\n");
+    } else {
+        print("\n");
+        print("I'M SORRY YOU DON'T LIKE IT THAT WAY.\n");
+    }
+    print("\n");
+    print("I REALLY ENJOYED MEETING YOU " + str + ".\n");
+    print("HAVE A NICE DAY!\n");
+}
+
+main();
diff --git a/00_Alternate_Languages/63_Name/name.bas b/00_Alternate_Languages/63_Name/name.bas
new file mode 100644
index 00000000..6cdf3f91
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/name.bas
@@ -0,0 +1,25 @@
+1 PRINT TAB(34);"NAME"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT: PRINT: PRINT
+5 DIM B$(40)
+10 PRINT "HELLO.": PRINT "MY NAME IS CREATIVE COMPUTER."
+20 PRINT "WHAT'S YOUR NAME (FIRST AND LAST";: INPUT A$: L=LEN(A$)
+30 PRINT: PRINT "THANK YOU, ";
+40 FOR I=1 TO L: B$(I)=MID$(A$,I,1): NEXT I
+50 FOR I=L TO 1 STEP -1: PRINT B$(I);: NEXT I
+60 PRINT ".": PRINT "OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART"
+70 PRINT "COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!": PRINT
+80 PRINT "BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER."
+90 PRINT "LET'S PUT THEM IN ORDER LIKE THIS: ";
+100 FOR J=2 TO L: I=J-1: T$=B$(J)
+110 IF T$>B$(I) THEN 130
+120 B$(I+1)=B$(I): I=I-1: IF I>0 THEN 110
+130 B$(I+1)=T$: NEXT J
+140 FOR I=1 TO L: PRINT B$(I);: NEXT I: PRINT: PRINT
+150 PRINT "DON'T YOU LIKE THAT BETTER";: INPUT D$
+160 IF D$="YES" THEN 180
+170 PRINT: PRINT "I'M SORRY YOU DON'T LIKE IT THAT WAY.": GOTO 200
+180 PRINT: PRINT "I KNEW YOU'D AGREE!!"
+200 PRINT: PRINT "I REALLY ENJOYED MEETING YOU ";A$;"."
+210 PRINT "HAVE A NICE DAY!"
+999 END
diff --git a/38_Fur_Trader/pascal/README.md b/00_Alternate_Languages/63_Name/pascal/README.md
similarity index 100%
rename from 38_Fur_Trader/pascal/README.md
rename to 00_Alternate_Languages/63_Name/pascal/README.md
diff --git a/00_Alternate_Languages/63_Name/perl/README.md b/00_Alternate_Languages/63_Name/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/63_Name/perl/name.pl b/00_Alternate_Languages/63_Name/perl/name.pl
new file mode 100644
index 00000000..512ffbb7
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/perl/name.pl
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+use strict;
+
+print ' 'x34 . "NAME\n";
+print ' 'x15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+
+print "HELLO.\n"; print "MY NAME IS CREATIVE COMPUTER.\n";
+print "WHAT'S YOUR NAME (FIRST AND LAST): ";
+chomp (my $A = );
+
+my @B= split("", $A); #Convert string to array of characters.
+
+print "\n"; print "THANK YOU, ";
+print reverse @B;
+
+print ".\n"; print "OOPS! I GUESS I GOT IT BACKWARDS. A SMART\n";
+print "COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!\n\n";
+print "BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.\n";
+print "LET'S PUT THEM IN ORDER LIKE THIS: ";
+print sort @B;
+
+print "\n\n";
+print "DON'T YOU LIKE THAT BETTER? ";
+chomp (my $D = );
+if (uc($D) eq "YES") {
+	print "\n"; print "I KNEW YOU'D AGREE!!\n";
+	} else {
+	print "\n"; print "I'M SORRY YOU DON'T LIKE IT THAT WAY.\n";
+	}
+print "\n"; print "I REALLY ENJOYED MEETING YOU $A.\n";
+print "HAVE A NICE DAY!\n";
+exit;
diff --git a/00_Alternate_Languages/63_Name/python/README.md b/00_Alternate_Languages/63_Name/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/63_Name/python/name.py b/00_Alternate_Languages/63_Name/python/name.py
new file mode 100644
index 00000000..5c567d5a
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/python/name.py
@@ -0,0 +1,62 @@
+"""
+NAME
+
+simple string manipulations on the user's name
+
+Ported by Dave LeCompte
+"""
+
+
+def print_with_tab(space_count, msg):
+    if space_count > 0:
+        spaces = " " * space_count
+    else:
+        spaces = ""
+    print(spaces + msg)
+
+
+def is_yes_ish(answer):
+    cleaned = answer.strip().upper()
+    if cleaned == "Y" or cleaned == "YES":
+        return True
+    return False
+
+
+def main():
+    print_with_tab(34, "NAME")
+    print_with_tab(15, "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+    print("HELLO.")
+    print("MY NAME iS CREATIVE COMPUTER.")
+    name = input("WHAT'S YOUR NAME (FIRST AND LAST)?")
+    print()
+    name_as_list = list(name)
+    reversed_name = "".join(name_as_list[::-1])
+    print(f"THANK YOU, {reversed_name}.")
+    print()
+    print("OOPS!  I GUESS I GOT IT BACKWARDS.  A SMART")
+    print("COMPUTER LIKE ME SHOULDN'T MAKE A MISTAKE LIKE THAT!")
+    print()
+    print()
+    print("BUT I JUST NOTICED YOUR LETTERS ARE OUT OF ORDER.")
+
+    sorted_name = "".join(sorted(name_as_list))
+    print(f"LET'S PUT THEM IN ORDER LIKE THIS: {sorted_name}")
+    print()
+    print()
+
+    print("DON'T YOU LIKE THAT BETTER?")
+    like_answer = input()
+    print()
+    if is_yes_ish(like_answer):
+        print("I KNEW YOU'D AGREE!!")
+    else:
+        print("I'M SORRY YOU DON'T LIKE IT THAT WAY.")
+    print()
+    print(f"I REALLY ENJOYED MEETING YOU, {name}.")
+    print("HAVE A NICE DAY!")
+
+
+main()
diff --git a/00_Alternate_Languages/63_Name/ruby/README.md b/00_Alternate_Languages/63_Name/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/63_Name/vbnet/Name.sln b/00_Alternate_Languages/63_Name/vbnet/Name.sln
new file mode 100644
index 00000000..29b92356
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/vbnet/Name.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Name", "Name.vbproj", "{178E4E2F-5264-47A1-9BC6-2B724E7DCC79}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{178E4E2F-5264-47A1-9BC6-2B724E7DCC79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{178E4E2F-5264-47A1-9BC6-2B724E7DCC79}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{178E4E2F-5264-47A1-9BC6-2B724E7DCC79}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{178E4E2F-5264-47A1-9BC6-2B724E7DCC79}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/63_Name/vbnet/Name.vbproj b/00_Alternate_Languages/63_Name/vbnet/Name.vbproj
new file mode 100644
index 00000000..a06d78f3
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/vbnet/Name.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Name
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/63_Name/vbnet/README.md b/00_Alternate_Languages/63_Name/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/63_Name/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/64_Nicomachus/README.md b/00_Alternate_Languages/64_Nicomachus/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/64_Nicomachus/csharp/Nicomachus.csproj b/00_Alternate_Languages/64_Nicomachus/csharp/Nicomachus.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/csharp/Nicomachus.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/64_Nicomachus/csharp/Nicomachus.sln b/00_Alternate_Languages/64_Nicomachus/csharp/Nicomachus.sln
new file mode 100644
index 00000000..5287cabf
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/csharp/Nicomachus.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nicomachus", "Nicomachus.csproj", "{AC3B6DDA-13CE-40FC-B9E0-4246390DFC20}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{AC3B6DDA-13CE-40FC-B9E0-4246390DFC20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AC3B6DDA-13CE-40FC-B9E0-4246390DFC20}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AC3B6DDA-13CE-40FC-B9E0-4246390DFC20}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AC3B6DDA-13CE-40FC-B9E0-4246390DFC20}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/64_Nicomachus/csharp/README.md b/00_Alternate_Languages/64_Nicomachus/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/64_Nicomachus/java/README.md b/00_Alternate_Languages/64_Nicomachus/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/64_Nicomachus/java/src/Nicomachus.java b/00_Alternate_Languages/64_Nicomachus/java/src/Nicomachus.java
new file mode 100644
index 00000000..9996ecd2
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/java/src/Nicomachus.java
@@ -0,0 +1,185 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Nichomachus
+ * 

+ * Based on the Basic game of Nichomachus here + * https://github.com/coding-horror/basic-computer-games/blob/main/64%20Nicomachus/nicomachus.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. + */ + +public class Nicomachus { + + public static final long TWO_SECONDS = 2000; + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + START_GAME, + GET_INPUTS, + RESULTS, + PLAY_AGAIN + } + + int remainderNumberDividedBy3; + int remainderNumberDividedBy5; + int remainderNumberDividedBy7; + + // Current game state + private GAME_STATE gameState; + + public Nicomachus() { + kbScanner = new Scanner(System.in); + gameState = GAME_STATE.START_GAME; + } + + /** + * Main game loop + */ + public void play() throws Exception { + + do { + switch (gameState) { + + case START_GAME: + intro(); + gameState = GAME_STATE.GET_INPUTS; + break; + + case GET_INPUTS: + + System.out.println("PLEASE THINK OF A NUMBER BETWEEN 1 AND 100."); + remainderNumberDividedBy3 = displayTextAndGetNumber("YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF? "); + remainderNumberDividedBy5 = displayTextAndGetNumber("YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF? "); + remainderNumberDividedBy7 = displayTextAndGetNumber("YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF? "); + + gameState = GAME_STATE.RESULTS; + + case RESULTS: + System.out.println("LET ME THINK A MOMENT..."); + // Simulate the basic programs for/next loop to delay things. + // Here we are sleeping for one second. + Thread.sleep(TWO_SECONDS); + + // Calculate the number the player was thinking of. + int answer = (70 * remainderNumberDividedBy3) + (21 * remainderNumberDividedBy5) + + (15 * remainderNumberDividedBy7); + + // Something similar was in the original basic program + // (to test if the answer was 105 and deducting 105 until it was <= 105 + while (answer > 105) { + answer -= 105; + } + + do { + String input = displayTextAndGetInput("YOUR NUMBER WAS " + answer + ", RIGHT? "); + if (yesEntered(input)) { + System.out.println("HOW ABOUT THAT!!"); + break; + } else if (noEntered(input)) { + System.out.println("I FEEL YOUR ARITHMETIC IS IN ERROR."); + break; + } else { + System.out.println("EH? I DON'T UNDERSTAND '" + input + "' TRY 'YES' OR 'NO'."); + } + } while (true); + + gameState = GAME_STATE.PLAY_AGAIN; + break; + + case PLAY_AGAIN: + System.out.println("LET'S TRY ANOTHER"); + gameState = GAME_STATE.GET_INPUTS; + break; + } + + // Original basic program looped until CTRL-C + } while (true); + } + + private void intro() { + System.out.println(addSpaces(33) + "NICOMA"); + System.out.println(addSpaces(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!"); + System.out.println(); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to an Integer + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private int displayTextAndGetNumber(String text) { + return Integer.parseInt(displayTextAndGetInput(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.nextLine(); + } + + /** + * Return a string of x spaces + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String addSpaces(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + + /** + * Checks whether player entered Y or YES to a question. + * + * @param text player string from kb + * @return true of Y or YES was entered, otherwise false + */ + private boolean yesEntered(String text) { + return stringIsAnyValue(text, "Y", "YES"); + } + + /** + * Checks whether player entered N or NO to a question. + * + * @param text player string from kb + * @return true of N or NO was entered, otherwise false + */ + private boolean noEntered(String text) { + return stringIsAnyValue(text, "N", "NO"); + } + + /** + * Check whether a string equals one of a variable number of values + * Useful to check for Y or YES for example + * Comparison is case insensitive. + * + * @param text source string + * @param values a range of values to compare against the source string + * @return true if a comparison was found in one of the variable number of strings passed + */ + private boolean stringIsAnyValue(String text, String... values) { + + return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text)); + } + + public static void main(String[] args) throws Exception { + + Nicomachus nicomachus = new Nicomachus(); + nicomachus.play(); + } +} diff --git a/00_Alternate_Languages/64_Nicomachus/javascript/README.md b/00_Alternate_Languages/64_Nicomachus/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/64_Nicomachus/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/64_Nicomachus/javascript/nicomachus.html b/00_Alternate_Languages/64_Nicomachus/javascript/nicomachus.html new file mode 100644 index 00000000..2fe069f8 --- /dev/null +++ b/00_Alternate_Languages/64_Nicomachus/javascript/nicomachus.html @@ -0,0 +1,9 @@ + + +NICOMACHUS + + +


+
+
+
diff --git a/00_Alternate_Languages/64_Nicomachus/javascript/nicomachus.js b/00_Alternate_Languages/64_Nicomachus/javascript/nicomachus.js
new file mode 100644
index 00000000..93083d78
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/javascript/nicomachus.js
@@ -0,0 +1,91 @@
+// NICOMACHUS
+//
+// 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 str;
+var b;
+
+// Main program
+async function main()
+{
+    print(tab(33) + "NICOMA\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!\n");
+    while (1) {
+        print("\n");
+        print("PLEASE THINK OF A NUMBER BETWEEN 1 AND 100.\n");
+        print("YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF");
+        a = parseInt(await input());
+        print("YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF");
+        b = parseInt(await input());
+        print("YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF");
+        c = parseInt(await input());
+        print("\n");
+        print("LET ME THINK A MOMENT...\n");
+        print("\n");
+        d = 70 * a + 21 * b + 15 * c;
+        while (d > 105)
+            d -= 105;
+        print("YOUR NUMBER WAS " + d + ", RIGHT");
+        while (1) {
+            str = await input();
+            print("\n");
+            if (str == "YES") {
+                print("HOW ABOUT THAT!!\n");
+                break;
+            } else if (str == "NO") {
+                print("I FEEL YOUR ARITHMETIC IS IN ERROR.\n");
+                break;
+            } else {
+                print("EH?  I DON'T UNDERSTAND '" + str + "'  TRY 'YES' OR 'NO'.\n");
+            }
+        }
+        print("\n");
+        print("LET'S TRY ANOTHER.\n");
+    }
+}
+
+main();
diff --git a/00_Alternate_Languages/64_Nicomachus/nicomachus.bas b/00_Alternate_Languages/64_Nicomachus/nicomachus.bas
new file mode 100644
index 00000000..d478bc3c
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/nicomachus.bas
@@ -0,0 +1,34 @@
+2 PRINT TAB(33);"NICOMA"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT: PRINT: PRINT
+10 PRINT "BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!"
+20 PRINT
+30 PRINT "PLEASE THINK OF A NUMBER BETWEEN 1 AND 100."
+40 PRINT "YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF";
+45 INPUT A
+50 PRINT "YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF";
+55 INPUT B
+60 PRINT "YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF";
+65 INPUT C
+70 PRINT
+80 PRINT "LET ME THINK A MOMENT..."
+85 PRINT
+90 FOR I=1 TO 1500: NEXT I
+100 D=70*A+21*B+15*C
+110 IF D<=105 THEN 140
+120 D=D-105
+130 GOTO 110
+140 PRINT "YOUR NUMBER WAS";D;", RIGHT";
+160 INPUT A$
+165 PRINT
+170 IF A$="YES" THEN 220
+180 IF A$="NO" THEN 240
+190 PRINT "EH?  I DON'T UNDERSTAND '";A$;"'  TRY 'YES' OR 'NO'."
+200 GOTO 160
+220 PRINT "HOW ABOUT THAT!!"
+230 GOTO 250
+240 PRINT "I FEEL YOUR ARITHMETIC IS IN ERROR."
+250 PRINT
+260 PRINT "LET'S TRY ANOTHER."
+270 GOTO 20
+999 END
diff --git a/39_Golf/pascal/README.md b/00_Alternate_Languages/64_Nicomachus/pascal/README.md
similarity index 100%
rename from 39_Golf/pascal/README.md
rename to 00_Alternate_Languages/64_Nicomachus/pascal/README.md
diff --git a/00_Alternate_Languages/64_Nicomachus/perl/README.md b/00_Alternate_Languages/64_Nicomachus/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/64_Nicomachus/perl/nicomachus.pl b/00_Alternate_Languages/64_Nicomachus/perl/nicomachus.pl
new file mode 100644
index 00000000..25485930
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/perl/nicomachus.pl
@@ -0,0 +1,44 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 33 . "NICOMA\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+print "BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!\n";
+
+
+while (1) {
+	print "\n";
+	print "PLEASE THINK OF A NUMBER BETWEEN 1 AND 100.\n";
+	print "YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF";
+	print "? "; chomp(my $A = );
+	print "YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF";
+	print "? "; chomp(my $B = );
+	print "YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF";
+	print "? "; chomp(my $C = );
+	print "\n";
+	print "LET ME THINK A MOMENT...\n";
+	print "\n";
+	for (my $I=1; $I<=1500; $I++) { }
+	my $D= 70*$A+21*$B+15*$C;
+
+	while ($D>105) {
+		$D= $D-105;
+		}
+
+	print "YOUR NUMBER WAS $D, RIGHT";
+
+	my $Flag=0;
+	do {
+		print "? "; chomp($A = uc());
+		print "\n";
+		if ($A eq "YES") { print "HOW ABOUT THAT!!\n"; $Flag=1; }
+		if ($A eq "NO") { print "I FEEL YOUR ARITHMETIC IS IN ERROR.\n"; $Flag=1; }
+		if ($Flag==0) { print "EH? I DON'T UNDERSTAND '$A' TRY 'YES' OR 'NO'.\n"; }
+		} until ($Flag==1);
+
+	print "\n";
+	print "LET'S TRY ANOTHER.\n";
+	} #goto Line20;
+exit;
diff --git a/00_Alternate_Languages/64_Nicomachus/python/README.md b/00_Alternate_Languages/64_Nicomachus/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/64_Nicomachus/python/nicomachus.py b/00_Alternate_Languages/64_Nicomachus/python/nicomachus.py
new file mode 100644
index 00000000..bcc7a8a3
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/python/nicomachus.py
@@ -0,0 +1,78 @@
+"""
+NICOMACHUS
+
+Math exercise/demonstration
+
+Ported by Dave LeCompte
+"""
+
+# PORTING NOTE
+#
+# The title, as printed ingame, is "NICOMA", hinting at a time when
+# filesystems weren't even 8.3, but could only support 6 character
+# filenames.
+
+import time
+
+
+def print_with_tab(spaces_count, msg):
+    if spaces_count > 0:
+        spaces = " " * spaces_count
+    else:
+        spaces = ""
+    print(spaces + msg)
+
+
+def get_yes_or_no():
+    while True:
+        response = input().upper()
+        if response == "YES":
+            return True
+        elif response == "NO":
+            return False
+        print(f"EH?  I DON'T UNDERSTAND '{response}'  TRY 'YES' OR 'NO'.")
+
+
+def play_game():
+    print("PLEASE THINK OF A NUMBER BETWEEN 1 AND 100.")
+    print("YOUR NUMBER DIVIDED BY 3 HAS A REMAINDER OF")
+    a = int(input())
+    print("YOUR NUMBER DIVIDED BY 5 HAS A REMAINDER OF")
+    b = int(input())
+    print("YOUR NUMBER DIVIDED BY 7 HAS A REMAINDER OF")
+    c = int(input())
+    print()
+    print("LET ME THINK A MOMENT...")
+    print()
+
+    time.sleep(2.5)
+
+    d = (70 * a + 21 * b + 15 * c) % 105
+
+    print(f"YOUR NUMBER WAS {d}, RIGHT?")
+
+    response = get_yes_or_no()
+
+    if response:
+        print("HOW ABOUT THAT!!")
+    else:
+        print("I FEEL YOUR ARITHMETIC IS IN ERROR.")
+    print()
+    print("LET'S TRY ANOTHER")
+
+
+def main():
+    print_with_tab(33, "NICOMA")
+    print_with_tab(15, "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+    print("BOOMERANG PUZZLE FROM ARITHMETICA OF NICOMACHUS -- A.D. 90!")
+    print()
+    while True:
+        play_game()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/64_Nicomachus/ruby/README.md b/00_Alternate_Languages/64_Nicomachus/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/64_Nicomachus/vbnet/Nicomachus.sln b/00_Alternate_Languages/64_Nicomachus/vbnet/Nicomachus.sln
new file mode 100644
index 00000000..bea341c4
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/vbnet/Nicomachus.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Nicomachus", "Nicomachus.vbproj", "{B4987617-A235-4CBA-A158-A668B6C36FE1}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B4987617-A235-4CBA-A158-A668B6C36FE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B4987617-A235-4CBA-A158-A668B6C36FE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B4987617-A235-4CBA-A158-A668B6C36FE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B4987617-A235-4CBA-A158-A668B6C36FE1}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/64_Nicomachus/vbnet/Nicomachus.vbproj b/00_Alternate_Languages/64_Nicomachus/vbnet/Nicomachus.vbproj
new file mode 100644
index 00000000..404fd9d9
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/vbnet/Nicomachus.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Nicomachus
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/64_Nicomachus/vbnet/README.md b/00_Alternate_Languages/64_Nicomachus/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/64_Nicomachus/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/65_Nim/README.md b/00_Alternate_Languages/65_Nim/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/65_Nim/csharp/Nim.csproj b/00_Alternate_Languages/65_Nim/csharp/Nim.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/csharp/Nim.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/65_Nim/csharp/Nim.sln b/00_Alternate_Languages/65_Nim/csharp/Nim.sln
new file mode 100644
index 00000000..dd324894
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/csharp/Nim.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nim", "Nim.csproj", "{00B15B50-9CB1-46B1-8066-5877F972EE88}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{00B15B50-9CB1-46B1-8066-5877F972EE88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{00B15B50-9CB1-46B1-8066-5877F972EE88}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{00B15B50-9CB1-46B1-8066-5877F972EE88}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{00B15B50-9CB1-46B1-8066-5877F972EE88}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/65_Nim/csharp/README.md b/00_Alternate_Languages/65_Nim/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/65_Nim/java/README.md b/00_Alternate_Languages/65_Nim/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/65_Nim/javascript/README.md b/00_Alternate_Languages/65_Nim/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/65_Nim/javascript/nim.html b/00_Alternate_Languages/65_Nim/javascript/nim.html
new file mode 100644
index 00000000..db914b25
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/javascript/nim.html
@@ -0,0 +1,9 @@
+
+
+NIM
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/65_Nim/javascript/nim.js b/00_Alternate_Languages/65_Nim/javascript/nim.js
new file mode 100644
index 00000000..ddd09d98
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/javascript/nim.js
@@ -0,0 +1,270 @@
+// NIM
+//
+// 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 a = [];
+var b = [];
+var d = [];
+
+// Main program
+async function main()
+{
+    print(tab(33) + "NIM\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    for (i = 1; i <= 100; i++) {
+        a[i] = 0;
+        b[i] = [];
+        for (j = 0; j <= 10; j++)
+            b[i][j] = 0;
+    }
+    d[0] = 0;
+    d[1] = 0;
+    d[2] = 0;
+    print("DO YOU WANT INSTRUCTIONS");
+    while (1) {
+        str = await input();
+        str = str.toUpperCase();
+        if (str == "YES" || str == "NO")
+            break;
+        print("PLEASE ANSWER YES OR NO\n");
+    }
+    if (str == "YES") {
+        print("THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS.\n");
+        print("ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND\n");
+        print("THE MACHINE ALTERNATELY.  ON YOUR TURN, YOU MAY TAKE\n");
+        print("ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST\n");
+        print("TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM\n");
+        print("ONLY ONE PILE ON A SINGLE TURN.  YOU MUST SPECIFY WHETHER\n");
+        print("WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT,\n");
+        print("THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE\n");
+        print("ORIGINALLY IN EACH PILE.  EACH PILE MAY CONTAIN A\n");
+        print("DIFFERENT NUMBER OF OBJECTS.\n");
+        print("THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE\n");
+        print("NUMBER OF OBJECTS REMAINING IN THE PILES AFTER  EACH OF ITS\n");
+        print("MOVES.\n");
+    }
+    while (1) {
+        print("\n");
+        while (1) {
+            print("ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST");
+            w = parseInt(await input());
+            if (w == 1 || w == 2)
+                break;
+        }
+        while (1) {
+            print("ENTER NUMBER OF PILES");
+            n = parseInt(await input());
+            if (n >= 1 && n <= 100)
+                break;
+        }
+        print("ENTER PILE SIZES\n");
+        for (i = 1; i <= n; i++) {
+            while (1) {
+                print(i + " ");
+                a[i] = parseInt(await input());
+                if (a[i] >= 1 && a[i] <= 2000)
+                    break;
+            }
+        }
+        print("DO YOU WANT TO MOVE FIRST");
+        while (1) {
+            str = await input();
+            str = str.toUpperCase();
+            if (str == "YES" || str == "NO")
+                break;
+            print("PLEASE ANSWER YES OR NO.\n");
+        }
+        if (str == "YES")
+            player_first = true;
+        else
+            player_first = false;
+        while (1) {
+            if (!player_first) {
+                if (w != 1) {
+                    c = 0;
+                    for (i = 1; i <= n; i++) {
+                        if (a[i] == 0)
+                            continue;
+                        c++;
+                        if (c == 3)
+                            break;
+                        d[c] = i;
+                    }
+                    if (i > n) {
+                        if (c == 2) {
+                            if (a[d[1]] == 1 || a[d[2]] == 1) {
+                                print("MACHINE WINS\n");
+                                break;
+                            }
+                        } else {
+                            if (a[d[1]] > 1)
+                                print("MACHINE WINS\n");
+                            else
+                                print("MACHINE LOSES\n");
+                            break;
+                        }
+
+                    } else {
+                        c = 0;
+                        for (i = 1; i <= n; i++) {
+                            if (a[i] > 1)
+                                break;
+                            if (a[i] == 0)
+                                continue;
+                            c++;
+                        }
+                        if (i > n && c % 2) {
+                            print("MACHINE LOSES\n");
+                            break;
+                        }
+                    }
+                }
+                for (i = 1; i <= n; i++) {
+                    e = a[i];
+                    for (j = 0; j <= 10; j++) {
+                        f = e / 2;
+                        b[i][j] = 2 * (f - Math.floor(f));
+                        e = Math.floor(f);
+                    }
+                }
+                for (j = 10; j >= 0; j--) {
+                    c = 0;
+                    h = 0;
+                    for (i = 1; i <= n; i++) {
+                        if (b[i][j] == 0)
+                            continue;
+                        c++;
+                        if (a[i] <= h)
+                            continue;
+                        h = a[i];
+                        g = i;
+                    }
+                    if (c % 2)
+                        break;
+                }
+                if (j < 0) {
+                    do {
+                        e = Math.floor(n * Math.random() + 1);
+                    } while (a[e] == 0) ;
+                    f = Math.floor(a[e] * Math.random() + 1);
+                    a[e] -= f;
+                } else {
+                    a[g] = 0;
+                    for (j = 0; j <= 10; j++) {
+                        b[g][j] = 0;
+                        c = 0;
+                        for (i = 1; i <= n; i++) {
+                            if (b[i][j] == 0)
+                                continue;
+                            c++;
+                        }
+                        a[g] = a[g] + (c % 2) * Math.pow(2, j);
+                    }
+                    if (w != 1) {
+                        c = 0;
+                        for (i = 1; i <= n; i++) {
+                            if (a[i] > 1)
+                                break;
+                            if (a[i] == 0)
+                                continue;
+                            c++;
+                        }
+                        if (i > n && c % 2 == 0)
+                            a[g] = 1 - a[g];
+                    }
+                }
+                print("PILE  SIZE\n");
+                for (i = 1; i <= n; i++)
+                    print(" " + i + "  " + a[i] + "\n");
+                if (w != 2) {
+                    if (game_completed()) {
+                        print("MACHINE WINS");
+                        break;
+                    }
+                }
+            } else {
+                player_first = false;
+            }
+            while (1) {
+                print("YOUR MOVE - PILE , NUMBER TO BE REMOVED");
+                str = await input();
+                x = parseInt(str);
+                y = parseInt(str.substr(str.indexOf(",") + 1));
+                if (x < 1 || x > n)
+                    continue;
+                if (y < 1 || y > a[x])
+                    continue;
+                break;
+            }
+            a[x] -= y;
+            if (game_completed()) {
+                print("MACHINE LOSES");
+                break;
+            }
+        }
+        print("DO YOU WANT TO PLAY ANOTHER GAME");
+        while (1) {
+            str = await input();
+            str = str.toUpperCase();
+            if (str == "YES" || str == "NO")
+                break;
+            print("PLEASE ANSWER YES OR NO.\n");
+        }
+        if (str == "NO")
+            break;
+    }
+}
+
+function game_completed()
+{
+    for (var i = 1; i <= n; i++) {
+        if (a[i] != 0)
+            return false;
+    }
+    return true;
+}
+
+main();
diff --git a/00_Alternate_Languages/65_Nim/nim.bas b/00_Alternate_Languages/65_Nim/nim.bas
new file mode 100644
index 00000000..d078a0c6
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/nim.bas
@@ -0,0 +1,156 @@
+100 PRINT TAB(33);"NIM"
+110 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+120 PRINT:PRINT:PRINT
+210 DIM A(100),B(100,10),D(2)
+220 PRINT "THIS IS THE GAME OF NIM."
+230 PRINT "DO YOU WANT INSTRUCTIONS";
+240 INPUT Z$
+250 IF Z$="NO" THEN 440
+260 IF Z$="no" THEN 440
+270 IF Z$="YES" THEN 310
+280 IF Z$="yes" THEN 310
+290 PRINT "PLEASE ANSWER YES OR NO"
+300 GOTO 240
+310 PRINT "THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS."
+320 PRINT "ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND"
+330 PRINT "THE MACHINE ALTERNATELY.  ON YOUR TURN, YOU MAY TAKE"
+340 PRINT "ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST"
+350 PRINT "TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM"
+360 PRINT "ONLY ONE PILE ON A SINGLE TURN.  YOU MUST SPECIFY WHETHER"
+370 PRINT "WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT,"
+380 PRINT "THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE"
+390 PRINT "ORIGINALLY IN EACH PILE.  EACH PILE MAY CONTAIN A"
+400 PRINT "DIFFERENT NUMBER OF OBJECTS."
+410 PRINT "THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE"
+420 PRINT "NUMBER OF OBJECTS REMAINING IN THE PILES AFTER  EACH OF ITS"
+430 PRINT "MOVES."
+440 PRINT
+450 PRINT "ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST";
+460 INPUT W
+470 IF W=1 THEN 490
+480 IF W<>2 THEN 450
+490 PRINT "ENTER NUMBER OF PILES";
+500 INPUT N
+510 IF N>100 THEN 490
+520 IF N<1 THEN 490
+530 IF N<>INT(N) THEN 490
+540 PRINT "ENTER PILE SIZES"
+550 FOR I=1 TO N
+560 PRINT I;
+570 INPUT A(I)
+580 IF A(I)>2000 THEN 560
+590 IF A(I)<1 THEN 560
+600 IF A(I)<>INT(A(I)) THEN 560
+610 NEXT I
+620 PRINT "DO YOU WANT TO MOVE FIRST";
+630 INPUT Q9$
+640 IF Q9$="YES" THEN 1450
+650 IF Q9$="yes" THEN 1450
+660 IF Q9$="NO" THEN 700
+670 IF Q9$="no" THEN 700
+680 PRINT "PLEASE ANSWER YES OR NO."
+690 GOTO 630
+700 IF W=1 THEN 940
+710 LET C=0
+720 FOR I=1 TO N
+730 IF A(I)=0 THEN 770
+740 LET C=C+1
+750 IF C=3 THEN 840
+760 LET D(C)=I
+770 NEXT I
+780 IF C=2 THEN 920
+790 IF A(D(1))>1 THEN 820
+800 PRINT "MACHINE LOSES"
+810 GOTO 1640
+820 PRINT "MACHINE WINS"
+830 GOTO 1640
+840 LET C=0
+850 FOR I=1 TO N
+860 IF A(I)>1 THEN 940
+870 IF A(I)=0 THEN 890
+880 LET C=C+1
+890 NEXT I
+900 IF C/2<>INT(C/2) THEN 800
+910 GOTO 940
+920 IF A(D(1))=1 THEN 820
+930 IF A(D(2))=1 THEN 820
+940 FOR I=1 TO N
+950 LET E=A(I)
+960 FOR J=0 TO 10
+970 LET F=E/2
+980 LET B(I,J)=2*(F-INT(F))
+990 LET E=INT(F)
+1000 NEXT J
+1010 NEXT I
+1020 FOR J=10 TO 0 STEP -1
+1030 LET C=0
+1040 LET H=0
+1050 FOR I=1 TO N
+1060 IF B(I,J)=0 THEN 1110
+1070 LET C=C+1
+1080 IF A(I)<=H THEN 1110
+1090 LET H=A(I)
+1100 LET G=I
+1110 NEXT I
+1120 IF C/2<>INT(C/2) THEN 1190
+1130 NEXT J
+1140 LET E=INT(N*RND(1)+1)
+1150 IF A(E)=0 THEN 1140
+1160 LET F=INT(A(E)*RND(1)+1)
+1170 LET A(E)=A(E)-F
+1180 GOTO 1380
+1190 LET A(G)=0
+1200 FOR J=0 TO 10
+1210 LET B(G,J)=0
+1220 LET C=0
+1230 FOR I=1 TO N
+1240 IF B(I,J)=0 THEN 1260
+1250 LET C=C+1
+1260 NEXT I
+1270 LET A(G)=A(G)+2*(C/2-INT(C/2))*2^J
+1280 NEXT J
+1290 IF W=1 THEN 1380
+1300 LET C=0
+1310 FOR I=1 TO N
+1320 IF A(I)>1 THEN 1380
+1330 IF A(I)=0 THEN 1350
+1340 LET C=C+1
+1350 NEXT I
+1360 IF C/2<>INT(C/2) THEN 1380
+1370 LET A(G)=1-A(G)
+1380 PRINT "PILE  SIZE"
+1390 FOR I=1 TO N
+1400 PRINT I;A(I)
+1410 NEXT I
+1420 IF W=2 THEN 1450
+1430 GOSUB 1570
+1440 IF Z=1 THEN 820
+1450 PRINT "YOUR MOVE - PILE, NUMBER TO BE REMOVED";
+1460 INPUT X,Y
+1470 IF X>N THEN 1450
+1480 IF X<1 THEN 1450
+1490 IF X<>INT(X) THEN 1450
+1500 IF Y>A(X) THEN 1450
+1510 IF Y<1 THEN 1450
+1520 IF Y<>INT(Y) THEN 1450
+1530 LET A(X)=A(X)-Y
+1540 GOSUB 1570
+1550 IF Z=1 THEN 800
+1560 GOTO 700
+1570 LET Z=0
+1580 FOR I=1 TO N
+1590 IF A(I)=0 THEN 1610
+1600 RETURN
+1610 NEXT I
+1620 LET Z=1
+1630 RETURN
+1640 PRINT "do you want to play another game";
+1650 INPUT Q9$
+1660 IF Q9$="YES" THEN 1720
+1670 IF Q9$="yes" THEN 1720
+1680 IF Q9$="NO" THEN 1730
+1690 IF Q9$="no" THEN 1730
+1700 PRINT "PLEASE.  YES OR NO."
+1710 GOTO 1650
+1720 GOTO 440
+1730 END
diff --git a/40_Gomoko/pascal/README.md b/00_Alternate_Languages/65_Nim/pascal/README.md
similarity index 100%
rename from 40_Gomoko/pascal/README.md
rename to 00_Alternate_Languages/65_Nim/pascal/README.md
diff --git a/00_Alternate_Languages/65_Nim/perl/README.md b/00_Alternate_Languages/65_Nim/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/65_Nim/python/README.md b/00_Alternate_Languages/65_Nim/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/65_Nim/python/Traditional_NIM.py b/00_Alternate_Languages/65_Nim/python/Traditional_NIM.py
new file mode 100644
index 00000000..c7b904ce
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/python/Traditional_NIM.py
@@ -0,0 +1,122 @@
+import random
+
+
+# Class of the Game
+class NIM:
+    def __init__(self):
+        self.piles = {1: 7, 2: 5, 3: 3, 4: 1}
+
+    def remove_pegs(self, command):
+        try:
+
+            pile, num = command.split(",")
+            num = int(num)
+            pile = int(pile)
+
+        except Exception as e:
+
+            if "not enough values" in str(e):
+                print(
+                    '\nNot a valid command. Your command should be in the form of "1,3", Try Again\n'
+                )
+
+            else:
+                print("\nError, Try again\n")
+            return None
+
+        if self._command_integrity(num, pile):
+            self.piles[pile] -= num
+        else:
+            print("\nInvalid value of either Peg or Pile\n")
+
+    def get_ai_move(self):
+        possible_pile = []
+        for k, v in self.piles.items():
+            if v != 0:
+                possible_pile.append(k)
+
+        pile = random.choice(possible_pile)
+
+        num = random.randint(1, self.piles[pile])
+
+        return pile, num
+
+    def _command_integrity(self, num, pile):
+        if pile <= 4 and pile >= 1:
+            if num <= self.piles[pile]:
+                return True
+
+        return False
+
+    def print_pegs(self):
+        for pile, peg in self.piles.items():
+            print("Pile {} : {}".format(pile, "O " * peg))
+
+    def help(self):
+        print("-" * 10)
+        print('\nThe Game is player with a number of Piles of Objects("O" == one peg)')
+        print("\nThe Piles are arranged as given below(Tradional NIM)\n")
+        self.print_pegs()
+        print(
+            '\nAny Number of of Objects are removed one pile by "YOU" and the machine alternatively'
+        )
+        print("\nOn your turn, you may take all the objects that remain in any pile")
+        print("but you must take ATLEAST one object")
+        print("\nAnd you may take objects from only one pile on a single turn.")
+        print("\nThe winner is defined as the one that picks the last remaning object")
+        print("-" * 10)
+
+    def check_for_win(self):
+        sum = 0
+        for k, v in self.piles.items():
+            sum += v
+
+        if sum == 0:
+            return True
+
+        else:
+            return False
+
+
+def main():
+    # Game initialization
+    game = NIM()
+
+    print("Hello, This is a game of NIM")
+    help = input("Do You Need Instruction (YES or NO): ")
+
+    if help.lower() == "yes":
+        game.help()
+
+    # Start game loop
+    input("\nPress Enter to start the Game:\n")
+    end = False
+    while True:
+        game.print_pegs()
+
+        # Players Move
+        command = input("\nYOUR MOVE - Number of PILE, Number of Object? ")
+        game.remove_pegs(command)
+        end = game.check_for_win()
+        if end:
+            print("\nPlayer Wins the Game, Congratulations!!")
+            input("\nPress any key to exit")
+            break
+
+        # Computers Move
+        command = game.get_ai_move()
+        print(
+            "\nA.I MOVE - A.I Removed {} pegs from Pile {}".format(
+                command[1], command[0]
+            )
+        )
+        game.remove_pegs(str(command[0]) + "," + str(command[1]))
+        end = game.check_for_win()
+        if end:
+            print("\nComputer Wins the Game, Better Luck Next Time\n")
+            input("Press any key to exit")
+            break
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/65_Nim/ruby/README.md b/00_Alternate_Languages/65_Nim/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/65_Nim/ruby/nim.rb b/00_Alternate_Languages/65_Nim/ruby/nim.rb
new file mode 100644
index 00000000..d6b157b3
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/ruby/nim.rb
@@ -0,0 +1,280 @@
+puts "NIM".center(80)
+puts"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".center(80)
+puts "\n\n\n"
+
+#210 DIM A(100),B(100,10),D(2)
+$pileArray = Array.new[100]
+$bArray = Array.new
+$dArray = Array.new[2]
+$winOption = 0 # take-last option
+$numberOfPiles = 1
+$c = 0
+$e = 0
+$f = 0
+$g = 0
+$h = 0
+
+def displayTheRules
+puts "THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS."
+puts "ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND"
+puts "THE MACHINE ALTERNATELY.  ON YOUR TURN, YOU MAY TAKE"
+puts "ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST"
+puts "TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM"
+puts "ONLY ONE PILE ON A SINGLE TURN.  YOU MUST SPECIFY WHETHER"
+puts "WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT,"
+puts "THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE"
+puts "ORIGINALLY IN EACH PILE.  EACH PILE MAY CONTAIN A"
+puts "DIFFERENT NUMBER OF OBJECTS."
+puts "THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE"
+puts "NUMBER OF OBJECTS REMAINING IN THE PILES AFTER  EACH OF ITS"
+puts "MOVES."
+end
+
+def sub1570
+    $z=0
+    for i in 1..$numberOfPiles do
+        if $pileArray[i] != 0 then
+            return
+        end
+        $z=1
+        return
+    end
+end
+
+def playAnother
+    put "do you want to play another game";
+    return gets.strip.ucase == "YES"
+end
+puts "THIS IS THE GAME OF NIM."
+print "DO YOU WANT INSTRUCTIONS?"
+240
+wantInstructions = gets.strip.upcase
+if wantInstructions == "YES" then
+    displayTheRules
+end
+#250 IF Z$="NO" THEN 440
+#260 IF Z$="no" THEN 440
+#270 IF Z$="YES" THEN displayTheRules
+#280 IF Z$="yes" THEN displayTheRules
+#290 PRINT "PLEASE ANSWER YES OR NO"
+#300 GOTO 240
+
+def sub490 # get number of piles
+    print "ENTER NUMBER OF PILES:"
+    while $numberOfPiles < 0 && $numberOfPiles <= 100 do
+        $numberOfPiles = gets.strip.to_i
+    end
+end
+
+def getPileSizes
+    puts "ENTER PILE SIZES:"
+    for i in 1..$numberOfPiles do
+        print i
+        while true do
+            $pileArray[i] = gets.strip.to_i
+            if $pileArray[i] < 2000 && $pileArray[i] > 0 then
+                break
+            end
+        end
+    end
+end
+
+def sub440 # get win option
+    puts ""
+    $winOption = 0
+    while $winOption != 1 && q != 2 do
+        puts "ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST"
+        $winOption = gets.strip.to_i
+    end
+end
+
+puts "DO YOU WANT TO MOVE FIRST?";
+#630 INPUT Q9$
+moveFirst = ""
+while moveFirst != "YES" && moveFirst != "NO" do
+    moveFirst = gets.strip.upcase
+    case moveFirst
+        when "YES"
+            yourMove
+        when "NO"
+            machineMove
+    end
+end
+
+#640 IF Q9$="YES" THEN 1450
+#650 IF Q9$="yes" THEN 1450
+#660 IF Q9$="NO" THEN 700
+#670 IF Q9$="no" THEN 700
+#680 PRINT "PLEASE ANSWER YES OR NO."
+#690 GOTO 630
+
+def machineMove
+    if $winOption == 1 then
+        sub940 # take last
+    end
+    $c=0
+    for i in 1..$numberOfPiles do
+    if $pileArray[i] != 0 then 770
+    $c=$c+1
+    if $c == 3 then
+        sub840
+    end
+        $dArray[$c-1]=i
+    end
+    end
+
+    if $c == 2 then
+        sub920
+    end
+    if $pileArray[$dArray[0]] > 1 then
+        machineWins
+    end
+    machineLoses
+end
+
+def machineLoses
+    puts "MACHINE LOSES"
+# 810 GOTO playAnother
+    if playAnother then
+        sub440 # loop for another
+    end
+end
+
+def machineWins
+    puts "MACHINE WINS"
+#    830 GOTO playAnother
+    if playAnother then
+        sub440 # loop for another
+    end
+end
+
+def sub840
+    $c=0
+    for i in 1..$numberOfPiles do
+    if $pileArray[i] > 1 then
+        sub940
+    end
+    if $pileArray[i] == 0 then 890
+        $c=$c+1
+    end
+    if $c/2 != ($c/2).to_i then
+        machineLoses
+    end
+    sub940 # goto
+    end
+end
+
+def sub920
+    if $pileArray[$dArray[0]] == 1 then
+        machineWins
+    end
+    if $pileArray[$dArray[1]] == 1 then
+        machineWins
+    end
+end
+
+def sub940
+    for i in 1..$numberOfPiles do
+        e=$pileArray[i]
+        for j in 0..10 do
+        $f = $e/2
+        $bArray[i][j] = 2*($f-($f.to_i))
+        $e = $f.to_i
+        end
+    end
+end
+
+#for j in 10..0 STEP -1 do
+10..0.step(-1).each do|index|
+    $c=0
+    $h=0
+    for i in 1..$numberOfPiles do
+        if $bArray[i][index] != 0 then
+            $c=$c+1
+            if $pileArray[i] > $h then
+                $h = $pileArray[i]
+                $g = i
+            end
+        end
+    end
+end
+
+if $c/2 != ($c/2).to_i then 1190
+end
+$e = rand($numberOfPiles).to_i
+#if $pileArray[$e] == 0 then 1140
+
+$f = rand($pileArray[$e]).to_i
+$pileArray[$e] = $pileArray[$e]-$f
+sub1380
+$pileArray[$g]=0
+for j in 0..10 do
+$bArray[$g][index]=0
+$c=0
+for i in 1..$numberOfPiles do
+    if $bArray[i][index] != 0 then
+            $c=$c+1
+        end
+    end
+$pileArray[$g]=$pileArray[$g]+2*($c/2-($c/2)).to_i*2^j
+end
+if $winOption == 1 then
+    sub1380
+end
+$c=0
+for i in 1..$numberOfPiles do
+if $pileArray[i]>1 then
+    sub1380
+end
+if $pileArray[i] != 0 then
+    $c=$c+1
+end
+if $c/2 == ($c/2).to_i then
+    sub1380
+end
+$pileArray[$g] == 1 -$pileArray[$g]
+
+def sub1380
+    puts "PILE  SIZE"
+    for i in 1..$numberOfPiles do
+        put i
+        put $pileArray[i]
+    end
+    if $winOption == 2 then # avoid take-last option
+        yourMove
+    end
+    sub1570
+    if $z == 1 then
+        machineWins
+    end
+end
+
+def yourMove
+    put "YOUR MOVE - PILE, NUMBER TO BE REMOVED"
+#    1460 INPUT x,y
+x = gets.strip.to_i
+y = gets.strip.to_i
+    if x > $numberOfPiles then yourMove
+    if x < 1 then yourMove
+    if x != INT(x) then yourMove
+    if y > $pileArray[x] then yourMove
+    if y < 1 then
+        yourMove
+    end
+    if y != INT(y) then
+        yourMove
+    end
+
+    $pileArray[x] = $pileArray[x]-y
+    sub1570 # gosub
+    if $z == 1 then
+        machineLoses
+    end
+#    1560 GOTO 700
+end
+
+end
+end
+end
+end
+end
diff --git a/00_Alternate_Languages/65_Nim/rust/src/main.rs b/00_Alternate_Languages/65_Nim/rust/src/main.rs
new file mode 100644
index 00000000..beeba85c
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/rust/src/main.rs
@@ -0,0 +1,409 @@
+/*
+ * Nim
+ * Originally from the wonderful book: _Basic Computer Games_
+ * Port to Rust By David Lotts
+*/
+use nanorand::{tls::TlsWyRand, Rng};
+use std::io::{self, Write};
+use text_io::{read, try_read};
+
+/// Play Nim
+// line numbers from the orginal Basic program are in the end of line comments. 
+// If you see two number comments: the first one is a 
+// GOTO or THEN destination, second is the current line. Example: // 800 //210
+fn main() {
+    let mut rng = nanorand::tls_rng();
+    println!("{:>37}", "NIM"); //100
+    println!("{:>15}{}", "", "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"); //110
+    println!();
+    println!();
+    println!(); //120
+    let mut piles = [0.0; 100];
+    let mut b_piles = [[0.0; 100]; 11];
+    let mut ix_do = [0usize; 3]; //210
+    println!("THIS IS THE GAME OF NIM."); //220
+                                          //230
+    loop {
+        let instuct_me = input("DO YOU WANT INSTRUCTIONS"); //240
+        if instuct_me == "NO" || instuct_me == "no" {
+            break;
+        } //440   //260
+        if instuct_me == "YES" || instuct_me == "yes" {
+            instructions();
+            break;
+        } //310   //280
+        println!("PLEASE ANSWER YES OR NO"); //290
+    } //300
+    'play_again: loop {
+        println!(); //440
+        let winner_take_last: bool = loop {
+            let choice = input_int("ENTER WIN OPTION - 1 TO TAKE LAST, 2 TO AVOID LAST"); //460
+            if (1..=2).contains(&choice) {
+                break choice == 1;
+            } //490  //470
+        };
+        let np = loop {
+            //490
+            let choice = input_int("ENTER NUMBER OF PILES"); //500
+            if choice <= 100 && choice >= 1 {
+                break choice;
+            } //490   //510
+              //490   //520
+              //490   //530
+        };
+        println!("ENTER PILE SIZES"); //540
+        for ix in 0..np as usize {
+            //550
+            piles[ix] = loop {
+                let choice = input_int(&(ix + 1).to_string()); //570
+                if choice <= 2000 && choice >= 1 && choice >= 1 {
+                    break choice as f64;
+                } //560   //580
+                  //560   //600
+            }
+        } //610
+        let human_first = loop {
+            //620
+            let choice = input("DO YOU WANT TO MOVE FIRST"); //630
+            let choice = choice.to_lowercase();
+            if choice == "yes" {
+                break true;
+            } //1450   //650
+            if choice == "no" {
+                break false;
+            } //700   //670
+            println!("PLEASE ANSWER YES OR NO."); //680
+        }; //690
+
+        let mut winner = WinState::GameOn;
+        if human_first {
+            winner = human_turn(winner_take_last, np, &mut piles);
+        };
+        //### main game loop
+        if winner.is_game_on() {
+            winner = loop {
+                // break on winner returning from here:
+                let win = machines_turn(
+                    &mut rng,
+                    winner_take_last,
+                    np,
+                    &mut piles,
+                    &mut ix_do,
+                    &mut b_piles,
+                );
+                if !win.is_game_on() {
+                    break win;
+                }; //starts at 700
+
+                println!("PILE  SIZE"); //1380
+                for ix in 0..np as usize {
+                    //1390
+                    println!("{} {}", ix + 1, piles[ix]); //1400
+                } //  NEXT ix   //1410
+
+                // break on winner returning from here:
+                let win = human_turn(winner_take_last, np, &mut piles);
+                if !win.is_game_on() {
+                    break win;
+                };
+                //  GOTO 700   //1560
+            };
+        }
+        println!(
+            "MACHINE {}",
+            if winner == WinState::ComputerWins {
+                "WINS"
+            } else {
+                "LOSES"
+            }
+        );
+        loop {
+            // Game over //1640
+            let choice = input("do you want to play another game"); //1650
+            match choice.to_ascii_lowercase().as_str() {
+                "yes" => break,                       //1720   //1660
+                "no" => break 'play_again,            //1730   //1680
+                _ => println!("PLEASE.  YES OR NO."), //1700
+            } //  GOTO 1650    //1710
+        } //  GOTO 440   //1720
+    } //  END   //1730
+}
+
+#[derive(PartialEq)]
+enum WinState {
+    GameOn,
+    ComputerWins,
+    HumanWins,
+}
+
+impl WinState {
+    /// Returns `true` if the win state is [`GameOn`].
+    ///
+    /// [`GameOn`]: WinState::GameOn
+    fn is_game_on(&self) -> bool {
+        matches!(self, Self::GameOn)
+    }
+}
+
+/// Computer's turn
+fn machines_turn(
+    rng: &mut TlsWyRand,
+    winner_take_last: bool,
+    np: i32,
+    piles: &mut [f64; 100],
+    ix_do: &mut [usize; 3],
+    b_piles: &mut [[f64; 100]; 11],
+) -> WinState {
+    if !winner_take_last {
+        //940   //700
+        //### Loser takes last, check for winner
+        let mut count = 0; //710
+        'wayout: loop {
+            'outer: loop {
+                for ix in 0..np as usize {
+                    //720
+                    if piles[ix] == 0.0 {
+                        continue;
+                    } //730
+                    count += 1; //740
+                    if count == 3 {
+                        break 'outer;
+                    } //840   //750
+                    ix_do[count] = ix; //760
+                } //770
+                  // exactly two piles remain
+                if count == 2 {
+                    // println!("Only two piles remain : unused0={} pile1={} pile2={}",ix_do[0]+1,ix_do[1]+1,ix_do[2]+1); //diagnostic
+                    if piles[ix_do[1]] == 1.0 || piles[ix_do[2]] == 1.0 {
+                        //920
+                        return WinState::ComputerWins;
+                    } //820   //930
+                    break 'wayout;
+                } //920   //780
+                  // exactly one pile remains, loser takes last, and before machine's turn
+                  // println!("Only one pile remains : pile={}",ix_do[1]); //diagnostic
+                assert!(piles[ix_do[1]] > 0.0);
+                if piles[ix_do[1]] == 1.0 {
+                    //820    //790
+                    return WinState::HumanWins; //800
+                                                // GOTO 1640   //810
+                } else {
+                    return WinState::ComputerWins; //820
+                                                   // GOTO 1640   //830
+                }
+            }
+            count = 0; //840
+            let mut is_all_ones = true;
+            for ix in 0..np as usize {
+                // FOR ix=1 TO N   //850
+                if piles[ix] > 1.0 {
+                    is_all_ones = false;
+                    break;
+                } //940   //860
+                if piles[ix] != 0.0 {
+                    //890   //870
+                    count = count + 1; //880
+                }
+            } // NEXT ix   //890
+            if is_all_ones && count % 2 != 0 {
+                //800   //900
+                return WinState::HumanWins;
+            }
+            break; // GOTO 940   //910
+        }
+    }
+    //### winner take last (or first?) -- check for winner
+    for ix in 0..np as usize {
+        //940
+        let mut sticks = piles[ix]; //950
+        for jx in 0..=10 {
+            //960
+            let half = sticks / 2.0; //970
+            b_piles[ix][jx] = 2.0 * (half - half.trunc()); //980
+            sticks = half.trunc(); //990
+        } //  NEXT J   //1000
+    } //  NEXT I   //1010
+
+    let mut is_odd = false;
+    let mut ix_max_pile = usize::MAX; // make sure this fails if ever used.
+    for jx in (0..=10).rev() {
+        //1020
+        let mut count = 0; //1030
+        let mut highest = 0.0; //1040
+        for ix in 0..np as usize {
+            //1050
+            if b_piles[ix][jx] == 0.0 {
+                continue;
+            }; //1110   //1060
+            count = count + 1; //1070
+            if piles[ix] <= highest as f64 {
+                continue;
+            }; //1110   //1080
+            highest = piles[ix]; //1090
+            ix_max_pile = ix; //1100
+        } //NEXT I   //1110
+          // println!("if none are odd, use random: count={} odd={}", count,count%2!=0); //diagnostic
+        if count % 2 != 0 {
+            is_odd = true;
+            break;
+        } // C/2<>INT(C/2) //1190   //1120
+    } //  NEXT J   //1130
+    if !is_odd {
+        let mut ix_random;
+        loop {
+            ix_random = rng.generate_range(0..np as usize); //(N*RND(1)+1).trunc();   //1140
+            if piles[ix_random] != 0.0 {
+                break;
+            } //1140   //1150
+        }
+        let remove_random = rng.generate_range(1..=piles[ix_random] as i32); // INT(A[E]*RND(1)+1)   //1160
+        piles[ix_random] = piles[ix_random] - remove_random as f64; //1170
+        // println!("I choose random: pile={} removed={}",ix_random+1,remove_random) //diagnostic
+        // GOTO 1380   //1180
+    } else {
+        // println!("max pile: pile={}, was={} setting to 0. Expect add back.",ix_max_pile+1,piles[ix_max_pile]); //diagnostic
+        piles[ix_max_pile] = 0.0; //1190
+        for jx in 0..=10 {
+            //1200
+            b_piles[ix_max_pile][jx] = 0.0; //1210
+            let mut countum = 0; //1220
+            for ix in 0..np as usize {
+                //1230
+                if b_piles[ix][jx] == 0.0 {
+                    continue;
+                } //1260   //1240
+                countum += 1; // count non-empty  //1250
+            } //  NEXT ix   //1260
+            piles[ix_max_pile] =
+                piles[ix_max_pile] + ((countum % 2) * 2usize.pow(jx as u32)) as f64;
+            //1270
+            // println!("I choose max pile : pile={}, add back=odd?2^{}:0={}",ix_max_pile+1,jx,((countum%2)*2usize.pow(jx as u32))); //diagnostic
+        } //  NEXT J   //1280
+
+        'done: loop {
+            if !winner_take_last {
+                //1380   //1290
+                let mut counter = 0; //1300
+                for ix in 0..np as usize {
+                    //1310
+                    if piles[ix] > 1.0 {
+                        break 'done;
+                    } //1380   //1320
+                    if piles[ix] != 0.0 {
+                        //1350  //1330
+                        counter += 1; //1340
+                    }
+                } //  NEXT ix   //1350
+                  // done if C is odd
+                if counter % 2 != 0 {
+                    break;
+                } //1380   //1360
+                  // println!("max pile if even: 1 - pile : pile={}, before 1-p = {}",ix_max_pile+1,piles[ix_max_pile]); //diagnostic
+                piles[ix_max_pile] = 1.0 - piles[ix_max_pile]; //1370
+            }
+            break;
+        }
+    }
+    return WinState::GameOn; //1380 is after this
+}
+
+/// Human decide what you want to do and see if there is a winner
+fn human_turn(winner_take_last: bool, np: i32, piles: &mut [f64; 100]) -> WinState {
+    if winner_take_last {
+        //1450   //1420
+        let is_all_empty = one_if_all_zero(np, &piles); //  GOSUB 1570   //1430
+        if is_all_empty == 1 {
+            return WinState::ComputerWins;
+        } //820   //1440  //### machine wins
+    }
+    //### many things go here
+    loop {
+        //1450
+        let (pile_choice, remove_choice) = input_2int("YOUR MOVE - PILE, NUMBER TO BE REMOVED"); //1460
+        if pile_choice > np || pile_choice < 1 {
+            continue;
+        } //1450   //1480
+        let ix_choice = (pile_choice - 1) as usize;
+        if remove_choice < 1 || remove_choice as f64 > piles[ix_choice] {
+            continue;
+        }; //1450   //1500
+           // remove the humans choice:
+        piles[ix_choice] = piles[ix_choice] - remove_choice as f64; //1530
+        break;
+    }
+    if one_if_all_zero(np, &piles) == 1
+    //  GOSUB 1570   //1540
+    {
+        return WinState::HumanWins;
+    } //800   //1550  //### machine loses!
+    return WinState::GameOn;
+}
+
+/// returns 0 if all A are 0, otherwise 1
+fn one_if_all_zero(np: i32, piles: &[f64; 100]) -> i32 {
+    // sets Z to the return value
+    //1570
+    for ix in 0..np as usize {
+        //1580
+        if piles[ix] != 0.0 {
+            return 0;
+        } //1610   //1590
+          //1600
+    } //1610
+    return 1; //1620
+} //1630
+
+fn instructions() {
+    println!("THE GAME IS PLAYED WITH A NUMBER OF PILES OF OBJECTS.");
+    println!("ANY NUMBER OF OBJECTS ARE REMOVED FROM ONE PILE BY YOU AND");
+    println!("THE MACHINE ALTERNATELY.  ON YOUR TURN, YOU MAY TAKE");
+    println!("ALL THE OBJECTS THAT REMAIN IN ANY PILE, BUT YOU MUST");
+    println!("TAKE AT LEAST ONE OBJECT, AND YOU MAY TAKE OBJECTS FROM");
+    println!("ONLY ONE PILE ON A SINGLE TURN.  YOU MUST SPECIFY WHETHER");
+    println!("WINNING IS DEFINED AS TAKING OR NOT TAKING THE LAST OBJECT,");
+    println!("THE NUMBER OF PILES IN THE GAME, AND HOW MANY OBJECTS ARE");
+    println!("ORIGINALLY IN EACH PILE.  EACH PILE MAY CONTAIN A");
+    println!("DIFFERENT NUMBER OF OBJECTS.");
+    println!("THE MACHINE WILL SHOW ITS MOVE BY LISTING EACH PILE AND THE");
+    println!("NUMBER OF OBJECTS REMAINING IN THE PILES AFTER  EACH OF ITS");
+    println!("MOVES.");
+}
+
+/// print the prompt, wait for a number and newline.  Loop if invalid.
+fn input(prompt: &str) -> String {
+    loop {
+        print!("{} ? ", prompt);
+        io::stdout().flush().unwrap();
+        // TODO:  asks twice on win10, not linux.  \r vs \n?
+        let innn: String = read!("{}\n");
+        let out: String = innn.trim().to_string();
+        if out != "" {
+            return out;
+        }
+    }
+}
+fn input_int(prompt: &str) -> i32 {
+    loop {
+        print!("{} ? ", prompt);
+        io::stdout().flush().unwrap();
+        match try_read!() {
+            Ok(n) => return n,
+            Err(_) => {}
+        }
+    }
+}
+
+fn input_2int(prompt: &str) -> (i32, i32) {
+    loop {
+        let inp = input(prompt);
+        let nums: Vec = inp
+            .split(",")
+            .filter_map(|c| c.parse::().ok())
+            .collect();
+        if nums.len() != 2 {
+            println!("Enter two numbers like: 9,9",);
+            continue;
+        }
+        return (nums[0], nums[1]);
+    }
+}
diff --git a/00_Alternate_Languages/65_Nim/vbnet/Nim.sln b/00_Alternate_Languages/65_Nim/vbnet/Nim.sln
new file mode 100644
index 00000000..17c6bf86
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/vbnet/Nim.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Nim", "Nim.vbproj", "{224F08AA-BE60-4B49-877F-36F239C56F6F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{224F08AA-BE60-4B49-877F-36F239C56F6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{224F08AA-BE60-4B49-877F-36F239C56F6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{224F08AA-BE60-4B49-877F-36F239C56F6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{224F08AA-BE60-4B49-877F-36F239C56F6F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/65_Nim/vbnet/Nim.vbproj b/00_Alternate_Languages/65_Nim/vbnet/Nim.vbproj
new file mode 100644
index 00000000..f551edd0
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/vbnet/Nim.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Nim
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/65_Nim/vbnet/README.md b/00_Alternate_Languages/65_Nim/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/65_Nim/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/66_Number/README.md b/00_Alternate_Languages/66_Number/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/66_Number/csharp/Number.csproj b/00_Alternate_Languages/66_Number/csharp/Number.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/csharp/Number.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/66_Number/csharp/Number.sln b/00_Alternate_Languages/66_Number/csharp/Number.sln
new file mode 100644
index 00000000..f42e7e2a
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/csharp/Number.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Number", "Number.csproj", "{F39E3DE8-3564-424C-AD89-D47478FD6E47}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F39E3DE8-3564-424C-AD89-D47478FD6E47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F39E3DE8-3564-424C-AD89-D47478FD6E47}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F39E3DE8-3564-424C-AD89-D47478FD6E47}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F39E3DE8-3564-424C-AD89-D47478FD6E47}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/66_Number/csharp/README.md b/00_Alternate_Languages/66_Number/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/66_Number/csharp/program.cs b/00_Alternate_Languages/66_Number/csharp/program.cs
new file mode 100644
index 00000000..b73c9c7b
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/csharp/program.cs
@@ -0,0 +1,126 @@
+using System.Text;
+
+namespace Number
+{
+    class Number
+    {
+        private void DisplayIntro()
+        {
+            Console.WriteLine();
+            Console.WriteLine("NUMBER".PadLeft(23));
+            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("You have 100 points.  By guessing numbers from 1 to 5, you");
+            Console.WriteLine("can gain or lose points depending upon how close you get to");
+            Console.WriteLine("a random number selected by the computer.");
+            Console.WriteLine();
+            Console.WriteLine("You occaisionally will get a jackpot which will double(!)");
+            Console.WriteLine("your point count.  You win when you get 500 points.");
+            Console.WriteLine();
+
+        }
+        private int PromptForGuess()
+        {
+            bool Success = false;
+            int Guess = 0;
+
+            while (!Success)
+            {
+                Console.Write("Guess a number from 1 to 5? ");
+                string LineInput = Console.ReadLine().Trim().ToLower();
+
+                if (int.TryParse(LineInput, out Guess))
+                {
+                    if (Guess >= 0 && Guess <= 5)
+                        Success = true;
+                }
+                else
+                    Console.WriteLine("Please enter a number between 1 and 5.");
+            }
+
+            return Guess;
+        }
+
+        private void GetRandomNumbers(out int Random1, out int Random2, out int Random3, out int Random4, out int Random5)
+        {
+            Random rand = new Random();
+
+            // Get a unique set of random numbers between 1 and 5
+            // I assume this is what the original BASIC  FNR(X)=INT(5*RND(1)+1) is doing
+            Random1 = (int)(5 * rand.NextDouble() + 1);
+            do
+            {
+                Random2 = (int)(5 * rand.NextDouble() + 1);
+            } while (Random2 == Random1);
+            do
+            {
+                Random3 = (int)(5 * rand.NextDouble() + 1);
+            } while (Random3 == Random1 || Random3 == Random2);
+            do
+            {
+                Random4 = (int)(5 * rand.NextDouble() + 1);
+            } while (Random4 == Random1 || Random4 == Random2 || Random4 == Random3);
+            do
+            {
+                Random5 = (int)(5 * rand.NextDouble() + 1);
+            } while (Random5 == Random1 || Random5 == Random2 || Random5 == Random3 || Random5 == Random4);
+
+        }
+        private void Play()
+        {
+
+            int Points = 100;
+            bool Win = false;
+            int Random1, Random2, Random3, Random4, Random5;
+            int Guess = 0;
+
+            GetRandomNumbers(out Random1, out Random2, out Random3, out Random4, out Random5);
+
+            while (!Win)
+            {
+
+                Guess = PromptForGuess();
+
+                if (Guess == Random1)
+                    Points -= 5;
+                else if (Guess == Random2)
+                    Points += 5;
+                else if (Guess == Random3)
+                {
+                    Points += Points;
+                    Console.WriteLine("You hit the jackpot!!!");
+                }
+                else if (Guess == Random4)
+                    Points += 1;
+                else if (Guess == Random5)
+                    Points -= (int)(Points * 0.5);
+
+                if (Points > 500)
+                {
+                    Console.WriteLine("!!!!You Win!!!! with {0} points.", Points);
+                    Win = true;
+                }
+                else
+                    Console.WriteLine("You have {0} points.", Points);
+            }
+        }
+
+        public void PlayTheGame()
+        {
+            DisplayIntro();
+
+            Play();
+        }
+    }
+    class Program
+    {
+        static void Main(string[] args)
+        {
+
+            new Number().PlayTheGame();
+
+        }
+    }
+}
diff --git a/00_Alternate_Languages/66_Number/java/1/Number.java b/00_Alternate_Languages/66_Number/java/1/Number.java
new file mode 100644
index 00000000..c3df4ebf
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/java/1/Number.java
@@ -0,0 +1,69 @@
+
+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();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/66_Number/java/2/Number.java b/00_Alternate_Languages/66_Number/java/2/Number.java
new file mode 100644
index 00000000..2e481fca
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/java/2/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.");
+	}
+}
diff --git a/00_Alternate_Languages/66_Number/java/README.md b/00_Alternate_Languages/66_Number/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/66_Number/javascript/README.md b/00_Alternate_Languages/66_Number/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/66_Number/javascript/number.html b/00_Alternate_Languages/66_Number/javascript/number.html
new file mode 100644
index 00000000..5e384186
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/javascript/number.html
@@ -0,0 +1,9 @@
+
+
+NUMBER
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/66_Number/javascript/number.js b/00_Alternate_Languages/66_Number/javascript/number.js
new file mode 100644
index 00000000..06e236d5
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/javascript/number.js
@@ -0,0 +1,93 @@
+// NUMBER
+//
+// 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(33) + "NUMBER\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU\n");
+    print("CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO\n");
+    print("A RANDOM NUMBER SELECTED BY THE COMPUTER.\n");
+    print("\n");
+    print("YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)\n");
+    print("YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS.\n");
+    print("\n");
+    p = 0;
+    while (1) {
+        do {
+            print("GUESS A NUMBER FROM 1 TO 5");
+            g = parseInt(await input());
+        } while (g < 1 || g > 5) ;
+        r = Math.floor(5 * Math.random() + 1);
+        s = Math.floor(5 * Math.random() + 1);
+        t = Math.floor(5 * Math.random() + 1);
+        u = Math.floor(5 * Math.random() + 1);
+        v = Math.floor(5 * Math.random() + 1);
+        if (g == r) {
+            p -= 5;
+        } else if (g == s) {
+            p += 5;
+        } else if (g == t) {
+            p += p;
+            print("YOU HIT THE JACKPOT!!!\n");
+        } else if (g == u) {
+            p += 1;
+        } else if (g == v) {
+            p -= p * 0.5;
+        }
+        if (p <= 500) {
+            print("YOU HAVE " + p + " POINTS.\n");
+            print("\n");
+        } else {
+            print("!!!!YOU WIN!!!! WITH " + p + " POINTS.\n");
+            break;
+        }
+    }
+}
+
+main();
diff --git a/00_Alternate_Languages/66_Number/number.bas b/00_Alternate_Languages/66_Number/number.bas
new file mode 100644
index 00000000..c5b9ff7c
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/number.bas
@@ -0,0 +1,37 @@
+1 PRINT TAB(33);"NUMBER"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+4 PRINT "YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU"
+5 PRINT "CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO"
+6 PRINT "A RANDOM NUMBER SELECTED BY THE COMPUTER.": PRINT
+7 PRINT "YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)"
+8 PRINT "YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS."
+9 PRINT: P=100
+10 DEF FNR(X)=INT(5*RND(1)+1)
+12 INPUT "GUESS A NUMBER FROM 1 TO 5";G
+15 R=FNR(1)
+16 S=FNR(1)
+17 T=FNR(1)
+18 U=FNR(1)
+19 V=FNR(1)
+20 IF G=R THEN 30
+21 IF G=S THEN 40
+22 IF G=T THEN 50
+23 IF G=U THEN 60
+24 IF G=V THEN 70
+25 IF G>5 THEN 12
+30 P=P-5
+35 GOTO 80
+40 P=P+5
+45 GOTO 80
+50 P=P+P
+53 PRINT "YOU HIT THE JACKPOT!!!"
+55 GOTO 80
+60 P=P+1
+65 GOTO 80
+70 P=P-(P*.5)
+80 IF P>500 THEN 90
+82 PRINT "YOU HAVE";P;"POINTS.":PRINT
+85 GOTO 12
+90 PRINT "!!!!YOU WIN!!!! WITH ";P;"POINTS."
+99 END
diff --git a/41_Guess/pascal/README.md b/00_Alternate_Languages/66_Number/pascal/README.md
similarity index 100%
rename from 41_Guess/pascal/README.md
rename to 00_Alternate_Languages/66_Number/pascal/README.md
diff --git a/00_Alternate_Languages/66_Number/perl/README.md b/00_Alternate_Languages/66_Number/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/66_Number/perl/number.pl b/00_Alternate_Languages/66_Number/perl/number.pl
new file mode 100644
index 00000000..a5a5889b
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/perl/number.pl
@@ -0,0 +1,37 @@
+#!/usr/bin/perl
+use strict;
+
+print ' 'x 33 . "NUMBER\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+print "YOU HAVE 100 POINTS. BY GUESSING NUMBERS FROM 1 TO 5, YOU\n";
+print "CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO\n";
+print "A RANDOM NUMBER SELECTED BY THE COMPUTER.\n"; print "\n";
+print "YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)\n";
+print "YOUR POINT COUNT. YOU WIN WHEN YOU GET 500 POINTS.\n";
+print "\n"; my $P=100;
+
+Line12:
+while ($P<500) {
+	print "GUESS A NUMBER FROM 1 TO 5? "; chomp(my $G = );
+	my $R= &FNR(1);
+	my $S= &FNR(1);
+	my $T= &FNR(1);
+	my $U= &FNR(1);
+	my $V= &FNR(1);
+	if ($G eq $R) { $P=$P-5; }
+	if ($G eq $S) { $P=$P+5; }
+	if ($G eq $T) { $P=$P+$P; print "YOU HIT THE JACKPOT!!!\n"; }
+	if ($G eq $U) { $P=$P+1; }
+	if ($G eq $V) { $P=$P-($P*.5); }
+	if ($G<1 || $G>5) { redo; }
+	print "YOU HAVE $P POINTS.\n"; print "\n";
+	}
+print "!!!!YOU WIN!!!! WITH $P POINTS.\n";
+exit;
+
+
+sub FNR {
+	my ($X)= @_; #Useless...
+	return int(5*rand(1)+1);
+	}
diff --git a/00_Alternate_Languages/66_Number/python/README.md b/00_Alternate_Languages/66_Number/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/66_Number/python/number.py b/00_Alternate_Languages/66_Number/python/number.py
new file mode 100644
index 00000000..7746ff6a
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/python/number.py
@@ -0,0 +1,82 @@
+"""
+NUMBER
+
+A number guessing (gambling) game.
+
+Ported by Dave LeCompte
+"""
+
+import random
+
+
+def print_with_tab(num_spaces, msg):
+    if num_spaces > 0:
+        spaces = " " * num_spaces
+    else:
+        spaces = ""
+
+    print(spaces + msg)
+
+
+def print_instructions():
+    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.")
+    print()
+    print("YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)")
+    print("YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS.")
+    print()
+
+
+def fnr():
+    return random.randint(1, 5)
+
+
+def main():
+    print_with_tab(33, "NUMBER")
+    print_with_tab(15, "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+    print_instructions()
+
+    points = 100
+
+    while points <= 500:
+        print("GUESS A NUMBER FROM 1 TO 5")
+        guess = int(input())
+
+        if (guess < 1) or (guess > 5):
+            continue
+
+        r = fnr()
+        s = fnr()
+        t = fnr()
+        u = fnr()
+        v = fnr()
+
+        if guess == r:
+            # lose 5
+            points -= 5
+        elif guess == s:
+            # gain 5
+            points += 5
+        elif guess == t:
+            # double!
+            points += points
+            print("YOU HIT THE JACKPOT!!!")
+        elif guess == u:
+            # gain 1
+            points += 1
+        elif guess == v:
+            # lose half
+            points = points - (points * 0.5)
+
+        print(f"YOU HAVE {points} POINTS.")
+        print()
+    print(f"!!!!YOU WIN!!!! WITH {points} POINTS.")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/66_Number/ruby/README.md b/00_Alternate_Languages/66_Number/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/66_Number/rust/README.md b/00_Alternate_Languages/66_Number/rust/README.md
new file mode 100644
index 00000000..7e85f9a1
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/rust/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)
diff --git a/00_Alternate_Languages/66_Number/rust/src/main.rs b/00_Alternate_Languages/66_Number/rust/src/main.rs
new file mode 100644
index 00000000..70dfbfbf
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/rust/src/main.rs
@@ -0,0 +1,62 @@
+use rand::{Rng, prelude::thread_rng};
+use std::io;
+
+fn main() {
+    //DATA
+    let mut points: usize = 100;
+    let mut rng = thread_rng();
+    let mut number:u8;
+
+    //print welcome message
+    welcome();
+
+    //game loop
+    while points <= 500 {
+        //generate number
+        number = rng.gen_range(1..=5);
+        //NOTE: while looking at the original basic, I realized that the outcome of your guess is effectively random
+        //so instead of generating 5 variables with random values between 1-5 and doing something depedning which one has the value they guess...
+        //why not just let them "guess" and do a random action without using uneeded variables? .. so that's what I did.
+
+        //let them "guess"
+        println!("GUESS A NUMBER FROM 1 TO 5");//print prompt
+        if let Ok(_i) = io::stdin().read_line(&mut String::new()) {} // get input from standard in, and do nothing with it even if an error is thrown
+
+        //do something depending on the previously generated random number
+        match number {
+            1 => if points>=5{points -= 5},//the if statement here prevents overflow, points is stored as an unsigned integer, so we can't let it be negative
+            2 => points += 5,
+            3 => {//jackpot
+                points *= 2;
+                println!("YOU HIT THE JACKPOT!!!");
+            },
+            4 => points += 1,
+            5 => points /= 2,
+            _ => {},
+        };
+
+        //tell then how many points they have
+        println!("YOU HAVE {} POINTS.", points);
+    }
+
+    //print
+}
+
+/**
+ * print the welcome message
+ */
+fn welcome() {
+    println!("
+              CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
+
+
+
+    YOU HAVE 100 POINTS.  BY GUESSING NUMBERS FROM 1 TO 5, YOU
+    CAN GAIN OR LOSE POINTS DEPENDING UPON HOW CLOSE YOU GET TO
+    A RANDOM NUMBER SELECTED BY THE COMPUTER.
+
+    YOU OCCASIONALLY WILL GET A JACKPOT WHICH WILL DOUBLE(!)
+    YOUR POINT COUNT.  YOU WIN WHEN YOU GET 500 POINTS
+
+    ");
+}
diff --git a/00_Alternate_Languages/66_Number/vbnet/Number.sln b/00_Alternate_Languages/66_Number/vbnet/Number.sln
new file mode 100644
index 00000000..d0838e1a
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/vbnet/Number.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Number", "Number.vbproj", "{FEF524F1-E940-43AF-A7EF-4D0DEB1E3F1E}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{FEF524F1-E940-43AF-A7EF-4D0DEB1E3F1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FEF524F1-E940-43AF-A7EF-4D0DEB1E3F1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FEF524F1-E940-43AF-A7EF-4D0DEB1E3F1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FEF524F1-E940-43AF-A7EF-4D0DEB1E3F1E}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/66_Number/vbnet/Number.vbproj b/00_Alternate_Languages/66_Number/vbnet/Number.vbproj
new file mode 100644
index 00000000..ad922daf
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/vbnet/Number.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Number
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/66_Number/vbnet/README.md b/00_Alternate_Languages/66_Number/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/66_Number/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/67_One_Check/README.md b/00_Alternate_Languages/67_One_Check/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/67_One_Check/csharp/OneCheck.csproj b/00_Alternate_Languages/67_One_Check/csharp/OneCheck.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/csharp/OneCheck.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/67_One_Check/csharp/OneCheck.sln b/00_Alternate_Languages/67_One_Check/csharp/OneCheck.sln
new file mode 100644
index 00000000..f6a550c7
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/csharp/OneCheck.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneCheck", "OneCheck.csproj", "{3964167F-17D8-44FB-A9F7-EA2DB1C5DA3F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{3964167F-17D8-44FB-A9F7-EA2DB1C5DA3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3964167F-17D8-44FB-A9F7-EA2DB1C5DA3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3964167F-17D8-44FB-A9F7-EA2DB1C5DA3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3964167F-17D8-44FB-A9F7-EA2DB1C5DA3F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/67_One_Check/csharp/README.md b/00_Alternate_Languages/67_One_Check/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/67_One_Check/java/OneCheck.java b/00_Alternate_Languages/67_One_Check/java/OneCheck.java
new file mode 100644
index 00000000..88194b29
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/java/OneCheck.java
@@ -0,0 +1,252 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of One Check
+ * 

+ * Based on the BASIC game of One Check here + * https://github.com/coding-horror/basic-computer-games/blob/main/67%20One%20Check/onecheck.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 OneCheck { + + private final Scanner scan; // For user input + + private enum Step { + SHOW_INSTRUCTIONS, SHOW_BOARD, GET_MOVE, GET_SUMMARY, QUERY_RETRY + } + + public OneCheck() { + + scan = new Scanner(System.in); + + } // End of constructor OneCheck + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private static void showIntro() { + + System.out.println(" ".repeat(29) + "ONE CHECK"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + } // End of method showIntro + + private void startGame() { + + int fromSquare = 0; + int numJumps = 0; + int numPieces = 0; + int square = 0; + int startPosition = 0; + int toSquare = 0; + + // Move legality test variables + int fromTest1 = 0; + int fromTest2 = 0; + int toTest1 = 0; + int toTest2 = 0; + + int[] positions = new int[65]; + + Step nextStep = Step.SHOW_INSTRUCTIONS; + + String lineContent = ""; + String userResponse = ""; + + // Begin outer while loop + while (true) { + + // Begin switch + switch (nextStep) { + + case SHOW_INSTRUCTIONS: + + System.out.println("SOLITAIRE CHECKER PUZZLE BY DAVID AHL\n"); + System.out.println("48 CHECKERS ARE PLACED ON THE 2 OUTSIDE SPACES OF A"); + System.out.println("STANDARD 64-SQUARE CHECKERBOARD. THE OBJECT IS TO"); + System.out.println("REMOVE AS MANY CHECKERS AS POSSIBLE BY DIAGONAL JUMPS"); + System.out.println("(AS IN STANDARD CHECKERS). USE THE NUMBERED BOARD TO"); + System.out.println("INDICATE THE SQUARE YOU WISH TO JUMP FROM AND TO. ON"); + System.out.println("THE BOARD PRINTED OUT ON EACH TURN '1' INDICATES A"); + System.out.println("CHECKER AND '0' AN EMPTY SQUARE. WHEN YOU HAVE NO"); + System.out.println("POSSIBLE JUMPS REMAINING, INPUT A '0' IN RESPONSE TO"); + System.out.println("QUESTION 'JUMP FROM ?'\n"); + System.out.println("HERE IS THE NUMERICAL BOARD:\n"); + + nextStep = Step.SHOW_BOARD; + break; + + case SHOW_BOARD: + + // Begin loop through all squares + for (square = 1; square <= 57; square += 8) { + + lineContent = String.format("% -4d%-4d%-4d%-4d%-4d%-4d%-4d%-4d", square, square + 1, square + 2, + square + 3, square + 4, square + 5, square + 6, square + 7); + System.out.println(lineContent); + + } // End loop through all squares + + System.out.println(""); + System.out.println("AND HERE IS THE OPENING POSITION OF THE CHECKERS."); + System.out.println(""); + + Arrays.fill(positions, 1); + + // Begin generating start positions + for (square = 19; square <= 43; square += 8) { + + for (startPosition = square; startPosition <= square + 3; startPosition++) { + + positions[startPosition] = 0; + + } + } // End generating start positions + + numJumps = 0; + + printBoard(positions); + + nextStep = Step.GET_MOVE; + break; + + case GET_MOVE: + + System.out.print("JUMP FROM? "); + fromSquare = scan.nextInt(); + scan.nextLine(); // Discard newline + + // User requested summary + if (fromSquare == 0) { + nextStep = Step.GET_SUMMARY; + break; + } + + System.out.print("TO? "); + toSquare = scan.nextInt(); + scan.nextLine(); // Discard newline + System.out.println(""); + + // Check legality of move + fromTest1 = (int) Math.floor((fromSquare - 1.0) / 8.0); + fromTest2 = fromSquare - 8 * fromTest1; + toTest1 = (int) Math.floor((toSquare - 1.0) / 8.0); + toTest2 = toSquare - 8 * toTest1; + + if ((fromTest1 > 7) || + (toTest1 > 7) || + (fromTest2 > 8) || + (toTest2 > 8) || + (Math.abs(fromTest1 - toTest1) != 2) || + (Math.abs(fromTest2 - toTest2) != 2) || + (positions[(toSquare + fromSquare) / 2] == 0) || + (positions[fromSquare] == 0) || + (positions[toSquare] == 1)) { + + System.out.println("ILLEGAL MOVE. TRY AGAIN..."); + nextStep = Step.GET_MOVE; + break; + } + + positions[toSquare] = 1; + positions[fromSquare] = 0; + positions[(toSquare + fromSquare) / 2] = 0; + numJumps++; + + printBoard(positions); + + nextStep = Step.GET_MOVE; + break; + + case GET_SUMMARY: + + numPieces = 0; + + // Count remaining pieces + for (square = 1; square <= 64; square++) { + numPieces += positions[square]; + } + + System.out.println(""); + System.out.println("YOU MADE " + numJumps + " JUMPS AND HAD " + numPieces + " PIECES"); + System.out.println("REMAINING ON THE BOARD.\n"); + + nextStep = Step.QUERY_RETRY; + break; + + case QUERY_RETRY: + + while (true) { + System.out.print("TRY AGAIN? "); + userResponse = scan.nextLine(); + System.out.println(""); + + if (userResponse.toUpperCase().equals("YES")) { + nextStep = Step.SHOW_BOARD; + break; + } + else if (userResponse.toUpperCase().equals("NO")) { + System.out.println("O.K. HOPE YOU HAD FUN!!"); + return; + } + else { + System.out.println("PLEASE ANSWER 'YES' OR 'NO'."); + } + } + break; + + default: + System.out.println("INVALID STEP"); + nextStep = Step.QUERY_RETRY; + break; + + } // End of switch + + } // End outer while loop + + } // End of method startGame + + public void printBoard(int[] positions) { + + int column = 0; + int row = 0; + String lineContent = ""; + + // Begin loop through all rows + for (row = 1; row <= 57; row += 8) { + + // Begin loop through all columns + for (column = row; column <= row + 7; column++) { + + lineContent += " " + positions[column]; + + } // End loop through all columns + + System.out.println(lineContent); + lineContent = ""; + + } // End loop through all rows + + System.out.println(""); + + } // End of method printBoard + + public static void main(String[] args) { + + OneCheck game = new OneCheck(); + game.play(); + + } // End of method main + +} // End of class OneCheck diff --git a/00_Alternate_Languages/67_One_Check/java/README.md b/00_Alternate_Languages/67_One_Check/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/67_One_Check/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/67_One_Check/javascript/README.md b/00_Alternate_Languages/67_One_Check/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/67_One_Check/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/67_One_Check/javascript/onecheck.html b/00_Alternate_Languages/67_One_Check/javascript/onecheck.html new file mode 100644 index 00000000..ffdb77e5 --- /dev/null +++ b/00_Alternate_Languages/67_One_Check/javascript/onecheck.html @@ -0,0 +1,9 @@ + + +ONE CHECK + + +


+
+
+
diff --git a/00_Alternate_Languages/67_One_Check/javascript/onecheck.js b/00_Alternate_Languages/67_One_Check/javascript/onecheck.js
new file mode 100644
index 00000000..36876809
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/javascript/onecheck.js
@@ -0,0 +1,151 @@
+// ONE CHECK
+//
+// 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 a = [];
+
+// Main program
+async function main()
+{
+    print(tab(30) + "ONE CHECK\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    for (i = 0; i <= 64; i++)
+        a[i] = 0;
+    print("SOLITAIRE CHECKER PUZZLE BY DAVID AHL\n");
+    print("\n");
+    print("48 CHECKERS ARE PLACED ON THE 2 OUTSIDE SPACES OF A\n");
+    print("STANDARD 64-SQUARE CHECKERBOARD.  THE OBJECT IS TO\n");
+    print("REMOVE AS MANY CHECKERS AS POSSIBLE BY DIAGONAL JUMPS\n");
+    print("(AS IN STANDARD CHECKERS).  USE THE NUMBERED BOARD TO\n");
+    print("INDICATE THE SQUARE YOU WISH TO JUMP FROM AND TO.  ON\n");
+    print("THE BOARD PRINTED OUT ON EACH TURN '1' INDICATES A\n");
+    print("CHECKER AND '0' AN EMPTY SQUARE.  WHEN YOU HAVE NO\n");
+    print("POSSIBLE JUMPS REMAINING, INPUT A '0' IN RESPONSE TO\n");
+    print("QUESTION 'JUMP FROM ?'\n");
+    print("\n");
+    print("HERE IS THE NUMERICAL BOARD:\n");
+    print("\n");
+    while (1) {
+        for (j = 1; j <= 57; j += 8) {
+            str = "";
+            for (i = 0; i <= 7; i++) {
+                while (str.length < 4 * i)
+                    str += " ";
+                str += " " + (j + i);
+            }
+            print(str + "\n");
+        }
+        print("\n");
+        print("AND HERE IS THE OPENING POSITION OF THE CHECKERS.\n");
+        print("\n");
+        for (j = 1; j <= 64; j++)
+            a[j] = 1;
+        for (j = 19; j <= 43; j += 8)
+            for (i = j; i <= j + 3; i++)
+                a[i] = 0;
+        m = 0;
+        while (1) {
+            // Print board
+            for (j = 1; j <= 57; j += 8) {
+                str = "";
+                for (i = j; i <= j + 7; i++) {
+                    str += " " + a[i] + " ";
+                }
+                print(str + "\n");
+            }
+            print("\n");
+            while (1) {
+                print("JUMP FROM");
+                f = parseInt(await input());
+                if (f == 0)
+                    break;
+                print("TO");
+                t = parseInt(await input());
+                print("\n");
+                // Check legality of move
+                f1 = Math.floor((f - 1) / 8);
+                f2 = f - 8 * f1;
+                t1 = Math.floor((t - 1) / 8);
+                t2 = t - 8 * t1;
+                if (f1 > 7 || t1 > 7 || f2 > 8 || t2 > 8 || Math.abs(f1 - t1) != 2 || Math.abs(f2 - t2) != 2 || a[(t + f) / 2] == 0 || a[f] == 0 || a[t] == 1) {
+                    print("ILLEGAL MOVE.  TRY AGAIN...\n");
+                    continue;
+                }
+                break;
+            }
+            if (f == 0)
+                break;
+            // Update board
+            a[t] = 1;
+            a[f] = 0;
+            a[(t + f) / 2] = 0;
+            m++;
+        }
+        // End game summary
+        s = 0;
+        for (i = 1; i <= 64; i++)
+            s += a[i];
+        print("\n");
+        print("YOU MADE " + m + " JUMPS AND HAD " + s + " PIECES\n");
+        print("REMAINING ON THE BOARD.\n");
+        print("\n");
+        while (1) {
+            print("TRY AGAIN");
+            str = await input();
+            if (str == "YES")
+                break;
+            if (str == "NO")
+                break;
+            print("PLEASE ANSWER 'YES' OR 'NO'.\n");
+        }
+        if (str == "NO")
+            break;
+    }
+    print("\n");
+    print("O.K.  HOPE YOU HAD FUN!!\n");
+}
+
+main();
diff --git a/00_Alternate_Languages/67_One_Check/onecheck.bas b/00_Alternate_Languages/67_One_Check/onecheck.bas
new file mode 100644
index 00000000..2161a743
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/onecheck.bas
@@ -0,0 +1,86 @@
+2 PRINT TAB(30);"ONE CHECK"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT: PRINT: PRINT
+8 DIM A(64)
+10 PRINT "SOLITAIRE CHECKER PUZZLE BY DAVID AHL"
+15 PRINT
+20 PRINT "48 CHECKERS ARE PLACED ON THE 2 OUTSIDE SPACES OF A"
+25 PRINT "STANDARD 64-SQUARE CHECKERBOARD.  THE OBJECT IS TO"
+30 PRINT "REMOVE AS MANY CHECKERS AS POSSIBLE BY DIAGONAL JUMPS"
+35 PRINT "(AS IN STANDARD CHECKERS).  USE THE NUMBERED BOARD TO"
+40 PRINT "INDICATE THE SQUARE YOU WISH TO JUMP FROM AND TO.  ON"
+45 PRINT "THE BOARD PRINTED OUT ON EACH TURN '1' INDICATES A"
+50 PRINT "CHECKER AND '0' AN EMPTY SQUARE.  WHEN YOU HAVE NO"
+55 PRINT "POSSIBLE JUMPS REMAINING, INPUT A '0' IN RESPONSE TO"
+60 PRINT "QUESTION 'JUMP FROM ?'"
+62 PRINT
+63 PRINT "HERE IS THE NUMERICAL BOARD:"
+66 PRINT
+70 FOR J=1 TO 57 STEP 8
+74 PRINT J;TAB(4);J+1;TAB(8);J+2;TAB(12);J+3;TAB(16);J+4;TAB(20);J+5;
+75 PRINT TAB(24);J+6;TAB(28);J+7
+76 NEXT J
+77 PRINT
+78 PRINT "AND HERE IS THE OPENING POSITION OF THE CHECKERS."
+79 PRINT
+80 FOR J=1 TO 64
+82 A(J)=1
+84 NEXT J
+86 FOR J=19 TO 43 STEP 8
+88 FOR I=J TO J+3
+90 A(I)=0
+92 NEXT I
+94 NEXT J
+96 M=0
+98 GOTO 340
+100 INPUT "JUMP FROM";F
+105 IF F=0 THEN 500
+110 INPUT "TO";T
+112 PRINT
+118 REM *** CHECK LEGALITY OF MOVE
+120 F1=INT((F-1)/8)
+130 F2=F-8*F1
+140 T1=INT((T-1)/8)
+150 T2=T-8*T1
+160 IF F1>7 THEN 230
+170 IF T1>7 THEN 230
+180 IF F2>8 THEN 230
+190 IF T2>8 THEN 230
+200 IF ABS(F1-T1)<>2 THEN 230
+210 IF ABS(F2-T2)<>2 THEN 230
+212 IF A((T+F)/2)=0 THEN 230
+215 IF A(F)=0 THEN 230
+220 IF A(T)=1 THEN 230
+225 GOTO 250
+230 PRINT "ILLEGAL MOVE.  TRY AGAIN..."
+240 GOTO 100
+245 REM *** UPDATE BOARD
+250 A(T)=1
+260 A(F)=0
+270 A((T+F)/2)=0
+290 M=M+1
+310 REM *** PRINT BOARD
+340 FOR J=1 TO 57 STEP 8
+350 FOR I=J TO J+7
+360 PRINT A(I);
+370 NEXT I
+380 PRINT
+390 NEXT J
+400 PRINT
+410 GOTO 100
+490 REM *** END GAME SUMMARY
+500 S=0
+510 FOR I=1 TO 64
+520 S=S+A(I)
+530 NEXT I
+540 PRINT:PRINT "YOU MADE";M;"JUMPS AND HAD";S;"PIECES"
+550 PRINT "REMAINING ON THE BOARD."
+560 PRINT
+562 INPUT "TRY AGAIN";A$
+570 IF A$="YES" THEN 70
+575 IF A$="NO" THEN 600
+580 PRINT "PLEASE ANSWER 'YES' OR 'NO'."
+590 GOTO 562
+600 PRINT
+610 PRINT "O.K.  HOPE YOU HAD FUN!!"
+999 END
diff --git a/42_Gunner/pascal/README.md b/00_Alternate_Languages/67_One_Check/pascal/README.md
similarity index 100%
rename from 42_Gunner/pascal/README.md
rename to 00_Alternate_Languages/67_One_Check/pascal/README.md
diff --git a/00_Alternate_Languages/67_One_Check/perl/README.md b/00_Alternate_Languages/67_One_Check/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/67_One_Check/perl/onecheck.pl b/00_Alternate_Languages/67_One_Check/perl/onecheck.pl
new file mode 100644
index 00000000..62f1f0be
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/perl/onecheck.pl
@@ -0,0 +1,252 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'state' and 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use List::Util qw{ sum };   # Add all its arguments
+use Term::ReadLine;         # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+print <<'EOD';
+                              ONE CHECK
+               Creative Computing  Morristown, New Jersey
+
+
+
+Solitaire checker puzzle by David Ahl
+
+48 checkers are placed on the 2 outside spaces of a
+standard 64-square checkerboard.  The object is to
+remove as many checkers as possible by diagonal jumps
+(as in standard checkers).  Use the numbered board to
+indicate the square you wish to jump from and to.  On
+the board printed out on each turn '1' indicates a
+checker and '0' an empty square.  When you have no
+possible jumps remaining, input a '0' in response to
+question 'Jump from?'
+EOD
+
+while ( 1 ) {   # Iterate indefinitely
+
+    board_num();    # Display the numerical board.
+
+    # Initialize the board, which is a two-dimensional array.
+    my @board = map { [ ( 1 ) x 8 ] } 0 .. 7;   # Initialize to all 1.
+    for my $row ( 2 .. 5 ) {        # Set the center section to 0
+        for my $col ( 2 .. 5 ) {
+            $board[$row][$col] = 0;
+        }
+    }
+
+    print <<'EOD';
+And here is the opening position of the checkers.
+
+EOD
+    board_pos( \@board );
+
+    my $moves = 0;  # Number of moves made.
+
+    # A game proceeds while 'Jump from' is a true value. We make use of
+    # the fact that of the possible returns, only 0 evaluates false.
+    while ( my $jump_from = get_input(
+            'Jump from? ',
+            sub {
+                $ARG = lc;  # The caller sees this.
+                return 1 if $ARG eq 'b';
+                return unless m/ \A [0-9]+ \z /smx;
+                $ARG += 0;  # Numify, because string '00' is true.
+                return $ARG < 65;
+            },
+            "Please enter a number from 0 to 64, or 'b' to re-display the numeric board\n"
+        )
+    ) {
+        if ( $jump_from eq 'b' ) {
+            board_num();
+            board_pos( \@board );
+            next;
+        }
+
+        my $jump_to = get_input(
+            '       to? ',
+            sub { m/ \A [0-9]+ \z /smx },
+            "Please enter a number from 1 to 64\n",
+        );
+
+        if ( make_move( \@board, $jump_from, $jump_to ) ) {
+            $moves++;
+            board_pos( \@board );
+        } else {
+            say 'Illegal move.  Try again.';
+        }
+    }
+
+    my $checkers_left = sum( map { sum( @{ $board[$_] } ) } 0 .. 7 );
+    print <<"EOD";
+
+You made $moves jumps and had $checkers_left pieces
+remaining on the board.
+
+EOD
+
+    last unless get_yes_no( 'Try again' );
+
+}
+
+print <<'EOD';
+
+O.K.  Hope you had fun!!
+EOD
+
+# Print the numerical board
+sub board_num {
+    print <<'EOD';
+
+Here is the numerical board:
+
+EOD
+    foreach my $row ( 0 .. 7 ) {
+        state $tplt = ( '%3d' x 8 ) . "\n";
+        my $inx = $row * 8;
+        printf $tplt, map { $inx + $_ } 1 .. 8;
+    }
+    say '';
+    return;
+}
+
+# Print the board position
+sub board_pos {
+    my ( $board ) = @_;
+    for my $row ( 0 .. 7 ) {
+        state $tplt = ( '%2d' x 8 ) . "\n";
+        printf $tplt, @{ $board->[$row] };
+    }
+    say '';
+    return;
+}
+
+# Make the move. This is a subroutine for convenience in control flow.
+# We return a true value for success, and false for failure.
+sub make_move {
+    my ( $board, $jump_from, $jump_to ) = @_;
+    $jump_from -= 1;
+    $jump_to   -= 1;
+    my $from_row = int( $jump_from / 8 );   # Truncates toward 0
+    my $from_col = $jump_from % 8;
+    my $to_row   = int( $jump_to / 8 );     # Truncates toward 0
+    my $to_col   = $jump_to % 8;
+    return unless $board->[$from_row][$from_col];   # From must be occupied
+    return if $board->[$to_row][$to_col];           # To must be vacant
+    return unless abs( $from_row - $to_row ) == 2;  # Must cross two rows
+    return unless abs( $from_col - $to_col ) == 2;  # Must cross two cols
+    my $over_row = ( $from_row + $to_row ) / 2;     # The row jumped over
+    my $over_col = ( $from_col + $to_col ) / 2;     # The col jumped over
+    $board->[$from_row][$from_col] =                # Clear the from cell
+        $board->[$over_row][$over_col] = 0;         # and the jumped cell
+    $board->[$to_row][$to_col] = 1;                 # Occupy the to cell
+    return 1;
+}
+
+# Get input from the user. The arguments are:
+# * The prompt
+# * A reference to validation code. This code receives the response in
+#   $ARG and returns true for a valid response.
+# * A warning to print if the response is not valid. This must end in a
+#   return.
+# The first valid response is returned. An end-of-file terminates the
+# script.
+sub get_input {
+    my ( $prompt, $validate, $warning ) = @ARG;
+
+    # If no validator is passed, default to one that always returns
+    # true.
+    $validate ||= sub { 1 };
+
+    # Create the readline object. The 'state' causes the variable to be
+    # initialized only once, no matter how many times this subroutine is
+    # called. The do { ... } is a compound statement used because we
+    # need to tweak the created object before we store it.
+    state $term = do {
+        my $obj = Term::ReadLine->new( 'reverse' );
+        $obj->ornaments( 0 );
+        $obj;
+    };
+
+    while ( 1 ) {   # Iterate indefinitely
+
+        # Read the input into the topic variable, localized to prevent
+        # Spooky Action at a Distance. We exit on undef, which signals
+        # end-of-file.
+        exit unless defined( local $ARG = $term->readline( $prompt ) );
+
+        # Return the input if it is valid.
+        return $ARG if $validate->();
+
+        # Issue the warning, and go around the merry-go-round again.
+        warn $warning;
+    }
+}
+
+# Get a yes-or-no answer. The argument is the prompt, which will have
+# '? [y/n]: ' appended. The donkey work is done by get_input(), which is
+# requested to validate the response as beginning with 'y' or 'n',
+# case-insensitive. The return is a true value for 'y' and a false value
+# for 'n'.
+sub get_yes_no {
+    my ( $prompt ) = @ARG;
+    state $map_answer = {
+        n   => 0,
+        y   => 1,
+    };
+    my $resp = lc get_input(
+        "$prompt? [y/n]: ",
+        sub { m/ \A [yn] /smxi },
+        "Please respond 'y' or 'n'\n",
+    );
+    return $map_answer->{ substr $resp, 0, 1 };
+}
+
+__END__
+
+=head1 TITLE
+
+one check - Play the game 'One Check' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ one check.pl
+
+=head1 DETAILS
+
+This Perl script is a port of onecheck.
+
+This is a solitaire game played on a checker board, where the object is
+to eliminate as many checkers as possible by making diagonal jumps and
+removing the jumped checkers.
+
+It is pretty much a straight port of the BASIC original.
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :
diff --git a/00_Alternate_Languages/67_One_Check/python/README.md b/00_Alternate_Languages/67_One_Check/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/67_One_Check/python/onecheck.py b/00_Alternate_Languages/67_One_Check/python/onecheck.py
new file mode 100644
index 00000000..3510da70
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/python/onecheck.py
@@ -0,0 +1,128 @@
+# ONE CHECK
+
+# Port to python by imiro
+
+
+def tab(x):
+    return " " * x
+
+
+def main():
+
+    # Initial instructions
+    print(tab(30) + "ONE CHECK")
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+    print("SOLITAIRE CHECKER PUZZLE BY DAVID AHL")
+    print()
+    print("48 CHECKERS ARE PLACED ON THE 2 OUTSIDE SPACES OF A")
+    print("STANDARD 64-SQUARE CHECKERBOARD.  THE OBJECT IS TO")
+    print("REMOVE AS MANY CHECKERS AS POSSIBLE BY DIAGONAL JUMPS")
+    print("(AS IN STANDARD CHECKERS).  USE THE NUMBERED BOARD TO")
+    print("INDICATE THE SQUARE YOU WISH TO JUMP FROM AND TO.  ON")
+    print("THE BOARD PRINTED OUT ON EACH TURN '1' INDICATES A")
+    print("CHECKER AND '0' AN EMPTY SQUARE.  WHEN YOU HAVE NO")
+    print("POSSIBLE JUMPS REMAINING, INPUT A '0' IN RESPONSE TO")
+    print("QUESTION 'JUMP FROM ?'")
+    print()
+    print("HERE IS THE NUMERICAL BOARD:")
+    print()
+
+    while True:
+        for j in range(1, 64, 8):
+            for i in range(j, j + 7):
+                print(i, end=(" " * (3 if i < 10 else 2)))
+            print(j + 7)
+        print()
+        print("AND HERE IS THE OPENING POSITION OF THE CHECKERS.")
+        print()
+
+        (jumps, left) = play_game()
+
+        print()
+        print("YOU MADE " + jumps + " JUMPS AND HAD " + left + " PIECES")
+        print("REMAINING ON THE BOARD.")
+        print()
+
+        if not (try_again()):
+            break
+
+    print()
+    print("O.K.  HOPE YOU HAD FUN!!")
+
+
+def play_game():
+    # Initialize board
+    # Give more than 64 elements to accomodate 1-based indexing
+    board = [1] * 70
+    for j in range(19, 44, 8):
+        for i in range(j, j + 4):
+            board[i] = 0
+    jumps = 0
+    while True:
+        # print board
+        for j in range(1, 64, 8):
+            for i in range(j, j + 7):
+                print(board[i], end=" ")
+            print(board[j + 7])
+        print()
+
+        while True:
+            print("JUMP FROM", end=" ")
+            f = input()
+            f = int(f)
+            if f == 0:
+                break
+            print("TO", end=" ")
+            t = input()
+            t = int(t)
+            print()
+
+            # Check legality of move
+            f1 = (f - 1) // 8
+            f2 = f - 8 * f1
+            t1 = (t - 1) // 8
+            t2 = t - 8 * t1
+            if (
+                f1 > 7
+                or t1 > 7
+                or f2 > 8
+                or t2 > 8
+                or abs(f1 - t1) != 2
+                or abs(f2 - t2) != 2
+                or board[(t + f) // 2] == 0
+                or board[f] == 0
+                or board[t] == 1
+            ):
+                print("ILLEGAL MOVE.  TRY AGAIN...")
+                continue
+            break
+
+        if f == 0:
+            break
+        board[t] = 1
+        board[f] = 0
+        board[(t + f) // 2] = 0
+        jumps = jumps + 1
+
+    left = 0
+    for i in range(1, 64 + 1):
+        left = left + board[i]
+    return (str(jumps), str(left))
+
+
+def try_again():
+    print("TRY AGAIN", end=" ")
+    answer = input()
+    if answer.upper() == "YES":
+        return True
+    elif answer.upper() == "NO":
+        return False
+    print("PLEASE ANSWER 'YES' OR 'NO'.")
+    try_again()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/67_One_Check/ruby/README.md b/00_Alternate_Languages/67_One_Check/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/67_One_Check/vbnet/OneCheck.sln b/00_Alternate_Languages/67_One_Check/vbnet/OneCheck.sln
new file mode 100644
index 00000000..d641e964
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/vbnet/OneCheck.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "OneCheck", "OneCheck.vbproj", "{E19E8AE0-06FE-4EB5-9F24-7FF74D65F55A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{E19E8AE0-06FE-4EB5-9F24-7FF74D65F55A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E19E8AE0-06FE-4EB5-9F24-7FF74D65F55A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E19E8AE0-06FE-4EB5-9F24-7FF74D65F55A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E19E8AE0-06FE-4EB5-9F24-7FF74D65F55A}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/67_One_Check/vbnet/OneCheck.vbproj b/00_Alternate_Languages/67_One_Check/vbnet/OneCheck.vbproj
new file mode 100644
index 00000000..2b36f16f
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/vbnet/OneCheck.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    OneCheck
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/67_One_Check/vbnet/README.md b/00_Alternate_Languages/67_One_Check/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/67_One_Check/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/68_Orbit/README.md b/00_Alternate_Languages/68_Orbit/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/68_Orbit/csharp/Orbit.csproj b/00_Alternate_Languages/68_Orbit/csharp/Orbit.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/csharp/Orbit.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/68_Orbit/csharp/Orbit.sln b/00_Alternate_Languages/68_Orbit/csharp/Orbit.sln
new file mode 100644
index 00000000..0ca7e270
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/csharp/Orbit.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orbit", "Orbit.csproj", "{2912E79E-D9A2-488F-B77E-7C348E3347E7}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{2912E79E-D9A2-488F-B77E-7C348E3347E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2912E79E-D9A2-488F-B77E-7C348E3347E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2912E79E-D9A2-488F-B77E-7C348E3347E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2912E79E-D9A2-488F-B77E-7C348E3347E7}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/68_Orbit/csharp/README.md b/00_Alternate_Languages/68_Orbit/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/68_Orbit/java/Orbit.java b/00_Alternate_Languages/68_Orbit/java/Orbit.java
new file mode 100644
index 00000000..5ecdb770
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/java/Orbit.java
@@ -0,0 +1,192 @@
+import java.lang.Integer;
+import java.lang.Math;
+import java.util.Scanner;
+
+/**
+ * Game of Orbit
+ * 

+ * Based on the BASIC game of Orbit here + * https://github.com/coding-horror/basic-computer-games/blob/main/68%20Orbit/orbit.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 Orbit { + + private final Scanner scan; // For user input + + public Orbit() { + + scan = new Scanner(System.in); + + } // End of constructor Orbit + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private static void showIntro() { + + System.out.println(" ".repeat(32) + "ORBIT"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + System.out.println("SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP."); + System.out.println(""); + System.out.println("THE SHIP IS IN A CONSTANT POLAR ORBIT. ITS"); + System.out.println("DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM"); + System.out.println("10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN"); + System.out.println("CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS."); + System.out.println(""); + System.out.println("UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO"); + System.out.println("YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL"); + System.out.println("INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR"); + System.out.println("PHOTON BOMB EXPLODED. YOU HAVE SEVEN HOURS UNTIL THEY"); + System.out.println("HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE"); + System.out.println("YOUR PLANET'S GRAVITY."); + System.out.println(""); + System.out.println("YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR."); + System.out.println(""); + System.out.println("AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN"); + System.out.println("ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF"); + System.out.println("100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S"); + System.out.println("DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN."); + System.out.println(""); + System.out.println("AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP"); + System.out.println("WILL DESTROY IT."); + System.out.println(""); + System.out.println("BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT."); + System.out.println(""); + System.out.println(""); + System.out.println(" 90"); + System.out.println(" 0000000000000"); + System.out.println(" 0000000000000000000"); + System.out.println(" 000000 000000"); + System.out.println(" 00000 00000"); + System.out.println(" 00000 XXXXXXXXXXX 00000"); + System.out.println(" 00000 XXXXXXXXXXXXX 00000"); + System.out.println(" 0000 XXXXXXXXXXXXXXX 0000"); + System.out.println(" 0000 XXXXXXXXXXXXXXXXX 0000"); + System.out.println(" 0000 XXXXXXXXXXXXXXXXXXX 0000"); + System.out.println("180<== 00000 XXXXXXXXXXXXXXXXXXX 00000 ==>0"); + System.out.println(" 0000 XXXXXXXXXXXXXXXXXXX 0000"); + System.out.println(" 0000 XXXXXXXXXXXXXXXXX 0000"); + System.out.println(" 0000 XXXXXXXXXXXXXXX 0000"); + System.out.println(" 00000 XXXXXXXXXXXXX 00000"); + System.out.println(" 00000 XXXXXXXXXXX 00000"); + System.out.println(" 00000 00000"); + System.out.println(" 000000 000000"); + System.out.println(" 0000000000000000000"); + System.out.println(" 0000000000000"); + System.out.println(" 270"); + System.out.println(""); + System.out.println("X - YOUR PLANET"); + System.out.println("O - THE ORBIT OF THE ROMULAN SHIP"); + System.out.println(""); + System.out.println("ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING"); + System.out.println("COUNTERCLOCKWISE AROUND YOUR PLANET. DON'T FORGET THAT"); + System.out.println("WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE"); + System.out.println("AND ORBITAL RATE WILL REMAIN CONSTANT."); + System.out.println(""); + System.out.println("GOOD LUCK. THE FEDERATION IS COUNTING ON YOU."); + + } // End of method showIntro + + private void startGame() { + + double bombDistance = 0; + int bombAltitude = 0; + int bombAngle = 0; + int deltaAngle = 0; + int hour = 0; + int shipAltitude = 0; + int shipAngle = 0; + int shipRate = 0; + String userResponse = ""; + + // Begin outer while loop + while (true) { + shipAngle = (int) (361 * Math.random()); + shipAltitude = (int) (201 * Math.random() + 200); + shipRate = (int) (21 * Math.random() + 10); + + hour = 0; + + // Begin time limit loop + while (hour < 7) { + + System.out.println(""); + System.out.println(""); + System.out.println("THIS IS HOUR " + (hour + 1) + ", AT WHAT ANGLE DO YOU WISH TO SEND"); + System.out.print("YOUR PHOTON BOMB? "); + bombAngle = Integer.parseInt(scan.nextLine()); + + System.out.print("HOW FAR OUT DO YOU WISH TO DETONATE IT? "); + bombAltitude = Integer.parseInt(scan.nextLine()); + + System.out.println(""); + System.out.println(""); + + // Update ship position + shipAngle += shipRate; + + // Handle full revolutions + if (shipAngle >= 360) { + shipAngle -= 360; + } + + deltaAngle = Math.abs(shipAngle - bombAngle); + + // Keep angle in upper quadrants + if (deltaAngle >= 180) { + deltaAngle = 360 - deltaAngle; + } + + bombDistance = Math.sqrt(shipAltitude * shipAltitude + bombAltitude * bombAltitude - 2 * shipAltitude + * bombAltitude * Math.cos(deltaAngle * Math.PI / 180)); + + System.out.format("YOUR PHOTON BOMB EXPLODED " + "%.5f" + "*10^2 MILES FROM THE\n", bombDistance); + System.out.println("ROMULAN SHIP."); + + // Win condition + if (bombDistance <= 50) { + System.out.println("YOU HAVE SUCCESSFULLY COMPLETED YOUR MISSION."); + break; + } + + hour++; + + } // End time limit loop + + // Lose condition + if (hour == 7) { + System.out.println("YOU HAVE ALLOWED THE ROMULANS TO ESCAPE."); + } + + System.out.println("ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT."); + System.out.print("DO YOU WISH TO TRY TO DESTROY IT? "); + userResponse = scan.nextLine(); + + if (!userResponse.toUpperCase().equals("YES")) { + System.out.println("GOOD BYE."); + break; + } + + } // End outer while loop + + } // End of method startGame + + public static void main(String[] args) { + + Orbit game = new Orbit(); + game.play(); + + } // End of method main + +} // End of class Orbit diff --git a/00_Alternate_Languages/68_Orbit/java/README.md b/00_Alternate_Languages/68_Orbit/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/68_Orbit/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/68_Orbit/javascript/README.md b/00_Alternate_Languages/68_Orbit/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/68_Orbit/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/68_Orbit/javascript/orbit.html b/00_Alternate_Languages/68_Orbit/javascript/orbit.html new file mode 100644 index 00000000..b5ea3982 --- /dev/null +++ b/00_Alternate_Languages/68_Orbit/javascript/orbit.html @@ -0,0 +1,9 @@ + + +ORBIT + + +


+
+
+
diff --git a/00_Alternate_Languages/68_Orbit/javascript/orbit.js b/00_Alternate_Languages/68_Orbit/javascript/orbit.js
new file mode 100644
index 00000000..ed20fe0f
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/javascript/orbit.js
@@ -0,0 +1,155 @@
+// ORBIT
+//
+// 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 a = [];
+
+// Main program
+async function main()
+{
+    print(tab(33) + "ORBIT\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP.\n");
+    print("\n");
+    print("THE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS\n");
+    print("DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM\n");
+    print("10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN\n");
+    print("CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS.\n");
+    print("\n");
+    print("UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO\n");
+    print("YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL\n");
+    print("INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR\n");
+    print("PHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY\n");
+    print("HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE\n");
+    print("YOUR PLANET'S GRAVITY.\n");
+    print("\n");
+    print("YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR.\n");
+    print("\n");
+    print("AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN\n");
+    print("ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF\n");
+    print("100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S\n");
+    print("DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN.\n");
+    print("\n");
+    print("AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP\n");
+    print("WILL DESTROY IT.\n");
+    print("\n");
+    print("BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT.\n");
+    print("\n");
+    print("\n");
+    print("                          90\n");
+    print("                    0000000000000\n");
+    print("                 0000000000000000000\n");
+    print("               000000           000000\n");
+    print("             00000                 00000\n");
+    print("            00000    XXXXXXXXXXX    00000\n");
+    print("           00000    XXXXXXXXXXXXX    00000\n");
+    print("          0000     XXXXXXXXXXXXXXX     0000\n");
+    print("         0000     XXXXXXXXXXXXXXXXX     0000\n");
+    print("        0000     XXXXXXXXXXXXXXXXXXX     0000\n");
+    print("180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0\n");
+    print("        0000     XXXXXXXXXXXXXXXXXXX     0000\n");
+    print("         0000     XXXXXXXXXXXXXXXXX     0000\n");
+    print("          0000     XXXXXXXXXXXXXXX     0000\n");
+    print("           00000    XXXXXXXXXXXXX    00000\n");
+    print("            00000    XXXXXXXXXXX    00000\n");
+    print("             00000                 00000\n");
+    print("               000000           000000\n");
+    print("                 0000000000000000000\n");
+    print("                    0000000000000\n");
+    print("                         270\n");
+    print("\n");
+    print("X - YOUR PLANET\n");
+    print("O - THE ORBIT OF THE ROMULAN SHIP\n");
+    print("\n");
+    print("ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING\n");
+    print("COUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT\n");
+    print("WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE\n");
+    print("AND ORBITAL RATE WILL REMAIN CONSTANT.\n");
+    print("\n");
+    print("GOOD LUCK.  THE FEDERATION IS COUNTING ON YOU.\n");
+    while (1) {
+        a = Math.floor(360 * Math.random());
+        d = Math.floor(200 * Math.random() + 200);
+        r = Math.floor(20 * Math.random() + 10);
+        h = 0;
+        while (h < 7) {
+            print("\n");
+            print("\n");
+            print("THIS IS HOUR " + (h + 1) + ", AT WHAT ANGLE DO YOU WISH TO SEND\n");
+            print("YOUR PHOTON BOMB");
+            a1 = parseFloat(await input());
+            print("HOW FAR OUT DO YOU WISH TO DETONATE IT");
+            d1 = parseFloat(await input());
+            print("\n");
+            print("\n");
+            a += r;
+            if (a >= 360)
+                a -= 360;
+            t = Math.abs(a - a1);
+            if (t >= 180)
+                t = 360 - t;
+            c = Math.sqrt(d * d + d1 * d1 - 2 * d * d1 * Math.cos(t * Math.PI / 180));
+            print("YOUR PHOTON BOMB EXPLODED " + c + "*10^2 MILES FROM THE\n");
+            print("ROMULAN SHIP.\n");
+            if (c <= 50)
+                break;
+            h++;
+        }
+        if (h == 7) {
+            print("YOU HAVE ALLOWED THE ROMULANS TO ESCAPE.\n");
+        } else {
+            print("YOU HAVE SUCCESSFULLY COMPLETED YOUR MISSION.\n");
+        }
+        print("ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT.\n");
+        print("DO YOU WISH TO TRY TO DESTROY IT");
+        str = await input();
+        if (str != "YES")
+            break;
+    }
+    print("GOOD BYE.\n");
+}
+
+main();
diff --git a/00_Alternate_Languages/68_Orbit/orbit.bas b/00_Alternate_Languages/68_Orbit/orbit.bas
new file mode 100644
index 00000000..f290eee4
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/orbit.bas
@@ -0,0 +1,96 @@
+2 PRINT TAB(33);"ORBIT"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT:PRINT:PRINT
+10 PRINT "SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP."
+15 PRINT
+20 PRINT "THE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS"
+25 PRINT "DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM"
+30 PRINT "10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN"
+31 PRINT "CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS."
+35 PRINT
+40 PRINT "UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO"
+45 PRINT "YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL"
+50 PRINT "INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR"
+55 PRINT "PHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY"
+60 PRINT "HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE"
+65 PRINT "YOUR PLANET'S GRAVITY."
+70 PRINT
+75 PRINT "YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR."
+80 PRINT
+85 PRINT "AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN"
+90 PRINT "ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF"
+95 PRINT "100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S"
+100 PRINT "DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN."
+105 PRINT
+110 PRINT "AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP"
+111 PRINT "WILL DESTROY IT."
+114 PRINT
+115 PRINT "BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT."
+116 PRINT
+117 PRINT
+168 PRINT "                          90"
+170 PRINT "                    0000000000000"
+171 PRINT "                 0000000000000000000"
+172 PRINT "               000000           000000"
+173 PRINT "             00000                 00000"
+174 PRINT "            00000    XXXXXXXXXXX    00000"
+175 PRINT "           00000    XXXXXXXXXXXXX    00000"
+176 PRINT "          0000     XXXXXXXXXXXXXXX     0000"
+177 PRINT "         0000     XXXXXXXXXXXXXXXXX     0000"
+178 PRINT "        0000     XXXXXXXXXXXXXXXXXXX     0000"
+179 PRINT "180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0"
+180 PRINT "        0000     XXXXXXXXXXXXXXXXXXX     0000"
+181 PRINT "         0000     XXXXXXXXXXXXXXXXX     0000"
+182 PRINT "          0000     XXXXXXXXXXXXXXX     0000"
+183 PRINT "           00000    XXXXXXXXXXXXX    00000"
+184 PRINT "            00000    XXXXXXXXXXX    00000"
+185 PRINT "             00000                 00000"
+186 PRINT "               000000           000000"
+187 PRINT "                 0000000000000000000"
+188 PRINT "                    0000000000000"
+190 PRINT "                         270"
+192 PRINT
+195 PRINT "X - YOUR PLANET"
+196 PRINT "O - THE ORBIT OF THE ROMULAN SHIP"
+197 PRINT
+198 PRINT "ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING"
+199 PRINT "COUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT"
+200 PRINT "WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE"
+210 PRINT "AND ORBITAL RATE WILL REMAIN CONSTANT."
+220 PRINT
+230 PRINT "GOOD LUCK.  THE FEDERATION IS COUNTING ON YOU."
+270 A=INT(360*RND(1))
+280 D=INT(200*RND(1)+200)
+290 R=INT(20*RND(1)+10)
+300 H=0
+310 IF H=7 THEN 490
+320 H=H+1
+325 PRINT
+326 PRINT
+330 PRINT "THIS IS HOUR";H;", AT WHAT ANGLE DO YOU WISH TO SEND"
+335 PRINT "YOUR PHOTON BOMB";
+340 INPUT A1
+350 PRINT "HOW FAR OUT DO YOU WISH TO DETONATE IT";
+360 INPUT D1
+365 PRINT
+366 PRINT
+370 A=A+R
+380 IF A<360 THEN 400
+390 A=A-360
+400 T=ABS(A-A1)
+410 IF T<180 THEN 430
+420 T=360-T
+430 C=SQR(D*D+D1*D1-2*D*D1*COS(T*3.14159/180))
+440 PRINT "YOUR PHOTON BOMB EXPLODED";C;"*10^2 MILES FROM THE"
+445 PRINT "ROMULAN SHIP."
+450 IF C<=50 THEN 470
+460 GOTO 310
+470 PRINT "YOU HAVE SUCCESFULLY COMPLETED YOUR MISSION."
+480 GOTO 500
+490 PRINT "YOU HAVE ALLOWED THE ROMULANS TO ESCAPE."
+500 PRINT "ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT."
+510 PRINT "DO YOU WISH TO TRY TO DESTROY IT";
+520 INPUT C$
+530 IF C$="YES" THEN 270
+540 PRINT "GOOD BYE."
+999 END
diff --git a/43_Hammurabi/pascal/README.md b/00_Alternate_Languages/68_Orbit/pascal/README.md
similarity index 100%
rename from 43_Hammurabi/pascal/README.md
rename to 00_Alternate_Languages/68_Orbit/pascal/README.md
diff --git a/00_Alternate_Languages/68_Orbit/perl/README.md b/00_Alternate_Languages/68_Orbit/perl/README.md
new file mode 100644
index 00000000..e3bc2e31
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/perl/README.md
@@ -0,0 +1,11 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
+
+This Perl script is a port of orbit, which is the 68th entry in Basic
+Computer Games.
+
+In this game you are a planetary defense gunner trying to shoot down a
+cloaked Romulan ship before it can escape.
+
+This is pretty much a straight port of the BASIC into idiomatic Perl.
diff --git a/00_Alternate_Languages/68_Orbit/perl/orbit.pl b/00_Alternate_Languages/68_Orbit/perl/orbit.pl
new file mode 100644
index 00000000..f8e9fccf
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/perl/orbit.pl
@@ -0,0 +1,239 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'state' and 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use Term::ReadLine;     # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+use constant PI => atan2( 0, -1 );
+use constant DEG_TO_RAD => atan2( 0, -1 ) / 180;
+
+print <<'EOD';
+                                 ORBIT
+               Creative Computing  Morristown, New Jersey
+
+
+
+Somewhere above your planet is a Romulan ship.
+
+The ship is in a constant polar orbit.  Its
+distance from the center of your planet is from
+10,000 to 30,000 miles and at its present velocity can
+circle your planet once every 12 to 36 hours.
+
+Unfortunately, they are using a cloaking device so
+you are unable to see them, but with a special
+instrument you can tell how near their ship your
+photon bomb exploded.  You have seven hours until they
+have built up sufficient power in order to escape
+your planet's gravity.
+
+Your planet has enough power to fire one bomb an hour.
+
+At the beginning of each hour you will be asked to give an
+angle (between 0 and 360) and a distance in units of
+100 miles (between 100 and 300), after which your bomb's
+distance from the enemy ship will be given.
+
+An explosion within 5,000 miles of the Romulan ship
+will destroy it.
+
+Below is a diagram to help you visualize your plight.
+
+
+                          90
+                    0000000000000
+                 0000000000000000000
+               000000           000000
+             00000                 00000
+            00000    XXXXXXXXXXX    00000
+           00000    XXXXXXXXXXXXX    00000
+          0000     XXXXXXXXXXXXXXX     0000
+         0000     XXXXXXXXXXXXXXXXX     0000
+        0000     XXXXXXXXXXXXXXXXXXX     0000
+180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0
+        0000     XXXXXXXXXXXXXXXXXXX     0000
+         0000     XXXXXXXXXXXXXXXXX     0000
+          0000     XXXXXXXXXXXXXXX     0000
+           00000    XXXXXXXXXXXXX    00000
+            00000    XXXXXXXXXXX    00000
+             00000                 00000
+               000000           000000
+                 0000000000000000000
+                    0000000000000
+                         270
+
+X - Your planet
+O - The orbit of the Romulan ship
+
+On the above diagram, the Romulan ship is circling
+counterclockwise around your planet.  Don't forget that
+without sufficient power the Romulan ship's altitude
+and orbital rate will remain constant.
+
+Good luck.  The Federation is counting on you.
+EOD
+
+while ( 1 ) {   # Iterate indefinitely
+
+    my $romulan_angle = int( 360 * rand() );
+    my $romulan_distance = int( 200 * rand() + 200 );
+    my $romulan_velocity = int( 20 * rand() + 10 );
+
+    my $hour = 0;
+    while ( 1 ) {   # Iterate indefinitely
+        $hour++;
+
+        print <<"EOD";
+
+
+This is hour $hour, at what angle do you wish to send
+EOD
+        my $bomb_angle = get_input(
+            'do you wish to send your photon bomb? ',
+            sub { m/ \A [0-9]+ \z /smx },
+            "Please enter an integer angle in degrees\n",
+        );
+        say '';
+        my $bomb_distance = get_input(
+            'How far out do you wish to detonate it? ',
+            sub { m/ \A [0-9]+ \z /smx },
+            "Please enter an integer distance in hundreds of miles\n",
+        );
+
+        $romulan_angle = ( $romulan_angle + $romulan_velocity ) % 360;
+        my $miss_angle = abs( $romulan_angle - $bomb_angle );
+        $miss_angle = 360 - $miss_angle if $miss_angle >= 180;
+        my $miss_distance = int sqrt(
+            $romulan_distance * $romulan_distance +
+            $bomb_distance * $bomb_distance -
+            2 * $romulan_distance * $bomb_distance *
+                cos( $miss_angle * DEG_TO_RAD ) );
+        print <<"EOD";
+
+Your photon bomb exploded $miss_distance*10^2 miles from the
+Romulan ship.
+EOD
+        if ( $miss_distance <= 50 ) {
+            say "\nYou have successfully completed your mission.";
+            last;
+        } elsif ( $hour > 6 ) {
+            say "\nYou have allowed the Romulans to escape.";
+            last;
+        }
+    }
+
+    say "\nAnother Romulan ship has gone into orbit.";
+    last unless get_yes_no( 'Do you wish to try to destroy it' );
+}
+
+print <<'EOD';
+
+Good bye.
+EOD
+
+# Get input from the user. The arguments are:
+# * The prompt
+# * A reference to validation code. This code receives the response in
+#   $ARG and returns true for a valid response.
+# * A warning to print if the response is not valid. This must end in a
+#   return.
+# The first valid response is returned. An end-of-file terminates the
+# script.
+sub get_input {
+    my ( $prompt, $validate, $warning ) = @ARG;
+
+    # If no validator is passed, default to one that always returns
+    # true.
+    $validate ||= sub { 1 };
+
+    # Create the readline object. The 'state' causes the variable to be
+    # initialized only once, no matter how many times this subroutine is
+    # called. The do { ... } is a compound statement used because we
+    # need to tweak the created object before we store it.
+    state $term = do {
+        my $obj = Term::ReadLine->new( 'reverse' );
+        $obj->ornaments( 0 );
+        $obj;
+    };
+
+    while ( 1 ) {   # Iterate indefinitely
+
+        # Read the input into the topic variable, localized to prevent
+        # Spooky Action at a Distance. We exit on undef, which signals
+        # end-of-file.
+        exit unless defined( local $ARG = $term->readline( $prompt ) );
+
+        # Return the input if it is valid.
+        return $ARG if $validate->();
+
+        # Issue the warning, and go around the merry-go-round again.
+        warn $warning;
+    }
+}
+
+# Get a yes-or-no answer. The argument is the prompt, which will have
+# '? [y/n]: ' appended. The donkey work is done by get_input(), which is
+# requested to validate the response as beginning with 'y' or 'n',
+# case-insensitive. The return is a true value for 'y' and a false value
+# for 'n'.
+sub get_yes_no {
+    my ( $prompt ) = @ARG;
+    state $map_answer = {
+        n   => 0,
+        y   => 1,
+    };
+    my $resp = lc get_input(
+        "$prompt? [y/n]: ",
+        sub { m/ \A [yn] /smxi },
+        "Please respond 'y' or 'n'\n",
+    );
+    return $map_answer->{ substr $resp, 0, 1 };
+}
+
+__END__
+
+=head1 TITLE
+
+orbit - Play the game 'Orbit' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ orbit.pl
+
+=head1 DETAILS
+
+This Perl script is a port of orbit, which is the 68th entry in Basic
+Computer Games.
+
+In this game you are a planetary defense gunner trying to shoot down a
+cloaked Romulan ship before it can escape.
+
+This is pretty much a straight port of the BASIC into idiomatic Perl.
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :
diff --git a/00_Alternate_Languages/68_Orbit/python/README.md b/00_Alternate_Languages/68_Orbit/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/68_Orbit/python/orbit.py b/00_Alternate_Languages/68_Orbit/python/orbit.py
new file mode 100644
index 00000000..252be2a6
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/python/orbit.py
@@ -0,0 +1,163 @@
+"""
+ORBIT
+
+Orbital mechanics simulation
+
+Port by Dave LeCompte
+"""
+
+import math
+import random
+
+PAGE_WIDTH = 64
+
+
+def print_centered(msg):
+    spaces = " " * ((PAGE_WIDTH - len(msg)) // 2)
+    print(spaces + msg)
+
+
+def print_instructions():
+    print(
+        """SOMEWHERE ABOVE YOUR PLANET IS A ROMULAN SHIP.
+
+THE SHIP IS IN A CONSTANT POLAR ORBIT.  ITS
+DISTANCE FROM THE CENTER OF YOUR PLANET IS FROM
+10,000 TO 30,000 MILES AND AT ITS PRESENT VELOCITY CAN
+CIRCLE YOUR PLANET ONCE EVERY 12 TO 36 HOURS.
+
+UNFORTUNATELY, THEY ARE USING A CLOAKING DEVICE SO
+YOU ARE UNABLE TO SEE THEM, BUT WITH A SPECIAL
+INSTRUMENT YOU CAN TELL HOW NEAR THEIR SHIP YOUR
+PHOTON BOMB EXPLODED.  YOU HAVE SEVEN HOURS UNTIL THEY
+HAVE BUILT UP SUFFICIENT POWER IN ORDER TO ESCAPE
+YOUR PLANET'S GRAVITY.
+
+YOUR PLANET HAS ENOUGH POWER TO FIRE ONE BOMB AN HOUR.
+
+AT THE BEGINNING OF EACH HOUR YOU WILL BE ASKED TO GIVE AN
+ANGLE (BETWEEN 0 AND 360) AND A DISTANCE IN UNITS OF
+100 MILES (BETWEEN 100 AND 300), AFTER WHICH YOUR BOMB'S
+DISTANCE FROM THE ENEMY SHIP WILL BE GIVEN.
+
+AN EXPLOSION WITHIN 5,000 MILES OF THE ROMULAN SHIP
+WILL DESTROY IT.
+
+BELOW IS A DIAGRAM TO HELP YOU VISUALIZE YOUR PLIGHT.
+
+
+                          90
+                    0000000000000
+                 0000000000000000000
+               000000           000000
+             00000                 00000
+            00000    XXXXXXXXXXX    00000
+           00000    XXXXXXXXXXXXX    00000
+          0000     XXXXXXXXXXXXXXX     0000
+         0000     XXXXXXXXXXXXXXXXX     0000
+        0000     XXXXXXXXXXXXXXXXXXX     0000
+180<== 00000     XXXXXXXXXXXXXXXXXXX     00000 ==>0
+        0000     XXXXXXXXXXXXXXXXXXX     0000
+         0000     XXXXXXXXXXXXXXXXX     0000
+          0000     XXXXXXXXXXXXXXX     0000
+           00000    XXXXXXXXXXXXX    00000
+            00000    XXXXXXXXXXX    00000
+             00000                 00000
+               000000           000000
+                 0000000000000000000
+                    0000000000000
+                         270
+
+X - YOUR PLANET
+O - THE ORBIT OF THE ROMULAN SHIP
+
+ON THE ABOVE DIAGRAM, THE ROMULAN SHIP IS CIRCLING
+COUNTERCLOCKWISE AROUND YOUR PLANET.  DON'T FORGET THAT
+WITHOUT SUFFICIENT POWER THE ROMULAN SHIP'S ALTITUDE
+AND ORBITAL RATE WILL REMAIN CONSTANT.
+
+GOOD LUCK.  THE FEDERATION IS COUNTING ON YOU.
+"""
+    )
+
+
+def get_yes_or_no():
+    while True:
+        response = input().upper()
+        if response == "YES":
+            return True
+        elif response == "NO":
+            return False
+        else:
+            print("PLEASE TYPE 'YES' OR 'NO'")
+
+
+def game_over(is_success):
+    if is_success:
+        print("YOU HAVE SUCCESSFULLY COMPLETED YOUR MISSION.")
+    else:
+        print("YOU HAVE ALLOWED THE ROMULANS TO ESCAPE.")
+    print("ANOTHER ROMULAN SHIP HAS GONE INTO ORBIT.")
+    print("DO YOU WISH TO TRY TO DESTROY IT?")
+
+    return get_yes_or_no()
+
+
+def play_game():
+    rom_angle = random.randint(0, 359)
+    rom_distance = random.randint(100, 300)
+    rom_angular_velocity = random.randint(10, 30)
+    hour = 0
+    while hour < 7:
+        hour += 1
+        print()
+        print()
+        print(f"THIS IS HOUR {hour}, AT WHAT ANGLE DO YOU WISH TO SEND")
+        print("YOUR PHOTON BOMB?")
+
+        bomb_angle = float(input())
+        print("HOW FAR OUT DO YOU WISH TO DETONATE IT?")
+        bomb_distance = float(input())
+        print()
+        print()
+
+        rom_angle = (rom_angle + rom_angular_velocity) % 360
+        angular_difference = rom_angle - bomb_angle
+        c = math.sqrt(
+            rom_distance**2
+            + bomb_distance**2
+            - 2
+            * rom_distance
+            * bomb_distance
+            * math.cos(math.radians(angular_difference))
+        )
+
+        print(f"YOUR PHOTON BOMB EXPLODED {c:.4f}*10^2 MILES FROM THE")
+        print("ROMULAN SHIP.")
+
+        if c <= 50:
+            # Destroyed the Romulan
+            return True
+
+    # Ran out of time
+    return False
+
+
+def main():
+    print_centered("ORBIT")
+    print_centered("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+    print_instructions()
+
+    while True:
+        success = play_game()
+        again = game_over(success)
+        if not again:
+            return
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/68_Orbit/ruby/README.md b/00_Alternate_Languages/68_Orbit/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/68_Orbit/vbnet/Orbit.sln b/00_Alternate_Languages/68_Orbit/vbnet/Orbit.sln
new file mode 100644
index 00000000..b2b021d1
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/vbnet/Orbit.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Orbit", "Orbit.vbproj", "{4EC039CE-66F1-46ED-97B1-9DB2A2B8A648}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{4EC039CE-66F1-46ED-97B1-9DB2A2B8A648}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4EC039CE-66F1-46ED-97B1-9DB2A2B8A648}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4EC039CE-66F1-46ED-97B1-9DB2A2B8A648}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4EC039CE-66F1-46ED-97B1-9DB2A2B8A648}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/68_Orbit/vbnet/Orbit.vbproj b/00_Alternate_Languages/68_Orbit/vbnet/Orbit.vbproj
new file mode 100644
index 00000000..29be1358
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/vbnet/Orbit.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Orbit
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/68_Orbit/vbnet/README.md b/00_Alternate_Languages/68_Orbit/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/68_Orbit/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/69_Pizza/README.md b/00_Alternate_Languages/69_Pizza/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/69_Pizza/csharp/CustomerMap.cs b/00_Alternate_Languages/69_Pizza/csharp/CustomerMap.cs
new file mode 100644
index 00000000..d2214c26
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/csharp/CustomerMap.cs
@@ -0,0 +1,131 @@
+using System.Text;
+
+namespace Pizza
+{
+    internal class CustomerMap
+    {
+        private readonly int _mapSize;
+        private readonly string[,] _customerMap;
+
+        public CustomerMap(int mapSize)
+        {
+            _mapSize = mapSize;
+            _customerMap = GenerateCustomerMap();
+        }
+
+        /// 
+        /// Gets customer on position X, Y.
+        /// 
+        /// Represents X position.
+        /// Represents Y position.
+        /// If positions is valid then returns customer name otherwise returns empty string.
+        public string GetCustomerOnPosition(int x, int y)
+        {
+            if(IsPositionOutOfRange(x, y))
+            {
+                return string.Empty;
+            }
+
+            return _customerMap[y, x];
+        }
+
+        /// 
+        /// Overridden ToString for getting text representation of customers map.
+        /// 
+        /// Text representation of customers map.
+        public override string ToString()
+        {
+            int verticalSpace = 4;
+            int horizontalSpace = 5;
+
+            var mapToDisplay = new StringBuilder();
+
+            AppendXLine(mapToDisplay, horizontalSpace);
+
+            for (int i = _customerMap.GetLength(0) - 1; i >= 0; i--)
+            {
+                mapToDisplay.AppendLine("-", verticalSpace);
+                mapToDisplay.Append($"{i + 1}");
+                mapToDisplay.Append(' ', horizontalSpace);
+
+                for (var j = 0; j < _customerMap.GetLength(1); j++)
+                {
+                    mapToDisplay.Append($"{_customerMap[i, j]}");
+                    mapToDisplay.Append(' ', horizontalSpace);
+                }
+
+                mapToDisplay.Append($"{i + 1}");
+                mapToDisplay.Append(' ', horizontalSpace);
+                mapToDisplay.Append(Environment.NewLine);
+            }
+
+            mapToDisplay.AppendLine("-", verticalSpace);
+
+            AppendXLine(mapToDisplay, horizontalSpace);
+
+            return mapToDisplay.ToString();
+        }
+
+        /// 
+        /// Checks if position is out of range or not.
+        /// 
+        /// Represents X position.
+        /// Represents Y position.
+        /// True if position is out of range otherwise false.
+        private bool IsPositionOutOfRange(int x, int y)
+        {
+            return
+                x < 0 || x > _mapSize - 1 ||
+                y < 0 || y > _mapSize - 1;
+        }
+
+        /// 
+        /// Generates array which represents customers map.
+        /// 
+        /// Returns customers map.
+        private string[,] GenerateCustomerMap()
+        {
+            string[,] customerMap = new string[_mapSize, _mapSize];
+            string[] customerNames = GetCustomerNames(_mapSize * _mapSize);
+            int currentCustomerNameIndex = 0;
+
+            for (int i = 0; i < customerMap.GetLength(0); i++)
+            {
+                for (int j = 0; j < customerMap.GetLength(1); j++)
+                {
+                    customerMap[i, j] = customerNames[currentCustomerNameIndex++].ToString();
+                }
+            }
+
+            return customerMap;
+        }
+
+        /// 
+        /// Generates customer names. Names are represented by alphanumerics from 'A'. Name of last customer depends on passed parameter.
+        /// 
+        /// How many customers need to be generated.
+        /// List of customer names.
+        private static string[] GetCustomerNames(int numberOfCustomers)
+        {
+            // returns ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P"];
+            return Enumerable.Range(65, numberOfCustomers).Select(c => ((Char)c).ToString()).ToArray();
+        }
+
+        /// 
+        /// Appends line with X coordinates.
+        /// 
+        /// Current map where a new line will be appended.
+        /// Number of horizontal delimiters which will be added between each coordination.
+        private void AppendXLine(StringBuilder mapToDisplay, int horizontalSpace)
+        {
+            mapToDisplay.Append(' ');
+            mapToDisplay.Append('-', horizontalSpace);
+            for (var i = 0; i < _customerMap.GetLength(0); i++)
+            {
+                mapToDisplay.Append($"{i + 1}");
+                mapToDisplay.Append('-', horizontalSpace);
+            }
+            mapToDisplay.Append(Environment.NewLine);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/69_Pizza/csharp/Pizza.csproj b/00_Alternate_Languages/69_Pizza/csharp/Pizza.csproj
new file mode 100644
index 00000000..74abf5c9
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/csharp/Pizza.csproj
@@ -0,0 +1,10 @@
+
+
+  
+    Exe
+    net6.0
+    enable
+    enable
+  
+
+
diff --git a/00_Alternate_Languages/69_Pizza/csharp/Pizza.sln b/00_Alternate_Languages/69_Pizza/csharp/Pizza.sln
new file mode 100644
index 00000000..91785a8c
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/csharp/Pizza.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31912.275
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pizza", "Pizza.csproj", "{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6AABE938-39C4-4661-AEA5-23CECA1DFEE1}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {8F7E9FAD-38C5-47A2-B5CA-2B6E5947B982}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/69_Pizza/csharp/PizzaGame.cs b/00_Alternate_Languages/69_Pizza/csharp/PizzaGame.cs
new file mode 100644
index 00000000..b4157047
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/csharp/PizzaGame.cs
@@ -0,0 +1,296 @@
+namespace Pizza
+{
+    internal class PizzaGame
+    {
+        private const int CustomerMapSize = 4;
+        private readonly CustomerMap _customerMap = new CustomerMap(CustomerMapSize);
+
+        /// 
+        /// Starts game. Main coordinator for pizza game.
+        /// It is responsible for showing information, getting data from user and starting to delivery pizza.
+        /// 
+        public void Play()
+        {
+            ShowHeader();
+
+            string playerName = GetPlayerName();
+
+            ShowIntroduction(playerName);
+            ShowMap();
+
+            if (AskForMoreDirections())
+            {
+                ShowMoreDirections(playerName);
+
+                var playerUnderstands = AskIfPlayerUnderstand();
+                if (!playerUnderstands)
+                {
+                    return;
+                }
+            }
+
+            StartDelivery(playerName);
+            EndDelivery(playerName);
+        }
+
+        /// 
+        /// Starts with pizza delivering to customers.
+        /// Every 5 deliveries it is asking user whether want to continue in delivering.
+        /// 
+        /// Player name which was filled by user.
+        private void StartDelivery(string playerName)
+        {
+            var numberOfDeliveredPizzas = 0;
+            while (true)
+            {
+                numberOfDeliveredPizzas++;
+                string deliverPizzaToCustomer = GetRandomCustomer();
+
+                WriteEmptyLine();
+                Console.WriteLine($"HELLO {playerName}'S PIZZA.  THIS IS {deliverPizzaToCustomer}.");
+                Console.WriteLine("\tPLEASE SEND A PIZZA.");
+
+                DeliverPizzaByPlayer(playerName, deliverPizzaToCustomer);
+
+                if (numberOfDeliveredPizzas % 5 == 0)
+                {
+                    bool playerWantToDeliveryMorePizzas = AskQuestionWithYesNoResponse("DO YOU WANT TO DELIVER MORE PIZZAS?");
+                    if (!playerWantToDeliveryMorePizzas)
+                    {
+                        WriteEmptyLine();
+                        break;
+                    }
+                }
+            }
+        }
+
+        /// 
+        /// Gets random customer for which pizza should be delivered.
+        /// 
+        /// Customer name.
+        private string GetRandomCustomer()
+        {
+            int randomPositionOnX = Random.Shared.Next(0, CustomerMapSize);
+            int randomPositionOnY = Random.Shared.Next(0, CustomerMapSize);
+
+            return _customerMap.GetCustomerOnPosition(randomPositionOnX, randomPositionOnY);
+        }
+
+        /// 
+        /// Delivers pizza to customer by player. It verifies whether player was delivering pizza to correct customer.
+        /// 
+        /// Player name which was filled by user.
+        /// Customer name which order pizza.
+        private void DeliverPizzaByPlayer(string playerName, string deliverPizzaToCustomer)
+        {
+            while (true)
+            {
+                string userInput = GetPlayerInput($"\tDRIVER TO {playerName}:  WHERE DOES {deliverPizzaToCustomer} LIVE?");
+                var deliveredToCustomer = GetCustomerFromPlayerInput(userInput);
+                if (string.IsNullOrEmpty(deliveredToCustomer))
+                {
+                    deliveredToCustomer = "UNKNOWN CUSTOMER";
+                }
+
+                if (deliveredToCustomer.Equals(deliverPizzaToCustomer))
+                {
+                    Console.WriteLine($"HELLO {playerName}.  THIS IS {deliverPizzaToCustomer}, THANKS FOR THE PIZZA.");
+                    break;
+                }
+
+                Console.WriteLine($"THIS IS {deliveredToCustomer}.  I DID NOT ORDER A PIZZA.");
+                Console.WriteLine($"I LIVE AT {userInput}");
+            }
+        }
+
+        /// 
+        /// Gets customer name by user input with customer coordinations.
+        /// 
+        /// Input from users - it should represent customer coordination separated by ','.
+        /// If coordinations are correct and customer exists then returns true otherwise false.
+        private string GetCustomerFromPlayerInput(string userInput)
+        {
+            var pizzaIsDeliveredToPosition = userInput?
+                .Split(',')
+                .Select(i => int.TryParse(i, out var customerPosition) ? (customerPosition - 1) : -1)
+                .Where(i => i != -1)
+                .ToArray() ?? Array.Empty();
+            if (pizzaIsDeliveredToPosition.Length != 2)
+            {
+                return string.Empty;
+            }
+
+            return _customerMap.GetCustomerOnPosition(pizzaIsDeliveredToPosition[0], pizzaIsDeliveredToPosition[1]);
+        }
+
+        /// 
+        /// Shows game header in console.
+        /// 
+        private void ShowHeader()
+        {
+            Console.WriteLine("PIZZA".PadLeft(22));
+            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            WriteEmptyLine(3);
+            Console.WriteLine("PIZZA DELIVERY GAME");
+            WriteEmptyLine();
+        }
+
+        /// 
+        /// Asks user for name which will be used in game.
+        /// 
+        /// Player name.
+        private string GetPlayerName()
+        {
+            return GetPlayerInput("WHAT IS YOUR FIRST NAME:");
+        }
+
+        /// 
+        /// Shows game introduction in console
+        /// 
+        /// Player name which was filled by user.
+        private void ShowIntroduction(string playerName)
+        {
+            Console.WriteLine($"HI, {playerName}.  IN THIS GAME YOU ARE TO TAKE ORDERS");
+            Console.WriteLine("FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY");
+            Console.WriteLine("WHERE TO DELIVER THE ORDERED PIZZAS.");
+            WriteEmptyLine(2);
+        }
+
+        /// 
+        /// Shows customers map in console. In this method is used overridden method 'ToString' for getting text representation of customers map.
+        /// 
+        private void ShowMap()
+        {
+            Console.WriteLine("MAP OF THE CITY OF HYATTSVILLE");
+            WriteEmptyLine();
+
+            Console.WriteLine(_customerMap.ToString());
+
+            Console.WriteLine("THE OUTPUT IS A MAP OF THE HOMES WHERE");
+            Console.WriteLine("YOU ARE TO SEND PIZZAS.");
+            WriteEmptyLine();
+            Console.WriteLine("YOUR JOB IS TO GIVE A TRUCK DRIVER");
+            Console.WriteLine("THE LOCATION OR COORDINATES OF THE");
+            Console.WriteLine("HOME ORDERING THE PIZZA.");
+            WriteEmptyLine();
+        }
+
+        /// 
+        /// Asks user if needs more directions.
+        /// 
+        /// True if user need more directions otherwise false.
+        private bool AskForMoreDirections()
+        {
+            var playerNeedsMoreDirections = AskQuestionWithYesNoResponse("DO YOU NEED MORE DIRECTIONS?");
+            WriteEmptyLine();
+
+            return playerNeedsMoreDirections;
+        }
+
+        /// 
+        /// Shows more directions.
+        /// 
+        /// Player name which was filled by user.
+        private void ShowMoreDirections(string playerName)
+        {
+            Console.WriteLine("SOMEBODY WILL ASK FOR A PIZZA TO BE");
+            Console.WriteLine("DELIVERED.  THEN A DELIVERY BOY WILL");
+            Console.WriteLine("ASK YOU FOR THE LOCATION.");
+            Console.WriteLine("\tEXAMPLE:");
+            Console.WriteLine("THIS IS J.  PLEASE SEND A PIZZA.");
+            Console.WriteLine($"DRIVER TO {playerName}.  WHERE DOES J LIVE?");
+            Console.WriteLine("YOUR ANSWER WOULD BE 2,3");
+        }
+
+        /// 
+        /// Asks user if understands to instructions.
+        /// 
+        /// True if user understand otherwise false.
+        private bool AskIfPlayerUnderstand()
+        {
+            var playerUnderstands = AskQuestionWithYesNoResponse("UNDERSTAND?");
+            if (!playerUnderstands)
+            {
+                Console.WriteLine("THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY");
+                return false;
+            }
+
+            WriteEmptyLine();
+            Console.WriteLine("GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.");
+            WriteEmptyLine();
+            Console.WriteLine("GOOD LUCK!!");
+            WriteEmptyLine();
+
+            return true;
+        }
+
+        /// 
+        /// Shows message about ending delivery in console.
+        /// 
+        /// Player name which was filled by user.
+        private void EndDelivery(string playerName)
+        {
+            Console.WriteLine($"O.K. {playerName}, SEE YOU LATER!");
+            WriteEmptyLine();
+        }
+
+        /// 
+        /// Gets input from user.
+        /// 
+        /// Question which is displayed in console.
+        /// User input.
+        private string GetPlayerInput(string question)
+        {
+            Console.Write($"{question} ");
+
+            while (true)
+            {
+                var userInput = Console.ReadLine();
+                if (!string.IsNullOrWhiteSpace(userInput))
+                {
+                    return userInput;
+                }
+            }
+        }
+
+        /// 
+        /// Asks user with required resposne 'YES', 'Y, 'NO', 'N'.
+        /// 
+        /// Question which is displayed in console.
+        /// True if user write 'YES', 'Y'. False if user write 'NO', 'N'.
+        private static bool AskQuestionWithYesNoResponse(string question)
+        {
+            var possitiveResponse = new string[] { "Y", "YES" };
+            var negativeResponse = new string[] { "N", "NO" };
+            var validUserInputs = possitiveResponse.Concat(negativeResponse);
+
+            Console.Write($"{question} ");
+
+            string? userInput;
+            while (true)
+            {
+                userInput = Console.ReadLine();
+                if (!string.IsNullOrWhiteSpace(userInput) && validUserInputs.Contains(userInput.ToUpper()))
+                {
+                    break;
+                }
+
+                Console.Write($"'YES' OR 'NO' PLEASE, NOW THEN, {question} ");
+            }
+
+            return possitiveResponse.Contains(userInput.ToUpper());
+        }
+
+        /// 
+        /// Writes empty line in console.
+        /// 
+        /// Number of empty lines which will be written in console. Parameter is optional and default value is 1.
+        private void WriteEmptyLine(int numberOfEmptyLines = 1)
+        {
+            for (int i = 0; i < numberOfEmptyLines; i++)
+            {
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/69_Pizza/csharp/Program.cs b/00_Alternate_Languages/69_Pizza/csharp/Program.cs
new file mode 100644
index 00000000..48cc4e27
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/csharp/Program.cs
@@ -0,0 +1,11 @@
+namespace Pizza
+{
+    internal class Program
+    {
+        static void Main(string[] args)
+        {
+            var pizzaGame = new PizzaGame();
+            pizzaGame.Play();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/69_Pizza/csharp/README.md b/00_Alternate_Languages/69_Pizza/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/69_Pizza/csharp/StringBuilderExtensions.cs b/00_Alternate_Languages/69_Pizza/csharp/StringBuilderExtensions.cs
new file mode 100644
index 00000000..d3d769d3
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/csharp/StringBuilderExtensions.cs
@@ -0,0 +1,21 @@
+using System.Text;
+
+namespace Pizza
+{
+    internal static class StringBuilderExtensions
+    {
+        /// 
+        /// Extensions for adding new lines of specific value.
+        /// 
+        /// Extended class.
+        /// Value which will be repeated.
+        /// Number of lines that will be appended.
+        public static void AppendLine(this StringBuilder stringBuilder, string value, int numberOfLines)
+        {
+            for (int i = 0; i < numberOfLines; i++)
+            {
+                stringBuilder.AppendLine(value);
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/69_Pizza/java/README.md b/00_Alternate_Languages/69_Pizza/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/69_Pizza/java/src/Pizza.java b/00_Alternate_Languages/69_Pizza/java/src/Pizza.java
new file mode 100644
index 00000000..051bffce
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/java/src/Pizza.java
@@ -0,0 +1,318 @@
+import java.util.Scanner;
+
+/**
+ * Game of Pizza
+ * 

+ * Based on the Basic game of Hurkle here + * https://github.com/coding-horror/basic-computer-games/blob/main/69%20Pizza/pizza.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. + */ +public class Pizza { + + private final int MAX_DELIVERIES = 5; + + private enum GAME_STATE { + STARTING, + ENTER_NAME, + DRAW_MAP, + MORE_DIRECTIONS, + START_DELIVER, + DELIVER_PIZZA, + TOO_DIFFICULT, + END_GAME, + GAME_OVER + } + + // houses that can order pizza + private final char[] houses = new char[]{'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + 'J', 'K', 'L', 'M', 'N', 'O', 'P'}; + + // size of grid + private final int[] gridPos = new int[]{1, 2, 3, 4}; + + private GAME_STATE gameState; + + private String playerName; + + // How many pizzas have been successfully delivered + private int pizzaDeliveryCount; + + // current house that ordered a pizza + private int currentHouseDelivery; + + // Used for keyboard input + private final Scanner kbScanner; + + public Pizza() { + + gameState = GAME_STATE.STARTING; + + // Initialise kb scanner + kbScanner = new Scanner(System.in); + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + // Show an introduction the first time the game is played. + case STARTING: + init(); + intro(); + gameState = GAME_STATE.ENTER_NAME; + break; + + // Enter the players name + case ENTER_NAME: + playerName = displayTextAndGetInput("WHAT IS YOUR FIRST NAME? "); + System.out.println("HI " + playerName + ". IN GAME YOU ARE TO TAKE ORDERS"); + System.out.println("FOR PIZZAS. THEN YOU ARE TO TELL A DELIVERY BOY"); + System.out.println("WHERE TO DELIVER THE ORDERED PIZZAS."); + System.out.println(); + gameState = GAME_STATE.DRAW_MAP; + break; + + // Draw the map + case DRAW_MAP: + drawMap(); + gameState = GAME_STATE.MORE_DIRECTIONS; + break; + + // need more directions (how to play) ? + case MORE_DIRECTIONS: + extendedIntro(); + String moreInfo = displayTextAndGetInput("DO YOU NEED MORE DIRECTIONS? "); + if (!yesOrNoEntered(moreInfo)) { + System.out.println("'YES' OR 'NO' PLEASE, NOW THEN,"); + } else { + // More instructions selected + if (yesEntered(moreInfo)) { + displayMoreDirections(); + // Player understand now? + if (yesEntered(displayTextAndGetInput("UNDERSTAND? "))) { + System.out.println("GOOD. YOU ARE NOW READY TO START TAKING ORDERS."); + System.out.println(); + System.out.println("GOOD LUCK!!"); + System.out.println(); + gameState = GAME_STATE.START_DELIVER; + } else { + // Not understood, essentially game over + gameState = GAME_STATE.TOO_DIFFICULT; + } + } else { + // no more directions were needed, start delivering pizza + gameState = GAME_STATE.START_DELIVER; + } + } + + break; + + // Too difficult to understand, game over! + case TOO_DIFFICULT: + System.out.println("JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY"); + gameState = GAME_STATE.GAME_OVER; + break; + + // Delivering pizza + case START_DELIVER: + // select a random house and "order" a pizza for them. + currentHouseDelivery = (int) (Math.random() + * (houses.length) + 1) - 1; // Deduct 1 for 0-based array + + System.out.println("HELLO " + playerName + "'S PIZZA. THIS IS " + + houses[currentHouseDelivery] + "."); + System.out.println(" PLEASE SEND A PIZZA."); + gameState = GAME_STATE.DELIVER_PIZZA; + break; + + // Try and deliver the pizza + case DELIVER_PIZZA: + + String question = " DRIVER TO " + playerName + ": WHERE DOES " + + houses[currentHouseDelivery] + " LIVE ? "; + String answer = displayTextAndGetInput(question); + + // Convert x,y entered by player to grid position of a house + int x = getDelimitedValue(answer, 0); + int y = getDelimitedValue(answer, 1); + int calculatedPos = (x + (y - 1) * 4) - 1; + + // Did the player select the right house to deliver? + if (calculatedPos == currentHouseDelivery) { + System.out.println("HELLO " + playerName + ". THIS IS " + houses[currentHouseDelivery] + + ", THANKS FOR THE PIZZA."); + pizzaDeliveryCount++; + + // Delivered enough pizza? + + if (pizzaDeliveryCount > MAX_DELIVERIES) { + gameState = GAME_STATE.END_GAME; + } else { + gameState = GAME_STATE.START_DELIVER; + } + } else { + System.out.println("THIS IS " + houses[calculatedPos] + ". I DID NOT ORDER A PIZZA."); + System.out.println("I LIVE AT " + x + "," + y); + // Don't change gameState so state is executed again + } + + break; + + // Sign off message for cases where the Chief is not upset + case END_GAME: + if (yesEntered(displayTextAndGetInput("DO YOU WANT TO DELIVER MORE PIZZAS? "))) { + init(); + gameState = GAME_STATE.START_DELIVER; + } else { + System.out.println(); + System.out.println("O.K. " + playerName + ", SEE YOU LATER!"); + System.out.println(); + gameState = GAME_STATE.GAME_OVER; + } + break; + + // GAME_OVER State does not specifically have a case + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + private void drawMap() { + + System.out.println("MAP OF THE CITY OF HYATTSVILLE"); + System.out.println(); + System.out.println(" -----1-----2-----3-----4-----"); + int k = 3; + for (int i = 1; i < 5; i++) { + System.out.println("-"); + System.out.println("-"); + System.out.println("-"); + System.out.println("-"); + + System.out.print(gridPos[k]); + int pos = 16 - 4 * i; + System.out.print(" " + houses[pos]); + System.out.print(" " + houses[pos + 1]); + System.out.print(" " + houses[pos + 2]); + System.out.print(" " + houses[pos + 3]); + System.out.println(" " + gridPos[k]); + k = k - 1; + } + System.out.println("-"); + System.out.println("-"); + System.out.println("-"); + System.out.println("-"); + System.out.println(" -----1-----2-----3-----4-----"); + } + + /** + * Basic information about the game + */ + private void intro() { + System.out.println("PIZZA"); + System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println(); + System.out.println("PIZZA DELIVERY GAME"); + System.out.println(); + } + + private void extendedIntro() { + System.out.println("THE OUTPUT IS A MAP OF THE HOMES WHERE"); + System.out.println("YOU ARE TO SEND PIZZAS."); + System.out.println(); + System.out.println("YOUR JOB IS TO GIVE A TRUCK DRIVER"); + System.out.println("THE LOCATION OR COORDINATES OF THE"); + System.out.println("HOME ORDERING THE PIZZA."); + System.out.println(); + } + + private void displayMoreDirections() { + System.out.println(); + System.out.println("SOMEBODY WILL ASK FOR A PIZZA TO BE"); + System.out.println("DELIVERED. THEN A DELIVERY BOY WILL"); + System.out.println("ASK YOU FOR THE LOCATION."); + System.out.println(" EXAMPLE:"); + System.out.println("THIS IS J. PLEASE SEND A PIZZA."); + System.out.println("DRIVER TO " + playerName + ". WHERE DOES J LIVE?"); + System.out.println("YOUR ANSWER WOULD BE 2,3"); + System.out.println(); + } + + private void init() { + pizzaDeliveryCount = 1; + } + + /** + * Accepts a string delimited by comma's and returns the nth delimited + * value (starting at count 0). + * + * @param text - text with values separated by comma's + * @param pos - which position to return a value for + * @return the int representation of the value + */ + private int getDelimitedValue(String text, int pos) { + String[] tokens = text.split(","); + return Integer.parseInt(tokens[pos]); + } + + /** + * Returns true if a given string is equal to at least one of the values specified in the call + * to the stringIsAnyValue method + * + * @param text string to search + * @return true if string is equal to one of the varargs + */ + private boolean yesEntered(String text) { + return stringIsAnyValue(text, "Y", "YES"); + } + + /** + * returns true if Y, YES, N, or NO was the compared value in text + * case-insensitive + * + * @param text search string + * @return true if one of the varargs was found in text + */ + private boolean yesOrNoEntered(String text) { + return stringIsAnyValue(text, "Y", "YES", "N", "NO"); + } + + /** + * Returns true if a given string contains at least one of the varargs (2nd parameter). + * Note: Case insensitive comparison. + * + * @param text string to search + * @param values varargs of type string containing values to compare + * @return true if one of the varargs arguments was found in text + */ + private boolean stringIsAnyValue(String text, String... values) { + + // Cycle through the variable number of values and test each + for (String val : values) { + if (text.equalsIgnoreCase(val)) { + return true; + } + } + + // no matches + return false; + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + +} diff --git a/00_Alternate_Languages/69_Pizza/java/src/PizzaGame.java b/00_Alternate_Languages/69_Pizza/java/src/PizzaGame.java new file mode 100644 index 00000000..b7074fa4 --- /dev/null +++ b/00_Alternate_Languages/69_Pizza/java/src/PizzaGame.java @@ -0,0 +1,8 @@ +public class PizzaGame { + + public static void main(String[] args) { + + Pizza pizza = new Pizza(); + pizza.play(); + } +} diff --git a/00_Alternate_Languages/69_Pizza/javascript/README.md b/00_Alternate_Languages/69_Pizza/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/69_Pizza/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/69_Pizza/javascript/pizza.html b/00_Alternate_Languages/69_Pizza/javascript/pizza.html new file mode 100644 index 00000000..30134499 --- /dev/null +++ b/00_Alternate_Languages/69_Pizza/javascript/pizza.html @@ -0,0 +1,9 @@ + + +PIZZA + + +


+
+
+
diff --git a/00_Alternate_Languages/69_Pizza/javascript/pizza.js b/00_Alternate_Languages/69_Pizza/javascript/pizza.js
new file mode 100644
index 00000000..11547b21
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/javascript/pizza.js
@@ -0,0 +1,155 @@
+// PIZZA
+//
+// 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 = [, "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P"];
+var ma = [, "1","2","3","4"];
+var a = [];
+
+// Main program
+async function main()
+{
+    print(tab(33) + "PIZZA\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("PIZZA DELIVERY GAME\n");
+    print("\n");
+    print("WHAT IS YOUR FIRST NAME");
+    ns = await input();
+    print("\n");
+    print("HI, " + ns + ". IN THIS GAME YOU ARE TO TAKE ORDERS\n");
+    print("FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY\n");
+    print("WHERE TO DELIVER THE ORDERED PIZZAS.\n");
+    print("\n");
+    print("\n");
+    print("MAP OF THE CITY OF HYATTSVILLE\n");
+    print("\n");
+    print(" -----1-----2-----3-----4-----\n");
+    k = 4;
+    for (i = 1; i <= 4; i++) {
+        print("-\n");
+        print("-\n");
+        print("-\n");
+        print("-\n");
+        print(ma[k]);
+        s1 = 16 - 4 * i + 1;
+        print("     " + sa[s1] + "     " + sa[s1 + 1] + "     " + sa[s1 + 2] + "     ");
+        print(sa[s1 + 3] + "     " + ma[k] + "\n");
+        k--;
+    }
+    print("-\n");
+    print("-\n");
+    print("-\n");
+    print("-\n");
+    print(" -----1-----2-----3-----4-----\n");
+    print("\n");
+    print("THE OUTPUT IS A MAP OF THE HOMES WHERE\n");
+    print("YOU ARE TO SEND PIZZAS.\n");
+    print("\n");
+    print("YOUR JOB IS TO GIVE A TRUCK DRIVER\n");
+    print("THE LOCATION OR COORDINATES OF THE\n");
+    print("HOME ORDERING THE PIZZA.\n");
+    print("\n");
+    while (1) {
+        print("DO YOU NEED MORE DIRECTIONS");
+        str = await input();
+        if (str == "YES" || str == "NO")
+            break;
+        print("'YES' OR 'NO' PLEASE, NOW THEN, ");
+    }
+    if (str == "YES") {
+        print("\n");
+        print("SOMEBODY WILL ASK FOR A PIZZA TO BE\n");
+        print("DELIVERED.  THEN A DELIVERY BOY WILL\n");
+        print("ASK YOU FOR THE LOCATION.\n");
+        print("     EXAMPLE:\n");
+        print("THIS IS J.  PLEASE SEND A PIZZA.\n");
+        print("DRIVER TO " + ns + ".  WHERE DOES J LIVE?\n");
+        print("YOUR ANSWER WOULD BE 2,3\n");
+        print("\n");
+        print("UNDERSTAND");
+        str = await input();
+        if (str != "YES") {
+            print("THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY");
+            return;
+        }
+        print("GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.\n");
+        print("\n");
+        print("GOOD LUCK!!\n");
+        print("\n");
+    }
+    while (1) {
+        for (i = 1; i <= 5; i++) {
+            s = Math.floor(Math.random() * 16 + 1);
+            print("\n");
+            print("HELLO " + ns + "'S PIZZA.  THIS IS " + sa[s] + ".\n");
+            print("  PLEASE SEND A PIZZA.\n");
+            while (1) {
+                print("  DRIVER TO " + ns + ":  WHERE DOES " + sa[s] + " LIVE");
+                str = await input();
+                a[1] = parseInt(str);
+                a[2] = parseInt(str.substr(str.indexOf(",") + 1));
+                t = a[1] + (a[2] - 1) * 4;
+                if (t != s) {
+                    print("THIS IS " + sa[t] + ". I DID NOT ORDER A PIZZA.\n");
+                    print("I LIVE AT " + a[1] + "," + a[2] + "\n");
+                } else {
+                    break;
+                }
+            }
+            print("HELLO " + ns + ".  THIS IS " + sa[s] + ", THANKS FOR THE PIZZA.\n");
+        }
+        print("\n");
+        print("DO YOU WANT TO DELIVER MORE PIZZAS");
+        str = await input();
+        if (str != "YES")
+            break;
+    }
+    print("\n");
+    print("O.K. " + ns + ", SEE YOU LATER!\n");
+    print("\n");
+}
+
+main();
diff --git a/44_Hangman/pascal/README.md b/00_Alternate_Languages/69_Pizza/pascal/README.md
similarity index 100%
rename from 44_Hangman/pascal/README.md
rename to 00_Alternate_Languages/69_Pizza/pascal/README.md
diff --git a/00_Alternate_Languages/69_Pizza/perl/README.md b/00_Alternate_Languages/69_Pizza/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/69_Pizza/perl/pizza.pl b/00_Alternate_Languages/69_Pizza/perl/pizza.pl
new file mode 100644
index 00000000..8d3e707f
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/perl/pizza.pl
@@ -0,0 +1,110 @@
+#!/usr/bin/perl
+#use strict;
+# Automatic converted by bas2perl.pl
+
+print ' 'x33 . "PIZZA". "\n";
+print ' 'x15 . "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY". "\n";
+print "\n"; print "\n"; print "\n";
+my @S; my @M;
+print "PIZZA DELIVERY GAME". "\n"; print "\n";
+print "WHAT IS YOUR FIRST NAME? "; chomp($N = uc()); print "\n";
+print "HI, ". $N. ".  IN THIS GAME YOU ARE TO TAKE ORDERS". "\n";
+print "FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY". "\n";
+print "WHERE TO DELIVER THE ORDERED PIZZAS.". "\n"; print "\n"; print "\n";
+for ($I=1; $I<=16; $I++) {
+$S[$I]= ; chomp($S[$I]);;
+}
+for ($I=1; $I<=4; $I++) {
+$M[$I]= ; chomp($M[$I]);;
+}
+# TO DATA SEGMENT;
+# TO DATA SEGMENT;
+print "MAP OF THE CITY OF HYATTSVILLE". "\n"; print "\n";
+print " -----1-----2-----3-----4-----". "\n";
+$K=4;
+for ($I=1; $I<=4; $I++) {
+print "-". "\n"; print "-". "\n"; print "-". "\n"; print "-". "\n";
+print $M[$K];
+$S1=16-4*$I+1;
+print "     ". $S[$S1]. "     ". $S[$S1+1]. "     ". $S[$S1+2]. "     ";
+print $S[$S1+3]. "     ". $M[$K]. "\n";
+$K=$K-1;
+}
+print "-". "\n"; print "-". "\n"; print "-". "\n"; print "-". "\n";
+print " -----1-----2-----3-----4-----". "\n"; print "\n";
+print "THE OUTPUT IS A MAP OF THE HOMES WHERE". "\n";
+print "YOU ARE TO SEND PIZZAS.". "\n"; print "\n";
+print "YOUR JOB IS TO GIVE A TRUCK DRIVER". "\n";
+print "THE LOCATION OR COORDINATES OF THE". "\n";
+print "HOME ORDERING THE PIZZA.". "\n"; print "\n";
+
+Line520:
+print "DO YOU NEED MORE DIRECTIONS? "; chomp($A = uc());
+if ($A eq "YES") { goto Line590; }
+if ($A eq "NO") { goto Line750; }
+print "'YES' OR 'NO' PLEASE, NOW THEN,". "\n"; goto Line520;
+
+Line590:
+print "\n"; print "SOMEBODY WILL ASK FOR A PIZZA TO BE". "\n";
+print "DELIVERED.  THEN A DELIVERY BOY WILL". "\n";
+print "ASK YOU FOR THE LOCATION.". "\n"; print "     EXAMPLE:". "\n";
+print "THIS IS J.  PLEASE SEND A PIZZA.". "\n";
+print "DRIVER TO ". $N. ".  WHERE DOES J LIVE?". "\n";
+print "YOUR ANSWER WOULD BE 2,3". "\n"; print "\n";
+print "UNDERSTAND? "; chomp($A = uc());
+if ($A eq "YES") { goto Line690; }
+print "THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY". "\n";
+goto Line999;
+
+Line690:
+print "GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.". "\n"; print "\n";
+print "GOOD LUCK!!". "\n"; print "\n";
+
+Line750:
+for ($I=1; $I<=5; $I++) {
+$S=int(rand(1)*16+1); print "\n";
+print "HELLO ". $N. "'S PIZZA.  THIS IS ". $S[$S]. ".";
+print "  PLEASE SEND A PIZZA.". "\n";
+
+Line780:
+print "  DRIVER TO ". $N. ":  WHERE DOES ". $S[$S]. " LIVE";
+print "? "; chomp($Inp_ = uc()); ($A[1],$A[2])= split(/,/, $Inp_);
+$T=$A[1]+($A[2]-1)*4;
+if ($T eq $S) { goto Line920; }
+print "THIS IS ". $S[$T]. ".  I DID NOT ORDER A PIZZA.". "\n";
+print "I LIVE AT ". $A[1]. ",". $A[2]. "\n";
+goto Line780;
+
+Line920:
+print "HELLO ". $N. ".  THIS IS ". $S[$S]. ", THANKS FOR THE PIZZA.". "\n";
+}
+print "\n"; print "DO YOU WANT TO DELIVER MORE PIZZAS? "; chomp($A = uc());
+if ($A eq "YES") { goto Line750; }
+print "\n"; print "O.K. ". $N. ", SEE YOU LATER!". "\n"; print "\n";
+
+Line999:
+exit;
+
+
+
+__DATA__
+A
+B
+C
+D
+E
+F
+G
+H
+I
+J
+K
+L
+M
+N
+O
+P
+1
+2
+3
+4
diff --git a/00_Alternate_Languages/69_Pizza/pizza.bas b/00_Alternate_Languages/69_Pizza/pizza.bas
new file mode 100644
index 00000000..a3d4e4f1
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/pizza.bas
@@ -0,0 +1,68 @@
+5 PRINT TAB(33);"PIZZA"
+10 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+15 PRINT: PRINT: PRINT
+20 DIM S$(16),M$(4)
+30 PRINT "PIZZA DELIVERY GAME": PRINT
+50 INPUT "WHAT IS YOUR FIRST NAME";N$: PRINT
+80 PRINT "HI, ";N$;".  IN THIS GAME YOU ARE TO TAKE ORDERS"
+90 PRINT "FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY"
+100 PRINT "WHERE TO DELIVER THE ORDERED PIZZAS.": PRINT: PRINT
+140 FOR I=1 TO 16
+150 READ S$(I)
+160 NEXT I
+170 FOR I=1 TO 4
+180 READ M$(I)
+190 NEXT I
+200 DATA "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O"
+210 DATA "P","1","2","3","4"
+230 PRINT "MAP OF THE CITY OF HYATTSVILLE": PRINT
+250 PRINT " -----1-----2-----3-----4-----"
+260 K=4
+270 FOR I=1 TO 4
+280 PRINT "-": PRINT "-": PRINT"-": PRINT "-"
+320 PRINT M$(K);
+330 S1=16-4*I+1
+340 PRINT "     ";S$(S1);"     ";S$(S1+1);"     ";S$(S1+2);"     ";
+350 PRINT S$(S1+3);"     ";M$(K)
+380 K=K-1
+390 NEXT I
+400 PRINT "-": PRINT "-": PRINT "-": PRINT "-"
+440 PRINT " -----1-----2-----3-----4-----": PRINT
+460 PRINT "THE OUTPUT IS A MAP OF THE HOMES WHERE"
+470 PRINT "YOU ARE TO SEND PIZZAS.": PRINT
+490 PRINT "YOUR JOB IS TO GIVE A TRUCK DRIVER"
+500 PRINT "THE LOCATION OR COORDINATES OF THE"
+510 PRINT "HOME ORDERING THE PIZZA.": PRINT
+520 INPUT "DO YOU NEED MORE DIRECTIONS";A$
+530 IF A$="YES" THEN 590
+540 IF A$="NO" THEN 750
+550 PRINT "'YES' OR 'NO' PLEASE, NOW THEN,": GOTO 520
+590 PRINT: PRINT "SOMEBODY WILL ASK FOR A PIZZA TO BE"
+600 PRINT "DELIVERED.  THEN A DELIVERY BOY WILL"
+610 PRINT "ASK YOU FOR THE LOCATION.":PRINT "     EXAMPLE:"
+620 PRINT "THIS IS J.  PLEASE SEND A PIZZA."
+640 PRINT "DRIVER TO ";N$;".  WHERE DOES J LIVE?"
+650 PRINT "YOUR ANSWER WOULD BE 2,3": PRINT
+660 INPUT "UNDERSTAND";A$
+670 IF A$="YES" THEN 690
+680 PRINT "THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY"
+685 GOTO 999
+690 PRINT "GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.": PRINT
+700 PRINT "GOOD LUCK!!": PRINT
+750 FOR I=1 TO 5
+760 S=INT(RND(1)*16+1): PRINT
+770 PRINT "HELLO ";N$;"'S PIZZA.  THIS IS ";S$(S);".";
+775 PRINT "  PLEASE SEND A PIZZA."
+780 PRINT "  DRIVER TO ";N$;":  WHERE DOES ";S$(S);" LIVE";
+790 INPUT A(1),A(2)
+870 T=A(1)+(A(2)-1)*4
+880 IF T=S THEN 920
+890 PRINT "THIS IS ";S$(T);".  I DID NOT ORDER A PIZZA."
+900 PRINT "I LIVE AT ";A(1);",";A(2)
+910 GOTO 780
+920 PRINT "HELLO "N$;".  THIS IS ";S$(S);", THANKS FOR THE PIZZA."
+930 NEXT I
+940 PRINT: INPUT "DO YOU WANT TO DELIVER MORE PIZZAS";A$
+960 IF A$="YES" THEN 750
+970 PRINT: PRINT "O.K. ";N$;", SEE YOU LATER!":PRINT
+999 END
diff --git a/00_Alternate_Languages/69_Pizza/python/README.md b/00_Alternate_Languages/69_Pizza/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/69_Pizza/python/pizza.py b/00_Alternate_Languages/69_Pizza/python/pizza.py
new file mode 100644
index 00000000..0f59262d
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/python/pizza.py
@@ -0,0 +1,187 @@
+"""
+PIZZA
+
+A pizza delivery simulation
+
+Ported by Dave LeCompte
+"""
+
+import random
+
+PAGE_WIDTH = 64
+
+customer_names = [chr(65 + x) for x in range(16)]
+street_names = [str(n) for n in range(1, 5)]
+
+
+def print_centered(msg):
+    spaces = " " * ((PAGE_WIDTH - len(msg)) // 2)
+    print(spaces + msg)
+
+
+def print_header(title):
+    print_centered(title)
+    print_centered("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+
+def print_ticks():
+    for t in range(4):
+        print("-")
+
+
+def print_ruler():
+    print(" -----1-----2-----3-----4-----")
+
+
+def print_street(i):
+    street_number = 3 - i
+
+    street_name = street_names[street_number]
+    line = street_name
+
+    space = " " * 5
+    for customer_index in range(4):
+        line += space
+        customer_name = customer_names[4 * street_number + customer_index]
+        line += customer_name
+    line += space
+    line += street_name
+    print(line)
+
+
+def print_map():
+    print("MAP OF THE CITY OF HYATTSVILLE")
+    print()
+    print_ruler()
+    for i in range(4):
+        print_ticks()
+        print_street(i)
+    print_ticks()
+    print_ruler()
+    print()
+
+
+def print_instructions():
+    print("PIZZA DELIVERY GAME")
+    print()
+    print("WHAT IS YOUR FIRST NAME?")
+    player_name = input()
+    print()
+    print(f"HI, {player_name}.  IN THIS GAME YOU ARE TO TAKE ORDERS")
+    print("FOR PIZZAS.  THEN YOU ARE TO TELL A DELIVERY BOY")
+    print("WHERE TO DELIVER THE ORDERED PIZZAS.")
+    print()
+    print()
+
+    print_map()
+
+    print("THE OUTPUT IS A MAP OF THE HOMES WHERE")
+    print("YOU ARE TO SEND PIZZAS.")
+    print()
+    print("YOUR JOB IS TO GIVE A TRUCK DRIVER")
+    print("THE LOCATION OR COORDINATES OF THE")
+    print("HOME ORDERING THE PIZZA.")
+    print()
+
+    return player_name
+
+
+def yes_no_prompt(msg):
+    while True:
+        print(msg)
+        response = input().upper()
+
+        if response == "YES":
+            return True
+        elif response == "NO":
+            return False
+        print("'YES' OR 'NO' PLEASE, NOW THEN,")
+
+
+def print_more_directions(player_name):
+    print()
+    print("SOMEBODY WILL ASK FOR A PIZZA TO BE")
+    print("DELIVERED.  THEN A DELIVERY BOY WILL")
+    print("ASK YOU FOR THE LOCATION.")
+    print("     EXAMPLE:")
+    print("THIS IS J.  PLEASE SEND A PIZZA.")
+    print(f"DRIVER TO {player_name}.  WHERE DOES J LIVE?")
+    print("YOUR ANSWER WOULD BE 2,3")
+    print()
+
+
+def calculate_customer_index(x, y):
+    return 4 * (y - 1) + x - 1
+
+
+def deliver_to(customer_index, customer_name, player_name):
+    print(f"  DRIVER TO {player_name}:  WHERE DOES {customer_name} LIVE?")
+
+    coords = input()
+    xc, yc = (int(c) for c in coords.split(","))
+    delivery_index = calculate_customer_index(xc, yc)
+    if delivery_index == customer_index:
+        print(f"HELLO {player_name}.  THIS IS {customer_name}, THANKS FOR THE PIZZA.")
+        return True
+    else:
+        delivery_name = customer_names[delivery_index]
+        print(f"THIS IS {delivery_name}.  I DID NOT ORDER A PIZZA.")
+        print(f"I LIVE AT {xc},{yc}")
+        return False
+
+
+def play_game(num_turns, player_name):
+    for turn in range(num_turns):
+        x = random.randint(1, 4)
+        y = random.randint(1, 4)
+        customer_index = calculate_customer_index(x, y)
+        customer_name = customer_names[customer_index]
+
+        print()
+        print(
+            f"HELLO {player_name}'S PIZZA.  THIS IS {customer_name}.  PLEASE SEND A PIZZA."
+        )
+        while True:
+            success = deliver_to(customer_index, customer_name, player_name)
+            if success:
+                break
+
+
+def main():
+    print_header("PIZZA")
+
+    player_name = print_instructions()
+
+    more_directions = yes_no_prompt("DO YOU NEED MORE DIRECTIONS?")
+
+    if more_directions:
+        print_more_directions(player_name)
+
+        understand = yes_no_prompt("UNDERSTAND?")
+
+        if not understand:
+            print("THIS JOB IS DEFINITELY TOO DIFFICULT FOR YOU. THANKS ANYWAY")
+            return
+
+    print("GOOD.  YOU ARE NOW READY TO START TAKING ORDERS.")
+    print()
+    print("GOOD LUCK!!")
+    print()
+
+    while True:
+        num_turns = 5
+        play_game(num_turns, player_name)
+
+        print()
+        more = yes_no_prompt("DO YOU WANT TO DELIVER MORE PIZZAS?")
+        if not more:
+            print(f"O.K. {player_name}, SEE YOU LATER!")
+            print()
+            return
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/69_Pizza/ruby/README.md b/00_Alternate_Languages/69_Pizza/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/69_Pizza/vbnet/Pizza.sln b/00_Alternate_Languages/69_Pizza/vbnet/Pizza.sln
new file mode 100644
index 00000000..8fc145ee
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/vbnet/Pizza.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Pizza", "Pizza.vbproj", "{395C3162-11F0-459B-9027-45A8ED6E4E8E}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{395C3162-11F0-459B-9027-45A8ED6E4E8E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{395C3162-11F0-459B-9027-45A8ED6E4E8E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{395C3162-11F0-459B-9027-45A8ED6E4E8E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{395C3162-11F0-459B-9027-45A8ED6E4E8E}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/69_Pizza/vbnet/Pizza.vbproj b/00_Alternate_Languages/69_Pizza/vbnet/Pizza.vbproj
new file mode 100644
index 00000000..db16f023
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/vbnet/Pizza.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Pizza
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/69_Pizza/vbnet/README.md b/00_Alternate_Languages/69_Pizza/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/69_Pizza/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/70_Poetry/README.md b/00_Alternate_Languages/70_Poetry/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/70_Poetry/csharp/Poetry.csproj b/00_Alternate_Languages/70_Poetry/csharp/Poetry.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/csharp/Poetry.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/70_Poetry/csharp/Poetry.sln b/00_Alternate_Languages/70_Poetry/csharp/Poetry.sln
new file mode 100644
index 00000000..f62c6d2b
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/csharp/Poetry.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Poetry", "Poetry.csproj", "{965EE29C-4FEC-4A31-92C9-55FBA8FDB0CB}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{965EE29C-4FEC-4A31-92C9-55FBA8FDB0CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{965EE29C-4FEC-4A31-92C9-55FBA8FDB0CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{965EE29C-4FEC-4A31-92C9-55FBA8FDB0CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{965EE29C-4FEC-4A31-92C9-55FBA8FDB0CB}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/70_Poetry/csharp/README.md b/00_Alternate_Languages/70_Poetry/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/70_Poetry/java/Poetry.java b/00_Alternate_Languages/70_Poetry/java/Poetry.java
new file mode 100644
index 00000000..3b63dc1e
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/java/Poetry.java
@@ -0,0 +1,266 @@
+/**
+ * Game of Poetry
+ * 

+ * Based on the BASIC game of Poetry here + * https://github.com/coding-horror/basic-computer-games/blob/main/70%20Poetry/poetry.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 Poetry { + + private final static double COMMA_RATE = 0.19; + private final static double SPACE_RATE = 0.65; + private final static int PARAGRAPH_RATE = 20; + + private enum Step { + WORD_GROUP1, WORD_GROUP2, WORD_GROUP3, WORD_GROUP4, RANDOMIZE_COMMA, + RANDOMIZE_WHITESPACE, RANDOMIZE_COUNTERS + } + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private void showIntro() { + + System.out.println(" ".repeat(29) + "POETRY"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + } // End of method showIntro + + private void startGame() { + + int groupIndex = 0; + int paragraphIndex = 0; + int punctuationIndex = 0; + int wordIndex = 1; + + Step nextStep = Step.WORD_GROUP1; + + // Begin outer while loop + while (true) { + + switch (nextStep) { + + case WORD_GROUP1: + + if (wordIndex == 1) { + + System.out.print("MIDNIGHT DREARY"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 2) { + + System.out.print("FIERY EYES"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 3) { + + System.out.print("BIRD OR FIEND"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 4) { + + System.out.print("THING OF EVIL"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 5) { + + System.out.print("PROPHET"); + nextStep = Step.RANDOMIZE_COMMA; + } + break; + + case WORD_GROUP2: + + if (wordIndex == 1) { + + System.out.print("BEGUILING ME"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 2) { + + System.out.print("THRILLED ME"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 3) { + + System.out.print("STILL SITTING...."); + nextStep = Step.RANDOMIZE_WHITESPACE; + + } else if (wordIndex == 4) { + + System.out.print("NEVER FLITTING"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 5) { + + System.out.print("BURNED"); + nextStep = Step.RANDOMIZE_COMMA; + } + break; + + case WORD_GROUP3: + + if (wordIndex == 1) { + + System.out.print("AND MY SOUL"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 2) { + + System.out.print("DARKNESS THERE"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 3) { + + System.out.print("SHALL BE LIFTED"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 4) { + + System.out.print("QUOTH THE RAVEN"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 5) { + + if (punctuationIndex != 0) { + + System.out.print("SIGN OF PARTING"); + } + + nextStep = Step.RANDOMIZE_COMMA; + } + break; + + case WORD_GROUP4: + + if (wordIndex == 1) { + + System.out.print("NOTHING MORE"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 2) { + + System.out.print("YET AGAIN"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 3) { + + System.out.print("SLOWLY CREEPING"); + nextStep = Step.RANDOMIZE_WHITESPACE; + + } else if (wordIndex == 4) { + + System.out.print("...EVERMORE"); + nextStep = Step.RANDOMIZE_COMMA; + + } else if (wordIndex == 5) { + + System.out.print("NEVERMORE"); + nextStep = Step.RANDOMIZE_COMMA; + } + break; + + case RANDOMIZE_COMMA: + + // Insert commas + if ((punctuationIndex != 0) && (Math.random() <= COMMA_RATE)) { + + System.out.print(","); + punctuationIndex = 2; + } + nextStep = Step.RANDOMIZE_WHITESPACE; + break; + + + case RANDOMIZE_WHITESPACE: + + // Insert spaces + if (Math.random() <= SPACE_RATE) { + + System.out.print(" "); + punctuationIndex++; + + } + // Insert newlines + else { + + System.out.println(""); + punctuationIndex = 0; + } + nextStep = Step.RANDOMIZE_COUNTERS; + break; + + case RANDOMIZE_COUNTERS: + + wordIndex = (int)((int)(10 * Math.random()) / 2) + 1; + + groupIndex++; + paragraphIndex++; + + if ((punctuationIndex == 0) && (groupIndex % 2 == 0)) { + + System.out.print(" "); + } + + if (groupIndex == 1) { + + nextStep = Step.WORD_GROUP1; + + } else if (groupIndex == 2) { + + nextStep = Step.WORD_GROUP2; + + } else if (groupIndex == 3) { + + nextStep = Step.WORD_GROUP3; + + } else if (groupIndex == 4) { + + nextStep = Step.WORD_GROUP4; + + } else if (groupIndex == 5) { + + groupIndex = 0; + System.out.println(""); + + if (paragraphIndex > PARAGRAPH_RATE) { + + System.out.println(""); + punctuationIndex = 0; + paragraphIndex = 0; + nextStep = Step.WORD_GROUP2; + + } else { + + nextStep = Step.RANDOMIZE_COUNTERS; + } + } + break; + + default: + System.out.println("INVALID STEP"); + break; + } + + } // End outer while loop + + } // End of method startGame + + public static void main(String[] args) { + + Poetry poetry = new Poetry(); + poetry.play(); + + } // End of method main + +} // End of class Poetry diff --git a/00_Alternate_Languages/70_Poetry/java/README.md b/00_Alternate_Languages/70_Poetry/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/70_Poetry/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/70_Poetry/javascript/README.md b/00_Alternate_Languages/70_Poetry/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/70_Poetry/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/70_Poetry/javascript/poetry.html b/00_Alternate_Languages/70_Poetry/javascript/poetry.html new file mode 100644 index 00000000..01dd59bf --- /dev/null +++ b/00_Alternate_Languages/70_Poetry/javascript/poetry.html @@ -0,0 +1,9 @@ + + +POETRY + + +


+
+
+
diff --git a/00_Alternate_Languages/70_Poetry/javascript/poetry.js b/00_Alternate_Languages/70_Poetry/javascript/poetry.js
new file mode 100644
index 00000000..612e2eed
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/javascript/poetry.js
@@ -0,0 +1,173 @@
+// POETRY
+//
+// 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(30) + "POETRY\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+
+    times = 0;
+
+    i = 1;
+    j = 1;
+    k = 0;
+    u = 0;
+    while (1) {
+        if (j == 1) {
+            switch (i) {
+                case 1:
+                    print("MIDNIGHT DREARY");
+                    break;
+                case 2:
+                    print("FIERY EYES");
+                    break;
+                case 3:
+                    print("BIRD OF FIEND");
+                    break;
+                case 4:
+                    print("THING OF EVIL");
+                    break;
+                case 5:
+                    print("PROPHET");
+                    break;
+            }
+        } else if (j == 2) {
+            switch (i) {
+                case 1:
+                    print("BEGUILING ME");
+                    u = 2;
+                    break;
+                case 2:
+                    print("THRILLED ME");
+                    break;
+                case 3:
+                    print("STILL SITTING....");
+                    u = 0;
+                    break;
+                case 4:
+                    print("NEVER FLITTING");
+                    u = 2;
+                    break;
+                case 5:
+                    print("BURNED");
+                    break;
+            }
+        } else if (j == 3) {
+            switch (i) {
+                case 1:
+                    print("AND MY SOUL");
+                    break;
+                case 2:
+                    print("DARKNESS THERE");
+                    break;
+                case 3:
+                    print("SHALL BE LIFTED");
+                    break;
+                case 4:
+                    print("QUOTH THE RAVEN");
+                    break;
+                case 5:
+                    if (u == 0)
+                        break;
+                    print("SIGN OF PARTING");
+                    break;
+            }
+        } else if (j == 4) {
+            switch (i) {
+                case 1:
+                    print("NOTHING MORE");
+                    break;
+                case 2:
+                    print("YET AGAIN");
+                    break;
+                case 3:
+                    print("SLOWLY CREEPING");
+                    break;
+                case 4:
+                    print("...EVERMORE");
+                    break;
+                case 5:
+                    print("NEVERMORE");
+                    break;
+            }
+        }
+        if (u != 0 && Math.random() <= 0.19) {
+            print(",");
+            u = 2;
+        }
+        if (Math.random() <= 0.65) {
+            print(" ");
+            u++;
+        } else {
+            print("\n");
+            u = 0;
+        }
+        while (1) {
+            i = Math.floor(Math.floor(10 * Math.random()) / 2) + 1;
+            j++;
+            k++;
+            if (u == 0 && j % 2 == 0)
+                print("     ");
+            if (j != 5)
+                break;
+            j = 0;
+            print("\n");
+            if (k <= 20)
+                continue;
+            print("\n");
+            u = 0;
+            k = 0;
+            j = 2;
+            break;
+        }
+        if (u == 0 && k == 0 && j == 2 && ++times == 10)
+            break;
+    }
+}
+
+main();
diff --git a/45_Hello/pascal/README.md b/00_Alternate_Languages/70_Poetry/pascal/README.md
similarity index 100%
rename from 45_Hello/pascal/README.md
rename to 00_Alternate_Languages/70_Poetry/pascal/README.md
diff --git a/00_Alternate_Languages/70_Poetry/perl/README.md b/00_Alternate_Languages/70_Poetry/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/70_Poetry/perl/poetry.pl b/00_Alternate_Languages/70_Poetry/perl/poetry.pl
new file mode 100644
index 00000000..585915c4
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/perl/poetry.pl
@@ -0,0 +1,79 @@
+#!/usr/bin/perl
+#use strict;
+# Automatic converted by bas2perl.pl
+# Too much spaguetti code to be properly converted.
+
+
+print ' 'x 30 . "POETRY\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n"; print "\n"; print "\n";
+Line90:
+if ($I==1) { goto Line100; } elsif ($I==2) { goto Line101; } elsif ($I==3) { goto Line102; } elsif ($I==4) { goto Line103; } elsif ($I==5) { goto Line104; } ;
+Line100:
+print "MIDNIGHT DREARY"; goto Line210;
+Line101:
+print "FIERY EYES"; goto Line210;
+Line102:
+print "BIRD OR FIEND"; goto Line210;
+Line103:
+print "THING OF EVIL"; goto Line210;
+Line104:
+print "PROPHET"; goto Line210;
+Line110:
+if ($I==1) { goto Line111; } elsif ($I==2) { goto Line112; } elsif ($I==3) { goto Line113; } elsif ($I==4) { goto Line114; } elsif ($I==5) { goto Line115; } ;
+Line111:
+print "BEGUILING ME"; $U=2; goto Line210;
+Line112:
+print "THRILLED ME"; goto Line210;
+Line113:
+print "STILL SITTING...."; goto Line212;
+Line114:
+print "NEVER FLITTING"; $U=2; goto Line210;
+Line115:
+print "BURNED"; goto Line210;
+Line120:
+if ($I==1) { goto Line121; } elsif ($I==2) { goto Line122; } elsif ($I==3) { goto Line123; } elsif ($I==4) { goto Line124; } elsif ($I==5) { goto Line125; } ;
+Line121:
+print "AND MY SOUL"; goto Line210;
+Line122:
+print "DARKNESS THERE"; goto Line210;
+Line123:
+print "SHALL BE LIFTED"; goto Line210;
+Line124:
+print "QUOTH THE RAVEN"; goto Line210;
+Line125:
+if ($U==0) { goto Line210; }
+print "SIGN OF PARTING"; goto Line210;
+Line130:
+if ($I==1) { goto Line131; } elsif ($I==2) { goto Line132; } elsif ($I==3) { goto Line133; } elsif ($I==4) { goto Line134; } elsif ($I==5) { goto Line135; } ;
+Line131:
+print "NOTHING MORE"; goto Line210;
+Line132:
+print "YET AGAIN"; goto Line210;
+Line133:
+print "SLOWLY CREEPING"; goto Line210;
+Line134:
+print "...EVERMORE"; goto Line210;
+Line135:
+print "NEVERMORE";
+Line210:
+if ($U==0 || rand(1)>.19) { goto Line212; }
+print ","; $U=2;
+Line212:
+if (rand(1)>.65) { goto Line214; }
+print " "; $U=$U+1; goto Line215;
+Line214:
+print "\n"; $U=0;
+Line215:
+$I=int(int(10*rand(1))/2)+1;
+$J=$J+1; $K=$K+1;
+if ($U>0 || int($J/2)!=$J/2) { goto Line240; }
+print " ";
+Line240:
+if ($J==1) { goto Line90; } elsif ($J==2) { goto Line110; } elsif ($J==3) { goto Line120; } elsif ($J==4) { goto Line130; } elsif ($J==5) { goto Line250; } ;
+Line250:
+$J=0; print "\n"; if ($K>20) { goto Line270; }
+goto Line215;
+Line270:
+print "\n"; $U=0; $K=0; goto Line110;
+exit;
diff --git a/00_Alternate_Languages/70_Poetry/poetry.bas b/00_Alternate_Languages/70_Poetry/poetry.bas
new file mode 100644
index 00000000..3661287d
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/poetry.bas
@@ -0,0 +1,42 @@
+10 PRINT TAB(30);"POETRY"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+90 ON I GOTO 100,101,102,103,104
+100 PRINT "MIDNIGHT DREARY";:GOTO 210
+101 PRINT "FIERY EYES";:GOTO 210
+102 PRINT "BIRD OR FIEND";:GOTO 210
+103 PRINT "THING OF EVIL";:GOTO 210
+104 PRINT "PROPHET";:GOTO 210
+110 ON I GOTO 111,112,113,114,115
+111 PRINT "BEGUILING ME";:U=2:GOTO 210
+112 PRINT "THRILLED ME";:GOTO 210
+113 PRINT "STILL SITTING....";:GOTO 212
+114 PRINT "NEVER FLITTING";:U=2:GOTO 210
+115 PRINT "BURNED";:GOTO 210
+120 ON I GOTO 121,122,123,124,125
+121 PRINT "AND MY SOUL";:GOTO 210
+122 PRINT "DARKNESS THERE";:GOTO 210
+123 PRINT "SHALL BE LIFTED";:GOTO 210
+124 PRINT "QUOTH THE RAVEN";:GOTO 210
+125 IF U=0 THEN 210
+126 PRINT "SIGN OF PARTING";:GOTO 210
+130 ON I GOTO 131,132,133,134,135
+131 PRINT "NOTHING MORE";:GOTO 210
+132 PRINT "YET AGAIN";:GOTO 210
+133 PRINT "SLOWLY CREEPING";:GOTO 210
+134 PRINT "...EVERMORE";:GOTO 210
+135 PRINT "NEVERMORE";
+210 IF U=0 OR RND(1)>.19 THEN 212
+211 PRINT ",";:U=2
+212 IF RND(1)>.65 THEN 214
+213 PRINT " ";:U=U+1:GOTO 215
+214 PRINT : U=0
+215 I=INT(INT(10*RND(1))/2)+1
+220 J=J+1 : K=K+1
+230 IF U>0 OR INT(J/2)<>J/2 THEN 240
+235 PRINT "     ";
+240 ON J GOTO 90,110,120,130,250
+250 J=0 : PRINT : IF K>20 THEN 270
+260 GOTO 215
+270 PRINT : U=0 : K=0 : GOTO 110
+999 END
diff --git a/00_Alternate_Languages/70_Poetry/poetry.pl b/00_Alternate_Languages/70_Poetry/poetry.pl
new file mode 100644
index 00000000..585915c4
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/poetry.pl
@@ -0,0 +1,79 @@
+#!/usr/bin/perl
+#use strict;
+# Automatic converted by bas2perl.pl
+# Too much spaguetti code to be properly converted.
+
+
+print ' 'x 30 . "POETRY\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n"; print "\n"; print "\n";
+Line90:
+if ($I==1) { goto Line100; } elsif ($I==2) { goto Line101; } elsif ($I==3) { goto Line102; } elsif ($I==4) { goto Line103; } elsif ($I==5) { goto Line104; } ;
+Line100:
+print "MIDNIGHT DREARY"; goto Line210;
+Line101:
+print "FIERY EYES"; goto Line210;
+Line102:
+print "BIRD OR FIEND"; goto Line210;
+Line103:
+print "THING OF EVIL"; goto Line210;
+Line104:
+print "PROPHET"; goto Line210;
+Line110:
+if ($I==1) { goto Line111; } elsif ($I==2) { goto Line112; } elsif ($I==3) { goto Line113; } elsif ($I==4) { goto Line114; } elsif ($I==5) { goto Line115; } ;
+Line111:
+print "BEGUILING ME"; $U=2; goto Line210;
+Line112:
+print "THRILLED ME"; goto Line210;
+Line113:
+print "STILL SITTING...."; goto Line212;
+Line114:
+print "NEVER FLITTING"; $U=2; goto Line210;
+Line115:
+print "BURNED"; goto Line210;
+Line120:
+if ($I==1) { goto Line121; } elsif ($I==2) { goto Line122; } elsif ($I==3) { goto Line123; } elsif ($I==4) { goto Line124; } elsif ($I==5) { goto Line125; } ;
+Line121:
+print "AND MY SOUL"; goto Line210;
+Line122:
+print "DARKNESS THERE"; goto Line210;
+Line123:
+print "SHALL BE LIFTED"; goto Line210;
+Line124:
+print "QUOTH THE RAVEN"; goto Line210;
+Line125:
+if ($U==0) { goto Line210; }
+print "SIGN OF PARTING"; goto Line210;
+Line130:
+if ($I==1) { goto Line131; } elsif ($I==2) { goto Line132; } elsif ($I==3) { goto Line133; } elsif ($I==4) { goto Line134; } elsif ($I==5) { goto Line135; } ;
+Line131:
+print "NOTHING MORE"; goto Line210;
+Line132:
+print "YET AGAIN"; goto Line210;
+Line133:
+print "SLOWLY CREEPING"; goto Line210;
+Line134:
+print "...EVERMORE"; goto Line210;
+Line135:
+print "NEVERMORE";
+Line210:
+if ($U==0 || rand(1)>.19) { goto Line212; }
+print ","; $U=2;
+Line212:
+if (rand(1)>.65) { goto Line214; }
+print " "; $U=$U+1; goto Line215;
+Line214:
+print "\n"; $U=0;
+Line215:
+$I=int(int(10*rand(1))/2)+1;
+$J=$J+1; $K=$K+1;
+if ($U>0 || int($J/2)!=$J/2) { goto Line240; }
+print " ";
+Line240:
+if ($J==1) { goto Line90; } elsif ($J==2) { goto Line110; } elsif ($J==3) { goto Line120; } elsif ($J==4) { goto Line130; } elsif ($J==5) { goto Line250; } ;
+Line250:
+$J=0; print "\n"; if ($K>20) { goto Line270; }
+goto Line215;
+Line270:
+print "\n"; $U=0; $K=0; goto Line110;
+exit;
diff --git a/00_Alternate_Languages/70_Poetry/python/README.md b/00_Alternate_Languages/70_Poetry/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/70_Poetry/python/poetry.py b/00_Alternate_Languages/70_Poetry/python/poetry.py
new file mode 100644
index 00000000..f27a202e
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/python/poetry.py
@@ -0,0 +1,169 @@
+"""
+POETRY
+
+A poetry generator
+
+Ported by Dave LeCompte
+"""
+
+# PORTING EDITORIAL NOTE:
+#
+# The original code is a pretty convoluted mesh of GOTOs and global
+# state. This adaptation pulls things apart into phrases, but I have
+# left the variables as globals, which makes goes against decades of
+# wisdom that global state is bad.
+import random
+
+PAGE_WIDTH = 64
+
+
+# globals
+u = 0
+i = 0
+j = 0
+k = 0
+phrase = 1
+line = ""
+
+
+def print_centered(msg):
+    spaces = " " * ((PAGE_WIDTH - len(msg)) // 2)
+    print(spaces + msg)
+
+
+def process_phrase_1():
+    global line
+
+    line_1_options = [
+        "MIDNIGHT DREARY",
+        "FIERY EYES",
+        "BIRD OR FIEND",
+        "THING OF EVIL",
+        "PROPHET",
+    ]
+
+    line = line + line_1_options[i]
+    return line
+
+
+def process_phrase_2():
+    global line
+    global u
+
+    line_2_options = [
+        ("BEGUILING ME", 2),
+        ("THRILLED ME", None),
+        ("STILL SITTING....", None),
+        ("NEVER FLITTING", 2),
+        ("BURNED", None),
+    ]
+    words, u_modifier = line_2_options[i]
+    line += words
+    if not (u_modifier is None):
+        u = u_modifier
+
+
+def process_phrase_3():
+    global line
+
+    phrases = [
+        (False, "AND MY SOUL"),
+        (False, "DARKNESS THERE"),
+        (False, "SHALL BE LIFTED"),
+        (False, "QUOTH THE RAVEN"),
+        (True, "SIGN OF PARTING"),
+    ]
+
+    only_if_u, words = phrases[i]
+    if (not only_if_u) or (u > 0):
+        line = line + words
+
+
+def process_phrase_4():
+    global line
+
+    phrases = [
+        ("NOTHING MORE"),
+        ("YET AGAIN"),
+        ("SLOWLY CREEPING"),
+        ("...EVERMORE"),
+        ("NEVERMORE"),
+    ]
+
+    line += phrases[i]
+
+
+def maybe_comma():
+    # line 210
+    global u
+    global line
+
+    if len(line) > 0 and line[-1] == ".":
+        # don't follow a period with a comma, ever
+        return
+
+    if u != 0 and random.random() <= 0.19:
+        line += ", "
+        u = 2
+    # line 212
+    if random.random() <= 0.65:
+        line += " "
+        u += 1
+    else:
+        # line 214
+        print(line)
+        line = ""
+        u = 0
+
+
+def pick_phrase():
+    global phrase
+    global line
+    global i, j, k
+
+    i = random.randint(0, 4)
+    j += 1
+    k += 1
+
+    if u <= 0 and (j % 2) != 0:
+        # random indentation is fun!
+        line += " " * 5
+    phrase = j + 1
+
+
+def main():
+    print_centered("POETRY")
+    print_centered("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+    global line, phrase, j, k, u
+
+    phrase_processors = {
+        1: process_phrase_1,
+        2: process_phrase_2,
+        3: process_phrase_3,
+        4: process_phrase_4,
+    }
+
+    while True:
+        if phrase >= 1 and phrase <= 4:
+            phrase_processors[phrase]()
+            maybe_comma()
+        elif phrase == 5:
+            j = 0
+            print(line)
+            line = ""
+            if k > 20:
+                print()
+                u = 0
+                k = 0
+            else:
+                phrase = 2
+                continue
+        pick_phrase()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/70_Poetry/ruby/README.md b/00_Alternate_Languages/70_Poetry/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/70_Poetry/vbnet/Poetry.sln b/00_Alternate_Languages/70_Poetry/vbnet/Poetry.sln
new file mode 100644
index 00000000..8e235514
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/vbnet/Poetry.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Poetry", "Poetry.vbproj", "{422855D5-5841-40E0-AF1E-993FB25DE7B3}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{422855D5-5841-40E0-AF1E-993FB25DE7B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{422855D5-5841-40E0-AF1E-993FB25DE7B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{422855D5-5841-40E0-AF1E-993FB25DE7B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{422855D5-5841-40E0-AF1E-993FB25DE7B3}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/70_Poetry/vbnet/Poetry.vbproj b/00_Alternate_Languages/70_Poetry/vbnet/Poetry.vbproj
new file mode 100644
index 00000000..fc71a15e
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/vbnet/Poetry.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Poetry
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/70_Poetry/vbnet/README.md b/00_Alternate_Languages/70_Poetry/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/70_Poetry/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/71_Poker/README.md b/00_Alternate_Languages/71_Poker/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/71_Poker/csharp/Poker.csproj b/00_Alternate_Languages/71_Poker/csharp/Poker.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/csharp/Poker.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/71_Poker/csharp/Poker.sln b/00_Alternate_Languages/71_Poker/csharp/Poker.sln
new file mode 100644
index 00000000..5dd63fff
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/csharp/Poker.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Poker", "Poker.csproj", "{CAEDA88F-1585-41AA-8213-40012B044FA9}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{CAEDA88F-1585-41AA-8213-40012B044FA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CAEDA88F-1585-41AA-8213-40012B044FA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CAEDA88F-1585-41AA-8213-40012B044FA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CAEDA88F-1585-41AA-8213-40012B044FA9}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/71_Poker/csharp/README.md b/00_Alternate_Languages/71_Poker/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/71_Poker/java/Poker.java b/00_Alternate_Languages/71_Poker/java/Poker.java
new file mode 100644
index 00000000..426a71fd
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/java/Poker.java
@@ -0,0 +1,851 @@
+import java.util.Random;
+import java.util.Scanner;
+
+import static java.lang.System.out;
+
+/**
+ * Port of CREATIVE COMPUTING Poker written in Commodore 64 Basic to plain Java
+ *
+ * Original source scanned from magazine: https://www.atariarchives.org/basicgames/showpage.php?page=129
+ *
+ * I based my port on the OCR'ed source code here: https://github.com/coding-horror/basic-computer-games/blob/main/71_Poker/poker.bas
+ *
+ * Why? Because I remember typing this into my C64 when I was a tiny little developer and having great fun playing it!
+ *
+ * Goal: Keep the algorithms and UX more or less as-is; Improve the control flow a bit (no goto in Java!) and rename some stuff to be easier to follow.
+ *
+ * Result: There are probably bugs, please let me know.
+ */
+public class Poker {
+
+	public static void main(String[] args) {
+		new Poker().run();
+	}
+
+	float[] cards = new float[50]; // Index 1-5 = Human hand, index 6-10 = Computer hand
+	float[] B = new float[15];
+
+	float playerValuables = 1;
+	float computerMoney = 200;
+	float humanMoney = 200;
+	float pot = 0;
+
+	String J$ = "";
+	float computerHandValue = 0;
+
+	int K = 0;
+	float G = 0;
+	float T = 0;
+	int M = 0;
+	int D = 0;
+
+	int U = 0;
+	float N = 1;
+
+	float I = 0;
+
+	float X = 0;
+
+	int Z = 0;
+
+	String handDescription = "";
+
+	float V;
+
+	void run() {
+		printWelcome();
+		playRound();
+		startAgain();
+	}
+
+	void printWelcome() {
+		tab(33);
+		out.println("POKER");
+		tab(15);
+		out.print("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+		out.println();
+		out.println();
+		out.println();
+		out.println("WELCOME TO THE CASINO.  WE EACH HAVE $200.");
+		out.println("I WILL OPEN THE BETTING BEFORE THE DRAW; YOU OPEN AFTER.");
+		out.println("TO FOLD BET 0; TO CHECK BET .5.");
+		out.println("ENOUGH TALK -- LET'S GET DOWN TO BUSINESS.");
+		out.println();
+	}
+
+	void tab(int number) {
+		System.out.print("\t".repeat(number));
+	}
+
+	int random0to10() {
+		return new Random().nextInt(10);
+	}
+
+	int removeHundreds(long x) {
+		return _int(x - (100F * _int(x / 100F)));
+	}
+
+	void startAgain() {
+		pot = 0;
+		playRound();
+	}
+
+	void playRound() {
+		if (computerMoney <= 5) {
+			computerBroke();
+		}
+
+		out.println("THE ANTE IS $5.  I WILL DEAL:");
+		out.println();
+
+		if (humanMoney <= 5) {
+			playerBroke();
+		}
+
+		pot = pot + 10;
+		humanMoney = humanMoney - 5;
+		computerMoney = computerMoney - 5;
+		for (int Z = 1; Z < 10; Z++) {
+			generateCards(Z);
+		}
+		out.println("YOUR HAND:");
+		N = 1;
+		showHand();
+		N = 6;
+		I = 2;
+
+		describeHand();
+
+		out.println();
+
+		if (I != 6) {
+			if (U >= 13) {
+				if (U <= 16) {
+					Z = 35;
+				} else {
+					Z = 2;
+					if (random0to10() < 1) {
+						Z = 35;
+					}
+				}
+				computerOpens();
+				playerMoves();
+			} else if (random0to10() >= 2) {
+				computerChecks();
+			} else {
+				I = 7;
+				Z = 23;
+				computerOpens();
+				playerMoves();
+			}
+		} else if (random0to10() <= 7) {
+			if (random0to10() <= 7) {
+				if (random0to10() >= 1) {
+					Z = 1;
+					K = 0;
+					out.print("I CHECK. ");
+					playerMoves();
+				} else {
+					X = 11111;
+					I = 7;
+					Z = 23;
+					computerOpens();
+					playerMoves();
+				}
+			} else {
+				X = 11110;
+				I = 7;
+				Z = 23;
+				computerOpens();
+				playerMoves();
+			}
+		} else {
+			X = 11100;
+			I = 7;
+			Z = 23;
+			computerOpens();
+			playerMoves();
+		}
+	}
+
+	void playerMoves() {
+		playersTurn();
+		checkWinnerAfterFirstBet();
+		promptPlayerDrawCards();
+	}
+
+	void computerOpens() {
+		V = Z + random0to10();
+		computerMoves();
+		out.print("I'LL OPEN WITH $" + V);
+		K = _int(V);
+	}
+
+	@SuppressWarnings("StatementWithEmptyBody")
+	void computerMoves() {
+		if (computerMoney - G - V >= 0) {
+		} else if (G != 0) {
+			if (computerMoney - G >= 0) {
+				computerSees();
+			} else {
+				computerBroke();
+			}
+		} else {
+			V = computerMoney;
+		}
+	}
+
+	void promptPlayerDrawCards() {
+		out.println();
+		out.println("NOW WE DRAW -- HOW MANY CARDS DO YOU WANT");
+		inputPlayerDrawCards();
+	}
+
+	void inputPlayerDrawCards() {
+		T = Integer.parseInt(readString());
+		if (T == 0) {
+			computerDrawing();
+		} else {
+			Z = 10;
+			if (T < 4) {
+				playerDrawsCards();
+			} else {
+				out.println("YOU CAN'T DRAW MORE THAN THREE CARDS.");
+				inputPlayerDrawCards();
+			}
+		}
+	}
+
+	// line # 980
+	void computerDrawing() {
+		Z = _int(10 + T);
+		for (U = 6; U <= 10; U++) {
+			if (_int((float) (X / Math.pow(10F, (U - 6F)))) == (10 * (_int((float) (X / Math.pow(10, (U - 5))))))) {
+				drawNextCard();
+			}
+		}
+		out.print("I AM TAKING " + _int(Z - 10 - T) + " CARD");
+		if (Z == 11 + T) {
+			out.println();
+		} else {
+			out.println("S");
+		}
+
+		N = 6;
+		V = I;
+		I = 1;
+		describeHand();
+		startPlayerBettingAndReaction();
+	}
+
+	void drawNextCard() {
+		Z = Z + 1;
+		drawCard();
+	}
+
+	@SuppressWarnings("StatementWithEmptyBody")
+	void drawCard() {
+		cards[Z] = 100 * new Random().nextInt(4) + new Random().nextInt(100);
+		if (_int(cards[Z] / 100) > 3) {
+			drawCard();
+		} else if (cards[Z] - 100 * _int(cards[Z] / 100) > 12) {
+			drawCard();
+		} else if (Z == 1) {
+		} else {
+			for (K = 1; K <= Z - 1; K++) {
+				if (cards[Z] == cards[K]) {
+					drawCard();
+				}
+			}
+			if (Z <= 10) {
+			} else {
+				N = cards[U];
+				cards[U] = cards[Z];
+				cards[Z] = N;
+			}
+		}
+	}
+
+	void playerDrawsCards() {
+		out.println("WHAT ARE THEIR NUMBERS:");
+		for (int Q = 1; Q <= T; Q++) {
+			U = Integer.parseInt(readString());
+			drawNextCard();
+		}
+
+		out.println("YOUR NEW HAND:");
+		N = 1;
+		showHand();
+		computerDrawing();
+	}
+
+	void startPlayerBettingAndReaction() {
+		computerHandValue = U;
+		M = D;
+
+		if (V != 7) {
+			if (I != 6) {
+				if (U >= 13) {
+					if (U >= 16) {
+						Z = 2;
+						playerBetsAndComputerReacts();
+					} else {
+						Z = 19;
+						if (random0to10() == 8) {
+							Z = 11;
+						}
+						playerBetsAndComputerReacts();
+					}
+				} else {
+					Z = 2;
+					if (random0to10() == 6) {
+						Z = 19;
+					}
+					playerBetsAndComputerReacts();
+				}
+			} else {
+				Z = 1;
+				playerBetsAndComputerReacts();
+			}
+		} else {
+			Z = 28;
+			playerBetsAndComputerReacts();
+		}
+	}
+
+	void playerBetsAndComputerReacts() {
+		K = 0;
+		playersTurn();
+		if (T != .5) {
+			checkWinnerAfterFirstBetAndCompareHands();
+		} else if (V == 7 || I != 6) {
+			computerOpens();
+			promptAndInputPlayerBet();
+			checkWinnerAfterFirstBetAndCompareHands();
+		} else {
+			out.println("I'LL CHECK");
+			compareHands();
+		}
+	}
+
+	void checkWinnerAfterFirstBetAndCompareHands() {
+		checkWinnerAfterFirstBet();
+		compareHands();
+	}
+
+	void compareHands() {
+		out.println("NOW WE COMPARE HANDS:");
+		J$ = handDescription;
+		out.println("MY HAND:");
+		N = 6;
+		showHand();
+		N = 1;
+		describeHand();
+		out.print("YOU HAVE ");
+		K = D;
+		printHandDescriptionResult();
+		handDescription = J$;
+		K = M;
+		out.print(" AND I HAVE ");
+		printHandDescriptionResult();
+		out.print(". ");
+		if (computerHandValue > U) {
+			computerWins();
+		} else if (U > computerHandValue) {
+			humanWins();
+		} else if (handDescription.contains("A FLUS")) {
+			someoneWinsWithFlush();
+		} else if (removeHundreds(M) < removeHundreds(D)) {
+			humanWins();
+		} else if (removeHundreds(M) > removeHundreds(D)) {
+			computerWins();
+		} else {
+			handIsDrawn();
+		}
+	}
+
+	void printHandDescriptionResult() {
+		out.print(handDescription);
+		if (!handDescription.contains("A FLUS")) {
+			K = removeHundreds(K);
+			printCardValue();
+			if (handDescription.contains("SCHMAL")) {
+				out.print(" HIGH");
+			} else if (!handDescription.contains("STRAIG")) {
+				out.print("'S");
+			} else {
+				out.print(" HIGH");
+			}
+		} else {
+			K = K / 100;
+			printCardColor();
+			out.println();
+		}
+	}
+
+	void handIsDrawn() {
+		out.print("THE HAND IS DRAWN.");
+		out.print("ALL $" + pot + " REMAINS IN THE POT.");
+		playRound();
+	}
+
+	void someoneWinsWithFlush() {
+		if (removeHundreds(M) > removeHundreds(D)) {
+			computerWins();
+		} else if (removeHundreds(D) > removeHundreds(M)) {
+			humanWins();
+		} else {
+			handIsDrawn();
+		}
+	}
+
+	@SuppressWarnings("StatementWithEmptyBody")
+	void checkWinnerAfterFirstBet() {
+		if (I != 3) {
+			if (I != 4) {
+			} else {
+				humanWins();
+			}
+		} else {
+			out.println();
+			computerWins();
+		}
+	}
+
+	void computerWins() {
+		out.print(". I WIN. ");
+		computerMoney = computerMoney + pot;
+		potStatusAndNextRoundPrompt();
+	}
+
+	void potStatusAndNextRoundPrompt() {
+		out.println("NOW I HAVE $" + computerMoney + " AND YOU HAVE $" + humanMoney);
+		out.print("DO YOU WISH TO CONTINUE");
+
+		if (yesFromPrompt()) {
+			startAgain();
+		} else {
+			System.exit(0);
+		}
+	}
+
+	private boolean yesFromPrompt() {
+		String h = readString();
+		if (h != null) {
+			if (h.toLowerCase().matches("y|yes|yep|affirmative|yay")) {
+				return true;
+			} else if (h.toLowerCase().matches("n|no|nope|fuck off|nay")) {
+				return false;
+			}
+		}
+		out.println("ANSWER YES OR NO, PLEASE.");
+		return yesFromPrompt();
+	}
+
+	void computerChecks() {
+		Z = 0;
+		K = 0;
+		out.print("I CHECK. ");
+		playerMoves();
+	}
+
+	void humanWins() {
+		out.println("YOU WIN.");
+		humanMoney = humanMoney + pot;
+		potStatusAndNextRoundPrompt();
+	}
+
+	// line # 1740
+	void generateCards(int Z) {
+		cards[Z] = (100 * new Random().nextInt(4)) + new Random().nextInt(100);
+		if (_int(cards[Z] / 100) > 3) {
+			generateCards(Z);
+			return;
+		}
+		if (cards[Z] - 100 * (_int(cards[Z] / 100)) > 12) {
+			generateCards(Z);
+			return;
+		}
+		if (Z == 1) {return;}
+		for (int K = 1; K <= Z - 1; K++) {// TO Z-1
+			if (cards[Z] == cards[K]) {
+				generateCards(Z);
+				return;
+			}
+		}
+		if (Z <= 10) {return;}
+		float N = cards[U];
+		cards[U] = cards[Z];
+		cards[Z] = N;
+	}
+
+	// line # 1850
+	void showHand() {
+		for (int cardNumber = _int(N); cardNumber <= N + 4; cardNumber++) {
+			out.print(cardNumber + "--  ");
+			printCardValueAtIndex(cardNumber);
+			out.print(" OF");
+			printCardColorAtIndex(cardNumber);
+			if (cardNumber / 2 == (cardNumber / 2)) {
+				out.println();
+			}
+		}
+	}
+
+	// line # 1950
+	void printCardValueAtIndex(int Z) {
+		K = removeHundreds(_int(cards[Z]));
+		printCardValue();
+	}
+
+	void printCardValue() {
+		if (K == 9) {
+			out.print("JACK");
+		} else if (K == 10) {
+			out.print("QUEEN");
+		} else if (K == 11) {
+			out.print("KING");
+		} else if (K == 12) {
+			out.print("ACE");
+		} else if (K < 9) {
+			out.print(K + 2);
+		}
+	}
+
+	// line # 2070
+	void printCardColorAtIndex(int Z) {
+		K = _int(cards[Z] / 100);
+		printCardColor();
+	}
+
+	void printCardColor() {
+		if (K == 0) {
+			out.print(" CLUBS");
+		} else if (K == 1) {
+			out.print(" DIAMONDS");
+		} else if (K == 2) {
+			out.print(" HEARTS");
+		} else if (K == 3) {
+			out.print(" SPADES");
+		}
+	}
+
+	// line # 2170
+	void describeHand() {
+		U = 0;
+		for (Z = _int(N); Z <= N + 4; Z++) {
+			B[Z] = removeHundreds(_int(cards[Z]));
+			if (Z == N + 4) {continue;}
+			if (_int(cards[Z] / 100) != _int(cards[Z + 1] / 100)) {continue;}
+			U = U + 1;
+		}
+		if (U != 4) {
+			for (Z = _int(N); Z <= N + 3; Z++) {
+				for (K = Z + 1; K <= N + 4; K++) {
+					if (B[Z] <= B[K]) {continue;}
+					X = cards[Z];
+					cards[Z] = cards[K];
+					B[Z] = B[K];
+					cards[K] = X;
+					B[K] = cards[K] - 100 * _int(cards[K] / 100);
+				}
+			}
+			X = 0;
+			for (Z = _int(N); Z <= N + 3; Z++) {
+				if (B[Z] != B[Z + 1]) {continue;}
+				X = (float) (X + 11 * Math.pow(10, (Z - N)));
+				D = _int(cards[Z]);
+
+				if (U >= 11) {
+					if (U != 11) {
+						if (U > 12) {
+							if (B[Z] != B[Z - 1]) {
+								fullHouse();
+							} else {
+								U = 17;
+								handDescription = "FOUR ";
+							}
+						} else {
+							fullHouse();
+						}
+					} else if (B[Z] != B[Z - 1]) {
+						handDescription = "TWO PAIR, ";
+						U = 12;
+					} else {
+						handDescription = "THREE ";
+						U = 13;
+					}
+				} else {
+					U = 11;
+					handDescription = "A PAIR OF ";
+				}
+			}
+
+			if (X != 0) {
+				schmaltzHand();
+			} else {
+				if (B[_int(N)] + 3 == B[_int(N + 3)]) {
+					X = 1111;
+					U = 10;
+				}
+				if (B[_int(N + 1)] + 3 != B[_int(N + 4)]) {
+					schmaltzHand();
+				} else if (U != 10) {
+					U = 10;
+					X = 11110;
+					schmaltzHand();
+				} else {
+					U = 14;
+					handDescription = "STRAIGHT";
+					X = 11111;
+					D = _int(cards[_int(N + 4)]);
+				}
+			}
+		} else {
+			X = 11111;
+			D = _int(cards[_int(N)]);
+			handDescription = "A FLUSH IN";
+			U = 15;
+		}
+	}
+
+	void schmaltzHand() {
+		if (U >= 10) {
+			if (U != 10) {
+				if (U > 12) {return;}
+				if (removeHundreds(D) <= 6) {
+					I = 6;
+				}
+			} else {
+				if (I == 1) {
+					I = 6;
+				}
+			}
+		} else {
+			D = _int(cards[_int(N + 4)]);
+			handDescription = "SCHMALTZ, ";
+			U = 9;
+			X = 11000;
+			I = 6;
+		}
+	}
+
+	void fullHouse() {
+		U = 16;
+		handDescription = "FULL HOUSE, ";
+	}
+
+	void playersTurn() {
+		G = 0;
+		promptAndInputPlayerBet();
+	}
+
+	String readString() {
+		Scanner sc = new Scanner(System.in);
+		return sc.nextLine();
+	}
+
+	@SuppressWarnings("StatementWithEmptyBody")
+	void promptAndInputPlayerBet() {
+		out.println("WHAT IS YOUR BET");
+		T = readFloat();
+		if (T - _int(T) == 0) {
+			processPlayerBet();
+		} else if (K != 0) {
+			playerBetInvalidAmount();
+		} else if (G != 0) {
+			playerBetInvalidAmount();
+		} else if (T == .5) {
+		} else {
+			playerBetInvalidAmount();
+		}
+	}
+
+	private float readFloat() {
+		try {
+			return Float.parseFloat(readString());
+		} catch (Exception ex) {
+			System.out.println("INVALID INPUT, PLEASE TYPE A FLOAT. ");
+			return readFloat();
+		}
+	}
+
+	void playerBetInvalidAmount() {
+		out.println("NO SMALL CHANGE, PLEASE.");
+		promptAndInputPlayerBet();
+	}
+
+	void processPlayerBet() {
+		if (humanMoney - G - T >= 0) {
+			humanCanAffordBet();
+		} else {
+			playerBroke();
+			promptAndInputPlayerBet();
+		}
+	}
+
+	void humanCanAffordBet() {
+		if (T != 0) {
+			if (G + T >= K) {
+				processComputerMove();
+			} else {
+				out.println("IF YOU CAN'T SEE MY BET, THEN FOLD.");
+				promptAndInputPlayerBet();
+			}
+		} else {
+			I = 3;
+			moveMoneyToPot();
+		}
+	}
+
+	void processComputerMove() {
+		G = G + T;
+		if (G == K) {
+			moveMoneyToPot();
+		} else if (Z != 1) {
+			if (G > 3 * Z) {
+				computerRaisesOrSees();
+			} else {
+				computerRaises();
+			}
+		} else if (G > 5) {
+			if (T <= 25) {
+				computerRaisesOrSees();
+			} else {
+				computerFolds();
+			}
+		} else {
+			V = 5;
+			if (G > 3 * Z) {
+				computerRaisesOrSees();
+			} else {
+				computerRaises();
+			}
+		}
+	}
+
+	void computerRaises() {
+		V = G - K + random0to10();
+		computerMoves();
+		out.println("I'LL SEE YOU, AND RAISE YOU" + V);
+		K = _int(G + V);
+		promptAndInputPlayerBet();
+	}
+
+	void computerFolds() {
+		I = 4;
+		out.println("I FOLD.");
+	}
+
+	void computerRaisesOrSees() {
+		if (Z == 2) {
+			computerRaises();
+		} else {
+			computerSees();
+		}
+	}
+
+	void computerSees() {
+		out.println("I'LL SEE YOU.");
+		K = _int(G);
+		moveMoneyToPot();
+	}
+
+	void moveMoneyToPot() {
+		humanMoney = humanMoney - G;
+		computerMoney = computerMoney - K;
+		pot = pot + G + K;
+	}
+
+	void computerBusted() {
+		out.println("I'M BUSTED.  CONGRATULATIONS!");
+		System.exit(0);
+	}
+
+	@SuppressWarnings("StatementWithEmptyBody")
+	private void computerBroke() {
+		if ((playerValuables / 2) == _int(playerValuables / 2) && playerBuyBackWatch()) {
+		} else if (playerValuables / 3 == _int(playerValuables / 3) && playerBuyBackTieRack()) {
+		} else {
+			computerBusted();
+		}
+	}
+
+	private int _int(float v) {
+		return (int) Math.floor(v);
+	}
+
+	private boolean playerBuyBackWatch() {
+		out.println("WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50");
+		if (yesFromPrompt()) {
+			computerMoney = computerMoney + 50;
+			playerValuables = playerValuables / 2;
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	private boolean playerBuyBackTieRack() {
+		out.println("WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50");
+		if (yesFromPrompt()) {
+			computerMoney = computerMoney + 50;
+			playerValuables = playerValuables / 3;
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	// line # 3830
+	@SuppressWarnings("StatementWithEmptyBody")
+	void playerBroke() {
+		out.println("YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT.");
+		if (playerValuables / 2 != _int(playerValuables / 2) && playerSellWatch()) {
+		} else if (playerValuables / 3 != _int(playerValuables / 3) && playerSellTieTack()) {
+		} else {
+			playerBusted();
+		}
+	}
+
+	private void playerBusted() {
+		out.println("YOUR WAD IS SHOT. SO LONG, SUCKER!");
+		System.exit(0);
+	}
+
+	private boolean playerSellWatch() {
+		out.println("WOULD YOU LIKE TO SELL YOUR WATCH");
+		if (yesFromPrompt()) {
+			if (random0to10() < 7) {
+				out.println("I'LL GIVE YOU $75 FOR IT.");
+				humanMoney = humanMoney + 75;
+			} else {
+				out.println("THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25.");
+				humanMoney = humanMoney + 25;
+			}
+			playerValuables = playerValuables * 2;
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+	private boolean playerSellTieTack() {
+		out.println("WILL YOU PART WITH THAT DIAMOND TIE TACK");
+
+		if (yesFromPrompt()) {
+			if (random0to10() < 6) {
+				out.println("YOU ARE NOW $100 RICHER.");
+				humanMoney = humanMoney + 100;
+			} else {
+				out.println("IT'S PASTE.  $25.");
+				humanMoney = humanMoney + 25;
+			}
+			playerValuables = playerValuables * 3;
+			return true;
+		} else {
+			return false;
+		}
+	}
+
+}
diff --git a/00_Alternate_Languages/71_Poker/java/README.md b/00_Alternate_Languages/71_Poker/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/71_Poker/javascript/README.md b/00_Alternate_Languages/71_Poker/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/71_Poker/javascript/poker.html b/00_Alternate_Languages/71_Poker/javascript/poker.html
new file mode 100644
index 00000000..c2abd411
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/javascript/poker.html
@@ -0,0 +1,9 @@
+
+
+POKER
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/71_Poker/javascript/poker.js b/00_Alternate_Languages/71_Poker/javascript/poker.js
new file mode 100644
index 00000000..73f3c9f0
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/javascript/poker.js
@@ -0,0 +1,751 @@
+// POKER
+//
+// 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 aa = [];
+var ba = [];
+var b;
+var c;
+var d;
+var g;
+var i;
+var k;
+var m;
+var n;
+var p;
+var s;
+var u;
+var v;
+var x;
+var z;
+var hs;
+var is;
+var js;
+var ks;
+
+function fna(x)
+{
+    return Math.floor(10 * Math.random());
+}
+
+function fnb(x)
+{
+    return x % 100;
+}
+
+function im_busted()
+{
+    print("I'M BUSTED.  CONGRATULATIONS!\n");
+}
+
+// 1740
+function deal_card()
+{
+    while (1) {
+        aa[z] = 100 * Math.floor(4 * Math.random()) + Math.floor(100 * Math.random());
+        if (Math.floor(aa[z] / 100) > 3)    // Invalid suit
+            continue;
+        if (aa[z] % 100 > 12) // Invalid number
+            continue;
+        if (z != 1) {
+            for (k = 1; k <= z - 1; k++) {
+                if (aa[z] == aa[k])
+                    break;
+            }
+            if (k <= z - 1) // Repeated card
+                continue;
+            if (z > 10) {
+                n = aa[u];
+                aa[u] = aa[z];
+                aa[z] = n;
+            }
+        }
+        return;
+    }
+}
+
+// 1850
+function show_cards()
+{
+    for (z = n; z <= n + 4; z++) {
+        print(" " + z + "--  ");
+        k = fnb(aa[z]);
+        show_number();
+        print(" OF");
+        k = Math.floor(aa[z] / 100);
+        show_suit();
+        if (z % 2 == 0)
+            print("\n");
+    }
+    print("\n");
+}
+
+// 1950
+function show_number()
+{
+    if (k == 9)
+        print("JACK");
+    if (k == 10)
+        print("QUEEN");
+    if (k == 11)
+        print("KING");
+    if (k == 12)
+        print("ACE");
+    if (k < 9)
+        print(" " + (k + 2));
+}
+
+// 2070
+function show_suit()
+{
+    if (k == 0)
+        print(" CLUBS\t");
+    if (k == 1)
+        print(" DIAMONDS\t");
+    if (k == 2)
+        print(" HEARTS\t");
+    if (k == 3)
+        print(" SPADES\t");
+}
+
+// 2170
+function evaluate_hand()
+{
+    u = 0;
+    for (z = n; z <= n + 4; z++) {
+        ba[z] = fnb(aa[z]);
+        if (z != n + 4) {
+            if (Math.floor(aa[z] / 100) == Math.floor(aa[z + 1] / 100))
+                u++;
+        }
+    }
+    if (u == 4) {
+        x = 11111;
+        d = aa[n];
+        hs = "A FLUS";
+        is = "H IN";
+        u = 15;
+        return;
+    }
+    for (z = n; z <= n + 3; z++) {
+        for (k = z + 1; k <= n + 4; k++) {
+            if (ba[z] > ba[k]) {
+                x = aa[z];
+                aa[z] = aa[k];
+                ba[z] = ba[k];
+                aa[k] = x;
+                ba[k] = aa[k] - 100 * Math.floor(aa[k] / 100);
+            }
+        }
+    }
+    x = 0;
+    for (z = n; z <= n + 3; z++) {
+        if (ba[z] == ba[z + 1]) {
+            x = x + 11 * Math.pow(10, z - n);
+            d = aa[z];
+            if (u < 11) {
+                u = 11;
+                hs = "A PAIR";
+                is = " OF ";
+            } else if (u == 11) {
+                if (ba[z] == ba[z - 1]) {
+                    hs = "THREE";
+                    is = " ";
+                    u = 13;
+                } else {
+                    hs = "TWO P";
+                    is = "AIR, ";
+                    u = 12;
+                }
+            } else if (u == 12) {
+                u = 16;
+                hs = "FULL H";
+                is = "OUSE, ";
+            } else if (ba[z] == ba[z - 1]) {
+                u = 17;
+                hs = "FOUR";
+                is = " ";
+            } else {
+                u = 16;
+                hs = "FULL H";
+                is = "OUSE. ";
+            }
+        }
+    }
+    if (x == 0) {
+        if (ba[n] + 3 == ba[n + 3]) {
+            x = 1111;
+            u = 10;
+        }
+        if (ba[n + 1] + 3 == ba[n + 4]) {
+            if (u == 10) {
+                u = 14;
+                hs = "STRAIG";
+                is = "HT";
+                x = 11111;
+                d = aa[n + 4];
+                return;
+            }
+            u = 10;
+            x = 11110;
+        }
+    }
+    if (u < 10) {
+        d = aa[n + 4];
+        hs = "SCHMAL";
+        is = "TZ, ";
+        u = 9;
+        x = 11000;
+        i = 6;
+        return;
+    }
+    if (u == 10) {
+        if (i == 1)
+            i = 6;
+        return;
+    }
+    if (u > 12)
+        return;
+    if (fnb(d) > 6)
+        return;
+    i = 6;
+}
+
+function get_prompt(question, def)
+{
+    var str;
+
+    str = window.prompt(question, def);
+    print(question + "? " + str + "\n");
+    return str;
+}
+
+function player_low_in_money()
+{
+    print("\n");
+    print("YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT.\n");
+    str = "N";
+    if (o % 2 != 0) {
+        str = get_prompt("WOULD YOU LIKE TO SELL YOUR WATCH", "YES");
+        if (str.substr(0, 1) != "N") {
+            if (fna(0) < 7) {
+                print("I'LL GIVE YOU $75 FOR IT.\n");
+                s += 75;
+            } else {
+                print("THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25.\n");
+                s += 25;
+            }
+            o *= 2;
+        }
+    }
+    if (o % 3 == 0 && str.substr(0, 1) == "N") {
+        str = get_prompt("WILL YOU PART WITH THAT DIAMOND TIE TACK", "YES");
+        if (str.substr(0, 1) != "N") {
+            if (fna(0) < 6) {
+                print("YOU ARE NOW $100 RICHER.\n");
+                s += 100;
+            } else {
+                print("IT'S PASTE.  $25.\n");
+                s += 25;
+            }
+            o *= 3;
+        }
+    }
+    if (str.substr(0,1) == "N") {
+        print("YOUR WAD IS SHOT.  SO LONG, SUCKER!\n");
+        return true;
+    }
+    return false;
+}
+
+function computer_low_in_money()
+{
+    if (c - g - v >= 0)
+        return false;
+    if (g == 0) {
+        v = c;
+        return false;
+    }
+    if (c - g < 0) {
+        print("I'LL SEE YOU.\n");
+        k = g;
+        s = s - g;
+        c = c - k;
+        p = p + g + k;
+        return false;
+    }
+    js = "N";
+    if (o % 2 == 0) {
+        js = get_prompt("WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50", "YES");
+        if (js.substr(0, 1) != "N") {
+            c += 50;
+            o /= 2;
+        }
+    }
+    if (js.substr(0, 1) == "N" && o % 3 == 0) {
+        js = get_prompt("WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50", "YES");
+        if (js.substr(0, 1) != "N") {
+            c += 50;
+            o /= 3;
+        }
+    }
+    if (js.substr(0, 1) == "N") {
+        print("I'M BUSTED.  CONGRATULATIONS!\n");
+        return true;
+    }
+    return false;
+}
+
+function ask_for_bet()
+{
+    var forced;
+
+    if (t != Math.floor(t)) {
+        if (k != 0 || g != 0 || t != 0.5) {
+            print("NO SMALL CHANGE, PLEASE.\n");
+            return 0;
+        }
+        return 1;
+    }
+    if (s - g - t < 0) {
+        if (player_low_in_money())
+            return 2;
+        return 0;
+    }
+    if (t == 0) {
+        i = 3;
+    } else if (g + t < k) {
+        print("IF YOU CAN'T SEE MY BET, THEN FOLD.\n");
+        return 0;
+    } else {
+        g += t;
+        if (g != k) {
+            forced = false;
+            if (z != 1) {
+                if (g <= 3 * z)
+                    forced = true;
+            } else {
+                if (g <= 5) {
+                    if (z < 2) {
+                        v = 5;
+                        if (g <= 3 * z)
+                            forced = true;
+                    }
+                } else {
+                    if (z == 1 || t > 25) {
+                        i = 4;
+                        print("I FOLD.\n");
+                        return 1;
+                    }
+                }
+            }
+            if (forced || z == 2) {
+                v = g - k + fna(0);
+                if (computer_low_in_money())
+                    return 2;
+                print("I'LL SEE YOU, AND RAISE YOU " + v + "\n");
+                k = g + v;
+                return 0;
+            }
+            print("I'LL SEE YOU.\n");
+            k = g;
+        }
+    }
+    s -= g;
+    c -= k;
+    p += g + k;
+    return 1;
+}
+
+function check_for_win(type)
+{
+    if (type == 0 && i == 3 || type == 1) {
+        print("\n");
+        print("I WIN.\n");
+        c += p;
+    } else if (type == 0 && i == 4 || type == 2) {
+        print("\n");
+        print("YOU WIN.\n");
+        s += p;
+    } else {
+        return 0;
+    }
+    print("NOW I HAVE $" + c + " AND YOU HAVE $" + s + "\n");
+    return 1;
+}
+
+function show_hand()
+{
+    print(hs + is);
+    if (hs == "A FLUS") {
+        k = Math.floor(k / 100);
+        print("\n");
+        show_suit();
+        print("\n");
+    } else {
+        k = fnb(k);
+        show_number();
+        if (hs == "SCHMAL" || hs == "STRAIG")
+            print(" HIGH\n");
+        else
+            print("'S\n");
+    }
+}
+
+// Main program
+async function main()
+{
+    print(tab(33) + "POKER\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("WELCOME TO THE CASINO.  WE EACH HAVE $200.\n");
+    print("I WILL OPEN THE BETTING BEFORE THE DRAW; YOU OPEN AFTER.\n");
+    print("TO FOLD BET 0; TO CHECK BET .5.\n");
+    print("ENOUGH TALK -- LET'S GET DOWN TO BUSINESS.\n");
+    print("\n");
+    o = 1;
+    c = 200;
+    s = 200;
+    z = 0;
+    while (1) {
+        p = 0;
+        //
+        print("\n");
+        if (c <= 5) {
+            im_busted();
+            return;
+        }
+        print("THE ANTE IS $5, I WILL DEAL:\n");
+        print("\n");
+        if (s <= 5) {
+            if (player_low_in_money())
+                return;
+        }
+        p += 10;
+        s -= 5;
+        c -= 5;
+        for (z = 1; z <= 10; z++)
+            deal_card();
+        print("YOUR HAND:\n");
+        n = 1;
+        show_cards();
+        n = 6;
+        i = 2;
+        evaluate_hand();
+        print("\n");
+        first = true;
+        if (i == 6) {
+            if (fna(0) > 7) {
+                x = 11100;
+                i = 7;
+                z = 23;
+            } else if (fna(0) > 7) {
+                x = 11110;
+                i = 7;
+                z = 23;
+            } else if (fna(0) < 2) {
+                x = 11111;
+                i = 7;
+                z = 23;
+            } else {
+                z = 1;
+                k = 0;
+                print("I CHECK.\n");
+                first = false;
+            }
+        } else {
+            if (u < 13) {
+                if (fna(0) < 2) {
+                    i = 7;
+                    z = 23;
+                } else {
+                    z = 0;
+                    k = 0;
+                    print("I CHECK.\n");
+                    first = false;
+                }
+            } else if (u > 16) {
+                z = 2;
+                if (fna(0) < 1)
+                    z = 35;
+            } else {
+                z = 35;
+            }
+        }
+        if (first) {
+            v = z + fna(0);
+            g = 0;
+            if (computer_low_in_money())
+                return;
+            print("I'LL OPEN WITH $" + v + "\n");
+            k = v;
+        }
+        g = 0;
+        do {
+            print("\nWHAT IS YOUR BET");
+            t = parseFloat(await input());
+            status = ask_for_bet();
+        } while (status == 0) ;
+        if (status == 2)
+            return;
+        status = check_for_win(0);
+        if (status == 1) {
+            while (1) {
+                print("DO YOU WISH TO CONTINUE");
+                hs = await input();
+                if (hs == "YES") {
+                    status = 1;
+                    break;
+                }
+                if (hs == "NO") {
+                    status = 2;
+                    break;
+                }
+                print("ANSWER YES OR NO, PLEASE.\n");
+            }
+        }
+        if (status == 2)
+            return;
+        if (status == 1) {
+            p = 0;
+            continue;
+        }
+        print("\n");
+        print("NOW WE DRAW -- HOW MANY CARDS DO YOU WANT");
+        while (1) {
+            t = parseInt(await input());
+            if (t != 0) {
+                z = 10;
+                if (t >= 4) {
+                    print("YOU CAN'T DRAW MORE THAN THREE CARDS.\n");
+                    continue;
+                }
+                print("WHAT ARE THEIR NUMBERS:\n");
+                for (q = 1; q <= t; q++) {
+                    u = parseInt(await input());
+                    z++;
+                    deal_card();
+                }
+                print("YOUR NEW HAND:\n");
+                n = 1;
+                show_cards();
+            }
+            break;
+        }
+        z = 10 + t;
+        for (u = 6; u <= 10; u++) {
+            if (Math.floor(x / Math.pow(10, u - 6)) != 10 * Math.floor(x / Math.pow(10, u - 5)))
+                break;
+            z++;
+            deal_card();
+        }
+        print("\n");
+        print("I AM TAKING " + (z - 10 - t) + " CARD");
+        if (z != 11 + t) {
+            print("S");
+        }
+        print("\n");
+        n = 6;
+        v = i;
+        i = 1;
+        evaluate_hand();
+        b = u;
+        m = d;
+        if (v == 7) {
+            z = 28;
+        } else if (i == 6) {
+            z = 1;
+        } else {
+            if (u < 13) {
+                z = 2;
+                if (fna(0) == 6)
+                    z = 19;
+            } else if (u < 16) {
+                z = 19;
+                if (fna(0) == 8)
+                    z = 11;
+            } else {
+                z = 2;
+            }
+        }
+        k = 0;
+        g = 0;
+        do {
+            print("\nWHAT IS YOUR BET");
+            t = parseFloat(await input());
+            status = ask_for_bet();
+        } while (status == 0) ;
+        if (status == 2)
+            return;
+        if (t == 0.5) {
+            if (v != 7 && i == 6) {
+                print("I'LL CHECK\n");
+            } else {
+                v = z + fna(0);
+                if (computer_low_in_money())
+                    return;
+                print("I'LL BET $" + v + "\n");
+                k = v;
+                do {
+                    print("\nWHAT IS YOUR BET");
+                    t = parseFloat(await input());
+                    status = ask_for_bet();
+                } while (status == 0) ;
+                if (status == 2)
+                    return;
+                status = check_for_win(0);
+                if (status == 1) {
+                    while (1) {
+                        print("DO YOU WISH TO CONTINUE");
+                        hs = await input();
+                        if (hs == "YES") {
+                            status = 1;
+                            break;
+                        }
+                        if (hs == "NO") {
+                            status = 2;
+                            break;
+                        }
+                        print("ANSWER YES OR NO, PLEASE.\n");
+                    }
+                }
+                if (status == 2)
+                    return;
+                if (status == 1) {
+                    p = 0;
+                    continue;
+                }
+            }
+        } else {
+            status = check_for_win(0);
+            if (status == 1) {
+                while (1) {
+                    print("DO YOU WISH TO CONTINUE");
+                    hs = await input();
+                    if (hs == "YES") {
+                        status = 1;
+                        break;
+                    }
+                    if (hs == "NO") {
+                        status = 2;
+                        break;
+                    }
+                    print("ANSWER YES OR NO, PLEASE.\n");
+                }
+            }
+            if (status == 2)
+                return;
+            if (status == 1) {
+                p = 0;
+                continue;
+            }
+        }
+        print("\n");
+        print("NOW WE COMPARE HANDS:\n");
+        js = hs;
+        ks = is;
+        print("MY HAND:\n");
+        n = 6;
+        show_cards();
+        n = 1;
+        evaluate_hand();
+        print("\n");
+        print("YOU HAVE ");
+        k = d;
+        show_hand();
+        hs = js;
+        is = ks;
+        k = m;
+        print("AND I HAVE ");
+        show_hand();
+        status = 0;
+        if (b > u) {
+            status = 1;
+        } else if (u > b) {
+            status = 2;
+        } else {
+            if (hs != "A FLUS") {
+                if (fnb(m) < fnb(d))
+                    status = 2;
+                else if (fnb(m) > fnb(d))
+                    status = 1;
+            } else {
+                if (fnb(m) > fnb(d))
+                    status = 1;
+                else if (fnb(d) > fnb(m))
+                    status = 2;
+            }
+            if (status == 0) {
+                print("THE HAND IS DRAWN.\n");
+                print("ALL $" + p + " REMAINS IN THE POT.\n");
+                continue;
+            }
+        }
+        status = check_for_win(status);
+        if (status == 1) {
+            while (1) {
+                print("DO YOU WISH TO CONTINUE");
+                hs = await input();
+                if (hs == "YES") {
+                    status = 1;
+                    break;
+                }
+                if (hs == "NO") {
+                    status = 2;
+                    break;
+                }
+                print("ANSWER YES OR NO, PLEASE.\n");
+            }
+        }
+        if (status == 2)
+            return;
+        if (status == 1) {
+            p = 0;
+            continue;
+        }
+    }
+}
+
+main();
diff --git a/46_Hexapawn/pascal/README.md b/00_Alternate_Languages/71_Poker/pascal/README.md
similarity index 100%
rename from 46_Hexapawn/pascal/README.md
rename to 00_Alternate_Languages/71_Poker/pascal/README.md
diff --git a/00_Alternate_Languages/71_Poker/perl/README.md b/00_Alternate_Languages/71_Poker/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/71_Poker/poker.bas b/00_Alternate_Languages/71_Poker/poker.bas
new file mode 100644
index 00000000..82bfe862
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/poker.bas
@@ -0,0 +1,416 @@
+2 PRINT TAB(33);"POKER"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT: PRINT: PRINT
+10 DIM A(50),B(15)
+20 DEF FNA(X)=INT(10*RND(1))
+30 DEF FNB(X)=X-100*INT(X/100)
+40 PRINT "WELCOME TO THE CASINO.  WE EACH HAVE $200."
+50 PRINT "I WILL OPEN THE BETTING BEFORE THE DRAW; YOU OPEN AFTER."
+60 PRINT "TO FOLD BET 0; TO CHECK BET .5."
+70 PRINT "ENOUGH TALK -- LET'S GET DOWN TO BUSINESS."
+80 PRINT
+90 LET O=1
+100 LET C=200
+110 LET S=200
+120 LET P=0
+130 REM
+140 PRINT
+150 IF C<=5 THEN 3670
+160 PRINT "THE ANTE IS $5.  I WILL DEAL:"
+170 PRINT
+180 IF S>5 THEN 200
+190 GOSUB 3830
+200 LET P=P+10
+210 LET S=S-5
+220 LET C=C-5
+230 FOR Z=1 TO 10
+240 GOSUB 1740
+250 NEXT Z
+260 PRINT "YOUR HAND:"
+270 N=1
+280 GOSUB 1850
+290 N=6
+300 I=2
+310 GOSUB 2170
+320 PRINT
+330 IF I<>6 THEN 470
+340 IF FNA(0)<=7 THEN 370
+350 LET X=11100
+360 GOTO 420
+370 IF FNA(0)<=7 THEN 400
+380 LET X=11110
+390 GOTO 420
+400 IF FNA(0)>=1 THEN 450
+410 X=11111
+420 I=7
+430 Z=23
+440 GOTO 580
+450 Z=1
+460 GOTO 510
+470 IF U>=13 THEN 540
+480 IF FNA(0)>=2 THEN 500
+490 GOTO 420
+500 Z=0
+510 K=0
+520 PRINT "I CHECK."
+530 GOTO 620
+540 IF U<=16 THEN 570
+550 Z=2
+560 IF FNA(0)>=1 THEN 580
+570 Z=35
+580 V=Z+FNA(0)
+590 GOSUB 3480
+600 PRINT "I'LL OPEN WITH $"V
+610 K=V
+620 GOSUB 3050
+630 GOSUB 650
+640 GOTO 820
+650 IF I<>3 THEN 760
+660 PRINT
+670 PRINT "I WIN."
+680 C=C+P
+690 PRINT "NOW I HAVE $"C"AND YOU HAVE $"S
+700 PRINT "DO YOU WISH TO CONTINUE";
+710 INPUT H$
+720 IF H$="YES" THEN 120
+730 IF H$="NO" THEN 4100
+740 PRINT "ANSWER YES OR NO, PLEASE."
+750 GOTO 700
+760 IF I<>4 THEN 810
+770 PRINT
+780 PRINT "YOU WIN."
+790 S=S+P
+800 GOTO 690
+810 RETURN
+820 PRINT
+830 PRINT "NOW WE DRAW -- HOW MANY CARDS DO YOU WANT";
+840 INPUT T
+850 IF T=0 THEN 980
+860 Z=10
+870 IF T<4 THEN 900
+880 PRINT "YOU CAN'T DRAW MORE THAN THREE CARDS."
+890 GOTO 840
+900 PRINT "WHAT ARE THEIR NUMBERS:"
+910 FOR Q=1 TO T
+920 INPUT U
+930 GOSUB 1730
+940 NEXT Q
+950 PRINT "YOUR NEW HAND:"
+960 N=1
+970 GOSUB 1850
+980 Z=10+T
+990 FOR U=6 TO 10
+1000 IF INT(X/10^(U-6))<>10*INT(X/10^(U-5)) THEN 1020
+1010 GOSUB 1730
+1020 NEXT U
+1030 PRINT
+1040 PRINT "I AM TAKING"Z-10-T"CARD";
+1050 IF Z=11+T THEN 1090
+1060 PRINT "S"
+1070 PRINT
+1080 GOTO 1100
+1090 PRINT
+1100 N=6
+1110 V=I
+1120 I=1
+1130 GOSUB 2170
+1140 B=U
+1150 M=D
+1160 IF V<>7 THEN 1190
+1170 Z=28
+1180 GOTO 1330
+1190 IF I<>6 THEN 1220
+1200 Z=1
+1210 GOTO 1330
+1220 IF U>=13 THEN 1270
+1230 Z=2
+1240 IF FNA(0)<>6 THEN 1260
+1250 Z=19
+1260 GOTO 1330
+1270 IF U>=16 THEN 1320
+1280 Z=19
+1290 IF FNA(0)<>8 THEN 1310
+1300 Z=11
+1310 GOTO 1330
+1320 Z=2
+1330 K=0
+1340 GOSUB 3050
+1350 IF T<>.5 THEN 1450
+1360 IF V=7 THEN 1400
+1370 IF I<>6 THEN 1400
+1380 PRINT "I'LL CHECK"
+1390 GOTO 1460
+1400 V=Z+FNA(0)
+1410 GOSUB 3480
+1420 PRINT "I'LL BET $"V
+1430 K=V
+1440 GOSUB 3060
+1450 GOSUB 650
+1460 PRINT
+1470 PRINT "NOW WE COMPARE HANDS:"
+1480 J$=H$
+1490 K$=I$
+1500 PRINT "MY HAND:"
+1510 N=6
+1520 GOSUB 1850
+1530 N=1
+1540 GOSUB 2170
+1550 PRINT
+1560 PRINT "YOU HAVE ";
+1570 K=D
+1580 GOSUB 3690
+1590 H$=J$
+1600 I$=K$
+1610 K=M
+1620 PRINT "AND I HAVE ";
+1630 GOSUB 3690
+1640 IF B>U THEN 670
+1650 IF U>B THEN 780
+1660 IF H$="A FLUS" THEN 1700
+1662 IF FNB(M)FNB(D) THEN 670
+1670 PRINT "THE HAND IS DRAWN."
+1680 PRINT "ALL $"P"REMAINS IN THE POT."
+1690 GOTO 140
+1700 IF FNB(M)>FNB(D) THEN 670
+1710 IF FNB(D)>FNB(M) THEN 780
+1720 GOTO 1670
+1730 Z=Z+1
+1740 A(Z)=100*INT(4*RND(1))+INT(100*RND(1))
+1750 IF INT(A(Z)/100)>3 THEN 1740
+1760 IF A(Z)-100*INT(A(Z)/100)>12 THEN 1740
+1765 IF Z=1 THEN 1840
+1770 FOR K=1 TO Z-1
+1780 IF A(Z)=A(K) THEN 1740
+1790 NEXT K
+1800 IF Z<=10 THEN 1840
+1810 N=A(U)
+1820 A(U)=A(Z)
+1830 A(Z)=N
+1840 RETURN
+1850 FOR Z=N TO N+4
+1860 PRINT Z"--  ";
+1870 GOSUB 1950
+1880 PRINT " OF";
+1890 GOSUB 2070
+1900 IF Z/2<>INT(Z/2) THEN 1920
+1910 PRINT
+1920 NEXT Z
+1930 PRINT
+1940 RETURN
+1950 K=FNB(A(Z))
+1960 IF K<>9 THEN 1980
+1970 PRINT "JACK";
+1980 IF K<>10 THEN 2000
+1990 PRINT "QUEEN";
+2000 IF K<>11 THEN 2020
+2010 PRINT "KING";
+2020 IF K<>12 THEN 2040
+2030 PRINT "ACE";
+2040 IF K>=9 THEN 2060
+2050 PRINT K+2;
+2060 RETURN
+2070 K=INT(A(Z)/100)
+2080 IF K<>0 THEN 2100
+2090 PRINT " CLUBS",
+2100 IF K<>1 THEN 2120
+2110 PRINT " DIAMONDS",
+2120 IF K<>2 THEN 2140
+2130 PRINT " HEARTS",
+2140 IF K<>3 THEN 2160
+2150 PRINT " SPADES",
+2160 RETURN
+2170 U=0
+2180 FOR Z=N TO N+4
+2190 B(Z)=FNB(A(Z))
+2200 IF Z=N+4 THEN 2230
+2210 IF INT(A(Z)/100)<>INT(A(Z+1)/100) THEN 2230
+2220 U=U+1
+2230 NEXT Z
+2240 IF U<>4 THEN 2310
+2250 X=11111
+2260 D=A(N)
+2270 H$="A FLUS"
+2280 I$="H IN"
+2290 U=15
+2300 RETURN
+2310 FOR Z=N TO N+3
+2320 FOR K=Z+1 TO N+4
+2330 IF B(Z)<=B(K) THEN 2390
+2340 X=A(Z)
+2350 A(Z)=A(K)
+2360 B(Z)=B(K)
+2370 A(K)=X
+2380 B(K)=A(K)-100*INT(A(K)/100)
+2390 NEXT K
+2400 NEXT Z
+2410 X=0
+2420 FOR Z=N TO N+3
+2430 IF B(Z)<>B(Z+1) THEN 2470
+2440 X=X+11*10^(Z-N)
+2450 D=A(Z)
+2460 GOSUB 2760
+2470 NEXT Z
+2480 IF X<>0 THEN 2620
+2490 IF B(N)+3<>B(N+3) THEN 2520
+2500 X=1111
+2510 U=10
+2520 IF B(N+1)+3<>B(N+4) THEN 2620
+2530 IF U<>10 THEN 2600
+2540 U=14
+2550 H$="STRAIG"
+2560 I$="HT"
+2570 X=11111
+2580 D=A(N+4)
+2590 RETURN
+2600 U=10
+2610 X=11110
+2620 IF U>=10 THEN 2690
+2630 D=A(N+4)
+2640 H$="SCHMAL"
+2650 I$="TZ, "
+2660 U=9
+2670 X=11000
+2680 GOTO 2740
+2690 IF U<>10 THEN 2720
+2700 IF I=1 THEN 2740
+2710 GOTO 2750
+2720 IF U>12 THEN 2750
+2730 IF FNB(D)>6 THEN 2750
+2740 I=6
+2750 RETURN
+2760 IF U>=11 THEN 2810
+2770 U=11
+2780 H$="A PAIR"
+2790 I$=" OF "
+2800 RETURN
+2810 IF U<>11 THEN 2910
+2820 IF B(Z)<>B(Z-1) THEN 2870
+2830 H$="THREE"
+2840 I$=" "
+2850 U=13
+2860 RETURN
+2870 H$="TWO P"
+2880 I$="AIR, "
+2890 U=12
+2900 RETURN
+2910 IF U>12 THEN 2960
+2920 U=16
+2930 H$="FULL H"
+2940 I$="OUSE, "
+2950 RETURN
+2960 IF B(Z)<>B(Z-1) THEN 3010
+2970 U=17
+2980 H$="FOUR"
+2990 I$=" "
+3000 RETURN
+3010 U=16
+3020 H$="FULL H"
+3030 I$="OUSE, "
+3040 RETURN
+3050 G=0
+3060 PRINT:PRINT "WHAT IS YOUR BET";
+3070 INPUT T
+3080 IF T-INT(T)=0 THEN 3140
+3090 IF K<>0 THEN 3120
+3100 IF G<>0 THEN 3120
+3110 IF T=.5 THEN 3410
+3120 PRINT "NO SMALL CHANGE, PLEASE."
+3130 GOTO 3060
+3140 IF S-G-T>=0 THEN 3170
+3150 GOSUB 3830
+3160 GOTO 3060
+3170 IF T<>0 THEN 3200
+3180 I=3
+3190 GOTO 3380
+3200 IF G+T>=K THEN 3230
+3210 PRINT "IF YOU CAN'T SEE MY BET, THEN FOLD."
+3220 GOTO 3060
+3230 G=G+T
+3240 IF G=K THEN 3380
+3250 IF Z<>1 THEN 3420
+3260 IF G>5 THEN 3300
+3270 IF Z>=2 THEN 3350
+3280 V=5
+3290 GOTO 3420
+3300 IF Z=1 THEN 3320
+3310 IF T<=25 THEN 3350
+3320 I=4
+3330 PRINT "I FOLD."
+3340 RETURN
+3350 IF Z=2 THEN 3430
+3360 PRINT "I'LL SEE YOU."
+3370 K=G
+3380 S=S-G
+3390 C=C-K
+3400 P=P+G+K
+3410 RETURN
+3420 IF G>3*Z THEN 3350
+3430 V=G-K+FNA(0)
+3440 GOSUB 3480
+3450 PRINT "I'LL SEE YOU, AND RAISE YOU"V
+3460 K=G+V
+3470 GOTO 3060
+3480 IF C-G-V>=0 THEN 3660
+3490 IF G<>0 THEN 3520
+3500 V=C
+3510 RETURN
+3520 IF C-G>=0 THEN 3360
+3530 IF (O/2)<>INT(O/2) THEN 3600
+3540 PRINT "WOULD YOU LIKE TO BUY BACK YOUR WATCH FOR $50";
+3550 INPUT J$
+3560 IF LEFT$(J$,1)="N" THEN 3600
+3570 C=C+50
+3580 O=O/2
+3590 RETURN
+3600 IF O/3<>INT(O/3) THEN 3670
+3610 PRINT "WOULD YOU LIKE TO BUY BACK YOUR TIE TACK FOR $50";
+3620 INPUT J$
+3630 IF LEFT$(J$,1)="N" THEN 3670
+3640 C=C+50
+3650 O=O/3
+3660 RETURN
+3670 PRINT "I'M BUSTED.  CONGRATULATIONS!"
+3680 STOP
+3690 PRINT H$;I$;
+3700 IF H$<>"A FLUS" THEN 3750
+3710 K=INT(K/100)
+3720 GOSUB 2080
+3730 PRINT
+3740 RETURN
+3750 K=FNB(K)
+3760 GOSUB 1960
+3770 IF H$="SCHMAL" THEN 3790
+3780 IF H$<>"STRAIG" THEN 3810
+3790 PRINT " HIGH"
+3800 RETURN
+3810 PRINT "'S"
+3820 RETURN
+3830 PRINT
+3840 PRINT "YOU CAN'T BET WITH WHAT YOU HAVEN'T GOT."
+3850 IF O/2=INT(O/2) THEN 3970
+3860 PRINT "WOULD YOU LIKE TO SELL YOUR WATCH";
+3870 INPUT J$
+3880 IF LEFT$(J$,1)="N" THEN 3970
+3890 IF FNA(0)>=7 THEN 3930
+3900 PRINT "I'LL GIVE YOU $75 FOR IT."
+3910 S=S+75
+3920 GOTO 3950
+3930 PRINT "THAT'S A PRETTY CRUMMY WATCH - I'LL GIVE YOU $25."
+3940 S=S+25
+3950 O=O*2
+3960 RETURN
+3970 IF O/3<>INT(O/3) THEN 4090
+3980 PRINT "WILL YOU PART WITH THAT DIAMOND TIE TACK":
+3990 INPUT J$
+4000 IF LEFT$(J$,1)="N" THEN 4080
+4010 IF FNA(0)>=6 THEN 4050
+4020 PRINT "YOU ARE NOW $100 RICHER."
+4030 S=S+100
+4040 GOTO 4070
+4050 PRINT "IT'S PASTE.  $25."
+4060 S=S+25
+4070 O=O*3
+4080 RETURN
+4090 PRINT "YOUR WAD IS SHOT.  SO LONG, SUCKER!"
+4100 END
diff --git a/00_Alternate_Languages/71_Poker/python/README.md b/00_Alternate_Languages/71_Poker/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/71_Poker/ruby/README.md b/00_Alternate_Languages/71_Poker/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/71_Poker/vbnet/Poker.sln b/00_Alternate_Languages/71_Poker/vbnet/Poker.sln
new file mode 100644
index 00000000..f1514e74
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/vbnet/Poker.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Poker", "Poker.vbproj", "{107C29F8-C499-4E4A-B162-324CA17AA57F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{107C29F8-C499-4E4A-B162-324CA17AA57F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{107C29F8-C499-4E4A-B162-324CA17AA57F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{107C29F8-C499-4E4A-B162-324CA17AA57F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{107C29F8-C499-4E4A-B162-324CA17AA57F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/71_Poker/vbnet/Poker.vbproj b/00_Alternate_Languages/71_Poker/vbnet/Poker.vbproj
new file mode 100644
index 00000000..5e1a61a3
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/vbnet/Poker.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Poker
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/71_Poker/vbnet/README.md b/00_Alternate_Languages/71_Poker/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/71_Poker/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/72_Queen/README.md b/00_Alternate_Languages/72_Queen/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/72_Queen/csharp/Queen.csproj b/00_Alternate_Languages/72_Queen/csharp/Queen.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/csharp/Queen.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/72_Queen/csharp/Queen.sln b/00_Alternate_Languages/72_Queen/csharp/Queen.sln
new file mode 100644
index 00000000..b4d865ab
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/csharp/Queen.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Queen", "Queen.csproj", "{34BFC22A-4459-416E-B271-1E276689AC29}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{34BFC22A-4459-416E-B271-1E276689AC29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{34BFC22A-4459-416E-B271-1E276689AC29}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{34BFC22A-4459-416E-B271-1E276689AC29}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{34BFC22A-4459-416E-B271-1E276689AC29}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/72_Queen/csharp/README.md b/00_Alternate_Languages/72_Queen/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/72_Queen/java/README.md b/00_Alternate_Languages/72_Queen/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/72_Queen/javascript/README.md b/00_Alternate_Languages/72_Queen/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/72_Queen/javascript/queen.html b/00_Alternate_Languages/72_Queen/javascript/queen.html
new file mode 100644
index 00000000..ce191813
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/javascript/queen.html
@@ -0,0 +1,9 @@
+
+
+QUEEN
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/72_Queen/javascript/queen.js b/00_Alternate_Languages/72_Queen/javascript/queen.js
new file mode 100644
index 00000000..f07e1dd5
--- /dev/null
+++ b/00_Alternate_Languages/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();
diff --git a/47_Hi-Lo/pascal/README.md b/00_Alternate_Languages/72_Queen/pascal/README.md
similarity index 100%
rename from 47_Hi-Lo/pascal/README.md
rename to 00_Alternate_Languages/72_Queen/pascal/README.md
diff --git a/00_Alternate_Languages/72_Queen/perl/README.md b/00_Alternate_Languages/72_Queen/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/72_Queen/perl/queen.pl b/00_Alternate_Languages/72_Queen/perl/queen.pl
new file mode 100644
index 00000000..62682210
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/perl/queen.pl
@@ -0,0 +1,209 @@
+#!/usr/bin/env perl
+use v5.24;
+use warnings;
+use experimental 'signatures';
+no warnings 'experimental::signatures';
+
+use constant TARGET => 158;
+
+main(@ARGV);
+
+sub main (@args) {
+   welcome();
+   help() if ask_yes_no('DO YOU WANT INSTRUCTIONS');
+   do { one_match() } while ask_yes_no('ANYONE ELSE CARE TO TRY');
+   __exit();
+}
+
+sub one_match {
+   print_board();
+
+   # the player can choose the starting position in the top row or the
+   # right column
+   my $move = ask_first_move() or return forfeit();
+
+   # we alternate moves between computer or player from now on
+   while ('playing') {
+      $move = computer_move($move);
+      say "COMPUTER MOVES TO SQUARE $move";
+      return print_computer_victory() if $move == TARGET;
+
+      $move = ask_player_move($move) or return forfeit();
+      return print_player_victory() if $move == TARGET;
+   }
+}
+
+sub is_valid_move ($move, $current, $skip_prevalidation = 0) {
+
+   # pre-validation is needed for moves coming from the user
+   if (! $skip_prevalidation) {
+      state $valid_position = { map { $_ => 1 } board_identifiers() };
+      return 0 unless $move =~ m{\A [1-9]\d+ \z}mxs;
+      return 1 if $move == 0;
+      return 0 unless $valid_position->{$move};
+      return 0 if $move <= $current;
+   }
+
+   # the move might be valid in general, let's check from $current
+   my $delta = $move - $current;
+
+   # a valid move differs from the current position by a multiple of 10,
+   # or 11, or 21. If dividing by all of them yields a remainder, then
+   # the move is not valid
+   return 0 if $delta % 10 && $delta % 11 && $delta % 21;
+
+   # otherwise it is
+   return 1;
+}
+
+sub ask_player_move ($current) {
+   while ('necessary') {
+      my $move = ask_input('WHAT IS YOUR MOVE');
+      return $move if is_valid_move($move, $current);
+      say "\nY O U   C H E A T . . .  TRY AGAIN";
+   }
+}
+
+sub computer_move ($current) {
+
+   # this game has some optimal/safe positions from where it's possible
+   # to win with the right strategy. We will aim for them, if possible
+   state $optimals = [ 158, 127, 126, 75, 73 ];
+   for my $optimal ($optimals->@*) {
+
+      # moves can only increase, if we did not find any optimal move so far
+      # then there's no point going on
+      last if $optimal <= $current;
+
+      # computer moves are "syntactically" valid, skip pre-validation
+      return $optimal if is_valid_move($optimal, $current, 'skip');
+
+   }
+
+   # cannot reach an optimal position... resort to randomness
+   my $z = rand();
+   return $current + 11 if $z > 0.6; # move down
+   return $current + 21 if $z > 0.3; # move diagonally
+   return $current + 10;           ; # move horizontally
+}
+
+sub board_identifiers {
+   return (
+      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,
+   );
+}
+
+sub print_player_victory {
+   print <<'END';
+
+C O N G R A T U L A T I O N S . . .
+
+YOU HAVE WON--VERY WELL PLAYED.
+IT LOOKS LIKE I HAVE MET MY MATCH.
+THANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.
+
+END
+}
+
+sub print_computer_victory {
+   print <<'END';
+
+NICE TRY, BUT IT LOOKS LIKE I HAVE WON.
+THANKS FOR PLAYING.
+
+END
+}
+
+sub forfeit { say "\nIT LOOKS LIKE I HAVE WON BY FORFEIT.\n" }
+
+sub ask_input ($prompt) {
+   print "$prompt? ";
+   defined(my $input = ) or __exit();
+
+   # remove spaces from the input (including newlines), they are not used
+   $input =~ s{\s+}{}gmxs;
+
+   return $input;
+}
+
+sub ask_yes_no ($prompt) {
+   while ('necessary') {
+      my $input = ask_input($prompt);
+      return 1 if $input =~ m{\A (?: yes | y) \z}imxs;
+      return 0 if $input =~ m{\A (?:  no | n) \z}imxs;
+      say q{PLEASE ANSWER 'YES' OR 'NO'.};
+   }
+}
+
+sub ask_first_move {
+   while ('necessary') {
+      my $input = ask_input('WHERE WOULD YOU LIKE TO START');
+      if ($input =~ m{\A (?: 0 | [1-9]\d+) \z}mxs) {
+         return 0 unless $input;
+         my $diagonal = int($input / 10);
+         my $row = $input % 10;
+         return $input if $row == 1 || $row == $diagonal;
+      }
+      say <<'END'
+PLEASE READ THE DIRECTIONS AGAIN.
+YOU HAVE BEGUN ILLEGALLY.
+
+END
+   }
+}
+
+sub __exit {
+   say "\nOK --- THANKS AGAIN.";
+   exit 0;
+}
+
+sub welcome {
+   print <<'END'
+                                 QUEEN
+               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+
+
+
+END
+}
+
+sub help {
+   print <<'END';
+WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS
+MOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,
+DOWN, OR DIAGONALLY DOWN AND TO THE LEFT.
+
+THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER
+LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE
+COMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS.
+
+YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES
+ON THE TOP ROW OR RIGHT HAND COLUMN.
+THAT WILL BE YOUR FIRST MOVE.
+WE ALTERNATE MOVES.
+YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.
+BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.
+
+
+END
+}
+
+sub print_board {
+   say '';
+   my @ids = board_identifiers();
+   my $row_template = join '  ', ($ENV{ORIGINAL} ? '%d' : '%3d') x 8;
+   for my $A (0 .. 7) {
+      my $start = $A * 8;
+      my @range = $start .. $start + 7;
+      say ' ', sprintf $row_template, @ids[@range];
+      say "\n";
+   }
+   say '';
+}
diff --git a/00_Alternate_Languages/72_Queen/python/README.md b/00_Alternate_Languages/72_Queen/python/README.md
new file mode 100644
index 00000000..bfa388b7
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/python/README.md
@@ -0,0 +1,4 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/) by Christopher Phan.
+Supports Python version 3.8 or later.
diff --git a/00_Alternate_Languages/72_Queen/python/queen.py b/00_Alternate_Languages/72_Queen/python/queen.py
new file mode 100644
index 00000000..e7505a90
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/python/queen.py
@@ -0,0 +1,283 @@
+#!/usr/bin/env python3
+"""
+Implementation of Queens game in Python 3.
+
+Original game in BASIC by David Ahl in _BASIC Comuter Games_, published in 1978,
+as reproduced here:
+    https://www.atariarchives.org/basicgames/showpage.php?page=133
+
+Port to Python 3 by Christopher L. Phan 
+
+Supports Python version 3.8 or later.
+"""
+
+from random import random
+from typing import Final, FrozenSet, Optional, Tuple
+
+########################################################################################
+#                                  Optional configs
+########################################################################################
+# You can edit these variables to change the behavior of the game.
+#
+# The original implementation has a bug that allows a player to move off the board,
+# e.g. start at the nonexistant space 91. Change the variable FIX_BOARD_BUG to ``True``
+# to fix this behavior.
+#
+
+FIX_BOARD_BUG: Final[bool] = False
+
+# In the original implementation, the board is only printed once. Change the variable
+# SHOW_BOARD_ALWAYS to ``True`` to display the board every time.
+
+SHOW_BOARD_ALWAYS: Final[bool] = False
+
+# In the original implementaiton, the board is printed a bit wonky because of the
+# differing widths of the numbers. Change the variable ALIGNED_BOARD to ``True`` to
+# fix this.
+
+ALIGNED_BOARD: Final[bool] = False
+
+########################################################################################
+
+INSTR_TXT: Final[
+    str
+] = """WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS
+MOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,
+DOWN, OR DIAGONALLY DOWN AND TO THE LEFT.
+
+THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER
+LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE
+COMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS.
+
+YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES
+ON THE TOP ROW OR RIGHT HAND COLUMN.
+THAT WILL BE YOUR FIRST MOVE.
+WE ALTERNATE MOVES.
+YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE.
+BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE.
+
+"""
+
+
+WIN_MSG: Final[
+    str
+] = """C O N G R A T U L A T I O N S . . .
+
+YOU HAVE WON--VERY WELL PLAYED.
+IT LOOKS LIKE I HAVE MET MY MATCH.
+THANKS FOR PLAYING---I CAN'T WIN ALL THE TIME.
+
+"""
+
+LOSE_MSG: Final[
+    str
+] = """
+NICE TRY, BUT IT LOOKS LIKE I HAVE WON.
+THANKS FOR PLAYING.
+
+"""
+
+
+def loc_to_num(location: Tuple[int, int], fix_align: bool = False) -> str:
+    """Convert a position given by row, column into a space number."""
+    row, col = location
+    out_str: str = f"{row + 8 - col}{row + 1}"
+    if not fix_align or len(out_str) == 3:
+        return out_str
+    else:
+        return out_str + " "
+
+
+GAME_BOARD: Final[str] = (
+    "\n"
+    + "\n\n\n".join(
+        "".join(f" {loc_to_num((row, col), ALIGNED_BOARD)} " for col in range(8))
+        for row in range(8)
+    )
+    + "\n\n\n"
+)
+
+
+def num_to_loc(num: int) -> Tuple[int, int]:
+    """Convert a space number into a position given by row, column."""
+    row: int = num % 10 - 1
+    col: int = row + 8 - (num - row - 1) // 10
+    return row, col
+
+
+# The win location
+WIN_LOC: Final[Tuple[int, int]] = (7, 0)
+
+# These are the places (other than the win condition) that the computer will always
+# try to move into.
+COMPUTER_SAFE_SPOTS: Final[FrozenSet[Tuple[int, int]]] = frozenset(
+    [
+        (2, 3),
+        (4, 5),
+        (5, 1),
+        (6, 2),
+    ]
+)
+
+# These are the places that the computer will always try to move into.
+COMPUTER_PREF_MOVES: Final[
+    FrozenSet[Tuple[int, int]]
+] = COMPUTER_SAFE_SPOTS | frozenset([WIN_LOC])
+
+# These are the locations (not including the win location) from which either player can
+# force a win (but the computer will always choose one of the COMPUTER_PREF_MOVES).
+SAFE_SPOTS: Final[FrozenSet[Tuple[int, int]]] = COMPUTER_SAFE_SPOTS | frozenset(
+    [
+        (0, 4),
+        (3, 7),
+    ]
+)
+
+
+def str_with_tab(indent: int, text: str, uppercase: bool = True) -> str:
+    """Create a string with ``indent`` spaces followed by ``text``."""
+    if uppercase:
+        text = text.upper()
+    return " " * indent + text
+
+
+def intro():
+    """Print the intro and print instructions if desired."""
+    print(str_with_tab(33, "Queen"))
+    print(str_with_tab(15, "Creative Computing  Morristown, New Jersey"))
+    print("\n" * 2)
+    if ask("DO YOU WANT INSTRUCTIONS"):
+        print(INSTR_TXT)
+
+
+def get_move(current_loc: Optional[Tuple[int, int]]) -> Tuple[int, int]:
+    """Get the next move from the player."""
+    prompt: str
+    player_resp: str
+    move_raw: int
+    new_row: int
+    new_col: int
+    if current_loc is None:  # It's the first turn
+        prompt = "WHERE WOULD YOU LIKE TO START? "
+    else:
+        prompt = "WHAT IS YOUR MOVE? "
+        row, col = current_loc
+    while True:
+        player_resp = input(prompt).strip()
+        try:
+            move_raw = int(player_resp)
+            if move_raw == 0:  # Forfeit
+                return 8, 8
+            new_row, new_col = num_to_loc(move_raw)
+            if current_loc is None:
+                if (new_row == 0 or new_col == 7) and (
+                    not FIX_BOARD_BUG or (new_col >= 0 and new_row < 8)
+                ):
+                    return new_row, new_col
+                else:
+                    prompt = (
+                        "PLEASE READ THE DIRECTIONS AGAIN.\n"
+                        "YOU HAVE BEGUN ILLEGALLY.\n\n"
+                        "WHERE WOULD YOU LIKE TO START? "
+                    )
+            else:
+                if (
+                    (new_row == row and new_col < col)  # move left
+                    or (new_col == col and new_row > row)  # move down
+                    or (new_row - row == col - new_col)  # move diag left and down
+                ) and (not FIX_BOARD_BUG or (new_col >= 0 and new_row < 8)):
+                    return new_row, new_col
+                else:
+                    prompt = "Y O U   C H E A T . . .  TRY AGAIN? "
+
+        except ValueError:
+            prompt = "!NUMBER EXPECTED - RETRY INPUT LINE\n? "
+
+
+def random_computer_move(location: Tuple[int, int]) -> Tuple[int, int]:
+    """Make a random move."""
+    row, col = location
+    if (z := random()) > 0.6:
+        # Move down one space
+        return row + 1, col
+    elif z > 0.3:
+        # Move diagonaly (left and down) one space
+        return row + 1, col - 1
+    else:
+        # Move left one space
+        return row, col - 1
+
+
+def computer_move(location: Tuple[int, int]) -> Tuple[int, int]:
+    """Get the computer's move."""
+    # If the player has made an optimal move, then choose a random move
+    if location in SAFE_SPOTS:
+        return random_computer_move(location)
+    # We don't need to implmement the logic of checking for the player's win,
+    # because that is checked before this function is called.
+    row, col = location
+    for k in range(7, 0, -1):
+        # If the computer can move left k spaces and end in up in a safe spot or win,
+        # do it.
+        if (new_loc := (row, col - k)) in COMPUTER_PREF_MOVES:
+            return new_loc
+        # If the computer can move down k spaces and end up in a safe spot or win, do it.
+        if (new_loc := (row + k, col)) in COMPUTER_PREF_MOVES:
+            return new_loc
+        # If the computer can move diagonally k spaces and end up in a safe spot or win,
+        # do it.
+        if (new_loc := (row + k, col - k)) in COMPUTER_PREF_MOVES:
+            return new_loc
+        # As a fallback, do a random move. (NOTE: This shouldn't actally happen--it
+        # should always be possible to make an optimal move if the player doesn't play
+        # in a location in SAFE_SPOTS.
+    return random_computer_move(location)
+
+
+def main_game() -> None:
+    """Execute the main game."""
+    game_over: bool = False
+    location: Optional[Tuple[int, int]] = None  # Indicate it is the first turn
+    while not game_over:
+        location = get_move(location)
+        if location == (8, 8):  # (8, 8) is returned when the player enters 0
+            print("\nIT LOOKS LIKE I HAVE WON BY FORFEIT.\n")
+            game_over = True
+        elif location == WIN_LOC:  # Player wins (in lower left corner)
+            print(WIN_MSG)
+            game_over = True
+        else:
+            location = computer_move(location)
+            print(f"COMPUTER MOVES TO SQUARE {loc_to_num(location)}")
+            if location == WIN_LOC:  # Computer wins (in lower left corner)
+                print(LOSE_MSG)
+                game_over = True
+        # The default behavior is not to show the board each turn, but
+        # this can be modified by changing a flag at the start of the file.
+        if not game_over and SHOW_BOARD_ALWAYS:
+            print(GAME_BOARD)
+
+
+def ask(prompt: str) -> bool:
+    """Ask a yes/no question until user gives an understandable response."""
+    inpt: str
+    while True:
+        # Normalize input to uppercase, no whitespace, then get first character
+        inpt = input(prompt + "? ").upper().strip()[0]
+        print()
+        if inpt == "Y":
+            return True
+        elif inpt == "N":
+            return False
+        print("PLEASE ANSWER 'YES' OR 'NO'.")
+    return False
+
+
+if __name__ == "__main__":
+    intro()
+    still_playing: bool = True
+    while still_playing:
+        print(GAME_BOARD)
+        main_game()
+        still_playing = ask("ANYONE ELSE CARE TO TRY")
+    print("\nOK --- THANKS AGAIN.")
diff --git a/00_Alternate_Languages/72_Queen/queen.bas b/00_Alternate_Languages/72_Queen/queen.bas
new file mode 100644
index 00000000..e7b80810
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/queen.bas
@@ -0,0 +1,168 @@
+1 PRINT TAB(33);"QUEEN"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+10 DIM S(64)
+11 FOR I=1 TO 64
+12 READ S(I)
+13 NEXT I
+14 DATA  81,  71,  61,  51,  41,  31,  21,  11
+15 DATA  92,  82,  72,  62,  52,  42,  32,  22
+16 DATA 103,  93,  83,  73,  63,  53,  43,  33
+17 DATA 114, 104,  94,  84,  74,  64,  54,  44
+18 DATA 125, 115, 105,  95,  85,  75,  65,  55
+19 DATA 136, 126, 116, 106,  96,  86,  76,  66
+20 DATA 147, 137, 127, 117, 107,  97,  87,  77
+21 DATA 158, 148, 138, 128, 118, 108,  98,  88
+22 INPUT "DO YOU WANT INSTRUCTIONS";W$
+23 IF W$="NO" THEN 30
+24 IF W$="YES" THEN 28
+25 PRINT "PLEASE ANSWER 'YES' OR 'NO'."
+26 GOTO 22
+28 GOSUB 5000
+29 GOTO 100
+30 GOSUB 5160
+90 REM     ERROR CHECKS
+100 PRINT "WHERE WOULD YOU LIKE TO START";
+110 INPUT M1
+115 IF M1=0 THEN 232
+120 T1=INT(M1/10)
+130 U1=M1-10*T1
+140 IF U1=1 THEN 200
+150 IF U1=T1 THEN 200
+160 PRINT "PLEASE READ THE DIRECTIONS AGAIN."
+170 PRINT "YOU HAVE BEGUN ILLEGALLY."
+175 PRINT
+180 GOTO 100
+200 GOSUB 2000
+210 PRINT "COMPUTER MOVES TO SQUARE";M
+215 IF M=158 THEN 3400
+220 PRINT "WHAT IS YOUR MOVE";
+230 INPUT M1
+231 IF M1<>0 THEN 239
+232 PRINT
+233 PRINT "IT LOOKS LIKE I HAVE WON BY FORFEIT."
+234 PRINT
+235 GOTO 4000
+239 IF M1<=M THEN 3200
+240 T1=INT(M1/10)
+250 U1=M1-10*T1
+260 P=U1-U
+270 IF P<>0 THEN 300
+280 L=T1-T
+290 IF L<=0 THEN 3200
+295 GOTO 200
+300 IF T1-T <>P THEN 320
+310 GOTO 200
+320 IF T1-T <>2*P THEN 3200
+330 GOTO 200
+1990 REM     LOCATE MOVE FOR COMPUTER
+2000 IF M1=41 THEN 2180
+2010 IF M1=44 THEN 2180
+2020 IF M1=73 THEN 2180
+2030 IF M1=75 THEN 2180
+2040 IF M1=126 THEN 2180
+2050 IF M1=127 THEN 2180
+2060 IF M1=158 THEN 3300
+2065 C=0
+2070 FOR K=7 TO 1 STEP -1
+2080 U=U1
+2090 T=T1+K
+2100 GOSUB 3500
+2105 IF C=1 THEN 2160
+2110 U=U+K
+2120 GOSUB 3500
+2125 IF C=1 THEN 2160
+2130 T=T+K
+2140 GOSUB 3500
+2145 IF C=1 THEN 2160
+2150 NEXT K
+2155 GOTO 2180
+2160 C=0
+2170 RETURN
+2180 GOSUB 3000
+2190 RETURN
+2990 REM     RANDOM MOVE
+3000 Z=RND(1)
+3010 IF Z>.6 THEN 3110
+3020 IF Z>.3 THEN 3070
+3030 U=U1
+3040 T=T1+1
+3050 M=10*T+U
+3060 RETURN
+3070 U=U1+1
+3080 T=T1+2
+3090 M=10*T+U
+3100 RETURN
+3110 U=U1+1
+3120 T=T1+1
+3130 M=10*T+U
+3140 RETURN
+3190 REM     ILLEGAL MOVE MESSAGE
+3200 PRINT
+3210 PRINT "Y O U   C H E A T . . .  TRY AGAIN";
+3220 GOTO 230
+3290 REM     PLAYER WINS
+3300 PRINT
+3310 PRINT "C O N G R A T U L A T I O N S . . ."
+3320 PRINT
+3330 PRINT "YOU HAVE WON--VERY WELL PLAYED."
+3340 PRINT "IT LOOKS LIKE I HAVE MET MY MATCH."
+3350 PRINT "THANKS FOR PLAYING---I CAN'T WIN ALL THE TIME."
+3360 PRINT
+3370 GOTO 4000
+3390 REM     COMPUTER WINS
+3400 PRINT
+3410 PRINT "NICE TRY, BUT IT LOOKS LIKE I HAVE WON."
+3420 PRINT "THANKS FOR PLAYING."
+3430 PRINT
+3440 GOTO 4000
+3490 REM     TEST FOR COMPUTER MOVE
+3500 M=10*T+U
+3510 IF M=158 THEN 3570
+3520 IF M=127 THEN 3570
+3530 IF M=126 THEN 3570
+3540 IF M=75 THEN 3570
+3550 IF M=73 THEN 3570
+3560 RETURN
+3570 C=1
+3580 GOTO 3560
+3990 REM     ANOTHER GAME???
+4000 PRINT "ANYONE ELSE CARE TO TRY";
+4010 INPUT Q$
+4020 PRINT
+4030 IF Q$="YES" THEN 30
+4040 IF Q$="NO" THEN 4050
+4042 PRINT "PLEASE ANSWER 'YES' OR 'NO'."
+4045 GOTO 4000
+4050 PRINT:PRINT "OK --- THANKS AGAIN."
+4060 STOP
+4990 REM     DIRECTIONS
+5000 PRINT "WE ARE GOING TO PLAY A GAME BASED ON ONE OF THE CHESS"
+5010 PRINT "MOVES.  OUR QUEEN WILL BE ABLE TO MOVE ONLY TO THE LEFT,"
+5020 PRINT "DOWN, OR DIAGONALLY DOWN AND TO THE LEFT."
+5030 PRINT
+5040 PRINT "THE OBJECT OF THE GAME IS TO PLACE THE QUEEN IN THE LOWER"
+5050 PRINT "LEFT HAND SQUARE BY ALTERNATING MOVES BETWEEN YOU AND THE"
+5060 PRINT "COMPUTER.  THE FIRST ONE TO PLACE THE QUEEN THERE WINS."
+5070 PRINT
+5080 PRINT "YOU GO FIRST AND PLACE THE QUEEN IN ANY ONE OF THE SQUARES"
+5090 PRINT "ON THE TOP ROW OR RIGHT HAND COLUMN."
+5100 PRINT "THAT WILL BE YOUR FIRST MOVE."
+5110 PRINT "WE ALTERNATE MOVES."
+5120 PRINT "YOU MAY FORFEIT BY TYPING '0' AS YOUR MOVE."
+5130 PRINT "BE SURE TO PRESS THE RETURN KEY AFTER EACH RESPONSE."
+5140 PRINT
+5150 PRINT
+5160 PRINT
+5170 FOR A=0 TO 7
+5180 FOR B=1 TO 8
+5185 I=8*A+B
+5190 PRINT S(I);
+5200 NEXT B
+5210 PRINT
+5220 PRINT
+5230 PRINT
+5240 NEXT A
+5250 PRINT
+5260 RETURN
+9999 END
diff --git a/00_Alternate_Languages/72_Queen/ruby/README.md b/00_Alternate_Languages/72_Queen/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/72_Queen/vbnet/Queen.sln b/00_Alternate_Languages/72_Queen/vbnet/Queen.sln
new file mode 100644
index 00000000..33f87b9a
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/vbnet/Queen.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Queen", "Queen.vbproj", "{9FCBF8AB-8E16-4E1A-AA05-D64B475D36FC}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9FCBF8AB-8E16-4E1A-AA05-D64B475D36FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9FCBF8AB-8E16-4E1A-AA05-D64B475D36FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9FCBF8AB-8E16-4E1A-AA05-D64B475D36FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9FCBF8AB-8E16-4E1A-AA05-D64B475D36FC}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/72_Queen/vbnet/Queen.vbproj b/00_Alternate_Languages/72_Queen/vbnet/Queen.vbproj
new file mode 100644
index 00000000..19b46d90
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/vbnet/Queen.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Queen
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/72_Queen/vbnet/README.md b/00_Alternate_Languages/72_Queen/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/72_Queen/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/73_Reverse/README.md b/00_Alternate_Languages/73_Reverse/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/73_Reverse/csharp/README.md b/00_Alternate_Languages/73_Reverse/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/Generators/PositiveIntegerGenerator.cs b/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/Generators/PositiveIntegerGenerator.cs
new file mode 100644
index 00000000..66889bb5
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/Generators/PositiveIntegerGenerator.cs
@@ -0,0 +1,10 @@
+using FsCheck;
+
+namespace Reverse.Tests.Generators
+{
+    public static class PositiveIntegerGenerator
+    {
+        public static Arbitrary Generate() =>
+            Arb.Default.Int32().Filter(x => x > 0);
+    }
+}
diff --git a/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/Reverse.Tests.csproj b/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/Reverse.Tests.csproj
new file mode 100644
index 00000000..260de5e1
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/Reverse.Tests.csproj
@@ -0,0 +1,27 @@
+
+
+  
+    net5.0
+
+    false
+  
+
+  
+    
+    
+    
+    
+      runtime; build; native; contentfiles; analyzers; buildtransitive
+      all
+    
+    
+      runtime; build; native; contentfiles; analyzers; buildtransitive
+      all
+    
+  
+
+  
+    
+  
+
+
diff --git a/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/ReverserTests.cs b/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/ReverserTests.cs
new file mode 100644
index 00000000..6fe3bb77
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/ReverserTests.cs
@@ -0,0 +1,148 @@
+using FsCheck.Xunit;
+using Reverse.Tests.Generators;
+using System;
+using System.Linq;
+using Xunit;
+
+namespace Reverse.Tests
+{
+    public class ReverserTests
+    {
+        [Fact]
+        public void Constructor_CannotAcceptNumberLessThanZero()
+        {
+            Action action = () => new Reverser(0);
+
+            Assert.Throws(action);
+        }
+
+        [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })]
+        public void Constructor_CreatesRandomArrayOfSpecifiedLength(int size)
+        {
+            var sut = new TestReverser(size);
+
+            Assert.Equal(size, sut.GetArray().Length);
+        }
+
+        [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })]
+        public void ConstructorArray_MaxElementValueIsEqualToSize(int size)
+        {
+            var sut = new TestReverser(size);
+
+            Assert.Equal(size, sut.GetArray().Max());
+        }
+
+        [Property(Arbitrary = new[] { typeof(PositiveIntegerGenerator) })]
+        public void ConstructorArray_ReturnsRandomArrayWithDistinctElements(int size)
+        {
+            var sut = new TestReverser(size);
+            var array = sut.GetArray();
+            var arrayGroup = array.GroupBy(x => x);
+            var duplicateFound = arrayGroup.Any(x => x.Count() > 1);
+
+            Assert.False(duplicateFound);
+        }
+
+        [Theory]
+        [InlineData(new int[] { 1 }, new int[] { 1 })]
+        [InlineData(new int[] { 1, 2 }, new int[] { 2, 1 })]
+        [InlineData(new int[] { 1, 2, 3 }, new int[] { 3, 2, 1 })]
+        public void Reverse_WillReverseEntireArray(int[] input, int[] output)
+        {
+            var sut = new TestReverser(1);
+            sut.SetArray(input);
+
+            sut.Reverse(input.Length);
+
+            Assert.True(sut.GetArray().SequenceEqual(output));
+        }
+
+        [Fact]
+        public void Reverse_WithSpecifiedIndex_ReversesItemsUpToThatIndex()
+        {
+            var input = new int[] { 1, 2, 3, 4 };
+            var output = new int[] { 2, 1, 3, 4 };
+            var sut = new TestReverser(1);
+            sut.SetArray(input);
+
+            sut.Reverse(2);
+
+            Assert.True(sut.GetArray().SequenceEqual(output));
+        }
+
+        [Fact]
+        public void Reverse_WithIndexOne_DoesNothing()
+        {
+            var input = new int[] { 1, 2 };
+            var output = new int[] { 1, 2 };
+            var sut = new TestReverser(1);
+            sut.SetArray(input);
+
+            sut.Reverse(1);
+
+            Assert.True(sut.GetArray().SequenceEqual(output));
+        }
+
+        [Fact]
+        public void Reverse_WithIndexGreaterThanArrayLength_DoesNothing()
+        {
+            var input = new int[] { 1, 2 };
+            var output = new int[] { 1, 2 };
+            var sut = new TestReverser(1);
+            sut.SetArray(input);
+
+            sut.Reverse(sut.GetArray().Length + 1);
+
+            Assert.True(sut.GetArray().SequenceEqual(output));
+        }
+
+        [Fact]
+        public void Reverse_WithIndexLessThanZero_DoesNothing()
+        {
+            var input = new int[] { 1, 2 };
+            var output = new int[] { 1, 2 };
+            var sut = new TestReverser(1);
+            sut.SetArray(input);
+
+            sut.Reverse(-1);
+
+            Assert.True(sut.GetArray().SequenceEqual(output));
+        }
+
+        [Theory]
+        [InlineData(new int[] { 1 })]
+        [InlineData(new int[] { 1, 2 })]
+        [InlineData(new int[] { 1, 1 })]
+        public void IsArrayInAscendingOrder_WhenArrayElementsAreInNumericAscendingOrder_ReturnsTrue(int[] input)
+        {
+            var sut = new TestReverser(1);
+            sut.SetArray(input);
+
+            var result = sut.IsArrayInAscendingOrder();
+
+            Assert.True(result);
+        }
+
+        [Fact]
+        public void IsArrayInOrder_WhenArrayElementsAreNotInNumericAscendingOrder_ReturnsFalse()
+        {
+            var sut = new TestReverser(1);
+            sut.SetArray(new int[] { 2, 1 });
+
+            var result = sut.IsArrayInAscendingOrder();
+
+            Assert.False(result);
+        }
+
+        [Fact]
+        public void GetArrayString_ReturnsSpaceSeparatedElementsOfArrayInStringFormat()
+        {
+            var sut = new TestReverser(1);
+            sut.SetArray(new int[] { 1, 2 });
+
+            var result = sut.GetArrayString();
+
+            Assert.Equal(" 1  2 ", result);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/TestReverser.cs b/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/TestReverser.cs
new file mode 100644
index 00000000..a53004e1
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/csharp/Reverse.Tests/TestReverser.cs
@@ -0,0 +1,17 @@
+namespace Reverse.Tests
+{
+    internal class TestReverser : Reverser
+    {
+        public TestReverser(int arraySize) : base(arraySize) { }
+
+        public int[] GetArray()
+        {
+            return _array;
+        }
+
+        public void SetArray(int[] array)
+        {
+            _array = array;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/73_Reverse/csharp/Reverse.sln b/00_Alternate_Languages/73_Reverse/csharp/Reverse.sln
new file mode 100644
index 00000000..96c338be
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/csharp/Reverse.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32002.261
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reverse", "Reverse\Reverse.csproj", "{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Reverse.Tests", "Reverse.Tests\Reverse.Tests.csproj", "{96E824F8-0353-4FF2-9FEA-F850E2BE7312}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{39463B63-6A71-4DCF-A4F2-FAA74FDEEC01}.Release|Any CPU.Build.0 = Release|Any CPU
+		{96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{96E824F8-0353-4FF2-9FEA-F850E2BE7312}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {1DCA2723-D126-4B37-A698-D40DA03643A9}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/73_Reverse/csharp/Reverse/Program.cs b/00_Alternate_Languages/73_Reverse/csharp/Reverse/Program.cs
new file mode 100644
index 00000000..5f8c5967
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/csharp/Reverse/Program.cs
@@ -0,0 +1,130 @@
+using System;
+
+namespace Reverse
+{
+    class Program
+    {
+        private static int arrayLength = 9;
+        static void Main(string[] args)
+        {
+            PrintTitle();
+            Console.Write("DO YOU WANT THE RULES? ");
+            var needRulesInput = Console.ReadLine();
+            Console.WriteLine();
+            if (string.Equals(needRulesInput, "YES", StringComparison.OrdinalIgnoreCase))
+            {
+                DisplayRules();
+            }
+
+            var tryAgain = string.Empty;
+            while (!string.Equals(tryAgain, "NO", StringComparison.OrdinalIgnoreCase))
+            {
+                var reverser = new Reverser(arrayLength);
+
+                Console.WriteLine("HERE WE GO ... THE LIST IS:");
+                PrintList(reverser.GetArrayString());
+                var arrayIsInAscendingOrder = false;
+                var numberOfMoves = 0;
+                while (arrayIsInAscendingOrder == false)
+                {
+                    int index = ReadNextInput();
+
+                    if (index == 0)
+                    {
+                        break;
+                    }
+
+                    reverser.Reverse(index);
+                    PrintList(reverser.GetArrayString());
+                    arrayIsInAscendingOrder = reverser.IsArrayInAscendingOrder();
+                    numberOfMoves++;
+                }
+
+                if (arrayIsInAscendingOrder)
+                {
+                    Console.WriteLine($"YOU WON IT IN {numberOfMoves} MOVES!!!");
+
+                }
+
+                Console.WriteLine();
+                Console.WriteLine();
+                Console.Write("TRY AGAIN (YES OR NO) ");
+                tryAgain = Console.ReadLine();
+            }
+
+            Console.WriteLine();
+            Console.WriteLine("OK HOPE YOU HAD FUN!!");
+        }
+
+        private static int ReadNextInput()
+        {
+            Console.Write("HOW MANY SHALL I REVERSE? ");
+            var input = ReadIntegerInput();
+            while (input > 9 || input < 0)
+            {
+                if (input > 9)
+                {
+                    Console.WriteLine($"OOPS! TOO MANY! I CAN REVERSE AT MOST {arrayLength}");
+                }
+
+                if (input < 0)
+                {
+                    Console.WriteLine($"OOPS! TOO FEW! I CAN REVERSE BETWEEN 1 AND {arrayLength}");
+                }
+                Console.Write("HOW MANY SHALL I REVERSE? ");
+                input = ReadIntegerInput();
+            }
+
+            return input;
+        }
+
+        private static int ReadIntegerInput()
+        {
+            var input = Console.ReadLine();
+            int.TryParse(input, out var index);
+            return index;
+        }
+
+        private static void PrintList(string list)
+        {
+            Console.WriteLine();
+            Console.WriteLine(list);
+            Console.WriteLine();
+        }
+
+        private static void PrintTitle()
+        {
+            Console.WriteLine("\t\t   REVERSE");
+            Console.WriteLine("  CREATIVE COMPUTING  MORRISTON, NEW JERSEY");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("REVERSE -- A GAME OF SKILL");
+            Console.WriteLine();
+        }
+
+        private static void DisplayRules()
+        {
+            Console.WriteLine();
+            Console.WriteLine("THIS IS THE GAME OF 'REVERSE'. TO WIN, ALL YOU HAVE");
+            Console.WriteLine("TO DO IS ARRANGE A LIST OF NUMBERS (1 THOUGH 9 )");
+            Console.WriteLine("IN NUMERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU");
+            Console.WriteLine("TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO");
+            Console.WriteLine("REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:");
+            Console.WriteLine();
+            Console.WriteLine("2 3 4 5 1 6 7 8 9");
+            Console.WriteLine();
+            Console.WriteLine("AND YOU REVERSE 4, THE RESULT WILL BE:");
+            Console.WriteLine();
+            Console.WriteLine("5 4 3 2 1 6 7 8 9");
+            Console.WriteLine();
+            Console.WriteLine("NOW IF YOU REVERSE 5, YOU WIN!");
+            Console.WriteLine();
+            Console.WriteLine("1 2 3 4 5 6 7 8 9");
+            Console.WriteLine();
+            Console.WriteLine("NO DOUBT YOU WILL LIKE THIS GAME, BUT ");
+            Console.WriteLine("IF YOU WANT TO QUIT, REVERSE 0 (ZERO)");
+            Console.WriteLine();
+            Console.WriteLine();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/73_Reverse/csharp/Reverse/Reverse.csproj b/00_Alternate_Languages/73_Reverse/csharp/Reverse/Reverse.csproj
new file mode 100644
index 00000000..20827042
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/csharp/Reverse/Reverse.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+
diff --git a/00_Alternate_Languages/73_Reverse/csharp/Reverse/Reverser.cs b/00_Alternate_Languages/73_Reverse/csharp/Reverse/Reverser.cs
new file mode 100644
index 00000000..fdab5e96
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/csharp/Reverse/Reverser.cs
@@ -0,0 +1,82 @@
+using System;
+using System.Text;
+
+namespace Reverse
+{
+    public class Reverser
+    {
+        protected int[] _array;
+
+        public Reverser(int arraySize)
+        {
+            _array = CreateRandomArray(arraySize);
+        }
+
+        public void Reverse(int index)
+        {
+            if (index > _array.Length)
+            {
+                return;
+            }
+
+            for (int i = 0; i < index / 2; i++)
+            {
+                int temp = _array[i];
+                int upperIndex = index - 1 - i;
+                _array[i] = _array[upperIndex];
+                _array[upperIndex] = temp;
+            }
+        }
+
+        public bool IsArrayInAscendingOrder()
+        {
+            for (int i = 1; i < _array.Length; i++)
+            {
+                if (_array[i] < _array[i - 1])
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        private int[] CreateRandomArray(int size)
+        {
+            if (size < 1)
+            {
+                throw new ArgumentOutOfRangeException(nameof(size), "Array size must be a positive integer");
+            }
+
+            var array = new int[size];
+            for (int i = 1; i <= size; i++)
+            {
+                array[i - 1] = i;
+            }
+
+            var rnd = new Random();
+
+            for (int i = size; i > 1;)
+            {
+                int k = rnd.Next(i);
+                --i;
+                int temp = array[i];
+                array[i] = array[k];
+                array[k] = temp;
+            }
+            return array;
+        }
+
+        public string GetArrayString()
+        {
+            var sb = new StringBuilder();
+
+            foreach (int i in _array)
+            {
+                sb.Append(" " + i + " ");
+            }
+
+            return sb.ToString();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/73_Reverse/java/README.md b/00_Alternate_Languages/73_Reverse/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/73_Reverse/java/Reverse.java b/00_Alternate_Languages/73_Reverse/java/Reverse.java
new file mode 100644
index 00000000..603ef763
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/java/Reverse.java
@@ -0,0 +1,242 @@
+import java.util.Scanner;
+import java.lang.Math;
+
+/**
+ * Game of Reverse
+ * 

+ * Based on the BASIC game of Reverse here + * https://github.com/coding-horror/basic-computer-games/blob/main/73%20Reverse/reverse.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 Reverse { + + private final int NUMBER_COUNT = 9; + + private final Scanner scan; // For user input + + private enum Step { + INITIALIZE, PERFORM_REVERSE, TRY_AGAIN, END_GAME + } + + public Reverse() { + + scan = new Scanner(System.in); + + } // End of constructor Reverse + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private static void showIntro() { + + System.out.println(" ".repeat(31) + "REVERSE"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + System.out.println("REVERSE -- A GAME OF SKILL"); + System.out.println(""); + + } // End of method showIntro + + private void startGame() { + + int index = 0; + int numMoves = 0; + int numReverse = 0; + int tempVal = 0; + int[] numList = new int[NUMBER_COUNT + 1]; + + Step nextStep = Step.INITIALIZE; + + String userResponse = ""; + + System.out.print("DO YOU WANT THE RULES? "); + userResponse = scan.nextLine(); + + if (!userResponse.toUpperCase().equals("NO")) { + + this.printRules(); + } + + // Begin outer while loop + while (true) { + + // Begin outer switch + switch (nextStep) { + + case INITIALIZE: + + // Make a random list of numbers + numList[1] = (int)((NUMBER_COUNT - 1) * Math.random() + 2); + + for (index = 2; index <= NUMBER_COUNT; index++) { + + // Keep generating lists if there are duplicates + while (true) { + + numList[index] = (int)(NUMBER_COUNT * Math.random() + 1); + + // Search for duplicates + if (!this.findDuplicates(numList, index)) { + break; + } + } + } + + System.out.println(""); + System.out.println("HERE WE GO ... THE LIST IS:"); + + numMoves = 0; + + this.printBoard(numList); + + nextStep = Step.PERFORM_REVERSE; + break; + + case PERFORM_REVERSE: + + System.out.print("HOW MANY SHALL I REVERSE? "); + numReverse = Integer.parseInt(scan.nextLine()); + + if (numReverse == 0) { + + nextStep = Step.TRY_AGAIN; + + } else if (numReverse > NUMBER_COUNT) { + + System.out.println("OOPS! TOO MANY! I CAN REVERSE AT MOST " + NUMBER_COUNT); + nextStep = Step.PERFORM_REVERSE; + + } else { + + numMoves++; + + for (index = 1; index <= (int)(numReverse / 2.0); index++) { + + tempVal = numList[index]; + numList[index] = numList[numReverse - index + 1]; + numList[numReverse - index + 1] = tempVal; + } + + this.printBoard(numList); + + nextStep = Step.TRY_AGAIN; + + // Check for a win + for (index = 1; index <= NUMBER_COUNT; index++) { + + if (numList[index] != index) { + nextStep = Step.PERFORM_REVERSE; + } + } + + if (nextStep == Step.TRY_AGAIN) { + System.out.println("YOU WON IT IN " + numMoves + " MOVES!!!"); + System.out.println(""); + } + } + break; + + case TRY_AGAIN: + + System.out.println(""); + System.out.print("TRY AGAIN (YES OR NO)? "); + userResponse = scan.nextLine(); + + if (userResponse.toUpperCase().equals("YES")) { + nextStep = Step.INITIALIZE; + } else { + nextStep = Step.END_GAME; + } + break; + + case END_GAME: + + System.out.println(""); + System.out.println("O.K. HOPE YOU HAD FUN!!"); + return; + + default: + + System.out.println("INVALID STEP"); + break; + + } // End outer switch + + } // End outer while loop + + } // End of method startGame + + public boolean findDuplicates(int[] board, int length) { + + int index = 0; + + for (index = 1; index <= length - 1; index++) { + + // Identify duplicates + if (board[length] == board[index]) { + + return true; // Found a duplicate + } + } + + return false; // No duplicates found + + } // End of method findDuplicates + + public void printBoard(int[] board) { + + int index = 0; + + System.out.println(""); + + for (index = 1; index <= NUMBER_COUNT; index++) { + + System.out.format("%2d", board[index]); + } + + System.out.println("\n"); + + } // End of method printBoard + + public void printRules() { + + System.out.println(""); + System.out.println("THIS IS THE GAME OF 'REVERSE'. TO WIN, ALL YOU HAVE"); + System.out.println("TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH " + NUMBER_COUNT + ")"); + System.out.println("IN NUMERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU"); + System.out.println("TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO"); + System.out.println("REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:"); + System.out.println(""); + System.out.println("2 3 4 5 1 6 7 8 9"); + System.out.println(""); + System.out.println("AND YOU REVERSE 4, THE RESULT WILL BE:"); + System.out.println(""); + System.out.println("5 4 3 2 1 6 7 8 9"); + System.out.println(""); + System.out.println("NOW IF YOU REVERSE 5, YOU WIN!"); + System.out.println(""); + System.out.println("1 2 3 4 5 6 7 8 9"); + System.out.println(""); + System.out.println("NO DOUBT YOU WILL LIKE THIS GAME, BUT"); + System.out.println("IF YOU WANT TO QUIT, REVERSE 0 (ZERO)."); + System.out.println(""); + + } // End of method printRules + + public static void main(String[] args) { + + Reverse game = new Reverse(); + game.play(); + + } // End of method main + +} // End of class Reverse diff --git a/00_Alternate_Languages/73_Reverse/javascript/README.md b/00_Alternate_Languages/73_Reverse/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/73_Reverse/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/73_Reverse/javascript/reverse.html b/00_Alternate_Languages/73_Reverse/javascript/reverse.html new file mode 100644 index 00000000..3abddb0e --- /dev/null +++ b/00_Alternate_Languages/73_Reverse/javascript/reverse.html @@ -0,0 +1,9 @@ + + +REVERSE + + +


+
+
+
diff --git a/00_Alternate_Languages/73_Reverse/javascript/reverse.js b/00_Alternate_Languages/73_Reverse/javascript/reverse.js
new file mode 100644
index 00000000..802df4c0
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/javascript/reverse.js
@@ -0,0 +1,159 @@
+// REVERSE
+//
+// 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 a = [];
+var n;
+
+// Subroutine to print the rules
+function print_rules()
+{
+    print("\n");
+    print("THIS IS THE GAME OF 'REVERSE'.  TO WIN, ALL YOU HAVE\n");
+    print("TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH " + n + ")\n");
+    print("IN NUMERICAL ORDER FROM LEFT TO RIGHT.  TO MOVE, YOU\n");
+    print("TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO\n");
+    print("REVERSE.  FOR EXAMPLE, IF THE CURRENT LIST IS:\n");
+    print("\n");
+    print("2 3 4 5 1 6 7 8 9\n");
+    print("\n");
+    print("AND YOU REVERSE 4, THE RESULT WILL BE:\n");
+    print("\n");
+    print("5 4 3 2 1 6 7 8 9\n");
+    print("\n");
+    print("NOW IF YOU REVERSE 5, YOU WIN!\n");
+    print("\n");
+    print("1 2 3 4 5 6 7 8 9\n");
+    print("\n");
+    print("NO DOUBT YOU WILL LIKE THIS GAME, BUT\n");
+    print("IF YOU WANT TO QUIT, REVERSE 0 (ZERO).\n");
+    print("\n");
+}
+
+// Subroutine to print list
+function print_list()
+{
+    print("\n");
+    for (k = 1; k <= n; k++)
+        print(" " + a[k] + " ");
+    print("\n");
+    print("\n");
+}
+
+// Main program
+async function main()
+{
+    print(tab(32) + "REVERSE\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("REVERSE -- A GAME OF SKILL\n");
+    print("\n");
+    for (i = 0; i <= 20; i++)
+        a[i] = 0;
+    // *** N=NUMBER OF NUMBER
+    n = 9;
+    print("DO YOU WANT THE RULES? (YES OR NO)");
+    str = await input();
+    if (str.toUpperCase() === "YES" || str.toUpperCase() === "Y")
+        print_rules();
+    while (1) {
+        // *** Make a random list a(1) to a(n)
+        a[1] = Math.floor((n - 1) * Math.random() + 2);
+        for (k = 2; k <= n; k++) {
+            do {
+                a[k] = Math.floor(n * Math.random() + 1);
+                for (j = 1; j <= k - 1; j++) {
+                    if (a[k] == a[j])
+                        break;
+                }
+            } while (j <= k - 1) ;
+        }
+        // *** Print original list and start game
+        print("\n");
+        print("HERE WE GO ... THE LIST IS:\n");
+        t = 0;
+        print_list();
+        while (1) {
+            while (1) {
+                print("HOW MANY SHALL I REVERSE");
+                r = parseInt(await input());
+                if (r == 0)
+                    break;
+                if (r <= n)
+                    break;
+                print("OOPS! WRONG! I CAN REVERSE AT MOST " + n + "\n");
+            }
+            if (r == 0)
+                break;
+            t++;
+            // *** Reverse r numbers and print new list
+            for (k = 1; k <= Math.floor(r / 2); k++) {
+                z = a[k];
+                a[k] = a[r - k + 1];
+                a[r - k + 1] = z;
+            }
+            print_list();
+            // *** Check for a win
+            for (k = 1; k <= n; k++) {
+                if (a[k] != k)
+                    break;
+            }
+            if (k > n) {
+                print("YOU WON IT IN " + t + " MOVES!!!\n");
+                print("\n");
+                break;
+            }
+        }
+        print("\n");
+        print("TRY AGAIN? (YES OR NO)");
+        str = await input();
+        if (str.toUpperCase() === "NO" || str.toUpperCase() === "N")
+            break;
+    }
+    print("\n");
+    print("O.K. HOPE YOU HAD FUN!!\n");
+}
+
+main();
diff --git a/48_High_IQ/pascal/README.md b/00_Alternate_Languages/73_Reverse/pascal/README.md
similarity index 100%
rename from 48_High_IQ/pascal/README.md
rename to 00_Alternate_Languages/73_Reverse/pascal/README.md
diff --git a/00_Alternate_Languages/73_Reverse/perl/README.md b/00_Alternate_Languages/73_Reverse/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/73_Reverse/perl/reverse.pl b/00_Alternate_Languages/73_Reverse/perl/reverse.pl
new file mode 100644
index 00000000..94ef40e6
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/perl/reverse.pl
@@ -0,0 +1,234 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'state' and 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use List::Util qw{ shuffle };   # Shuffle an array.
+use Term::ReadLine;     # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+# Manifest constant for size of list.
+use constant NUMBER_OF_NUMBERS  => 9;
+
+print <<'EOD';
+                                REVERSE
+               Creative Computing  Morristown, New Jersey
+
+
+
+Reverse -- a game of skill
+
+EOD
+
+# Display the rules if desired. There is no straightforward way to
+# interpolate a manifest constant into a string, but @{[ ... ]} will
+# interpolate any expression.
+print <<"EOD" if get_yes_no( 'Do you want the rules' );
+
+This is the game of 'Reverse'.  To win, all you have
+to do is arrange a list of numbers (1 through @{[ NUMBER_OF_NUMBERS ]})
+in numerical order from left to right.  To move, you
+tell me how many numbers (counting from the left) to
+reverse.  For example, if the current list is:
+
+2 3 4 5 1 6 7 8 9
+
+and you reverse 4, the result will be:
+
+5 4 3 2 1 6 7 8 9
+
+Now if you reverse 5, you win!
+
+1 2 3 4 5 6 7 8 9
+
+No doubt you will like this game, but
+if you want to quit, reverse 0 (zero).
+
+EOD
+
+while ( 1 ) {   # Iterate until something interrupts us.
+
+    # Populate the list with the integers from 1, shuffled. If we
+    # accidentally generate a winning list, just redo the loop.
+    my @list = shuffle( 1 .. NUMBER_OF_NUMBERS );
+    redo if is_win( \@list );
+
+    print <<"EOD";
+
+Here we go ... The list is:
+EOD
+
+    my $moves = 0;  # Move counter
+
+    while ( 1 ) {   # Iterate until something interrupts us.
+        print <<"EOD";
+
+@list
+
+EOD
+
+        # Read the number of values to reverse. Zero is special-cased to
+        # take us out of this loop.
+        last unless my $max_index = get_input(
+            'How many shall I reverse (0 to quit)? ',
+            sub {
+                return m/ \A [0-9]+ \z /smx &&
+                    $ARG <= NUMBER_OF_NUMBERS;
+            },
+            "Oops! Too many! I can reverse at most " .
+                NUMBER_OF_NUMBERS,
+        );
+
+        --$max_index;   # Convert number to reverse to upper index
+
+        # Use a Perl array slice and the reverse() built-in to reverse
+        # the beginning of the list.
+        @list[ 0 .. $max_index ] = reverse @list[ 0 .. $max_index ];
+
+        $moves++;   # Count a move
+
+        # If we have not won, iterate again.
+        next unless is_win( \@list );
+
+        # Announce the win, and drop out of the loop.
+        print <<"EOD";
+
+You won it in $moves moves!!!
+EOD
+        last;
+    }
+
+    # Drop out of this loop unless the player wants to play again.
+    say '';
+    last unless get_yes_no( 'Try again' );
+}
+
+print <<'EOD';
+
+O.K. Hope you had fun!!
+EOD
+
+# Get input from the user. The arguments are:
+# * The prompt
+# * A reference to validation code. This code receives the response in
+#   $ARG and returns true for a valid response.
+# * A warning to print if the response is not valid. This must end in a
+#   return.
+# The first valid response is returned. An end-of-file terminates the
+# script.
+sub get_input {
+    my ( $prompt, $validate, $warning ) = @ARG;
+
+    # If no validator is passed, default to one that always returns
+    # true.
+    $validate ||= sub { 1 };
+
+    # Create the readline object. The 'state' causes the variable to be
+    # initialized only once, no matter how many times this subroutine is
+    # called. The do { ... } is a compound statement used because we
+    # need to tweak the created object before we store it.
+    state $term = do {
+        my $obj = Term::ReadLine->new( 'reverse' );
+        $obj->ornaments( 0 );
+        $obj;
+    };
+
+    while ( 1 ) {   # Iterate indefinitely
+
+        # Read the input into the topic variable, localized to prevent
+        # Spooky Action at a Distance. We exit on undef, which signals
+        # end-of-file.
+        exit unless defined( local $ARG = $term->readline( $prompt ) );
+
+        # Return the input if it is valid.
+        return $ARG if $validate->();
+
+        # Issue the warning, and go around the merry-go-round again.
+        warn $warning;
+    }
+}
+
+# Get a yes-or-no answer. The argument is the prompt, which will have
+# '? [y/n]: ' appended. The donkey work is done by get_input(), which is
+# requested to validate the response as beginning with 'y' or 'n',
+# case-insensitive. The return is a true value for 'y' and a false value
+# for 'n'.
+sub get_yes_no {
+    my ( $prompt ) = @ARG;
+    state $map_answer = {
+        n   => 0,
+        y   => 1,
+    };
+    my $resp = lc get_input(
+        "$prompt? [y/n]: ",
+        sub { m/ \A [yn] /smxi },
+        "Please respond 'y' or 'n'\n",
+    );
+    return $map_answer->{ substr $resp, 0, 1 };
+}
+
+# Determine if a given list represents a win. The argument is a
+# reference to the array containing the list. We return a true value for
+# a win, or a false value otherwise.
+sub is_win {
+    my ( $list ) = @_;
+    my $expect = 1; # We expect the first element to be 1;
+
+    # Iterate over the array.
+    foreach my $element ( @{ $list } ) {
+
+        # If the element does not have the expected value, we return
+        # false. We post-increment the expected value en passant.
+        $element == $expect++
+            or return 0;
+    }
+
+    # All elements had the expected value, so we won. Return a true
+    # value.
+    return 1;
+}
+
+__END__
+
+=head1 TITLE
+
+reverse.pl - Play the game 'reverse' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ reverse.pl
+
+=head1 DETAILS
+
+This Perl script is a port of C, which is the 73rd entry in
+Basic Computer Games.
+
+The cool thing about this port is the fact that, in a language with
+array slices, list assignments, and a C built-in, the
+reversal is a single assignment statement.
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :
diff --git a/00_Alternate_Languages/73_Reverse/python/README.md b/00_Alternate_Languages/73_Reverse/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/73_Reverse/python/reverse.py b/00_Alternate_Languages/73_Reverse/python/reverse.py
new file mode 100644
index 00000000..924fe244
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/python/reverse.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python3
+import random
+import textwrap
+
+NUMCNT = 9  # How many numbers are we playing with?
+
+
+def play():
+    print("REVERSE".center(72))
+    print("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".center(72))
+    print()
+    print()
+    print("REVERSE -- A GAME OF SKILL")
+    print()
+
+    if not input("DO YOU WANT THE RULES? (yes/no) ").lower().startswith("n"):
+        rules()
+
+    while True:
+        game_loop()
+
+        if not input("TRY AGAIN? (yes/no) ").lower().startswith("y"):
+            return
+
+
+def game_loop():
+    """Play the main game."""
+    # Make a random list from 1 to NUMCNT
+    numbers = list(range(1, NUMCNT + 1))
+    random.shuffle(numbers)
+
+    # Print original list and start the game
+    print()
+    print("HERE WE GO ... THE LIST IS:")
+    print_list(numbers)
+
+    turns = 0
+    while True:
+        try:
+            howmany = int(input("HOW MANY SHALL I REVERSE? "))
+            assert howmany >= 0
+        except (ValueError, AssertionError):
+            continue
+
+        if howmany == 0:
+            return
+
+        if howmany > NUMCNT:
+            print("OOPS! WRONG! I CAN REVERSE AT MOST", NUMCNT)
+            continue
+
+        turns += 1
+
+        # Reverse as many items as requested.
+        newnums = numbers[0:howmany]
+        newnums.reverse()
+        newnums.extend(numbers[howmany:])
+        numbers = newnums
+
+        print_list(numbers)
+
+        # Check for a win
+        if all(numbers[i] == i + 1 for i in range(NUMCNT)):
+            print(f"YOU WON IT IN {turns} MOVES!")
+            print()
+            return
+
+
+def print_list(numbers):
+    """Print out the list"""
+    print(" ".join(map(str, numbers)))
+
+
+def rules():
+    """Print out the rules"""
+    help = textwrap.dedent(
+        """
+        THIS IS THE GAME OF "REVERSE".  TO WIN, ALL YOU HAVE
+        TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH {})
+        IN NUMERICAL ORDER FROM LEFT TO RIGHT.  TO MOVE, YOU
+        TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO
+        REVERSE.  FOR EXAMPLE, IF THE CURRENT LIST IS:
+
+        2 3 4 5 1 6 7 8 9
+
+        AND YOU REVERSE 4, THE RESULT WILL BE:
+
+        5 4 3 2 1 6 7 8 9
+
+        NOW IF YOU REVERSE 5, YOU WIN!
+
+        1 2 3 4 5 6 7 8 9
+
+        NO DOUBT YOU WILL LIKE THIS GAME, BUT
+        IF YOU WANT TO QUIT, REVERSE 0 (ZERO).
+        """.format(
+            NUMCNT
+        )
+    )
+    print(help)
+    print()
+
+
+if __name__ == "__main__":
+    try:
+        play()
+    except KeyboardInterrupt:
+        pass
diff --git a/00_Alternate_Languages/73_Reverse/reverse.bas b/00_Alternate_Languages/73_Reverse/reverse.bas
new file mode 100644
index 00000000..37d48676
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/reverse.bas
@@ -0,0 +1,62 @@
+10 PRINT TAB(32);"REVERSE"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+100 PRINT "REVERSE -- A GAME OF SKILL": PRINT
+130 DIM A(20)
+140 REM *** N=NUMBER OF NUMBERS
+150 N=9
+160 PRINT "DO YOU WANT THE RULES";
+170 INPUT A$
+180 IF A$="NO" THEN 210
+190 GOSUB 710
+200 REM *** MAKE A RANDOM LIST A(1) TO A(N)
+210 A(1)=INT((N-1)*RND(1)+2)
+220 FOR K=2 TO N
+230 A(K)=INT(N*RND(1)+1)
+240 FOR J=1 TO K-1
+250 IF A(K)=A(J) THEN 230
+260 NEXT J:NEXT K
+280 REM *** PRINT ORIGINAL LIST AND START GAME
+290 PRINT: PRINT "HERE WE GO ... THE LIST IS:"
+310 T=0
+320 GOSUB 610
+330 PRINT "HOW MANY SHALL I REVERSE";
+340 INPUT R
+350 IF R=0 THEN 520
+360 IF R<=N THEN 390
+370 PRINT "OOPS! TOO MANY! I CAN REVERSE AT MOST";N:GOTO 330
+390 T=T+1
+400 REM *** REVERSE R NUMBERS AND PRINT NEW LIST
+410 FOR K=1 TO INT(R/2)
+420 Z=A(K)
+430 A(K)=A(R-K+1)
+440 A(R-K+1)=Z
+450 NEXT K
+460 GOSUB 610
+470 REM *** CHECK FOR A WIN
+480 FOR K=1 TO N
+490 IF A(K)<>K THEN 330
+500 NEXT K
+510 PRINT "YOU WON IT IN";T;"MOVES!!!":PRINT
+520 PRINT
+530 PRINT "TRY AGAIN (YES OR NO)";
+540 INPUT A$
+550 IF A$="YES" THEN 210
+560 PRINT: PRINT "O.K. HOPE YOU HAD FUN!!":GOTO 999
+600 REM *** SUBROUTINE TO PRINT LIST
+610 PRINT:FOR K=1 TO N:PRINT A(K);:NEXT K
+650 PRINT:PRINT:RETURN
+700 REM *** SUBROUTINE TO PRINT THE RULES
+710 PRINT:PRINT "THIS IS THE GAME OF 'REVERSE'.  TO WIN, ALL YOU HAVE"
+720 PRINT "TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH";N;")"
+730 PRINT "IN NUMERICAL ORDER FROM LEFT TO RIGHT.  TO MOVE, YOU"
+740 PRINT "TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO"
+750 PRINT "REVERSE.  FOR EXAMPLE, IF THE CURRENT LIST IS:"
+760 PRINT:PRINT "2 3 4 5 1 6 7 8 9"
+770 PRINT:PRINT "AND YOU REVERSE 4, THE RESULT WILL BE:"
+780 PRINT:PRINT "5 4 3 2 1 6 7 8 9"
+790 PRINT:PRINT "NOW IF YOU REVERSE 5, YOU WIN!"
+800 PRINT:PRINT "1 2 3 4 5 6 7 8 9":PRINT
+810 PRINT "NO DOUBT YOU WILL LIKE THIS GAME, BUT"
+820 PRINT "IF YOU WANT TO QUIT, REVERSE 0 (ZERO).":PRINT: RETURN
+999 END
diff --git a/00_Alternate_Languages/73_Reverse/ruby/README.md b/00_Alternate_Languages/73_Reverse/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/73_Reverse/ruby/reverse.rb b/00_Alternate_Languages/73_Reverse/ruby/reverse.rb
new file mode 100644
index 00000000..021eed18
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/ruby/reverse.rb
@@ -0,0 +1,110 @@
+ARRAYSIZE = 9
+$digitArray = Array.new(ARRAYSIZE)
+$winningArray = Array.new(ARRAYSIZE)
+
+# Method to print the rules
+def displayTheRules
+    puts "This is the game of 'Reverse'.  to win, all you have"
+    puts "to do is arrange a list of numbers (1 through " + ARRAYSIZE.to_s + ")"
+    puts "in numerical order from left to right.  to move, you"
+    puts "tell me how many numbers (counting from the left) to"
+    puts "reverse.  For example, if the current list is:"
+    puts "2 3 4 5 1 6 7 8 9"
+    puts "and you reverse 4, the result will be:"
+    puts "5 4 3 2 1 6 7 8 9"
+    puts "Now if you reverse 5, you win!"
+    puts "1 2 3 4 5 6 7 8 9"
+    puts "No doubt you will like this game, but"
+    puts "if you want to quit, reverse 0 (zero)."
+end
+
+# Method to print the list
+def printList
+    puts "\n" + $digitArray.join(" ") + "\n\n"
+end
+
+# Zero-based arrays contain digits 1-9
+# Make a random array and an ordered winning answer array A[0] to A[N]
+def makeRandomList
+    for kIndex in 0..ARRAYSIZE-1 do
+        $digitArray[kIndex] = kIndex+1
+        $winningArray[kIndex] = kIndex+1
+    end
+    # now randomize the digit array order
+    $digitArray.shuffle!
+end
+
+def checkForWin? (triesSoFar)
+    # Check for a win (all array elements in order)
+    if $digitArray == $winningArray then
+        puts "You won it in " + triesSoFar.to_s + " moves!!!\n\n"
+        puts "try again (yes or no)?"
+        tryAgain = gets.strip.upcase
+        if tryAgain == "YES" then
+            return true
+        end
+        puts "\nO.K. Hope you had fun!!"
+        exit
+    end
+    return false
+end
+
+def reverseIt (howManyToReverse, triesSoFar)
+    # REVERSE R NUMBERS AND PRINT NEW LIST
+
+    # extract and reverse the first howManyToReverse elements of the array
+    subArray = $digitArray.take(howManyToReverse)
+    subArray.reverse!
+
+    # get the remaining elements of the original array
+    endArray = $digitArray.slice(howManyToReverse, ARRAYSIZE)
+    # append those elements to the reversed elements
+    $digitArray = subArray.concat(endArray)
+
+    # if we got all in order, randomize again
+    isWinner = checkForWin?(triesSoFar)
+    if isWinner == true then
+        makeRandomList
+    end
+    printList # always print the newly ordered list
+    return isWinner
+end
+
+def askHowManyToReverse
+    puts "How many shall I reverse?";
+    rNumber = gets.to_i
+    if rNumber > 0 then
+        if rNumber > ARRAYSIZE then
+            puts "Oops! Too many! I can reverse at most " + ARRAYSIZE.to_s
+        end
+    else
+        rNumber = 0 # zero or negative values end the game
+    end
+    return rNumber
+end
+
+puts "REVERSE"
+puts "Creative Computing  Morristown, New Jersey\n\n\n"
+puts "REVERSE -- A game of skill\n\n"
+
+puts "Do you want the rules?"
+wantRules = gets.strip.upcase
+if wantRules == "YES" then
+    displayTheRules
+end
+
+makeRandomList
+howManyTries = 0
+puts "\nHere we go ... the list is:"
+printList # display the initial list
+# start the game loop
+r = askHowManyToReverse
+while r != 0 do # zero will end the game
+    if r <= ARRAYSIZE then
+        howManyTries = howManyTries+1
+        if reverseIt(r, howManyTries) then
+            howManyTries = 0
+        end
+    end
+    r = askHowManyToReverse
+end
diff --git a/00_Alternate_Languages/73_Reverse/vbnet/README.md b/00_Alternate_Languages/73_Reverse/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/73_Reverse/vbnet/Reverse.sln b/00_Alternate_Languages/73_Reverse/vbnet/Reverse.sln
new file mode 100644
index 00000000..8e8fa1ee
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/vbnet/Reverse.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Reverse", "Reverse.vbproj", "{8C9839D4-D0FD-47C2-B54D-429C55F1C6D0}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{8C9839D4-D0FD-47C2-B54D-429C55F1C6D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8C9839D4-D0FD-47C2-B54D-429C55F1C6D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8C9839D4-D0FD-47C2-B54D-429C55F1C6D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8C9839D4-D0FD-47C2-B54D-429C55F1C6D0}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/73_Reverse/vbnet/Reverse.vb b/00_Alternate_Languages/73_Reverse/vbnet/Reverse.vb
new file mode 100644
index 00000000..abe5fa1d
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/vbnet/Reverse.vb
@@ -0,0 +1,195 @@
+Imports System
+
+Module Reverse
+
+
+    '  VB.NET Port of Reverse from book BASIC COMPUTER GAMES.
+    '  Console app for .NET Core 3.1
+    '  Some simplification and error checking was added.
+    '  David Widel
+
+    Const NumberOfDigits As Integer = 9
+
+    Private Numbers As New Generic.List(Of Integer)
+
+
+
+    Sub Main(args As String())
+
+        DisplayIntro()
+
+        Console.WriteLine("DO YOU WANT THE RULES? (Y/N)")
+        If Console.ReadKey(True).Key = ConsoleKey.Y Then
+            DisplayRules()
+        End If
+
+
+
+        Dim playing As Boolean = True
+
+        Do While (playing)  ' New game loop.
+
+            InitializeRandomNumberList()
+
+            Console.WriteLine("HERE WE GO ... THE LIST IS:")
+            DisplayNumbers()
+
+            Dim Counter As Integer = 0
+
+            While True ' Turn loop.
+
+                Dim ReverseNumber As Integer = GetHowManyToReverse()
+                If ReverseNumber = 0 Then
+                    If Not TryAgain() Then
+                        playing = False
+                    End If
+                    Continue Do
+                End If
+
+                PerformReverse(ReverseNumber)
+                Counter += 1
+                DisplayNumbers()
+
+                If DidPlayerWin() Then
+                    Console.WriteLine("YOU WON IN " & Counter.ToString & " MOVES")
+                    If Not TryAgain() Then
+                        Console.WriteLine("O.K. HOPE YOU HAD FUN!!")
+                        playing = False
+                    End If
+                    Continue Do
+                End If
+
+            End While
+
+        Loop
+
+
+
+
+    End Sub
+
+    Sub DisplayIntro()
+        Console.WriteLine("REVERSE")
+        Console.WriteLine("CREATIVE COMPUTING    MORRISTOWN, NEW JERSEY")
+        Console.WriteLine("REVERSE -- A GAME OF SKILL")
+
+
+    End Sub
+
+    Sub DisplayRules()
+
+        Console.WriteLine("THIS IS THE GAME OF REVERSE. TO WIN, ALL YOU HAVE")
+        Console.WriteLine("TO DO IS ARRANGE A LIST OF NUMBERS (1 THROUGH " & NumberOfDigits.ToString & ")")
+        Console.WriteLine("IN NUMERICAL ORDER FROM LEFT TO RIGHT. TO MOVE, YOU")
+        Console.WriteLine("TELL ME HOW MANY NUMBERS (COUNTING FROM THE LEFT) TO")
+        Console.WriteLine("REVERSE. FOR EXAMPLE, IF THE CURRENT LIST IS:")
+        Console.WriteLine()
+        Console.WriteLine("2 3 4 5 1 6 7 8 9")
+        Console.WriteLine()
+        Console.WriteLine("AND YOU REVERSE 4, THE RESULT WILL BE:")
+        Console.WriteLine()
+        Console.WriteLine("5 4 3 2 1 6 7 8 9")
+        Console.WriteLine()
+        Console.WriteLine("NOW IF YOU REVERSE 5, YOU WIN!")
+        Console.WriteLine()
+        Console.WriteLine("1 2 3 4 5 6 7 8 9")
+        Console.WriteLine()
+        Console.WriteLine()
+        Console.WriteLine()
+        Console.WriteLine("NO DOUBT YOU WILL LIKE THIS GAME, BUT")
+        Console.WriteLine("IF YOU WANT TO QUIT, REVERSE O (ZERO).")
+        Console.WriteLine()
+
+    End Sub
+
+    Sub InitializeRandomNumberList()
+
+        Dim R As New Random
+        Numbers.Clear()
+
+        Do Until Numbers.Count = NumberOfDigits
+
+            Dim NewNumber = R.Next(1, NumberOfDigits + 1) 'Lower bound is inclusive, Upper bound is exclusive
+
+            If Not Numbers.Contains(NewNumber) Then
+                Numbers.Add(NewNumber)
+            End If
+
+        Loop
+
+
+        If DidPlayerWin() Then
+            Numbers.Reverse()
+        End If
+
+    End Sub
+
+    Private Sub DisplayNumbers()
+        For i As Integer = 0 To Numbers.Count - 1
+            Console.Write(Numbers(i).ToString(" #"))
+        Next
+        Console.WriteLine()
+    End Sub
+
+    Function GetHowManyToReverse() As Integer
+        Console.WriteLine("HOW MANY SHALL I REVERSE?")
+
+        Do
+
+            Dim K = Console.ReadLine
+            Dim ReverseNumber As Integer
+
+            If Integer.TryParse(K, ReverseNumber) Then
+                If ReverseNumber <= NumberOfDigits Then
+                    Return ReverseNumber
+                Else
+                    Console.WriteLine("OOPS! TOO MANY! I CAN REVERSE AT MOST " & NumberOfDigits.ToString)
+                End If
+            Else
+                'Added check.
+                Console.WriteLine("OOPS! NUMBERS PLEASE!")
+            End If
+
+        Loop
+
+    End Function
+
+    Sub PerformReverse(ReverseNumber As Integer)
+
+        ' We will make pointers to the 2 digits to swap, swap them, and converge the pointers.
+        Dim LowerPointer As Integer = 1
+        Dim UpperPointer As Integer = ReverseNumber
+
+        Do
+            'Since our list begins at 0 we must always subtract one to access a digit.
+            Dim temp As Integer = Numbers(LowerPointer - 1)
+            Numbers(LowerPointer - 1) = Numbers(UpperPointer - 1)
+            Numbers(UpperPointer - 1) = temp
+            LowerPointer += 1
+            UpperPointer -= 1
+
+        Loop Until UpperPointer <= LowerPointer
+
+    End Sub
+
+    Function DidPlayerWin() As Boolean
+        For i As Integer = 0 To Numbers.Count - 2
+            If Numbers(i) > Numbers(i + 1) Then Return False
+        Next
+        Return True
+    End Function
+
+
+    Private Function TryAgain() As Boolean
+        Console.WriteLine("TRY AGAIN? (Y OR N)")
+        If Console.ReadKey(True).Key = ConsoleKey.Y Then
+            Return True
+        Else
+            Return False
+        End If
+    End Function
+
+
+
+
+End Module
diff --git a/00_Alternate_Languages/73_Reverse/vbnet/Reverse.vbproj b/00_Alternate_Languages/73_Reverse/vbnet/Reverse.vbproj
new file mode 100644
index 00000000..978b4e56
--- /dev/null
+++ b/00_Alternate_Languages/73_Reverse/vbnet/Reverse.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Reverse
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Choice.cs b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Choice.cs
new file mode 100644
index 00000000..c981a45a
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Choice.cs
@@ -0,0 +1,19 @@
+namespace RockScissorsPaper
+{
+    public class Choice
+    {
+        public string Selector {get; private set; }
+        public string Name { get; private set; }
+        internal Choice CanBeat { get; set; }
+
+        public Choice(string selector, string name) {
+            Selector = selector;
+            Name = name;
+        }
+
+        public bool Beats(Choice choice)
+        {
+            return choice == CanBeat;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Choices.cs b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Choices.cs
new file mode 100644
index 00000000..3026d7cc
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Choices.cs
@@ -0,0 +1,42 @@
+using System;
+
+namespace RockScissorsPaper
+{
+    public class Choices
+    {
+        public static readonly Choice Rock = new Choice("3", "Rock");
+        public static readonly Choice Scissors = new Choice("2", "Scissors");
+        public static readonly Choice Paper = new Choice("1", "Paper");
+
+        private static readonly Choice[] _allChoices;
+        private static readonly Random _random = new Random();
+
+        static Choices()
+        {
+            Rock.CanBeat = Scissors;
+            Scissors.CanBeat = Paper;
+            Paper.CanBeat = Rock;
+
+            _allChoices = new[] { Rock, Scissors, Paper };
+        }
+
+        public static Choice GetRandom()
+        {
+            return _allChoices[_random.Next(_allChoices.GetLength(0))];
+        }
+
+        public static bool TryGetBySelector(string selector, out Choice choice)
+        {
+            foreach (var possibleChoice in _allChoices)
+            {
+                if (string.Equals(possibleChoice.Selector, selector))
+                {
+                    choice = possibleChoice;
+                    return true;
+                }
+            }
+            choice = null;
+            return false;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Game.cs b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Game.cs
new file mode 100644
index 00000000..8916a217
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Game.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Linq;
+
+namespace RockScissorsPaper
+{
+    public class Game
+    {
+        public int ComputerWins { get; private set; }
+        public int HumanWins { get; private set; }
+        public int TieGames { get; private set; }
+
+        public void PlayGame()
+        {
+            var computerChoice = Choices.GetRandom();
+            var humanChoice = GetHumanChoice();
+
+            Console.WriteLine("This is my choice...");
+            Console.WriteLine("...{0}", computerChoice.Name);
+
+            if (humanChoice.Beats(computerChoice))
+            {
+                Console.WriteLine("You win!!!");
+                HumanWins++;
+            }
+            else if (computerChoice.Beats(humanChoice))
+            {
+                Console.WriteLine("Wow!  I win!!!");
+                ComputerWins++;
+            }
+            else
+            {
+                Console.WriteLine("Tie game.  No winner.");
+                TieGames++;
+            }
+        }
+
+        public void WriteFinalScore()
+        {
+            Console.WriteLine();
+            Console.WriteLine("Here is the final game score:");
+            Console.WriteLine("I have won {0} game(s).", ComputerWins);
+            Console.WriteLine("You have one {0} game(s).", HumanWins);
+            Console.WriteLine("And {0} game(s) ended in a tie.", TieGames);
+        }
+
+        public Choice GetHumanChoice()
+        {
+            while (true)
+            {
+                Console.WriteLine("3=Rock...2=Scissors...1=Paper");
+                Console.WriteLine("1...2...3...What's your choice");
+                if (Choices.TryGetBySelector(Console.ReadLine(), out var choice))
+                    return choice;
+                Console.WriteLine("Invalid.");
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Program.cs b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Program.cs
new file mode 100644
index 00000000..acd49e4b
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/Program.cs
@@ -0,0 +1,48 @@
+using System;
+
+namespace RockScissorsPaper
+{
+    static class Program
+    {
+        static void Main(string[] args)
+        {
+            Console.WriteLine("GAME OF ROCK, SCISSORS, PAPER");
+            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+
+            var numberOfGames = GetNumberOfGames();
+
+            var game = new Game();
+            for (var gameNumber = 1; gameNumber <= numberOfGames; gameNumber++) {
+                Console.WriteLine();
+                Console.WriteLine("Game number {0}", gameNumber);
+
+                game.PlayGame();
+            }
+
+            game.WriteFinalScore();
+
+            Console.WriteLine();
+            Console.WriteLine("Thanks for playing!!");
+        }
+
+        static int GetNumberOfGames()
+        {
+            while (true) {
+                Console.WriteLine("How many games");
+                if (int.TryParse(Console.ReadLine(), out var number))
+                {
+                    if (number < 11 && number > 0)
+                        return number;
+                    Console.WriteLine("Sorry, but we aren't allowed to play that many.");
+                }
+                else
+                {
+                    Console.WriteLine("Sorry, I didn't understand.");
+                }
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/RockScissorsPaper.csproj b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/RockScissorsPaper.csproj
new file mode 100644
index 00000000..6e6a5510
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/RockScissorsPaper.csproj
@@ -0,0 +1,9 @@
+
+
+  
+    Exe
+    net5.0
+    RockScissorsPaper
+  
+
+
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/RockScissorsPaper.sln b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/RockScissorsPaper.sln
new file mode 100644
index 00000000..5c563dd8
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/csharp/RockScissorsPaper.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RockScissorsPaper", "RockScissorsPaper.csproj", "{162F12A7-72D0-44C8-9854-EA50C707690F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{162F12A7-72D0-44C8-9854-EA50C707690F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{162F12A7-72D0-44C8-9854-EA50C707690F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{162F12A7-72D0-44C8-9854-EA50C707690F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{162F12A7-72D0-44C8-9854-EA50C707690F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/java/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/java/src/RockScissors.java b/00_Alternate_Languages/74_Rock_Scissors_Paper/java/src/RockScissors.java
new file mode 100644
index 00000000..2720028a
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/java/src/RockScissors.java
@@ -0,0 +1,212 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Rock Scissors Paper
+ * 

+ * Based on the Basic game of Rock Scissors here + * https://github.com/coding-horror/basic-computer-games/blob/main/74%20Rock%20Scissors%20Paper/rockscissors.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. + */ + +public class RockScissors { + + public static final int MAX_GAMES = 10; + + public static final int PAPER = 1; + public static final int SCISSORS = 2; + public static final int ROCK = 3; + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + START_GAME, + GET_NUMBER_GAMES, + START_ROUND, + PLAY_ROUND, + GAME_RESULT, + GAME_OVER + } + + // Current game state + private GAME_STATE gameState; + + private enum WINNER { + COMPUTER, + PLAYER + } + + private WINNER gameWinner; + + int playerWins; + int computerWins; + int numberOfGames; + int currentGameCount; + int computersChoice; + + public RockScissors() { + kbScanner = new Scanner(System.in); + gameState = GAME_STATE.START_GAME; + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + case START_GAME: + intro(); + currentGameCount = 0; + gameState = GAME_STATE.GET_NUMBER_GAMES; + + break; + + case GET_NUMBER_GAMES: + numberOfGames = displayTextAndGetNumber("HOW MANY GAMES? "); + if (numberOfGames <= MAX_GAMES) { + gameState = GAME_STATE.START_ROUND; + } else { + System.out.println("SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY."); + } + break; + + case START_ROUND: + currentGameCount++; + if (currentGameCount > numberOfGames) { + gameState = GAME_STATE.GAME_RESULT; + break; + } + System.out.println("GAME NUMBER: " + (currentGameCount)); + computersChoice = (int) (Math.random() * 3) + 1; + gameState = GAME_STATE.PLAY_ROUND; + + case PLAY_ROUND: + System.out.println("3=ROCK...2=SCISSORS...1=PAPER"); + int playersChoice = displayTextAndGetNumber("1...2...3...WHAT'S YOUR CHOICE? "); + if (playersChoice >= PAPER && playersChoice <= ROCK) { + switch (computersChoice) { + case PAPER: + System.out.println("...PAPER"); + break; + case SCISSORS: + System.out.println("...SCISSORS"); + break; + case ROCK: + System.out.println("...ROCK"); + break; + } + + if (playersChoice == computersChoice) { + System.out.println("TIE GAME. NO WINNER."); + } else { + switch (playersChoice) { + case PAPER: + if (computersChoice == SCISSORS) { + gameWinner = WINNER.COMPUTER; + } else if (computersChoice == ROCK) { + // Don't need to re-assign here, as its initialized to + // false I'd argue this aids readability. + gameWinner = WINNER.PLAYER; + } + break; + case SCISSORS: + if (computersChoice == ROCK) { + gameWinner = WINNER.COMPUTER; + } else if (computersChoice == PAPER) { + // Don't need to re-assign here, as its initialized to + // false I'd argue this aids readability. + gameWinner = WINNER.PLAYER; + } + break; + case ROCK: + if (computersChoice == PAPER) { + gameWinner = WINNER.COMPUTER; + } else if (computersChoice == SCISSORS) { + // Don't need to re-assign here, as its initialized to + // false I'd argue this aids readability. + gameWinner = WINNER.PLAYER; + } + break; + } + + if (gameWinner == WINNER.COMPUTER) { + System.out.println("WOW! I WIN!!!"); + computerWins++; + } else { + System.out.println("YOU WIN!!!"); + playerWins++; + } + } + gameState = GAME_STATE.START_ROUND; + } else { + System.out.println("INVALID."); + } + + break; + + case GAME_RESULT: + System.out.println(); + System.out.println("HERE IS THE FINAL GAME SCORE:"); + System.out.println("I HAVE WON " + computerWins + " GAME" + (computerWins != 1 ? "S." : ".")); + System.out.println("YOU HAVE WON " + playerWins + " GAME" + (playerWins != 1 ? "S." : ".")); + int tiedGames = numberOfGames - (computerWins + playerWins); + System.out.println("AND " + tiedGames + " GAME" + (tiedGames != 1 ? "S " : " ") + "ENDED IN A TIE."); + System.out.println(); + System.out.println("THANKS FOR PLAYING!!"); + gameState = GAME_STATE.GAME_OVER; + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + private void intro() { + System.out.println(addSpaces(21) + "GAME OF ROCK, SCISSORS, PAPER"); + System.out.println(addSpaces(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to an Integer + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private int displayTextAndGetNumber(String text) { + return Integer.parseInt(displayTextAndGetInput(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.nextLine(); + } + + /** + * Return a string of x spaces + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String addSpaces(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + + public static void main(String[] args) { + + RockScissors rockScissors = new RockScissors(); + rockScissors.play(); + } +} diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/javascript/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/javascript/rockscissors.html b/00_Alternate_Languages/74_Rock_Scissors_Paper/javascript/rockscissors.html new file mode 100644 index 00000000..2b938a5f --- /dev/null +++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/javascript/rockscissors.html @@ -0,0 +1,9 @@ + + +ROCK, SCISSORS, PAPER + + +


+
+
+
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/javascript/rockscissors.js b/00_Alternate_Languages/74_Rock_Scissors_Paper/javascript/rockscissors.js
new file mode 100644
index 00000000..707712fb
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/javascript/rockscissors.js
@@ -0,0 +1,107 @@
+// ROCK, SCISSORS, PAPER
+//
+// 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 control section
+async function main()
+{
+    print(tab(21) + "GAME OF ROCK, SCISSORS, PAPER\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    while (1) {
+        print("HOW MANY GAMES");
+        q = parseInt(await input());
+        if (q >= 11)
+            print("SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\n");
+        else
+            break;
+    }
+    h = 0;  // Human
+    c = 0;  // Computer
+    for (g = 1; g <= q; g++ ) {
+        print("\n");
+        print("GAME NUMBER " + g + "\n");
+        x = Math.floor(Math.random() * 3 + 1);
+        while (1) {
+            print("3=ROCK...2=SCISSORS...1=PAPER\n");
+            print("1...2...3...WHAT'S YOUR CHOICE");
+            k = parseInt(await input());
+            if (k != 1 && k != 2 && k != 3)
+                print("INVALID.\n");
+            else
+                break;
+        }
+        print("THIS IS MY CHOICE...");
+        switch (x) {
+            case 1:
+                print("...PAPER\n");
+                break;
+            case 2:
+                print("...SCISSORS\n");
+                break;
+            case 3:
+                print("...ROCK\n");
+                break;
+        }
+        if (x == k) {
+            print("TIE GAME.  NO WINNER.\n");
+        } else if ((x > k && (k != 1 || x != 3)) || (x == 1 && k == 3)) {
+            print("WOW!  I WIN!!!\n");
+            c++;
+        } else {
+            print("YOU WIN!!!\n");
+            h++;
+        }
+    }
+    print("\n");
+    print("HERE IS THE FINAL GAME SCORE:\n");
+    print("I HAVE WON " + c + " GAME(S).\n");
+    print("YOU HAVE WON " + h + " GAME(S).\n");
+    print("AND " + (q - (c + h)) + " GAME(S) ENDED IN A TIE.\n");
+    print("\n");
+    print("THANKS FOR PLAYING!!\n");
+}
+
+main();
diff --git a/49_Hockey/pascal/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/pascal/README.md
similarity index 100%
rename from 49_Hockey/pascal/README.md
rename to 00_Alternate_Languages/74_Rock_Scissors_Paper/pascal/README.md
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/perl/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/perl/rockscissors.pl b/00_Alternate_Languages/74_Rock_Scissors_Paper/perl/rockscissors.pl
new file mode 100644
index 00000000..2f231651
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/perl/rockscissors.pl
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+use strict;
+
+
+print ' 'x 21 . "GAME OF ROCK, SCISSORS, PAPER\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+
+
+my $Q=0;
+my $C=0;
+my $H=0;
+
+do {
+	print "HOW MANY GAMES? "; chomp($Q = );
+	if ($Q>10) { print "SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\n"; }
+	} until ($Q<11);
+
+for (my $G=1; $G<=$Q; $G++) {
+	print "\n"; print "GAME NUMBER $G\n";
+	my $X=int(rand(1)*3+1);
+
+	my $K=0;
+	do {
+		print "3=ROCK...2=SCISSORS...1=PAPER\n";
+		print "1...2...3...WHAT'S YOUR CHOICE? "; chomp($K = );
+		if (($K-1)*($K-2)*($K-3)!=0) { print "INVALID.\n"; $K=0; }
+		} until ($K!=0);
+
+
+	print "THIS IS MY CHOICE...\n";
+	if ($X==1) { print "...PAPER\n"; }
+	if ($X==2) { print "...SCISSORS\n"; }
+	if ($X==3) { print "...ROCK\n"; }
+
+	#Original logic too complex...
+	if ($X==$K) { print "TIE GAME. NO WINNER.\n"; next; }
+	my $Who=0;
+	if ($X==1 && $K==3) { $Who=1; } #Paper wins over rock.
+	if ($X==2 && $K==1) { $Who=1; } #Scissors wins over paper.
+	if ($X==3 && $K==2) { $Who=1; } #Rock wins over scissors.
+	if ($Who==1) {
+		print "WOW! I WIN!!!\n"; $C=$C+1;
+		} else {
+		print "YOU WIN!!!\n"; $H=$H+1;
+		}
+	}
+
+print "\n"; print "HERE IS THE FINAL GAME SCORE:\n";
+print "I HAVE WON $C GAME(S).\n";
+print "YOU HAVE WON $H GAME(S).\n";
+print "AND ".($Q-($C+$H))." GAME(S) ENDED IN A TIE.\n";
+print "\n"; print "THANKS FOR PLAYING!!\n";
+exit;
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/python/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/python/rockscissors.py b/00_Alternate_Languages/74_Rock_Scissors_Paper/python/rockscissors.py
new file mode 100644
index 00000000..cc56adf6
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/python/rockscissors.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python3
+# ROCKSCISSORS
+#
+# Converted from BASIC to Python by Trevor Hobson
+
+import random
+
+
+def play_game():
+    """Play one round of the game"""
+
+    while True:
+        try:
+            games = int(input("How many games? "))
+            if games >= 11:
+                print("Sorry, but we aren't allowed to play that many.")
+            else:
+                break
+
+        except ValueError:
+            print("Please enter a number.")
+
+    won_computer = 0
+    won_human = 0
+
+    for game in range(games):
+        print("\nGame number", game + 1)
+        guess_computer = random.randint(1, 3)
+        print("3=Rock...2=Scissors...1=Paper")
+        guess_human = 0
+        while guess_human == 0:
+            try:
+                guess_human = int(input("1...2...3...What's your choice "))
+                if guess_human not in [1, 2, 3]:
+                    guess_human = 0
+                    print("Invalid")
+
+            except ValueError:
+                print("Please enter a number.")
+        print("This is my choice...")
+        if guess_computer == 1:
+            print("...Paper")
+        elif guess_computer == 2:
+            print("...Scissors")
+        elif guess_computer == 3:
+            print("...Rock")
+        if guess_computer == guess_human:
+            print("Tie Game. No winner")
+        elif guess_computer > guess_human:
+            if guess_human != 1 or guess_computer != 3:
+                print("Wow! I win!!!")
+                won_computer = won_computer + 1
+            else:
+                print("You win!!!")
+                won_human = won_human + 1
+        elif guess_computer == 1:
+            if guess_human != 3:
+                print("You win!!!")
+                won_human = won_human + 1
+            else:
+                print("Wow! I win!!!")
+                won_computer = won_computer + 1
+    print("\nHere is the final game score:")
+    print("I have won", won_computer, "game(s).")
+    print("You have won", won_human, "game(s).")
+    print("and", games - (won_computer + won_human), "game(s) ended in a tie.")
+    print("\nThanks for playing!!\n")
+
+
+def main():
+    print(" " * 21 + "GAME OF ROCK, SCISSORS, PAPER")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n")
+
+    keep_playing = True
+    while keep_playing:
+
+        play_game()
+
+        keep_playing = input("Play again? (yes or no) ").lower().startswith("y")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/rockscissors.bas b/00_Alternate_Languages/74_Rock_Scissors_Paper/rockscissors.bas
new file mode 100644
index 00000000..8c364b63
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/rockscissors.bas
@@ -0,0 +1,33 @@
+10 PRINT TAB(21);"GAME OF ROCK, SCISSORS, PAPER"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+25 PRINT:PRINT:PRINT
+30 INPUT "HOW MANY GAMES";Q
+40 IF Q<11 THEN 60
+50 PRINT "SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.": GOTO 30
+60 FOR G=1 TO Q
+70 PRINT: PRINT "GAME NUMBER";G
+80 X=INT(RND(1)*3+1)
+90 PRINT "3=ROCK...2=SCISSORS...1=PAPER"
+100 INPUT "1...2...3...WHAT'S YOUR CHOICE";K
+110 IF (K-1)*(K-2)*(K-3)<>0 THEN PRINT "INVALID.": GOTO 90
+120 PRINT "THIS IS MY CHOICE..."
+130 ON X GOTO 140,150,160
+140 PRINT "...PAPER": GOTO 170
+150 PRINT "...SCISSORS": GOTO 170
+160 PRINT "...ROCK"
+170 IF X=K THEN 250
+180 IF X>K THEN 230
+190 IF X=1 THEN 210
+200 PRINT "YOU WIN!!!":H=H+1: GOTO 260
+210 IF K<>3 THEN 200
+220 PRINT "WOW!  I WIN!!!":C=C+1:GOTO 260
+230 IF K<>1 OR X<>3 THEN 220
+240 GOTO 200
+250 PRINT "TIE GAME.  NO WINNER."
+260 NEXT G
+270 PRINT: PRINT "HERE IS THE FINAL GAME SCORE:"
+280 PRINT "I HAVE WON";C;"GAME(S)."
+290 PRINT "YOU HAVE WON";H;"GAME(S)."
+300 PRINT "AND";Q-(C+H);"GAME(S) ENDED IN A TIE."
+310 PRINT: PRINT "THANKS FOR PLAYING!!"
+320 END
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/ruby/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/ruby/rockscissors.rb b/00_Alternate_Languages/74_Rock_Scissors_Paper/ruby/rockscissors.rb
new file mode 100644
index 00000000..deae2a3f
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/ruby/rockscissors.rb
@@ -0,0 +1,79 @@
+SCREEN_WIDTH = 72
+
+MOVE_WORDS = {
+  1 => 'PAPER',
+  2 => 'SCISSORS',
+  3 => 'ROCK'
+}
+
+WIN_TABLE = {
+  1 => 3,
+  2 => 1,
+  3 => 2
+}
+
+def center_text(text)
+  text.rjust((SCREEN_WIDTH / 2) + (text.size / 2))
+end
+
+def ask_for_number_of_games
+  loop do
+    puts "HOW MANY GAMES"
+    response = STDIN.gets.to_i
+    return response if response > 0 and response < 11
+    puts "SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY."
+  end
+end
+
+def ask_for_human_move
+  loop do
+    puts "3=ROCK...2=SCISSORS...1=PAPER"
+    puts "1...2...3...WHAT'S YOUR CHOICE"
+    response = STDIN.gets.to_i
+    return response if [1,2,3].include?(response)
+    puts "INVALID"
+  end
+end
+
+def calculate_result(human_move, computer_move)
+  return 'TIE' if human_move == computer_move
+  return 'WIN' if WIN_TABLE[human_move] == computer_move
+  'LOSE'
+end
+
+puts center_text('GAME OF ROCK, SCISSORS, PAPER')
+puts center_text('CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY')
+puts
+puts
+puts
+
+number_of_games = ask_for_number_of_games
+games_won = 0
+games_lost = 0
+
+number_of_games.times do |game_number|
+  puts
+  puts "GAME NUMBER #{game_number + 1}"
+  computer_move = rand(3) + 1
+  human_move = ask_for_human_move
+  puts "THIS IS MY CHOICE..."
+  puts "...#{MOVE_WORDS[computer_move]}"
+
+  case calculate_result(human_move, computer_move)
+  when 'WIN'
+    puts "YOU WIN!!!"
+    games_won += 1
+  when 'TIE'
+    puts "TIE GAME.  NO WINNER."
+  when 'LOSE'
+    puts "WOW!  I WIN!!!"
+    games_lost = games_lost += 1
+  end
+end
+
+puts
+puts "HERE IS THE FINAL GAME SCORE:"
+puts "I HAVE WON #{games_lost} GAME(S)."
+puts "YOU HAVE WON #{games_won} GAME(S)."
+puts "AND #{number_of_games - (games_lost + games_won)} GAME(S) ENDED IN A TIE."
+puts "THANKS FOR PLAYING!!"
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/rust/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/rust/README.md
new file mode 100644
index 00000000..cd7631d4
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/rust/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Rust](https://www.rust-lang.org)
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/rust/src/main.rs b/00_Alternate_Languages/74_Rock_Scissors_Paper/rust/src/main.rs
new file mode 100644
index 00000000..98511bff
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/rust/src/main.rs
@@ -0,0 +1,147 @@
+/*
+ * Rock paper scissors
+ * Originally from the wonderful book: _Basic Computer Games_
+ * Port to Rust By David Lotts
+*/
+use nanorand::{tls::TlsWyRand, Rng};
+use std::io::{self, Write};
+use strum::EnumCount;
+use strum_macros::{Display, EnumCount, FromRepr};
+use text_io::try_read;
+fn main() {
+    let mut computer_wins = 0;
+    let mut human_wins = 0;
+    let mut rng = nanorand::tls_rng();
+    println!("{:>21}", "GAME OF ROCK, SCISSORS, PAPER");
+    println!("{:>15}", "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+    print!("\n\n\n");
+    // pass by reference in rust! input() modifies this variable.
+    let mut qty_games = 0;
+    loop {
+        input_int("HOW MANY GAMES", &mut qty_games);
+        if qty_games < 11 {
+            break;
+        }
+        println!("SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.");
+    }
+    for game_number in 1..=qty_games {
+        println!();
+        println!("GAME NUMBER {}", game_number);
+        let mut your_choice = 0;
+        loop {
+            println!("3=ROCK...2=SCISSORS...1=PAPER");
+            input_int("1...2...3...WHAT'S YOUR CHOICE", &mut your_choice);
+            // interesting validation in original BASIC: IF (K-1)*(K-2)*(K-3)==0
+            if (1..=3).contains(&your_choice) {
+                break;
+            }
+            println!("INVALID.");
+        }
+        // Convert number to enum.  Note the type change.  Really it is a new variable.
+        let your_choice = Choice::from_repr((your_choice - 1) as usize).unwrap();
+        let my_choice = Choice::new_random(&mut rng);
+
+        println!("THIS IS MY CHOICE...");
+        println!("...{}", my_choice.to_string());
+        let winner = Winner::decide_winner(my_choice, your_choice);
+        println!(
+            "{}",
+            match winner {
+                Winner::Tie => {
+                    "TIE GAME.  NO WINNER."
+                }
+                Winner::Computer => {
+                    computer_wins = computer_wins + 1;
+                    "WOW!  I WIN!!!"
+                }
+                Winner::Human => {
+                    human_wins = human_wins + 1;
+                    "YOU WIN!!!"
+                }
+            }
+        )
+    }
+    println!();
+    println!("HERE IS THE FINAL GAME SCORE:");
+    println!("I HAVE WON {} GAME(S).", computer_wins);
+    println!("YOU HAVE WON {} GAME(S).", human_wins);
+    println!(
+        "AND {} GAME(S) ENDED IN A TIE.",
+        qty_games - (computer_wins + human_wins)
+    );
+    println!();
+    println!("THANKS FOR PLAYING!!");
+}
+
+#[derive(FromRepr, Debug, PartialEq, EnumCount, Display)]
+pub enum Choice {
+    PAPER,
+    SCISSORS,
+    ROCK,
+}
+
+impl Choice {
+    /// Returns randomly selected paper..rock.
+    fn new_random(rng: &mut TlsWyRand) -> Choice {
+        Choice::from_repr(rng.generate_range(0..Choice::COUNT)).unwrap()
+    }
+}
+
+#[derive(FromRepr, Debug, PartialEq, EnumCount)]
+pub enum Winner {
+    Human,
+    Computer,
+    Tie,
+}
+
+impl Winner {
+    /// take opponent's choices and decide the winner
+    // I really learned alot about enums here, and now you can too!
+    // Originally I broke this out for auto testing.
+    pub fn decide_winner(my_choice: Choice, your_choice: Choice) -> Winner {
+        let my_choice = my_choice as u8;
+        let your_choice = your_choice as u8;
+        if my_choice == your_choice {
+            return Winner::Tie;
+        }
+        // wordy but clear way:
+        //    if (my_choice == 1 && your_choice == 3) || (my_choice > your_choice)
+        // consice but opaque way:
+        if 1 == (3 + my_choice - your_choice) % 3 {
+            return Winner::Computer;
+        }
+        return Winner::Human;
+    }
+}
+
+/// print the prompt, wait for a number and newline.  Loop if invalid.
+fn input_int(prompt: &str, number: &mut i32) {
+    loop {
+        print!("{} ? ", prompt);
+        io::stdout().flush().unwrap();
+        if let Ok(n) = try_read!() {
+            *number = n;
+            return;
+        }
+    }
+}
+
+/// Test winner decider for every case.
+#[cfg(test)]
+mod tests {
+    #[test]
+    fn winner_test() {
+        use super::*;
+        use Choice::*;
+        use Winner::*; //decide_winner(my_choice=computer, your_choice=human)
+        assert_eq!(Winner::decide_winner(PAPER, PAPER), Tie);
+        assert_eq!(Winner::decide_winner(PAPER, SCISSORS), Human);
+        assert_eq!(Winner::decide_winner(PAPER, ROCK), Computer);
+        assert_eq!(Winner::decide_winner(SCISSORS, PAPER), Computer);
+        assert_eq!(Winner::decide_winner(SCISSORS, SCISSORS), Tie);
+        assert_eq!(Winner::decide_winner(SCISSORS, ROCK), Human);
+        assert_eq!(Winner::decide_winner(ROCK, PAPER), Human);
+        assert_eq!(Winner::decide_winner(ROCK, SCISSORS), Computer);
+        assert_eq!(Winner::decide_winner(ROCK, ROCK), Tie);
+    }
+}
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/vbnet/README.md b/00_Alternate_Languages/74_Rock_Scissors_Paper/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/vbnet/RockScissorsPaper.sln b/00_Alternate_Languages/74_Rock_Scissors_Paper/vbnet/RockScissorsPaper.sln
new file mode 100644
index 00000000..481f3105
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/vbnet/RockScissorsPaper.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "RockScissorsPaper", "RockScissorsPaper.vbproj", "{05C592E9-1A74-4812-88CF-3B078A315378}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{05C592E9-1A74-4812-88CF-3B078A315378}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{05C592E9-1A74-4812-88CF-3B078A315378}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{05C592E9-1A74-4812-88CF-3B078A315378}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{05C592E9-1A74-4812-88CF-3B078A315378}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/74_Rock_Scissors_Paper/vbnet/RockScissorsPaper.vbproj b/00_Alternate_Languages/74_Rock_Scissors_Paper/vbnet/RockScissorsPaper.vbproj
new file mode 100644
index 00000000..e6cf95c5
--- /dev/null
+++ b/00_Alternate_Languages/74_Rock_Scissors_Paper/vbnet/RockScissorsPaper.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    RockScissorsPaper
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/75_Roulette/README.md b/00_Alternate_Languages/75_Roulette/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/75_Roulette/csharp/README.md b/00_Alternate_Languages/75_Roulette/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/75_Roulette/csharp/Roulette.csproj b/00_Alternate_Languages/75_Roulette/csharp/Roulette.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/csharp/Roulette.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/75_Roulette/csharp/Roulette.sln b/00_Alternate_Languages/75_Roulette/csharp/Roulette.sln
new file mode 100644
index 00000000..de44173b
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/csharp/Roulette.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Roulette", "Roulette.csproj", "{9FC3EC1F-2052-4D08-901C-5184E17740FC}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9FC3EC1F-2052-4D08-901C-5184E17740FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9FC3EC1F-2052-4D08-901C-5184E17740FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9FC3EC1F-2052-4D08-901C-5184E17740FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9FC3EC1F-2052-4D08-901C-5184E17740FC}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/75_Roulette/java/README.md b/00_Alternate_Languages/75_Roulette/java/README.md
new file mode 100644
index 00000000..ffa8a3ef
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/java/README.md
@@ -0,0 +1,10 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
+
+Two versions of Roulette has been contributed. They are indicated within given sub-folders
+
+- [oop](./oop) - Conversion by Andrew McGuinness (andrew@arobeia.co.uk)
+- [iterative](./iterative) - Conversion by Thomas Kwashnak ([Github](https://github.com/LittleTealeaf)).
+    - Implements features from JDK 17.
+    - Does make use of some object oriented programming, but acts as a more iterative solution.
diff --git a/00_Alternate_Languages/75_Roulette/java/iterative/Roulette.java b/00_Alternate_Languages/75_Roulette/java/iterative/Roulette.java
new file mode 100644
index 00000000..4d7b0e36
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/java/iterative/Roulette.java
@@ -0,0 +1,277 @@
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Random;
+import java.util.Scanner;
+import java.util.Set;
+
+public class Roulette {
+
+    private static Set RED_NUMBERS;
+
+    static {
+        RED_NUMBERS = Set.of(1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36);
+    }
+
+    private PrintStream out;
+    private Scanner scanner;
+    private int houseBalance, playerBalance;
+    private Random random;
+
+    public Roulette(PrintStream out, InputStream in) {
+        this.out = out;
+        this.scanner = new Scanner(in);
+        houseBalance = 100000;
+        playerBalance = 1000;
+        random = new Random();
+    }
+
+    public static void main(String[] args) {
+        new Roulette(System.out, System.in).play();
+    }
+
+    public void play() {
+        out.println("                                ROULETTE");
+        out.println("               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+        out.println("WELCOME TO THE ROULETTE TABLE\n");
+        out.print("DO YOU WANT INSTRUCTIONS? ");
+        if (scanner.nextLine().toLowerCase().charAt(0) != 'n') {
+            printInstructions();
+        }
+
+        do {
+
+            Bet[] bets = queryBets();
+
+            out.print("SPINNING...\n\n");
+            int result = random.nextInt(1, 39);
+
+            /*
+            Equivalent to following line
+            if(result == 37) {
+                out.println("00");
+            } else if(result == 38) {
+                out.println("0");
+            } else if(RED_NUMBERS.contains(result)) {
+                out.println(result + " RED");
+            } else {
+                out.println(result + " BLACK");
+            }
+             */
+            out.println(switch (result) {
+                case 37 -> "00";
+                case 38 -> "0";
+                default -> result + (RED_NUMBERS.contains(result) ? " RED" : " BLACK");
+            });
+
+            betResults(bets, result);
+            out.println();
+
+            out.println("TOTALS:\tME\t\tYOU");
+            out.format("\t\t%5d\t%d\n", houseBalance, playerBalance);
+        } while (playAgain());
+        if (playerBalance <= 0) {
+            out.println("THANKS FOR YOUR MONEY\nI'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL");
+        } else {
+            printCheck();
+        }
+        out.println("COME BACK SOON!");
+    }
+
+    public void printInstructions() {
+        out.println();
+        out.println("THIS IS THE BETTING LAYOUT");
+        out.println("  (*=RED)");
+        out.println();
+        out.println(" 1*    2     3*");
+        out.println(" 4     5*    6 ");
+        out.println(" 7*    8     9*");
+        out.println("10    11    12*");
+        out.println("---------------");
+        out.println("13    14*   15 ");
+        out.println("16*   17    18*");
+        out.println("19*   20    21*");
+        out.println("22    23*   24 ");
+        out.println("---------------");
+        out.println("25*   26    27*");
+        out.println("28    29    30*");
+        out.println("31    32*   33 ");
+        out.println("34*   35    36*");
+        out.println("---------------");
+        out.println("    00    0    ");
+        out.println();
+        out.println("TYPES OF BETS");
+        out.println();
+        out.println("THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET");
+        out.println("ON THAT NUMBER.");
+        out.println("THESE PAY OFF 35:1");
+        out.println();
+        out.println("THE 2:1 BETS ARE:");
+        out.println(" 37) 1-12     40) FIRST COLUMN");
+        out.println(" 38) 13-24    41) SECOND COLUMN");
+        out.println(" 39) 25-36    42) THIRD COLUMN");
+        out.println();
+        out.println("THE EVEN MONEY BETS ARE:");
+        out.println(" 43) 1-18     46) ODD");
+        out.println(" 44) 19-36    47) RED");
+        out.println(" 45) EVEN     48) BLACK");
+        out.println();
+        out.println(" 49)0 AND 50)00 PAY OFF 35:1");
+        out.println(" NOTE: 0 AND 00 DO NOT COUNT UNDER ANY");
+        out.println("       BETS EXCEPT THEIR OWN.");
+        out.println();
+        out.println("WHEN I ASK FOR EACH BET, TYPE THE NUMBER");
+        out.println("AND THE AMOUNT, SEPARATED BY A COMMA.");
+        out.println("FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500");
+        out.println("WHEN I ASK FOR A BET.");
+        out.println();
+        out.println("THE MINIMUM BET IS $5, THE MAXIMUM IS $500.");
+    }
+
+    private Bet[] queryBets() {
+        int numBets = -1;
+        while (numBets < 1) {
+            out.print("HOW MANY BETS? ");
+            try {
+                numBets = Integer.parseInt(scanner.nextLine());
+            } catch (NumberFormatException ignored) {
+            }
+        }
+
+        Bet[] bets = new Bet[numBets];
+
+        for (int i = 0; i < numBets; i++) {
+            while (bets[i] == null) {
+                try {
+                    out.print("NUMBER" + (i + 1) + "? ");
+                    String[] values = scanner.nextLine().split(",");
+                    int betNumber = Integer.parseInt(values[0]);
+                    int betValue = Integer.parseInt(values[1]);
+
+                    for (int j = 0; j < i; j++) {
+                        if (bets[j].num == betNumber) {
+                            out.println("YOU MADE THAT BET ONCE ALREADY,DUM-DUM");
+                            betNumber = -1; //Since -1 is out of the range, this will throw it out at the end
+                        }
+                    }
+
+                    if (betNumber > 0 && betNumber <= 50 && betValue >= 5 && betValue <= 500) {
+                        bets[i] = new Bet(betNumber,betValue);
+                    }
+                } catch (Exception ignored) {
+                }
+            }
+        }
+        return bets;
+    }
+
+    private void betResults(Bet[] bets, int num) {
+        for (int i = 0; i < bets.length; i++) {
+            Bet bet = bets[i];
+            /*
+            Using a switch statement of ternary operators that check if a certain condition is met based on the bet value
+            Returns the coefficient that the bet amount should be multiplied by to get the resulting value
+             */
+            int coefficient = switch (bet.num) {
+                case 37 -> (num <= 12) ? 2 : -1;
+                case 38 -> (num > 12 && num <= 24) ? 2 : -1;
+                case 39 -> (num > 24 && num < 37) ? 2 : -1;
+                case 40 -> (num < 37 && num % 3 == 1) ? 2 : -1;
+                case 41 -> (num < 37 && num % 3 == 2) ? 2 : -1;
+                case 42 -> (num < 37 && num % 3 == 0) ? 2 : -1;
+                case 43 -> (num <= 18) ? 1 : -1;
+                case 44 -> (num > 18 && num <= 36) ? 1 : -1;
+                case 45 -> (num % 2 == 0) ? 1 : -1;
+                case 46 -> (num % 2 == 1) ? 1 : -1;
+                case 47 -> RED_NUMBERS.contains(num) ? 1 : -1;
+                case 48 -> !RED_NUMBERS.contains(num) ? 1 : -1;
+                case 49 -> (num == 37) ? 35 : -1;
+                case 50 -> (num == 38) ? 35 : -1;
+                default -> (bet.num < 49 && bet.num == num) ? 35 : -1;
+            };
+
+            int betResult = bet.amount * coefficient;
+
+            if (betResult < 0) {
+                out.println("YOU LOSE " + -betResult + " DOLLARS ON BET " + (i + 1));
+            } else {
+                out.println("YOU WIN " + betResult + " DOLLARS ON BET " + (i + 1));
+            }
+
+            playerBalance += betResult;
+            houseBalance -= betResult;
+        }
+    }
+
+    private boolean playAgain() {
+
+        if (playerBalance <= 0) {
+            out.println("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!");
+            return false;
+        } else if (houseBalance <= 0) {
+            out.println("YOU BROKE THE HOUSE!");
+            playerBalance = 101000;
+            houseBalance = 0;
+            return false;
+        } else {
+            out.println("PLAY AGAIN?");
+            return scanner.nextLine().toLowerCase().charAt(0) == 'y';
+        }
+    }
+
+    private void printCheck() {
+        out.print("TO WHOM SHALL I MAKE THE CHECK? ");
+        String name = scanner.nextLine();
+
+        out.println();
+        for (int i = 0; i < 72; i++) {
+            out.print("-");
+        }
+        out.println();
+
+        for (int i = 0; i < 50; i++) {
+            out.print(" ");
+        }
+        out.println("CHECK NO. " + random.nextInt(0, 100));
+
+        for (int i = 0; i < 40; i++) {
+            out.print(" ");
+        }
+        out.println(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE));
+        out.println();
+
+        out.println("PAY TO THE ORDER OF -----" + name + "----- $" + (playerBalance));
+        out.println();
+
+        for (int i = 0; i < 40; i++) {
+            out.print(" ");
+        }
+        out.println("THE MEMORY BANK OF NEW YORK");
+
+        for (int i = 0; i < 40; i++) {
+            out.print(" ");
+        }
+        out.println("THE COMPUTER");
+
+        for (int i = 0; i < 40; i++) {
+            out.print(" ");
+        }
+        out.println("----------X-----");
+
+        for (int i = 0; i < 72; i++) {
+            out.print("-");
+        }
+        out.println();
+    }
+
+    public class Bet {
+
+        final int num, amount;
+
+        public Bet(int num, int amount) {
+            this.num = num;
+            this.amount = amount;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/75_Roulette/java/oop/Bet.java b/00_Alternate_Languages/75_Roulette/java/oop/Bet.java
new file mode 100644
index 00000000..8742ca6b
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/java/oop/Bet.java
@@ -0,0 +1,65 @@
+/* A bet has a target (the code entered, which is 1-36, or special values for
+ * the various groups, zero and double-zero), and an amount in dollars
+ */
+
+public class Bet {
+    public int target;
+    public int amount;
+
+    /* bet on a target, of an amount */
+    public Bet(int on, int of) {
+        target = on; amount = of;
+    }
+
+    /* check if this is a valid bet - on a real target and of a valid amount */
+    public boolean isValid() {
+        return ((target > 0) && (target <= 50) &&
+                (amount >= 5) && (amount <= 500));
+    }
+
+    /* utility to return either the odds amount in the case of a win, or zero for a loss */
+    private int m(boolean isWon, int odds) {
+        return isWon? odds: 0;
+    }
+
+    /* look at the wheel to see if this bet won.
+     * returns 0 if it didn't, or the odds if it did
+     */
+    public int winsOn(Wheel w) {
+        if (target < 37) {
+            // A number bet 1-36 wins at odds of 35 if it is the exact number
+            return m(w.isNumber() && (w.number() == target), 35);
+        } else
+            switch (target) {
+            case 37:   // 1-12, odds of 2
+                return m(w.isNumber() && (w.number() <= 12), 2);
+            case 38:   // 13-24, odds of 2
+                return m(w.isNumber() && (w.number() > 12) && (w.number() <= 24), 2);
+            case 39:   // 25-36, odds of 2
+                return m(w.isNumber() && (w.number() > 24), 2);
+            case 40:   // Column 1, odds of 2
+                return m(w.isNumber() && ((w.number() % 3) == 1), 2);
+            case 41:   // Column 2, odds of 2
+                return m(w.isNumber() && ((w.number() % 3) == 2), 2);
+            case 42:   // Column 3, odds of 2
+                return m(w.isNumber() && ((w.number() % 3) == 0), 2);
+            case 43:   // 1-18, odds of 1
+                return m(w.isNumber() && (w.number() <= 18), 1);
+            case 44:   // 19-36, odds of 1
+                return m(w.isNumber() && (w.number() > 18), 1);
+            case 45:   // even, odds of 1
+                return m(w.isNumber() && ((w.number() %2) == 0), 1);
+            case 46:   // odd, odds of 1
+                return m(w.isNumber() && ((w.number() %2) == 1), 1);
+            case 47:   // red, odds of 1
+                return m(w.isNumber() && (w.color() == Wheel.BLACK), 1);
+            case 48:   // black, odds of 1
+                return m(w.isNumber() && (w.color() == Wheel.RED), 1);
+            case 49: // single zero, odds of 35
+                return m(w.value().equals("0"), 35);
+            case 50: // double zero, odds of 35
+                return m(w.value().equals("00"), 35);
+            }
+        throw new RuntimeException("Program Error - invalid bet");
+    }
+}
diff --git a/00_Alternate_Languages/75_Roulette/java/oop/Roulette.java b/00_Alternate_Languages/75_Roulette/java/oop/Roulette.java
new file mode 100644
index 00000000..e7f9c444
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/java/oop/Roulette.java
@@ -0,0 +1,234 @@
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Random;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
+
+public class Roulette {
+    public static void main(String args[]) throws Exception {
+        Roulette r = new Roulette();
+        r.play();
+    }
+
+    private BufferedReader reader;
+    private PrintStream writer;
+
+    private int house;      // how much money does the house have
+    private int player;     // how much money does the player have
+    private Wheel wheel = new Wheel();
+
+    public Roulette() {
+        reader = new BufferedReader(new InputStreamReader(System.in));
+        writer = System.out;
+        house = 100000;
+        player = 1000;
+    }
+
+    // for a test / cheat mode -- set the random number generator to a known value
+    private void setSeed(long l) {
+        wheel.setSeed(l);
+    }
+
+    public void play() {
+        try {
+            intro();
+            writer.println("WELCOME TO THE ROULETTE TABLE\n" +
+                           "DO YOU WANT INSTRUCTIONS");
+            String instr = reader.readLine();
+            if (!instr.toUpperCase().startsWith("N"))
+                instructions();
+
+            while (betAndSpin()) { // returns true if the game is to continue
+            }
+
+            if (player <= 0) {
+                // player ran out of money
+                writer.println("THANKS FOR YOUR MONEY.\nI'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL");
+            } else {
+                // player has money -- print them a check
+                writer.println("TO WHOM SHALL I MAKE THE CHECK");
+
+                String payee = reader.readLine();
+
+                writer.println("-".repeat(72));
+                tab(50); writer.println("CHECK NO. " + (new Random().nextInt(100) + 1));
+                writer.println();
+                tab(40); writer.println(LocalDate.now().format(DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG)));
+                writer.println("\n\nPAY TO THE ORDER OF-----" + payee + "-----$ " + player);
+                writer.print("\n\n");
+                tab(10); writer.println("THE MEMORY BANK OF NEW YORK\n");
+                tab(40); writer.println("THE COMPUTER");
+                tab(40); writer.println("----------X-----\n");
+                writer.println("-".repeat(72));
+                writer.println("COME BACK SOON!\n");
+            }
+        }
+        catch (IOException e) {
+            // this should not happen
+            System.err.println("System error:\n" + e);
+        }
+    }
+
+    /* Write the starting introduction */
+    private void intro() throws IOException {
+        tab(32); writer.println("ROULETTE");
+        tab(15); writer.println("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n");
+    }
+
+    /* Display the game instructions */
+    private void instructions() {
+        String[] instLines = new String[] {
+            "THIS IS THE BETTING LAYOUT",
+            "  (*=RED)",
+            "" ,
+            " 1*    2     3*",
+            " 4     5*    6 ",
+            " 7*    8     9*",
+            "10    11    12*",
+            "---------------",
+            "13    14*   15 ",
+            "16*   17    18*",
+            "19*   20    21*",
+            "22    23*   24 ",
+            "---------------",
+            "25*   26    27*",
+            "28    29    30*",
+            "31    32*   33 ",
+            "34*   35    36*",
+            "---------------",
+            "    00    0    ",
+            "" ,
+            "TYPES OF BETS",
+            ""  ,
+            "THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET",
+            "ON THAT NUMBER.",
+            "THESE PAY OFF 35:1",
+            ""  ,
+            "THE 2:1 BETS ARE:",
+            " 37) 1-12     40) FIRST COLUMN",
+            " 38) 13-24    41) SECOND COLUMN",
+            " 39) 25-36    42) THIRD COLUMN",
+            ""  ,
+            "THE EVEN MONEY BETS ARE:",
+            " 43) 1-18     46) ODD",
+            " 44) 19-36    47) RED",
+            " 45) EVEN     48) BLACK",
+            "",
+            " 49)0 AND 50)00 PAY OFF 35:1",
+            " NOTE: 0 AND 00 DO NOT COUNT UNDER ANY",
+            "       BETS EXCEPT THEIR OWN.",
+            "",
+            "WHEN I ASK FOR EACH BET, TYPE THE NUMBER",
+            "AND THE AMOUNT, SEPARATED BY A COMMA.",
+            "FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500",
+            "WHEN I ASK FOR A BET.",
+            "",
+            "THE MINIMUM BET IS $5, THE MAXIMUM IS $500.",
+            "" };
+        writer.println(String.join("\n", instLines));
+    }
+
+    /* Take a set of bets from the player, then spin the wheel and work out the winnings *
+     * This returns true if the game is to continue afterwards
+     */
+    private boolean betAndSpin() throws IOException {
+        int betCount = 0;
+
+        while (betCount == 0) {   // keep asking how many bets until we get a good answer
+            try {
+                writer.println("HOW MANY BETS");
+                String howMany = reader.readLine();
+                betCount = Integer.parseInt(howMany.strip());
+
+                if ((betCount < 1) || (betCount > 100)) betCount = 0; // bad -- set zero and ask again
+            }
+            catch (NumberFormatException e) {
+                // this happens if the input is not a number
+                writer.println("INPUT ERROR");
+            }
+        }
+
+        HashSet betsMade = new HashSet<>(); // Bet targets already made, so we can spot repeats
+        ArrayList bets = new ArrayList<>();     // All the bets for this round
+
+        while (bets.size() < betCount) {
+            Bet bet = new Bet(0, 0);                 // an invalid bet to hold the place
+            while (!bet.isValid()) {                 // keep asking until it is valid
+                try {
+                    writer.println("NUMBER " + (bets.size() + 1));
+                    String fields[] = reader.readLine().split(",");
+                    if (fields.length == 2) {
+                        bet = new Bet(Integer.parseInt(fields[0].strip()),
+                                      Integer.parseInt(fields[1].strip()));
+                    }
+                }
+                catch (NumberFormatException e) {
+                    writer.println("INPUT ERROR");
+                }
+            }
+
+            // Check if there is already a bet on the same target
+            if (betsMade.contains(bet.target)) {
+                writer.println("YOU MADE THAT BET ONCE ALREADY,DUM-DUM");
+            } else {
+                betsMade.add(bet.target); // note this target has now been bet on
+                bets.add(bet);
+            }
+        }
+
+        writer.println("SPINNING\n\n");
+
+        wheel.spin(); // this deliberately takes some random amount of time
+
+        writer.println(wheel.value());
+
+        // go through the bets, and evaluate each one
+        int betNumber = 1;
+        for (Bet b : bets) {
+            int multiplier = b.winsOn(wheel);
+            if (multiplier == 0) {
+                // lost the amount of the bet
+                writer.println("YOU LOSE " + b.amount + " DOLLARS ON BET " + betNumber);
+                house += b.amount;
+                player -= b.amount;
+            } else {
+                // won the amount of the bet, multiplied by the odds
+                int winnings = b.amount * multiplier;
+                writer.println("YOU WIN " + winnings + " DOLLARS ON BET " + betNumber);
+                house -= winnings;
+                player += winnings;
+            }
+            ++betNumber;
+        }
+
+        writer.println("\nTOTALS:\tME\tYOU\n\t" + house + "\t" + player);
+
+        if (player <= 0) {
+            writer.println("OOPS! YOU JUST SPENT YOUR LAST DOLLAR");
+            return false;     // do not repeat since the player has no more money
+        }
+        if (house <= 0) {
+            writer.println("YOU BROKE THE HOUSE!");
+            player = 101000;  // can't win more than the house started with
+            return false;     // do not repeat since the house has no more money
+        }
+
+        // player still has money, and the house still has money, so ask the player
+        // if they want to continue
+        writer.println("AGAIN");
+        String doContinue = reader.readLine();
+
+        // repeat if the answer was not "n" or "no"
+        return (!doContinue.toUpperCase().startsWith("N"));
+    }
+
+    // utility to print n spaces for formatting
+    private void tab(int n) {
+        writer.print(" ".repeat(n));
+    }
+}
diff --git a/00_Alternate_Languages/75_Roulette/java/oop/Wheel.java b/00_Alternate_Languages/75_Roulette/java/oop/Wheel.java
new file mode 100644
index 00000000..a454b22c
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/java/oop/Wheel.java
@@ -0,0 +1,69 @@
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Random;
+
+// The roulette wheel
+public class Wheel {
+    // List the numbers which are black
+    private HashSet black = new HashSet<>(Arrays.asList(new Integer[] { 1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36 }));
+
+    private Random random = new Random();
+    private int pocket = 38;
+
+    public static final int ZERO=0;
+    public static final int BLACK=1;
+    public static final int RED=2;
+
+    // Set up a wheel. You call "spin", and then can check the result.
+    public Wheel() {
+    }
+
+    // Cheat / test mode
+    void setSeed(long l) {
+        random.setSeed(l);
+    }
+
+    // Spin the wheel onto a new random value.
+    public void spin() {
+        // keep spinning for a while
+        do {
+            try {
+                // 1 second delay. Where it stops, nobody knows
+                Thread.sleep(1000);
+            }
+            catch (InterruptedException e) {}
+
+            pocket = random.nextInt(38) + 1;
+        } while (random.nextInt(4) > 0); // keep spinning until it stops
+    }
+
+    // The string representation of the number; 1-36, 0, or 00
+    public String value() {
+        if (pocket == 37) return "0";
+        else if (pocket == 38) return "00";
+        else return String.valueOf(pocket);
+    }
+
+    // True if either 0 or 00 is hit
+    public boolean zero() {
+        return (pocket > 36);
+    }
+
+    // True if anything other than 0 or 00 is hit
+    public boolean isNumber() {
+        return (pocket < 37);
+    }
+
+    // The number rolled
+    public int number() {
+        if (zero()) return 0;
+        else return pocket;
+    }
+
+    // Either ZERO, BLACK, or RED
+    public int color() {
+        if (zero()) return ZERO;
+        else if (black.contains(pocket)) return BLACK;
+        else return RED;
+    }
+}
diff --git a/00_Alternate_Languages/75_Roulette/javascript/README.md b/00_Alternate_Languages/75_Roulette/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/75_Roulette/javascript/roulette.html b/00_Alternate_Languages/75_Roulette/javascript/roulette.html
new file mode 100644
index 00000000..02495892
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/javascript/roulette.html
@@ -0,0 +1,9 @@
+
+
+ROULETTE
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/75_Roulette/javascript/roulette.js b/00_Alternate_Languages/75_Roulette/javascript/roulette.js
new file mode 100644
index 00000000..db153017
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/javascript/roulette.js
@@ -0,0 +1,339 @@
+// ROULETTE
+//
+// 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 ba = [];
+var ca = [];
+var ta = [];
+var xa = [];
+var aa = [];
+
+var numbers = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
+
+// Main program
+async function main()
+{
+    print(tab(32) + "ROULETTE\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    // Roulette
+    // David Joslin
+    print("WELCOME TO THE ROULETTE TABLE\n");
+    print("\n");
+    print("DO YOU WANT INSTRUCTIONS");
+    str = await input();
+    if (str.substr(0, 1) != "N") {
+        print("\n");
+        print("THIS IS THE BETTING LAYOUT\n");
+        print("  (*=RED)\n");
+        print("\n");
+        print(" 1*    2     3*\n");
+        print(" 4     5*    6 \n");
+        print(" 7*    8     9*\n");
+        print("10    11    12*\n");
+        print("---------------\n");
+        print("13    14*   15 \n");
+        print("16*   17    18*\n");
+        print("19*   20    21*\n");
+        print("22    23*   24 \n");
+        print("---------------\n");
+        print("25*   26    27*\n");
+        print("28    29    30*\n");
+        print("31    32*   33 \n");
+        print("34*   35    36*\n");
+        print("---------------\n");
+        print("    00    0    \n");
+        print("\n");
+        print("TYPES OF BETS\n");
+        print("\n");
+        print("THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET\n");
+        print("ON THAT NUMBER.\n");
+        print("THESE PAY OFF 35:1\n");
+        print("\n");
+        print("THE 2:1 BETS ARE:\n");
+        print(" 37) 1-12     40) FIRST COLUMN\n");
+        print(" 38) 13-24    41) SECOND COLUMN\n");
+        print(" 39) 25-36    42) THIRD COLUMN\n");
+        print("\n");
+        print("THE EVEN MONEY BETS ARE:\n");
+        print(" 43) 1-18     46) ODD\n");
+        print(" 44) 19-36    47) RED\n");
+        print(" 45) EVEN     48) BLACK\n");
+        print("\n");
+        print(" 49)0 AND 50)00 PAY OFF 35:1\n");
+        print(" NOTE: 0 AND 00 DO NOT COUNT UNDER ANY\n");
+        print("       BETS EXCEPT THEIR OWN.\n");
+        print("\n");
+        print("WHEN I ASK FOR EACH BET, TYPE THE NUMBER\n");
+        print("AND THE AMOUNT, SEPARATED BY A COMMA.\n");
+        print("FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500\n");
+        print("WHEN I ASK FOR A BET.\n");
+        print("\n");
+        print("THE MINIMUM BET IS $5, THE MAXIMUM IS $500.\n");
+        print("\n");
+    }
+    // Program begins here
+    // Type of bet(number) odds
+    for (i = 1; i <= 100; i++) {
+        ba[i] = 0;
+        ca[i] = 0;
+        ta[i] = 0;
+    }
+    for (i = 1; i <= 38; i++)
+        xa[i] = 0;
+    p = 1000;
+    d = 100000;
+    while (1) {
+        do {
+            print("HOW MANY BETS");
+            y = parseInt(await input());
+        } while (y < 1) ;
+        for (i = 1; i <= 50; i++) {
+            aa[i] = 0;
+        }
+        for (c = 1; c <= y; c++) {
+            while (1) {
+                print("NUMBER " + c + " ");
+                str = await input();
+                x = parseInt(str);
+                z = parseInt(str.substr(str.indexOf(",") + 1));
+                ba[c] = z;
+                ta[c] = x;
+                if (x < 1 || x > 50)
+                    continue;
+                if (z < 1)
+                    continue;
+                if (z < 5 || z > 500)
+                    continue;
+                if (aa[x] != 0) {
+                    print("YOU MADE THAT BET ONCE ALREADY,DUM-DUM\n");
+                    continue;
+                }
+                aa[x] = 1;
+                break;
+            }
+        }
+        print("SPINNING\n");
+        print("\n");
+        print("\n");
+        do {
+            s = Math.floor(Math.random() * 100);
+        } while (s == 0 || s > 38) ;
+        xa[s]++;    // Not used
+        if (s > 37) {
+            print("00\n");
+        } else if (s == 37) {
+            print("0\n");
+        } else {
+            for (i1 = 1; i1 <= 18; i1++) {
+                if (s == numbers[i1 - 1])
+                    break;
+            }
+            if (i1 <= 18)
+                print(s + " RED\n");
+            else
+                print(s + " BLACK\n");
+        }
+        print("\n");
+        for (c = 1; c <= y; c++) {
+            won = 0;
+            switch (ta[c]) {
+                case 37:    // 1-12 (37) 2:1
+                    if (s > 12) {
+                        won = -ba[c];
+                    } else {
+                        won = ba[c] * 2;
+                    }
+                    break;
+                case 38:    // 13-24 (38) 2:1
+                    if (s > 12 && s < 25) {
+                        won = ba[c] * 2;
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+                case 39:    // 25-36 (39) 2:1
+                    if (s > 24 && s < 37) {
+                        won = ba[c] * 2;
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+                case 40:    // First column (40) 2:1
+                    if (s < 37 && s % 3 == 1) {
+                        won = ba[c] * 2;
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+                case 41:    // Second column (41) 2:1
+                    if (s < 37 && s % 3 == 2) {
+                        won = ba[c] * 2;
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+                case 42:    // Third column (42) 2:1
+                    if (s < 37 && s % 3 == 0) {
+                        won = ba[c] * 2;
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+                case 43:    // 1-18 (43) 1:1
+                    if (s < 19) {
+                        won = ba[c];
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+                case 44:    // 19-36 (44) 1:1
+                    if (s > 18 && s < 37) {
+                        won = ba[c];
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+                case 45:    // Even (45) 1:1
+                    if (s < 37 && s % 2 == 0) {
+                        won = ba[c];
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+                case 46:    // Odd (46) 1:1
+                    if (s < 37 && s % 2 != 0) {
+                        won = ba[c];
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+                case 47:    // Red (47) 1:1
+                    for (i = 1; i <= 18; i++) {
+                        if (s == numbers[i - 1])
+                            break;
+                    }
+                    if (i <= 18) {
+                        won = ba[c];
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+                case 48:    // Black (48) 1:1
+                    for (i = 1; i <= 18; i++) {
+                        if (s == numbers[i - 1])
+                            break;
+                    }
+                    if (i <= 18 || s > 36) {
+                        won = -ba[c];
+                    } else {
+                        won = ba[c];
+                    }
+                    break;
+                default:    // 1-36,0,00 (1-36,49,50) 35:1
+                    if (ta[c] < 49 && ta[c] == s
+                        || ta[c] == 49 && s == 37
+                        || ta[c] == 50 && s == 38) {
+                        won = ba[c] * 35;
+                    } else {
+                        won = -ba[c];
+                    }
+                    break;
+            }
+            d -= won;
+            p += won;
+            if (won < 0) {
+                print("YOU LOSE " + -won + " DOLLARS ON BET " + c + "\n");
+            } else {
+                print("YOU WIN " + won + " DOLLARS ON BET " + c + "\n");
+            }
+        }
+        print("\n");
+        print("TOTALS:\tME\tYOU\n");
+        print(" \t" + d + "\t" + p + "\n");
+        if (p <= 0) {
+            print("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!\n");
+            break;
+        } else if (d <= 0) {
+            print("YOU BROKE THE HOUSE!\n");
+            p = 101000;
+        }
+        print("AGAIN");
+        str = await input();
+        if (str.substr(0, 1) != "Y")
+            break;
+    }
+    if (p < 1) {
+        print("THANKS FOR YOUR MONEY.\n");
+        print("I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL\n");
+    } else {
+        print("TO WHOM SHALL I MAKE THE CHECK");
+        str = await input();
+        print("\n");
+        for (i = 1; i <= 72; i++)
+            print("-");
+        print("\n");
+        print(tab(50) + "CHECK NO. " + Math.floor(Math.random() * 100) + "\n");
+        print("\n");
+        print(tab(40) + new Date().toDateString());
+        print("\n");
+        print("\n");
+        print("PAY TO THE ORDER OF-----" + str + "-----$ " + p + "\n");
+        print("\n");
+        print("\n");
+        print(tab(10) + "\tTHE MEMORY BANK OF NEW YORK\n");
+        print("\n");
+        print(tab(40) + "\tTHE COMPUTER\n");
+        print(tab(40) + "----------X-----\n");
+        print("\n");
+        for (i = 1; i <= 72; i++)
+            print("-");
+        print("\n");
+        print("COME BACK SOON!\n");
+    }
+    print("\n");
+}
+
+main();
diff --git a/50_Horserace/pascal/README.md b/00_Alternate_Languages/75_Roulette/pascal/README.md
similarity index 100%
rename from 50_Horserace/pascal/README.md
rename to 00_Alternate_Languages/75_Roulette/pascal/README.md
diff --git a/00_Alternate_Languages/75_Roulette/perl/README.md b/00_Alternate_Languages/75_Roulette/perl/README.md
new file mode 100644
index 00000000..e7dcb811
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/perl/README.md
@@ -0,0 +1,15 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
+
+This conversion consists of three files in `75_Roulette/perl/`:
+
+- `roulette.pl` is the port of the BASIC to Perl;
+- `roulette-test.t` is a Perl test for correctness of display and payout;
+- `make-roulette-test.pl` generates roulette-test.t from roulette.bas.
+
+The ported version of the game numbers the slots from 0 rather than 1, and uses a dispatch table to figure out the payout.
+
+The Perl test loads `roulette.pl` and verifies the Perl slot display and payout logic against the BASIC for all combinations of slots and bets. If any tests fail that fact will be noted at the end of the output.
+
+The test code is generated by reading the BASIC, retaining only the slot display and payout logic (based on line numbers), and wrapping this in code that generates all combinations of bet and spin result. The result is run, and the result is captured and parsed to produce `roulette-test.t`. `make-roulette-test.pl` has some command-line options that may be of interest. `--help` will display the documentation.
diff --git a/00_Alternate_Languages/75_Roulette/perl/make-roulette-test.pl b/00_Alternate_Languages/75_Roulette/perl/make-roulette-test.pl
new file mode 100644
index 00000000..100fd8d7
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/perl/make-roulette-test.pl
@@ -0,0 +1,263 @@
+#!/usr/bin/env perl
+
+use 5.014;	# For s///r
+
+use strict;
+use warnings;
+
+use File::Temp;
+use Getopt::Long 2.33 qw{ :config auto_version };
+use IPC::Cmd qw{ can_run };	# Core as of Perl 5.9.5.
+use Pod::Usage;
+
+our $VERSION = '0.000_01';
+
+my %opt = (
+    program	=> find_basic(),
+    output	=> make_default_output(),
+);
+
+GetOptions( \%opt,
+    qw{ output=s program=s },
+    help => sub { pod2usage( { -verbose => 2 } ) },
+) or pod2usage( { -verbose => 0 } );
+
+die "No default BASIC found; you must specify --program\n"
+    unless defined $opt{program};
+
+my $game_dir = ( File::Spec->splitdir( $0 ) )[0];
+my $basic_file = File::Spec->catfile( $game_dir, 'roulette.bas' );
+open my $basic_handle, '<', $basic_file
+    or die "Unable to open $basic_file: $!\n";
+
+my $munged = File::Temp->new();
+
+print { $munged } <<'EOD';
+1000 Y=50
+1010 DIM B(100),C(100),T(100)
+1090 FOR S=1 TO 38
+1095 PRINT "SPIN ";S
+1100 FOR C=1 TO Y
+1110 B(C)=1
+1120 T(C)=C
+1130 NEXT C
+EOD
+
+transcribe( $basic_file, $basic_handle, $munged, 1860, 2810 );
+transcribe( $basic_file, $basic_handle, $munged, 2950 );
+
+say { $munged } '4000 NEXT S';
+
+$munged->flush();
+
+if ( $opt{output} ne '-' ) {
+    my $dir = ( File::Spec->splitpath( $0 ) )[1];
+    my $fn = File::Spec->rel2abs( $opt{output}, $dir );
+    $fn = File::Spec->abs2rel( $fn );
+    open my $fh, '>', $fn
+	or die "Unable to open $fn: $!\n";
+    warn "Writing $fn\n";
+    select $fh;
+}
+
+print <<'EOD';
+package main;
+
+use 5.010;
+
+use strict;
+use warnings;
+
+use File::Spec;
+use Test::More 0.88;	# Because of done_testing();
+
+EOD
+
+print <<"EOD";
+# NOTE: This file is generated by $0.
+# Any edits made to it will be lost the next time it is regenerated.
+# Caveat coder.
+
+EOD
+
+print <<'EOD';
+my $dir = ( File::Spec->splitpath( $0 ) )[1];
+my $script = File::Spec->catfile( $dir, 'roulette.pl' );
+{
+    # Modern Perls do not have . in @INC, but we need it there to load a
+    # relative path.
+    local @INC = ( File::Spec->curdir(), @INC );
+    require $script;	# Load game as module
+}
+
+EOD
+
+my $spin;
+my $name;
+foreach ( `$opt{program} @{[ $munged->filename() ]}` ) {
+    s/\N{U+1D}/ /smxg;	# Artifact of the BASIC I'm using.
+    s/ \s+ \z //smx;
+    s/ \A \s+ //smx;
+    if ( $_ eq '' ) {
+	# Ignore empty lines.
+    } elsif ( m/ \A SPIN \s* ( [0-9]+ ) /smx ) {
+	$spin = $1 - 1;	# BASIC is 1-based, but Perl is 0-based
+    } elsif ( m/ \A YOU \s+ WIN \s* ( [0-9]+ ) \s*
+	DOLLARS \s+ ON \s+ BET \s* ( [0-9]+ ) /smx ) {
+	say "is payout( $spin, $2 ), $1, 'Spin $spin ($name), bet $2 pays $1';";
+    } elsif ( m/ \A YOU \s+ LOSE \s* ( [0-9]+ ) \s*
+	DOLLARS \s+ ON \s+ BET \s* ( [0-9]+ ) /smx ) {
+	say "is payout( $spin, $2 ), -$1, 'Spin $spin ($name), bet $2 pays -$1';";
+    } elsif ( m/ \A \s* ( [0-9]+ ) (?: \s* ( [[:alpha:]]+ ) )? \z /smx ) {
+	$name = $2 ? sprintf( '%d %s', $1, ucfirst lc $2 ) : $1;
+	say "is format_spin( $spin ), '$name', 'Spin $spin is $name';";
+    } else {
+	die "Unexpected input $_";
+    }
+}
+
+print <<'EOD';
+
+done_testing;
+
+1;
+
+# ex: set textwidth=72 :
+EOD
+
+sub find_basic {
+    # yabasic seems not to work
+    foreach my $prog ( qw{ basic cbmbasic } ) {
+	return $prog if can_run( $prog )
+    }
+    return undef;
+}
+
+sub make_default_output {
+    ( my $rslt = $0 ) =~ s/ [.] pl \z /.t/smx;
+    $rslt =~ s/ .* \b make- //smx;
+    return $rslt;
+}
+
+sub transcribe {
+    my ( $in_file, $in_handle, $out_handle, $first_line, $last_line ) = @_;
+    $last_line //= $first_line;
+
+    while ( <$in_handle> ) {
+	m/ \A \s* ( [0-9]+ )+ \s /smx
+	    or next;
+	$1 < $first_line
+	    and next;
+	say { $out_handle } sprintf '%04d REM BEGIN VERBATIM FROM %s',
+	$first_line - 10, $in_file;
+	print { $out_handle } $_;
+	last;
+    }
+    while ( <$in_handle> ) {
+	m/ \A \s* ( [0-9]+ )+ \s /smx
+	    and $1 > $last_line
+	    and last;
+	print { $out_handle } $_;
+    }
+    say { $out_handle } sprintf '%04d REM END VERBATIM FROM %s',
+	$last_line + 10, $in_file;
+
+    return;
+}
+
+__END__
+
+=head1 TITLE
+
+make-roulette-test.pl - Generate the tests for 75_Roulette/perl/roulette.pl
+
+=head1 SYNOPSIS
+
+ perl 75_Roulette/perl/make-roulette-test.pl
+ perl 75_Roulette/perl/make-roulette-test.pl --program mybasic
+ perl 75_Roulette/perl/make-roulette-test.pl --help
+ perl 75_Roulette/perl/make-roulette-test.pl --version
+
+=head1 OPTIONS
+
+<<< replace boiler plate >>>
+
+=head2 --help
+
+This option displays the documentation for this script. The script then
+exits.
+
+=head2 --output
+
+ --output fubar.t
+
+This option specifies the output file. This needs to be in the same
+directory as F, and defaults to that directory. A single
+dash (C<'-'>) is special-cased to send the output to standard out.
+
+The default is C<--output=test-roulette.t>.
+
+=head2 --program
+
+ --program my_basic
+
+This option specifies the name of your BASIC interpreter. This must be
+the name of an executable file in your PATH (aliases do not work).
+
+The default is the first-found in the list C.
+
+=head2 --version
+
+This option displays the version of this script. The script then exits.
+
+=head1 DETAILS
+
+This Perl script generates F, which tests
+F. The latter is expected to be written as a modulino.
+
+This script assumes that:
+
+=over
+
+=item * it is in the same directory as F;
+
+=item * F is in the first-level subdirectory under the current directory;
+
+=back
+
+The generated test assumes that it is in the same directory as
+F.
+
+This script works by abstracting the internals of F and
+wrapping them in a loop that generates all possible spins, and places
+all possible bets on each spin. The generated BASIC is written to a
+temporary file, and executed by a BASIC interpreter. The output is
+parsed and used to generate the output.
+
+Obviously there is some ad-hocery going on, and this script has only
+been tested under C, which was what I had on hand.
+
+B the abstraction process is driven by BASIC line numbers. Any
+change of these puts the ad-hocery at risk.
+
+=head1 AUTHOR
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set textwidth=72 :
diff --git a/00_Alternate_Languages/75_Roulette/perl/roulette.pl b/00_Alternate_Languages/75_Roulette/perl/roulette.pl
new file mode 100644
index 00000000..7cd5de70
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/perl/roulette.pl
@@ -0,0 +1,319 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'state' and 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use POSIX qw{ strftime };   # Time formatting
+use Term::ReadLine;         # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+# A main() function is not usual in Perl scripts. I have installed one
+# here to make the script into a "modulino." The next line executes
+# main() if and only if caller() returns false. It will do this if we
+# were loaded by another Perl script but not otherwise. This was done so
+# I could test the payout and spin formatting logic.
+main() unless caller;
+
+sub main {
+
+    print <<'EOD';
+                                ROULETTE
+               Creative Computing  Morristown, New Jersey
+
+
+
+
+Welcome to the roulette table.
+
+EOD
+
+    if ( get_yes_no( 'Do you want instructions' ) ) {
+        print <<'EOD';
+
+This is the betting layout
+  (*=red)
+
+ 1*    2     3*
+ 4     5*    6
+ 7*    8     9*
+10    11    12*
+---------------
+13    14*   15
+16*   17    18*
+19*   20    21*
+22    23*   24
+---------------
+25*   26    27*
+28    29    30*
+31    32*   33
+34*   35    36*
+---------------
+    00    0
+
+Types of bets:
+
+The numbers 1 to 36 signify a straight bet
+on that number.
+These pay off 35:1
+
+The 2:1 bets are:
+ 37) 1-12     40) first column
+ 38) 13-24    41) second column
+ 39) 25-36    42) third column
+
+The even money bets are:
+ 43) 1-18     46) odd
+ 44) 19-36    47) red
+ 45) even     48) black
+
+ 49) 0 and 50) 00 pay off 35:1
+ Note: 0 and 00 do not count under any
+       bets except their own.
+
+When I ask for each bet, type the number
+and the amount, separated by a comma.
+For example: to bet $500 on black, type 48,500
+when I ask for a bet.
+
+The minimum bet is $5, the maximum is $500.
+
+EOD
+}
+
+    my $P = 1000;
+    my $D = 100000.;
+
+    while ( 1 ) {   # Iterate indefinitely
+
+        my $Y = get_input( 'How many bets? ',
+            sub { m/ \A [0-9]+ \z /smx && $ARG > 0 && $ARG <= 50 },
+            "Please enter a positive integer no greater than 50\n",
+        );
+        my @B;
+        my @T;
+        foreach my $C ( 1 .. $Y ) {
+            my ( $X, $Z ) = split qr< , >smx, get_input(
+                "Number $C: ",
+                sub { m/ \A ( [0-9]+ ) , ( [0-9]+ ) \z /smx
+                    && $1 > 0 && $1 <= 50 && $2 >= 5 && $2 <= 500 },
+                "Please enter two comma-separated positive numbers\n",
+            );
+            if ( $B[$X] ) {
+                say 'You made that bet once already, dum-dum.';
+                redo;
+            }
+            $B[$X] = $Z;    # BASIC does $B[$C] = $Z
+            $T[$C] = $X;
+        }
+
+        print <<'EOD';
+
+    Spinning ...
+
+EOD
+        my $S = int rand 38;    # Zero-based, versus 1-based in BASIC
+
+        say format_spin( $S );
+
+        say '';
+
+        foreach my $C ( 1 .. $Y ) {
+            my $X = $T[$C];
+            my $payout = payout( $S, $X ) * $B[$X];
+            $D -= $payout;
+            $P += $payout;
+            if ( $payout > 0 ) {
+                say "You win $payout dollars on bet $C";
+            } else {
+                $payout = -$payout;
+                say "You lose $payout dollars on bet $C";
+            }
+        }
+        say "Totals\tMe\tYou";
+        say "\t$D\t$P";
+        say '';
+
+
+        last unless get_yes_no( 'Again' );
+    }
+
+    say '';
+
+    if ( $P > 0 ) {
+        my $B = get_input(
+            'To whom shall I make out the check? ',
+        );
+        my $check_number = 1000 + int rand 9000;
+        my $todays_date = strftime( '%B %d, %Y', localtime );
+        print <<"EOD";
+
+------------------------------------------------------------ Check number $check_number
+
+                                        $todays_date
+
+Pay to the order of ------ $B -----  \$$P
+
+          The Memory Bank of New York
+
+                                        The Computer
+                                        ---------X-----
+
+-------------------------------------------------------------------------------
+
+Come back soon!
+EOD
+    } else {
+        print <<'EOD';
+Thanks for your money.
+I'll use it to buy a solid gold roulette wheel
+EOD
+    }
+}
+
+{
+    # Define the kind of each possible spin. 0 is '0' or '00', 1 is
+    # black, and 2 is red. We assign the values in a BEGIN block because
+    # execution never actually reaches this point in the script.
+    my @kind;
+    BEGIN {
+        @kind = ( 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1,
+            2, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 0,
+            0 );
+    }
+
+    # Convert the spin (0-37) to its name on the wheel.
+    sub format_spin {
+        my ( $number ) = @_;
+        state $format = [
+            sub { '0' x ( $_[0] - 35 ) },
+            sub { sprintf '%s Black', $_[0] + 1 },
+            sub { sprintf '%s Red', $_[0] + 1 },
+        ];
+        return $format->[$kind[$number]]( $number );
+    }
+
+    # Compute the payout given the spin (0-37) and the bet (1-50).
+    sub payout {
+        my ( $number, $bet ) = @_;
+        # We compute the payout on '0' and '00' directly, since under
+        # our rules they are only eligible for the 35-to-1 bet.
+        $kind[$number]
+            or return $number == $bet - 49 + 36 ? 35 : -1;
+        --$bet; # #bet is 1-based coming in
+        # Dispatch table for computing the payout for spins 0-36.
+        state $payout = [
+            ( sub { $_[0] == $_[1] ? 35 : -1 } ) x 36,
+            ( sub { int( $_[0] / 12 ) == $_[1] - 36 ? 2 : -1 } ) x 3,
+            ( sub { $_[0] % 3 == $_[1] - 39 ? 2 : -1 } ) x 3,
+            ( sub { int( $_[0] / 18 ) == $_[1] - 42 ? 1 : -1 } ) x 2,
+            ( sub { $_[0] % 2 == 45 - $_[1] ? 1 : -1 } ) x 2,
+            ( sub { $kind[$_[0]] == 48 - $_[1] ? 1 : -1 } ) x 2,
+            ( sub { -1 } ) x 2, # Bet on '0' or '00' loses
+        ];
+        return $payout->[$bet]->( $number, $bet );
+    }
+}
+
+# Get input from the user. The arguments are:
+# * The prompt
+# * A reference to validation code. This code receives the response in
+#   $ARG and returns true for a valid response.
+# * A warning to print if the response is not valid. This must end in a
+#   return.
+# The first valid response is returned. An end-of-file terminates the
+# script.
+sub get_input {
+    my ( $prompt, $validate, $warning ) = @ARG;
+
+    # If no validator is passed, default to one that always returns
+    # true.
+    $validate ||= sub { 1 };
+
+    # Create the readline object. The 'state' causes the variable to be
+    # initialized only once, no matter how many times this subroutine is
+    # called. The do { ... } is a compound statement used because we
+    # need to tweak the created object before we store it.
+    state $term = do {
+        my $obj = Term::ReadLine->new( 'reverse' );
+        $obj->ornaments( 0 );
+        $obj;
+    };
+
+    while ( 1 ) {   # Iterate indefinitely
+
+        # Read the input into the topic variable, localized to prevent
+        # Spooky Action at a Distance. We exit on undef, which signals
+        # end-of-file.
+        exit unless defined( local $ARG = $term->readline( $prompt ) );
+
+        # Return the input if it is valid.
+        return $ARG if $validate->();
+
+        # Issue the warning, and go around the merry-go-round again.
+        warn $warning;
+    }
+}
+
+# Get a yes-or-no answer. The argument is the prompt, which will have
+# '? [y/n]: ' appended. The donkey work is done by get_input(), which is
+# requested to validate the response as beginning with 'y' or 'n',
+# case-insensitive. The return is a true value for 'y' and a false value
+# for 'n'.
+sub get_yes_no {
+    my ( $prompt ) = @ARG;
+    state $map_answer = {
+        n   => 0,
+        y   => 1,
+    };
+    my $resp = lc get_input(
+        "$prompt? [y/n]: ",
+        sub { m/ \A [yn] /smxi },
+        "Please respond 'y' or 'n'\n",
+    );
+    return $map_answer->{ substr $resp, 0, 1 };
+}
+
+__END__
+
+=head1 TITLE
+
+roulette - Play the game 'Roulette' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ roulette.pl
+
+=head1 DETAILS
+
+This Perl script is a port of roulette, which is the 75th
+entry in Basic Computer Games.
+
+The main internal changes are converting the roulette slot numbering to
+0-based and replacing most of the payout logic with a dispatch table.
+These changes were tested for correctness against the original BASIC.
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :
diff --git a/00_Alternate_Languages/75_Roulette/python/README.md b/00_Alternate_Languages/75_Roulette/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/75_Roulette/python/roulette.py b/00_Alternate_Languages/75_Roulette/python/roulette.py
new file mode 100644
index 00000000..14690de9
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/python/roulette.py
@@ -0,0 +1,221 @@
+import random
+from datetime import date
+
+global RED_NUMBERS
+RED_NUMBERS = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36]
+
+
+def print_instructions():
+    print(
+        """
+THIS IS THE BETTING LAYOUT
+  (*=RED)
+
+ 1*    2     3*
+ 4     5*    6
+ 7*    8     9*
+10    11    12*
+---------------
+13    14*   15
+16*   17    18*
+19*   20    21*
+22    23*   24
+---------------
+25*   26    27*
+28    29    30*
+31    32*   33
+34*   35    36*
+---------------
+    00    0
+
+TYPES OF BETS
+
+THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET
+ON THAT NUMBER.
+THESE PAY OFF 35:1
+
+THE 2:1 BETS ARE:
+37) 1-12     40) FIRST COLUMN
+38) 13-24    41) SECOND COLUMN
+39) 25-36    42) THIRD COLUMN
+
+THE EVEN MONEY BETS ARE:
+43) 1-18     46) ODD
+44) 19-36    47) RED
+45) EVEN     48) BLACK
+
+ 49)0 AND 50)00 PAY OFF 35:1
+NOTE: 0 AND 00 DO NOT COUNT UNDER ANY
+   BETS EXCEPT THEIR OWN.
+
+WHEN I ASK FOR EACH BET, TYPE THE NUMBER
+AND THE AMOUNT, SEPARATED BY A COMMA.
+FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500
+WHEN I ASK FOR A BET.
+
+THE MINIMUM BET IS $5, THE MAXIMUM IS $500.
+
+    """
+    )
+
+
+def query_bets():
+    """Queries the user to input their bets"""
+    betCount = -1
+    while betCount <= 0:
+        try:
+            betCount = int(input("HOW MANY BETS? "))
+        except Exception:
+            ...
+
+    bet_IDs = [-1] * betCount
+    bet_Values = [0] * betCount
+
+    for i in range(betCount):
+        while bet_IDs[i] == -1:
+            try:
+                inString = input("NUMBER " + str(i + 1) + "? ").split(",")
+                id, val = int(inString[0]), int(inString[1])
+
+                # check other bet_IDs
+                for j in range(i):
+                    if id != -1 and bet_IDs[j] == id:
+                        id = -1
+                        print("YOU ALREADY MADE THAT BET ONCE, DUM-DUM")
+                        break
+
+                if id > 0 and id <= 50 and val >= 5 and val <= 500:
+                    bet_IDs[i] = id
+                    bet_Values[i] = val
+            except Exception:
+                ...
+    return bet_IDs, bet_Values
+
+
+def bet_results(bet_IDs, bet_Values, result):
+    """Computes the results, prints them, and returns the total net winnings"""
+    total_winnings = 0
+
+    def get_modifier(id, num):
+        if id == 37 and num <= 12:
+            return 2
+        elif id == 38 and num > 12 and num <= 24:
+            return 2
+        elif id == 39 and num > 24 and num < 37:
+            return 2
+        elif id == 40 and num < 37 and num % 3 == 1:
+            return 2
+        elif id == 41 and num < 37 and num % 3 == 2:
+            return 2
+        elif id == 42 and num < 37 and num % 3 == 0:
+            return 2
+        elif id == 43 and num <= 18:
+            return 1
+        elif id == 44 and num > 18 and num <= 36:
+            return 1
+        elif id == 45 and num % 2 == 0:
+            return 1
+        elif id == 46 and num % 2 == 1:
+            return 1
+        elif id == 47 and num in RED_NUMBERS:
+            return 1
+        elif id == 48 and num not in RED_NUMBERS:
+            return 1
+        elif id < 37 and id == num:
+            return 35
+        else:
+            return -1
+
+    for i in range(len(bet_IDs)):
+        winnings = bet_Values[i] * get_modifier(bet_IDs[i], result)
+        total_winnings += winnings
+
+        if winnings >= 0:
+            print("YOU WIN " + str(winnings) + " DOLLARS ON BET " + str(i + 1))
+        else:
+            print("YOU LOSE " + str(winnings * -1) + " DOLLARS ON BET " + str(i + 1))
+
+    return winnings
+
+
+def print_check(amount):
+    """Prints a check of a given amount"""
+    name = input("TO WHOM SHALL I MAKE THE CHECK? ")
+
+    print("-" * 72)
+    print()
+    print(" " * 40 + "CHECK NO. " + str(random.randint(0, 100)))
+    print(" " * 40 + str(date.today()))
+    print()
+    print("PAY TO THE ORDER OF -----" + name + "----- $" + str(amount))
+    print()
+    print(" " * 40 + "THE MEMORY BANK OF NEW YORK")
+    print(" " * 40 + "THE COMPUTER")
+    print(" " * 40 + "----------X-----")
+    print("-" * 72)
+
+
+def main():
+    player_balance = 1000
+    host_balance = 100000
+
+    print(" " * 32 + "ROULETTE")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+    if stringtobool(input("DO YOU WANT INSTRUCTIONS? ")):
+        print_instructions()
+
+    while True:
+        bet_IDs, bet_Values = query_bets()
+
+        print("SPINNING")
+        print()
+        print()
+
+        val = random.randint(0, 38)
+        if val == 38:
+            print("0")
+        elif val == 37:
+            print("00")
+        elif val in RED_NUMBERS:
+            print(str(val) + " RED")
+        else:
+            print(str(val) + " BLACK")
+
+        print()
+        total_winnings = bet_results(bet_IDs, bet_Values, val)
+        player_balance += total_winnings
+        host_balance -= total_winnings
+
+        print()
+        print("TOTALS:\tME\t\tYOU")
+        print("\t\t" + str(host_balance) + "\t" + str(player_balance))
+
+        if player_balance <= 0:
+            print("OOPS! YOU JUST SPENT YOUR LAST DOLLAR!")
+            break
+        elif host_balance <= 0:
+            print("YOU BROKE THE HOUSE!")
+            player_balance = 101000
+            break
+        if not stringtobool(input("PLAY AGAIN? ")):
+            break
+
+    if player_balance <= 0:
+        print("THANKS FOR YOUR MONEY")
+        print("I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL")
+    else:
+        print_check(player_balance)
+    print("COME BACK SOON!")
+
+
+def stringtobool(string):
+    """Converts a string to a bool"""
+    return string.lower() in ("yes", "y", "true", "t", "yes")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/75_Roulette/roulette.bas b/00_Alternate_Languages/75_Roulette/roulette.bas
new file mode 100644
index 00000000..461231c0
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/roulette.bas
@@ -0,0 +1,239 @@
+10 PRINT TAB(32);"ROULETTE"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+40 PRINT "ENTER THE CURRENT DATE (AS IN 'JANUARY 23, 1979') -";
+50 INPUT D$,E$
+1000 REM-ROULETTE
+1010 REM-DAVID JOSLIN
+1020 PRINT "WELCOME TO THE ROULETTE TABLE"
+1030 PRINT
+1040 PRINT "DO YOU WANT INSTRUCTIONS";
+1050 INPUT Y$
+1060 IF LEFT$(Y$,1)="N" THEN 1550
+1070 PRINT
+1080 PRINT "THIS IS THE BETTING LAYOUT"
+1090 PRINT "  (*=RED)"
+1100 PRINT
+1110 PRINT " 1*    2     3*"
+1120 PRINT " 4     5*    6 "
+1130 PRINT " 7*    8     9*"
+1140 PRINT "10    11    12*"
+1150 PRINT "---------------"
+1160 PRINT "13    14*   15 "
+1170 PRINT "16*   17    18*"
+1180 PRINT "19*   20    21*"
+1190 PRINT "22    23*   24 "
+1200 PRINT "---------------"
+1210 PRINT "25*   26    27*"
+1220 PRINT "28    29    30*"
+1230 PRINT "31    32*   33 "
+1240 PRINT "34*   35    36*"
+1250 PRINT "---------------"
+1260 PRINT "    00    0    "
+1270 PRINT
+1280 PRINT "TYPES OF BETS"
+1290 PRINT
+1300 PRINT "THE NUMBERS 1 TO 36 SIGNIFY A STRAIGHT BET"
+1310 PRINT "ON THAT NUMBER."
+1320 PRINT "THESE PAY OFF 35:1"
+1330 PRINT
+1340 PRINT "THE 2:1 BETS ARE:"
+1350 PRINT " 37) 1-12     40) FIRST COLUMN"
+1360 PRINT " 38) 13-24    41) SECOND COLUMN"
+1370 PRINT " 39) 25-36    42) THIRD COLUMN"
+1380 PRINT
+1390 PRINT "THE EVEN MONEY BETS ARE:"
+1400 PRINT " 43) 1-18     46) ODD"
+1410 PRINT " 44) 19-36    47) RED"
+1420 PRINT " 45) EVEN     48) BLACK"
+1430 PRINT
+1440 PRINT " 49)0 AND 50)00 PAY OFF 35:1"
+1450 PRINT " NOTE: 0 AND 00 DO NOT COUNT UNDER ANY"
+1460 PRINT "       BETS EXCEPT THEIR OWN."
+1470 PRINT
+1480 PRINT "WHEN I ASK FOR EACH BET, TYPE THE NUMBER"
+1490 PRINT "AND THE AMOUNT, SEPARATED BY A COMMA."
+1500 PRINT "FOR EXAMPLE: TO BET $500 ON BLACK, TYPE 48,500"
+1510 PRINT "WHEN I ASK FOR A BET."
+1520 PRINT
+1530 PRINT "THE MINIMUM BET IS $5, THE MAXIMUM IS $500."
+1540 PRINT
+1550 REM-PROGRAM BEGINS HERE
+1560 REM-TYPE OF BET(NUMBER) ODDS
+1570 REM  DON'T NEED TO DIMENSION STRINGS
+1580 DIM B(100),C(100),T(100),X(38)
+1590 DIM A(50)
+1600 FOR I=1 TO 38: X(I)=0: NEXT I: REM  MAT X=ZER
+1610 P=1000
+1620 D=100000.
+1630 PRINT "HOW MANY BETS";
+1640 INPUT Y
+1650 IF Y<1 OR Y<>INT(Y) THEN 1630
+1660 FOR I=1 TO 50: A(I)=0: NEXT I: REM  MAT A=ZER
+1670 FOR C=1 TO Y
+1680 PRINT "NUMBER";C;
+1690 INPUT X,Z
+1700 B(C)=Z
+1710 T(C)=X
+1720 IF X<1 OR X>50 OR X<>INT(X) THEN 1680
+1730 IF Z<1 OR Z<>INT(Z) THEN 1680
+1740 IF Z<5 OR Z>500 THEN 1680
+1750 IF A(X)=0 THEN 1780
+1760 PRINT "YOU MADE THAT BET ONCE ALREADY,DUM-DUM"
+1770 GOTO 1680
+1780 A(X)=1
+1790 NEXT C
+1800 PRINT "SPINNING"
+1810 PRINT
+1820 PRINT
+1830 S=INT(RND(1)*100)
+1840 IF S=0 OR S>38 THEN 1830
+1850 X(S)=X(S)+1
+1860 IF S<37 THEN 1920
+1870 IF S=37 THEN 1900
+1880 PRINT "00"
+1890 GOTO 2020
+1900 PRINT "0"
+1910 GOTO 2020
+1920 RESTORE
+1930 FOR I1=1 TO 18
+1940 READ R
+1950 IF R=S THEN 2000
+1960 NEXT I1
+1970 A$="BLACK"
+1980 PRINT S;A$
+1990 GOTO 2020
+2000 A$="RED"
+2010 GOTO 1980
+2020 PRINT
+2030 FOR C=1 TO Y
+2040 IF T(C)<37 THEN 2710
+2050 ON T(C)-36 GOTO 2090,2190,2220,2250,2300,2350,2400,2470,2500
+2060 ON T(C)-45 GOTO 2530,2560,2630
+2070 GOTO 2710
+2080 STOP
+2090 REM  1-12(37) 2:1
+2100 IF S <= 12 THEN 2150
+2110 PRINT "YOU LOSE";B(C);"DOLLARS ON BET";C
+2120 D=D+B(C)
+2130 P=P-B(C)
+2140 GOTO 2180
+2150 PRINT "YOU WIN";B(C)*2;"DOLLARS ON BET"C
+2160 D=D-B(C)*2
+2170 P=P+B(C)*2
+2180 GOTO 2810
+2190 REM  13-24(38) 2:1
+2200 IF S>12 AND S<25 THEN 2150
+2210 GOTO 2110
+2220 REM  25-36(39) 2:1
+2230 IF S>24 AND S<37 THEN 2150
+2240 GOTO 2110
+2250 REM  FIRST COLUMN(40) 2:1
+2260 FOR I=1 TO 34 STEP 3
+2270 IF S=I THEN 2150
+2280 NEXT I
+2290 GOTO 2110
+2300 REM  SECOND COLUMN(41) 2:1
+2310 FOR I=2 TO 35 STEP 3
+2320 IF S=I THEN 2150
+2330 NEXT I
+2340 GOTO 2110
+2350 REM  THIRD COLUMN(42) 2:1
+2360 FOR I=3 TO 36 STEP 3
+2370 IF S=I THEN 2150
+2380 NEXT I
+2390 GOTO 2110
+2400 REM  1-18(43) 1:1
+2410 IF S<19 THEN 2430
+2420 GOTO 2110
+2430 PRINT "YOU WIN";B(C);"DOLLARS ON BET";C
+2440 D=D-B(C)
+2450 P=P+B(C)
+2460 GOTO 2810
+2470 REM  19-36(44) 1:1
+2480 IF S<37 AND S>18 THEN 2430
+2490 GOTO 2110
+2500 REM  EVEN(45) 1:1
+2510 IF S/2=INT(S/2) AND S<37 THEN 2430
+2520 GOTO 2110
+2530 REM  ODD(46) 1:1
+2540 IF S/2<>INT(S/2) AND S<37 THEN 2430
+2550 GOTO 2110
+2560 REM  RED(47) 1:1
+2570 RESTORE
+2580 FOR I=1 TO 18
+2590 READ R
+2600 IF S=R THEN 2430
+2610 NEXT I
+2620 GOTO 2110
+2630 REM  BLACK(48) 1:1
+2640 RESTORE
+2650 FOR I=1 TO 18
+2660 READ R
+2670 IF S=R THEN 2110
+2680 NEXT I
+2690 IF S>36 THEN 2110
+2700 GOTO 2430
+2710 REM--1TO36,0,00(1-36,49,50)35:1
+2720 IF T(C)<49 THEN 2760
+2730 IF T(C)=49 AND S=37 THEN 2780
+2740 IF T(C)=50 AND S=38 THEN 2780
+2750 GOTO 2110
+2760 IF T(C)=S THEN 2780
+2770 GOTO 2110
+2780 PRINT "YOU WIN";B(C)*35;"DOLLARS ON BET";C
+2790 D=D-B(C)*35
+2800 P=P+B(C)*35
+2810 NEXT C
+2820 PRINT
+2830 PRINT "TOTALS:","ME","YOU"
+2840 PRINT " ",D,P
+2850 IF P>0 THEN 2880
+2860 PRINT "OOPS! YOU JUST SPENT YOUR LAST DOLLAR!"
+2870 GOTO 3190
+2880 IF D>0 THEN 2920
+2890 PRINT "YOU BROKE THE HOUSE!"
+2900 P=101000.
+2910 GOTO 2960
+2920 PRINT "AGAIN";
+2930 INPUT Y$
+2940 IF LEFT$(Y$,1)="Y" THEN 1630
+2950 DATA 1,3,5,7,9,12,14,16,18,19,21,23,25,27,30,32,34,36
+2960 IF P<1 THEN 3190
+2970 PRINT "TO WHOM SHALL I MAKE THE CHECK";
+2980 INPUT B$
+2990 PRINT
+3000 FOR I=1 TO 72: PRINT "-";: NEXT I: REM PRINT 72 DASHES
+3010 PRINT TAB(50);"CHECK NO. ";INT(RND(1)*100)
+3020 PRINT
+3030 GOSUB 3230
+3040 PRINT TAB(40);M$
+3050 PRINT
+3060 PRINT
+3070 PRINT "PAY TO THE ORDER OF-----";B$;"-----$ ";
+3080 PRINT P
+3090 PRINT
+3100 PRINT
+3110 PRINT TAB(10),"THE MEMORY BANK OF NEW YORK"
+3120 PRINT
+3130 PRINT TAB(40),"THE COMPUTER"
+3140 PRINT TAB(40)"----------X-----"
+3150 PRINT
+3160 FOR I=1 TO 62: PRINT "-";: NEXT I
+3170 PRINT "COME BACK SOON!"
+3180 GOTO 3210
+3190 PRINT "THANKS FOR YOUR MONEY."
+3200 PRINT "I'LL USE IT TO BUY A SOLID GOLD ROULETTE WHEEL"
+3210 PRINT
+3220 GOTO 3420
+3230 REM
+3240 REM     THIS ROUTINE RETURNS THE CURRENT DATE IN M$
+3250 REM     IF YOU HAVE SYSTEM FUNCTIONS TO HANDLE THIS
+3260 REM     THEY CAN BE USED HERE.  HOWEVER IN THIS
+3270 REM     PROGRAM, WE JUST INPUT THE DATE AT THE START
+3280 REM     THE GAME
+3290 REM
+3300 REM     THE DATE IS RETURNED IN VARIABLE M$
+3310 M$=D$+", "+E$
+3320 RETURN
+3420 END
diff --git a/00_Alternate_Languages/75_Roulette/ruby/README.md b/00_Alternate_Languages/75_Roulette/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/75_Roulette/vbnet/README.md b/00_Alternate_Languages/75_Roulette/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/75_Roulette/vbnet/Roulette.sln b/00_Alternate_Languages/75_Roulette/vbnet/Roulette.sln
new file mode 100644
index 00000000..a9db1b6e
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/vbnet/Roulette.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Roulette", "Roulette.vbproj", "{B2D2B22C-D332-4153-8ACF-E8136283FBC7}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B2D2B22C-D332-4153-8ACF-E8136283FBC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B2D2B22C-D332-4153-8ACF-E8136283FBC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B2D2B22C-D332-4153-8ACF-E8136283FBC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B2D2B22C-D332-4153-8ACF-E8136283FBC7}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/75_Roulette/vbnet/Roulette.vbproj b/00_Alternate_Languages/75_Roulette/vbnet/Roulette.vbproj
new file mode 100644
index 00000000..d5c17f88
--- /dev/null
+++ b/00_Alternate_Languages/75_Roulette/vbnet/Roulette.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Roulette
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/76_Russian_Roulette/README.md b/00_Alternate_Languages/76_Russian_Roulette/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/76_Russian_Roulette/csharp/Program.cs b/00_Alternate_Languages/76_Russian_Roulette/csharp/Program.cs
new file mode 100644
index 00000000..43a8d4bc
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/csharp/Program.cs
@@ -0,0 +1,106 @@
+using System;
+
+namespace RussianRoulette
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            PrintTitle();
+
+            var includeRevolver = true;
+            while (true)
+            {
+                PrintInstructions(includeRevolver);
+                switch (PlayGame())
+                {
+                    case GameResult.Win:
+                        includeRevolver = true;
+                        break;
+                    case GameResult.Chicken:
+                    case GameResult.Dead:
+                        includeRevolver = false;
+                        break;
+                }
+            }
+        }
+
+        private static void PrintTitle()
+        {
+            Console.WriteLine("           Russian Roulette");
+            Console.WriteLine("Creative Computing  Morristown, New Jersey");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("This is a game of >>>>>>>>>>Russian Roulette.");
+        }
+
+        private static void PrintInstructions(bool includeRevolver)
+        {
+            Console.WriteLine();
+            if (includeRevolver)
+            {
+                Console.WriteLine("Here is a revolver.");
+            }
+            else
+            {
+                Console.WriteLine();
+                Console.WriteLine();
+                Console.WriteLine("...Next Victim...");
+            }
+            Console.WriteLine("Type '1' to spin chamber and pull trigger.");
+            Console.WriteLine("Type '2' to give up.");
+        }
+
+        private static GameResult PlayGame()
+        {
+            var rnd = new Random();
+            var round = 0;
+            while (true)
+            {
+                round++;
+                Console.Write("Go: ");
+                var input = Console.ReadKey().KeyChar;
+                Console.WriteLine();
+                if (input != '2')
+                {
+                    // Random.Next will retun a value that is the same or greater than the minimum and
+                    // less than the maximum.
+                    // A revolver has 6 rounds.
+                    if (rnd.Next(1, 7) == 6)
+                    {
+                        Console.WriteLine("     Bang!!!!!   You're dead!");
+                        Console.WriteLine("Condolences will be sent to your relatives.");
+                        return GameResult.Dead;
+                    }
+                    else
+                    {
+                        if (round > 10)
+                        {
+                            Console.WriteLine("You win!!!!!");
+                            Console.WriteLine("Let someone else blow their brains out.");
+                            return GameResult.Win;
+                        }
+                        else
+                        {
+                            Console.WriteLine("- CLICK -");
+                            Console.WriteLine();
+                        }
+                    }
+                }
+                else
+                {
+                    Console.WriteLine("     CHICKEN!!!!!");
+                    return GameResult.Chicken;
+                }
+            }
+        }
+
+        private enum GameResult
+        {
+            Win,
+            Chicken,
+            Dead
+        }
+    }
+}
diff --git a/00_Alternate_Languages/76_Russian_Roulette/csharp/README.md b/00_Alternate_Languages/76_Russian_Roulette/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/76_Russian_Roulette/csharp/RussianRoulette.csproj b/00_Alternate_Languages/76_Russian_Roulette/csharp/RussianRoulette.csproj
new file mode 100644
index 00000000..20827042
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/csharp/RussianRoulette.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+
diff --git a/00_Alternate_Languages/76_Russian_Roulette/csharp/RussianRoulette.sln b/00_Alternate_Languages/76_Russian_Roulette/csharp/RussianRoulette.sln
new file mode 100644
index 00000000..1e4b621e
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/csharp/RussianRoulette.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31019.35
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RussianRoulette", "RussianRoulette.csproj", "{9F052B4A-FA33-4BBE-9D9D-3CF8152569F1}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9F052B4A-FA33-4BBE-9D9D-3CF8152569F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9F052B4A-FA33-4BBE-9D9D-3CF8152569F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9F052B4A-FA33-4BBE-9D9D-3CF8152569F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9F052B4A-FA33-4BBE-9D9D-3CF8152569F1}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {97F5B1B0-A80A-4C1F-9F76-8D68B4A49E82}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/76_Russian_Roulette/java/README.md b/00_Alternate_Languages/76_Russian_Roulette/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/76_Russian_Roulette/java/src/RussianRoulette.java b/00_Alternate_Languages/76_Russian_Roulette/java/src/RussianRoulette.java
new file mode 100644
index 00000000..dd799a06
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/java/src/RussianRoulette.java
@@ -0,0 +1,143 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Russian Roulette Paper
+ * 

+ * Based on the Basic game of Russian Roulette here + * https://github.com/coding-horror/basic-computer-games/blob/main/76%20Russian%20Roulette/russianroulette.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. + */ + +public class RussianRoulette { + + public static final int BULLETS_IN_CHAMBER = 10; + public static final double CHANCE_OF_GETTING_SHOT = .833333d; + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + INIT, + GAME_START, + FIRE_BULLET, + NEXT_VICTIM + } + + // Current game state + private GAME_STATE gameState; + + int bulletsShot; + + public RussianRoulette() { + kbScanner = new Scanner(System.in); + gameState = GAME_STATE.INIT; + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + case INIT: + intro(); + gameState = GAME_STATE.GAME_START; + + break; + + case GAME_START: + bulletsShot = 0; + System.out.println(); + System.out.println("HERE IS A REVOLVER."); + System.out.println("TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER."); + System.out.println("TYPE '2' TO GIVE UP."); + gameState = GAME_STATE.FIRE_BULLET; + break; + + case FIRE_BULLET: + + int choice = displayTextAndGetNumber("GO "); + + // Anything but selecting give up = have a shot + if (choice != 2) { + bulletsShot++; + if (Math.random() > CHANCE_OF_GETTING_SHOT) { + System.out.println(" BANG!!!!! YOU'RE DEAD!"); + System.out.println("CONDOLENCES WILL BE SENT TO YOUR RELATIVES."); + gameState = GAME_STATE.NEXT_VICTIM; + } else if (bulletsShot > BULLETS_IN_CHAMBER) { + System.out.println("YOU WIN!!!!!"); + System.out.println("LET SOMEONE ELSE BLOW HIS BRAINS OUT."); + gameState = GAME_STATE.GAME_START; + } else { + // Phew player survived this round + System.out.println("- CLICK -"); + } + } else { + // Player gave up + System.out.println(" CHICKEN!!!!!"); + gameState = GAME_STATE.NEXT_VICTIM; + + } + break; + + case NEXT_VICTIM: + System.out.println("...NEXT VICTIM..."); + gameState = GAME_STATE.GAME_START; + } + // Infinite loop - based on original basic version + } while (true); + } + + private void intro() { + System.out.println(addSpaces(28) + "RUSSIAN ROULETTE"); + System.out.println(addSpaces(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE."); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to an Integer + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private int displayTextAndGetNumber(String text) { + return Integer.parseInt(displayTextAndGetInput(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.nextLine(); + } + + /** + * Return a string of x spaces + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String addSpaces(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + + public static void main(String[] args) { + + RussianRoulette russianRoulette = new RussianRoulette(); + russianRoulette.play(); + } +} diff --git a/00_Alternate_Languages/76_Russian_Roulette/javascript/README.md b/00_Alternate_Languages/76_Russian_Roulette/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/76_Russian_Roulette/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/76_Russian_Roulette/javascript/russianroulette.html b/00_Alternate_Languages/76_Russian_Roulette/javascript/russianroulette.html new file mode 100644 index 00000000..782fa23e --- /dev/null +++ b/00_Alternate_Languages/76_Russian_Roulette/javascript/russianroulette.html @@ -0,0 +1,9 @@ + + +RUSSIAN ROULETTE + + +


+
+
+
diff --git a/00_Alternate_Languages/76_Russian_Roulette/javascript/russianroulette.js b/00_Alternate_Languages/76_Russian_Roulette/javascript/russianroulette.js
new file mode 100644
index 00000000..cb50c6ca
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/javascript/russianroulette.js
@@ -0,0 +1,93 @@
+// RUSSIAN ROULETTE
+//
+// 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(28) + "RUSSIAN ROULETTE\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\n");
+    restart = true;
+    while (1) {
+        if (restart) {
+            restart = false;
+            print("\n");
+            print("HERE IS A REVOLVER.\n");
+        }
+        print("TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER.\n");
+        print("TYPE '2' TO GIVE UP.\n");
+        print("GO");
+        n = 0;
+        while (1) {
+            i = parseInt(await input());
+            if (i == 2) {
+                print("     CHICKEN!!!!!\n");
+                break;
+            }
+            n++;
+            if (Math.random() > 0.833333) {
+                print("     BANG!!!!!   YOU'RE DEAD!\n");
+                print("CONDOLENCES WILL BE SENT TO YOUR RELATIVES.\n");
+                break;
+            }
+            if (n > 10) {
+                print("YOU WIN!!!!!\n");
+                print("LET SOMEONE ELSE BLOW HIS BRAINS OUT.\n");
+                restart = true;
+                break;
+            }
+            print("- CLICK -\n");
+            print("\n");
+        }
+        print("\n");
+        print("\n");
+        print("\n");
+        print("...NEXT VICTIM...\n");
+    }
+}
+
+main();
diff --git a/51_Hurkle/pascal/README.md b/00_Alternate_Languages/76_Russian_Roulette/pascal/README.md
similarity index 100%
rename from 51_Hurkle/pascal/README.md
rename to 00_Alternate_Languages/76_Russian_Roulette/pascal/README.md
diff --git a/00_Alternate_Languages/76_Russian_Roulette/perl/README.md b/00_Alternate_Languages/76_Russian_Roulette/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/76_Russian_Roulette/perl/russianroulette.pl b/00_Alternate_Languages/76_Russian_Roulette/perl/russianroulette.pl
new file mode 100644
index 00000000..dbb5ac98
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/perl/russianroulette.pl
@@ -0,0 +1,37 @@
+#!/usr/bin/perl
+#use strict;
+# Automatic converted by bas2perl.pl
+
+print ' 'x28 . "RUSSIAN ROULETTE\n";
+print ' 'x15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n"; print "\n"; print "\n";
+print "THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.\n";
+Line10:
+print "\n"; print "HERE IS A REVOLVER.\n";
+Line20:
+print "TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER.\n";
+print "TYPE '2' TO GIVE UP.\n";
+print "GO";
+$N=0;
+Line30:
+print "? "; chomp($I = );
+if ($I ne 2) { goto Line35; }
+print " CHICKEN!!!!!\n";
+goto Line72;
+Line35:
+$N=$N+1;
+if (rand(1)>.833333) { goto Line70; }
+if ($N>10) { goto Line80; }
+print "- CLICK -\n";
+print "\n"; goto Line30;
+Line70:
+print " BANG!!!!! YOU'RE DEAD!\n";
+print "CONDOLENCES WILL BE SENT TO YOUR RELATIVES.\n";
+Line72:
+print "\n"; print "\n"; print "\n";
+print "...NEXT VICTIM...\n"; goto Line20;
+Line80:
+print "YOU WIN!!!!!\n";
+print "LET SOMEONE ELSE BLOW HIS BRAINS OUT.\n";
+goto Line10;
+exit;
diff --git a/00_Alternate_Languages/76_Russian_Roulette/python/README.md b/00_Alternate_Languages/76_Russian_Roulette/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/76_Russian_Roulette/python/russianroulette.py b/00_Alternate_Languages/76_Russian_Roulette/python/russianroulette.py
new file mode 100644
index 00000000..2ace69cd
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/python/russianroulette.py
@@ -0,0 +1,92 @@
+########################################################
+#
+# Russian Roulette
+#
+# From Basic Computer Games (1978)
+#
+#    In this game, you are given by the computer a
+#   revolver loaded with one bullet and five empty
+#   chambers. You spin the chamber and pull the trigger
+#   by inputting a "1", or, if you want to quit, input
+#   a "2". You win if you play ten times and are still
+#   alive.
+#    Tom Adametx wrote this program while a student at
+#   Curtis Jr. High School in Sudbury, Massachusetts.
+#
+########################################################
+
+
+from random import random
+
+NUMBER_OF_ROUNDS = 9
+
+
+def initial_message():
+    print(" " * 28 + "Russian Roulette")
+    print(" " * 15 + "Creative Computing  Morristown, New Jersey\n\n\n")
+    print("This is a game of >>>>>>>>>>Russian Roulette.\n")
+    print("Here is a Revolver.")
+
+
+def parse_input():
+    correct_input = False
+    while not correct_input:
+        try:
+            i = int(input("? "))
+            correct_input = True
+        except ValueError:
+            print("Number expected...")
+    return i
+
+
+initial_message()
+while True:
+    dead = False
+    n = 0
+    print("Type '1' to Spin chamber and pull trigger")
+    print("Type '2' to Give up")
+    print("Go")
+    while not dead:
+        i = parse_input()
+
+        if i == 2:
+            break
+
+        if random() > 0.8333333333333334:
+            dead = True
+        else:
+            print("- CLICK -\n")
+            n += 1
+
+        if n > NUMBER_OF_ROUNDS:
+            break
+    if dead:
+        print("BANG!!!!!   You're Dead!")
+        print("Condolences will be sent to your relatives.\n\n\n")
+        print("...Next victim...")
+    else:
+        if n > NUMBER_OF_ROUNDS:
+            print("You win!!!!!")
+            print("Let someone else blow his brain out.\n")
+        else:
+            print("     Chicken!!!!!\n\n\n")
+            print("...Next victim....")
+
+
+########################################################
+# Porting Notes
+#
+#    Altough the description says that accepts "1" or "2",
+#   the original game accepts any number as input, and
+#   if it's different of "2" the program considers
+#   as if the user had passed "1". That feature was
+#   kept in this port.
+#    Also, in the original game you must "pull the trigger"
+#   11 times instead of 10 in orden to win,
+#   given that N=0 at the beginning and the condition to
+#   win is "IF N > 10 THEN  80". That was fixed in this
+#   port, asking the user to pull the trigger only ten
+#   times, tough the number of round can be set changing
+#   the constant NUMBER_OF_ROUNDS.
+#
+########################################################
diff --git a/00_Alternate_Languages/76_Russian_Roulette/ruby/README.md b/00_Alternate_Languages/76_Russian_Roulette/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/76_Russian_Roulette/ruby/russianroulette.rb b/00_Alternate_Languages/76_Russian_Roulette/ruby/russianroulette.rb
new file mode 100644
index 00000000..abb3ad35
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/ruby/russianroulette.rb
@@ -0,0 +1,73 @@
+puts <<~INSTRUCTIONS
+                            RUSSIAN ROULETTE
+               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+
+
+
+THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE.
+
+HERE IS A REVOLVER.
+
+INSTRUCTIONS
+
+NUMBER_OF_ROUNDS = 9
+
+def parse_input
+    correct_input = false
+
+    while not correct_input
+        puts " ?"
+        inp = gets.chomp
+        if inp == "1" or inp == "2"
+            correct_input = true
+        end
+    end
+
+    inp
+end
+
+while true
+
+    dead = false
+    n = 0
+
+    puts "TYPE \'1\' TO SPIN CHAMBER AND PULL TRIGGER"
+    puts "TYPE \'2\' TO GIVE UP"
+    puts "GO"
+
+    while not dead
+
+        inp = parse_input
+
+        if inp == "2"
+            break
+        end
+
+        if rand > 0.8333333333333334
+            dead = true
+        else
+            puts "- CLICK -"
+            n += 1
+        end
+
+        if n > NUMBER_OF_ROUNDS
+            break
+        end
+
+    end
+
+    if dead
+        puts "BANG!!!!!   You're Dead!"
+        puts "Condolences will be sent to your relatives.\n\n\n"
+        puts "...Next victim..."
+    else
+        if n > NUMBER_OF_ROUNDS
+            puts "You win!!!!!"
+            puts "Let someone else blow his brain out.\n"
+        else
+            puts "     Chicken!!!!!\n\n\n"
+            puts "...Next victim...."
+        end
+    end
+
+end
diff --git a/00_Alternate_Languages/76_Russian_Roulette/russianroulette.bas b/00_Alternate_Languages/76_Russian_Roulette/russianroulette.bas
new file mode 100644
index 00000000..437e53c1
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/russianroulette.bas
@@ -0,0 +1,26 @@
+1 PRINT TAB(28);"RUSSIAN ROULETTE"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+5 PRINT "THIS IS A GAME OF >>>>>>>>>>RUSSIAN ROULETTE."
+10 PRINT:PRINT "HERE IS A REVOLVER."
+20 PRINT "TYPE '1' TO SPIN CHAMBER AND PULL TRIGGER."
+22 PRINT "TYPE '2' TO GIVE UP."
+23 PRINT "GO";
+25 N=0
+30 INPUT I
+31 IF I<>2 THEN 35
+32 PRINT "     CHICKEN!!!!!"
+33 GOTO 72
+35 N=N+1
+40 IF RND(1)>.833333 THEN 70
+45 IF N>10 THEN 80
+50 PRINT "- CLICK -"
+60 PRINT: GOTO 30
+70 PRINT "     BANG!!!!!   YOU'RE DEAD!"
+71 PRINT "CONDOLENCES WILL BE SENT TO YOUR RELATIVES."
+72 PRINT:PRINT:PRINT
+75 PRINT "...NEXT VICTIM...":GOTO 20
+80 PRINT "YOU WIN!!!!!"
+85 PRINT "LET SOMEONE ELSE BLOW HIS BRAINS OUT."
+90 GOTO 10
+99 END
diff --git a/00_Alternate_Languages/76_Russian_Roulette/vbnet/README.md b/00_Alternate_Languages/76_Russian_Roulette/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/76_Russian_Roulette/vbnet/RussianRoulette.sln b/00_Alternate_Languages/76_Russian_Roulette/vbnet/RussianRoulette.sln
new file mode 100644
index 00000000..8a87ebbb
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/vbnet/RussianRoulette.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "RussianRoulette", "RussianRoulette.vbproj", "{19A2F0DB-9F77-4E3A-9346-4FDDAF0A457F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{19A2F0DB-9F77-4E3A-9346-4FDDAF0A457F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{19A2F0DB-9F77-4E3A-9346-4FDDAF0A457F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{19A2F0DB-9F77-4E3A-9346-4FDDAF0A457F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{19A2F0DB-9F77-4E3A-9346-4FDDAF0A457F}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/76_Russian_Roulette/vbnet/RussianRoulette.vbproj b/00_Alternate_Languages/76_Russian_Roulette/vbnet/RussianRoulette.vbproj
new file mode 100644
index 00000000..dbfebdae
--- /dev/null
+++ b/00_Alternate_Languages/76_Russian_Roulette/vbnet/RussianRoulette.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    RussianRoulette
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/77_Salvo/README.md b/00_Alternate_Languages/77_Salvo/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/77_Salvo/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/77_Salvo/csharp/README.md b/00_Alternate_Languages/77_Salvo/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/77_Salvo/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/77_Salvo/csharp/Salvo.csproj b/00_Alternate_Languages/77_Salvo/csharp/Salvo.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/77_Salvo/csharp/Salvo.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/77_Salvo/csharp/Salvo.sln b/00_Alternate_Languages/77_Salvo/csharp/Salvo.sln
new file mode 100644
index 00000000..290237a3
--- /dev/null
+++ b/00_Alternate_Languages/77_Salvo/csharp/Salvo.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Salvo", "Salvo.csproj", "{F3AFBC83-22A7-4837-9DA3-F3EE854DD8CA}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F3AFBC83-22A7-4837-9DA3-F3EE854DD8CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F3AFBC83-22A7-4837-9DA3-F3EE854DD8CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F3AFBC83-22A7-4837-9DA3-F3EE854DD8CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F3AFBC83-22A7-4837-9DA3-F3EE854DD8CA}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/77_Salvo/java/README.md b/00_Alternate_Languages/77_Salvo/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/77_Salvo/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/77_Salvo/javascript/README.md b/00_Alternate_Languages/77_Salvo/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/77_Salvo/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/77_Salvo/javascript/salvo.html b/00_Alternate_Languages/77_Salvo/javascript/salvo.html
new file mode 100644
index 00000000..25752f0f
--- /dev/null
+++ b/00_Alternate_Languages/77_Salvo/javascript/salvo.html
@@ -0,0 +1,9 @@
+
+
+SALVO
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/77_Salvo/javascript/salvo.js b/00_Alternate_Languages/77_Salvo/javascript/salvo.js
new file mode 100644
index 00000000..7fb9d6df
--- /dev/null
+++ b/00_Alternate_Languages/77_Salvo/javascript/salvo.js
@@ -0,0 +1,504 @@
+// SALVO
+//
+// 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 aa = [];
+var ba = [];
+var ca = [];
+var da = [];
+var ea = [];
+var fa = [];
+var ga = [];
+var ha = [];
+var ka = [];
+var w;
+var r3;
+var x;
+var y;
+var v;
+var v2;
+
+function sgn(k)
+{
+    if (k < 0)
+        return -1;
+    if (k > 0)
+        return 1;
+    return 0;
+}
+
+function fna(k)
+{
+    return (5 - k) * 3 - 2 * Math.floor(k / 4) + sgn(k - 1) - 1;
+}
+
+function fnb(k)
+{
+    return k + Math.floor(k / 4) - sgn(k - 1);
+}
+
+function generate_random()
+{
+    x = Math.floor(Math.random() * 10 + 1);
+    y = Math.floor(Math.random() * 10 + 1);
+    v = Math.floor(3 * Math.random() - 1);
+    v2 = Math.floor(3 * Math.random() - 1);
+}
+
+// Main program
+async function main()
+{
+    print(tab(33) + "SALVO\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    z8 = 0;
+    for (w = 1; w <= 12; w++) {
+        ea[w] = -1;
+        ha[w] = -1;
+    }
+    for (x = 1; x <= 10; x++) {
+        ba[x] = [];
+        ka[x] = [];
+        for (y = 1; y <= 10; y++) {
+            ba[x][y] = 0;
+            ka[x][y] = 0;
+        }
+    }
+    for (x = 1; x <= 12; x++) {
+        fa[x] = 0;
+        ga[x] = 0;
+    }
+    for (x = 1; x <= 10; x++) {
+        aa[x] = [];
+        for (y = 1; y <= 10; y++) {
+            aa[x][y] = 0;
+        }
+    }
+    u6 = 0;
+    for (k = 4; k >= 1; k--) {
+        do {
+            generate_random();
+        } while (v + v2 + v * v2 == 0 || y + v * fnb(k) > 10 || y + v * fnb(k) < 1 || x + v2 * fnb(k) > 10 || x + v2 * fnb(k) < 1) ;
+        u6++;
+        if (u6 > 25) {
+            for (x = 1; x <= 10; x++) {
+                aa[x] = [];
+                for (y = 1; y <= 10; y++) {
+                    aa[x][y] = 0;
+                }
+            }
+            u6 = 0;
+            k = 5;
+            continue;
+        }
+        for (z = 0; z <= fnb(k); z++) {
+            fa[z + fna(k)] = x + v2 * z;
+            ga[z + fna(k)] = y + v * z;
+        }
+        u8 = fna(k);
+        if (u8 <= u8 + fnb(k)) {
+            retry = false;
+            for (z2 = u8; z2 <= u8 + fnb(k); z2++) {
+                if (u8 >= 2) {
+                    for (z3 = 1; z3 < u8 - 1; z3++) {
+                        if (Math.sqrt(Math.pow((fa[z3] - fa[z2]), 2)) + Math.pow((ga[z3] - ga[z2]), 2) < 3.59) {
+                            retry = true;
+                            break;
+                        }
+                    }
+                    if (retry)
+                        break;
+                }
+            }
+            if (retry) {
+                k++;
+                continue;
+            }
+        }
+        for (z = 0; z <= fnb(k); z++) {
+            if (k - 1 < 0)
+                sk = -1;
+            else if (k - 1 > 0)
+                sk = 1;
+            else
+                sk = 0;
+            aa[fa[z + u8]][ga[z + u8]] = 0.5 + sk * (k - 1.5);
+        }
+        u6 = 0;
+    }
+    print("ENTER COORDINATES FOR...\n");
+    print("BATTLESHIP\n");
+    for (x = 1; x <= 5; x++) {
+        str = await input();
+        y = parseInt(str);
+        z = parseInt(str.substr(str.indexOf(",") + 1));
+        ba[y][z] = 3;
+    }
+    print("CRUISER\n");
+    for (x = 1; x <= 3; x++) {
+        str = await input();
+        y = parseInt(str);
+        z = parseInt(str.substr(str.indexOf(",") + 1));
+        ba[y][z] = 2;
+    }
+    print("DESTROYER
\n"); + for (x = 1; x <= 2; x++) { + str = await input(); + y = parseInt(str); + z = parseInt(str.substr(str.indexOf(",") + 1)); + ba[y][z] = 1; + } + print("DESTROYER\n"); + for (x = 1; x <= 2; x++) { + str = await input(); + y = parseInt(str); + z = parseInt(str.substr(str.indexOf(",") + 1)); + ba[y][z] = 0.5; + } + while (1) { + print("DO YOU WANT TO START"); + js = await input(); + if (js == "WHERE ARE YOUR SHIPS?") { + print("BATTLESHIP\n"); + for (z = 1; z <= 5; z++) + print(" " + fa[z] + " " + ga[z] + "\n"); + print("CRUISER\n"); + print(" " + fa[6] + " " + ga[6] + "\n"); + print(" " + fa[7] + " " + ga[7] + "\n"); + print(" " + fa[8] + " " + ga[8] + "\n"); + print("DESTROYER\n"); + print(" " + fa[9] + " " + ga[9] + "\n"); + print(" " + fa[10] + " " + ga[10] + "\n"); + print("DESTROYER\n"); + print(" " + fa[11] + " " + ga[11] + "\n"); + print(" " + fa[12] + " " + ga[12] + "\n"); + } else { + break; + } + } + c = 0; + print("DO YOU WANT TO SEE MY SHOTS"); + ks = await input(); + print("\n"); + if (js != "YES") + first_time = true; + else + first_time = false; + while (1) { + if (first_time) { + first_time = false; + } else { + if (js == "YES") { + c++; + print("\n"); + print("TURN " + c + "\n"); + } + a = 0; + for (w = 0.5; w <= 3; w += 0.5) { + loop1: + for (x = 1; x <= 10; x++) { + for (y = 1; y <= 10; y++) { + if (ba[x][y] == w) { + a += Math.floor(w + 0.5); + break loop1; + } + } + } + } + for (w = 1; w <= 7; w++) { + ca[w] = 0; + da[w] = 0; + fa[w] = 0; + ga[w] = 0; + } + p3 = 0; + for (x = 1; x <= 10; x++) { + for (y = 1; y <= 10; y++) { + if (aa[x][y] <= 10) + p3++; + } + } + print("YOU HAVE " + a + " SHOTS.\n"); + if (p3 < a) { + print("YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES.\n"); + print("YOU HAVE WON.\n"); + return; + } + if (a == 0) { + print("I HAVE WON.\n"); + return; + } + for (w = 1; w <= a; w++) { + while (1) { + str = await input(); + x = parseInt(str); + y = parseInt(str.substr(str.indexOf(",") + 1)); + if (x >= 1 && x <= 10 && y >= 1 && y <= 10) { + if (aa[x][y] > 10) { + print("YOU SHOT THERE BEFORE ON TURN " + (aa[x][y] - 10) + "\n"); + continue; + } + break; + } + print("ILLEGAL, ENTER AGAIN.\n"); + } + ca[w] = x; + da[w] = y; + } + for (w = 1; w <= a; w++) { + if (aa[ca[w]][da[w]] == 3) { + print("YOU HIT MY BATTLESHIP.\n"); + } else if (aa[ca[w]][da[w]] == 2) { + print("YOU HIT MY CRUISER.\n"); + } else if (aa[ca[w]][da[w]] == 1) { + print("YOU HIT MY DESTROYER.\n"); + } else if (aa[ca[w]][da[w]] == 0.5) { + print("YOU HIT MY DESTROYER.\n"); + } + aa[ca[w]][da[w]] = 10 + c; + } + } + a = 0; + if (js != "YES") { + c++; + print("\n"); + print("TURN " + c + "\n"); + } + a = 0; + for (w = 0.5; w <= 3; w += 0.5) { + loop2: + for (x = 1; x <= 10; x++) { + for (y = 1; y <= 10; y++) { + if (ba[x][y] == w) { + a += Math.floor(w + 0.5); + break loop2; + } + } + } + } + p3 = 0; + for (x = 1; x <= 10; x++) { + for (y = 1; y <= 10; y++) { + if (aa[x][y] <= 10) + p3++; + } + } + print("I HAVE " + a + " SHOTS.\n"); + if (p3 < a) { + print("I HAVE MORE SHOTS THAN BLANK SQUARES.\n"); + print("I HAVE WON.\n"); + return; + } + if (a == 0) { + print("YOU HAVE WON.\n"); + return; + } + for (w = 1; w <= 12; w++) { + if (ha[w] > 0) + break; + } + if (w <= 12) { + for (r = 1; r <= 10; r++) { + ka[r] = []; + for (s = 1; s <= 10; s++) + ka[r][s] = 0; + } + for (u = 1; u <= 12; u++) { + if (ea[u] >= 10) + continue; + for (r = 1; r <= 10; r++) { + for (s = 1; s <= 10; s++) { + if (ba[r][s] >= 10) { + ka[r][s] = -10000000; + } else { + for (m = sgn(1 - r); m <= sgn(10 - r); m++) { + for (n = sgn(1 - s); n <= sgn(10 - s); n++) { + if (n + m + n * m != 0 && ba[r + m][s + n] == ea[u]) + ka[r][s] += ea[u] - s * Math.floor(ha[u] + 0.5); + } + } + } + } + } + } + for (r = 1; r <= a; r++) { + fa[r] = r; + ga[r] = r; + } + for (r = 1; r <= 10; r++) { + for (s = 1; s <= 10; s++) { + q9 = 1; + for (m = 1; m <= a; m++) { + if (ka[fa[m]][ga[m]] < ka[fa[q9]][ga[q9]]) + q9 = m; + } + if ((r > a || r != s) && ka[r][s] >= ka[fa[q9]][ga[q9]]) { + for (m = 1; m <= a; m++) { + if (fa[m] != r) { + fa[q9] = r; + ga[q9] = s; + break; + } + if (ga[m] == s) + break; + } + } + } + } + } else { + // RANDOM + w = 0; + r3 = 0; + generate_random(); + r2 = 0; + while (1) { + r3++; + if (r3 > 100) { + generate_random(); + r2 = 0; + r3 = 1; + } + if (x > 10) { + x = 10 - Math.floor(Math.random() * 2.5); + } else if (x <= 0) { + x = 1 + Math.floor(Math.random() * 2.5); + } + if (y > 10) { + y = 10 - Math.floor(Math.random() * 2.5); + } else if (y <= 0) { + y = 1 + Math.floor(Math.random() * 2.5); + } + while (1) { + valid = true; + if (x < 1 || x > 10 || y < 1 || y > 10 || ba[x][y] > 10) { + valid = false; + } else { + for (q9 = 1; q9 <= w; q9++) { + if (fa[q9] == x && ga[q9] == y) { + valid = false; + break; + } + } + if (q9 > w) + w++; + } + if (valid) { + fa[w] = x; + ga[w] = y; + if (w == a) { + finish = true; + break; + } + } + if (r2 == 6) { + r2 = 0; + finish = false; + break; + } + x1 = [1,-1, 1,1,0,-1][r2]; + y1 = [1, 1,-3,1,2, 1][r2]; + r2++; + x += x1; + y += y1; + } + if (finish) + break; + } + } + if (ks == "YES") { + for (z5 = 1; z5 <= a; z5++) + print(" " + fa[z5] + " " + ga[z5] + "\n"); + } + for (w = 1; w <= a; w++) { + hit = false; + if (ba[fa[w]][ga[w]] == 3) { + print("I HIT YOUR BATTLESHIP.\n"); + hit = true; + } else if (ba[fa[w]][ga[w]] == 2) { + print("I HIT YOUR CRUISER.\n"); + hit = true; + } else if (ba[fa[w]][ga[w]] == 1) { + print("I HIT YOUR DESTROYER.\n"); + hit = true; + } else if (ba[fa[w]][ga[w]] == 0.5) { + print("I HIT YOUR DESTROYER.\n"); + hit = true; + } + if (hit) { + for (q = 1; q <= 12; q++) { + if (ea[q] != -1) + continue; + ea[q] = 10 + c; + ha[q] = ba[fa[w]][ga[w]]; + m3 = 0; + for (m2 = 1; m2 <= 12; m2++) { + if (ha[m2] == ha[q]) + m3++; + } + if (m3 == Math.floor(ha[q] + 0.5) + 1 + Math.floor(Math.floor(ha[q] + 0.5) / 3)) { + for (m2 = 1; m2 <= 12; m2++) { + if (ha[m2] == ha[q]) { + ea[m2] = -1; + ha[m2] = -1; + } + } + } + break; + } + if (q > 12) { + print("PROGRAM ABORT:\n"); + for (q = 1; q <= 12; q++) { + print("ea[" + q + "] = " + ea[q] + "\n"); + print("ha[" + q + "] = " + ha[q] + "\n"); + } + return; + } + } + ba[fa[w]][ga[w]] = 10 + c; + } + } +} + +main(); diff --git a/52_Kinema/pascal/README.md b/00_Alternate_Languages/77_Salvo/pascal/README.md similarity index 100% rename from 52_Kinema/pascal/README.md rename to 00_Alternate_Languages/77_Salvo/pascal/README.md diff --git a/00_Alternate_Languages/77_Salvo/perl/README.md b/00_Alternate_Languages/77_Salvo/perl/README.md new file mode 100644 index 00000000..e69c8b81 --- /dev/null +++ b/00_Alternate_Languages/77_Salvo/perl/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Perl](https://www.perl.org/) diff --git a/00_Alternate_Languages/77_Salvo/python/README.md b/00_Alternate_Languages/77_Salvo/python/README.md new file mode 100644 index 00000000..781945ec --- /dev/null +++ b/00_Alternate_Languages/77_Salvo/python/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Python](https://www.python.org/about/) diff --git a/00_Alternate_Languages/77_Salvo/python/salvo.py b/00_Alternate_Languages/77_Salvo/python/salvo.py new file mode 100644 index 00000000..4de418ca --- /dev/null +++ b/00_Alternate_Languages/77_Salvo/python/salvo.py @@ -0,0 +1,528 @@ +import random +import re + +################### +# +# static variables +# +################### + +BOARD_WIDTH = 10 +BOARD_HEIGHT = 10 + +# 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 + [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 + +#################################### +# +# 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 + +# 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 + +# +# SHOTS +# +#################################### + +# flag indicating whose turn +# it currently is +COMPUTER = 0 +PLAYER = 1 +active_turn = COMPUTER + +#################### +# +# 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 +# +# ask user for single (x,y) coordinate +# validate the coordinates are within the bounds +# of the board width and height. mimic the behavior +# of the original program which exited with error +# messages if coordinates where outside of array bounds. +# if input is not numeric, print error out to user and +# let them try again. +def input_coord(): + match = None + while not match: + coords = input("? ") + match = re.match(COORD_REGEX, coords) + if not match: + print("!NUMBER EXPECTED - RETRY INPUT LINE") + x = int(match.group(1)) + y = int(match.group(2)) + + if x > BOARD_HEIGHT or y > BOARD_WIDTH: + print("!OUT OF ARRAY BOUNDS IN LINE 1540") + exit() + + if x <= 0 or y <= 0: + print("!NEGATIVE ARRAY DIM IN LINE 1540") + exit() + + return x, y + + +# 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() + + # 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 + + +# 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)] + + +# print_board +# +# print out the game board for testing +# purposes +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 + + +# 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(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): + ship_hit = square + board[x - 1][y - 1] = 10 + current_turn + return ship_hit + + +# 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 +# +# 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("{:>38}".format("SALVO")) + print("{:>57s}".format("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")) + print("") + print("{:>52s}".format("ORIGINAL BY LAWRENCE SIEGEL, 1973")) + print("{:>56s}".format("PYTHON 3 PORT BY TODD KAISER, MARCH 2021")) + print("\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(f"{x:2}", f"{y:2}") + 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 + 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) + + +#################################### +# +# 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 + + +# 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 execute_turn(turn): + + global num_computer_shots + global num_player_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 + + hits = [] + for shot in shots: + 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 + else: + num_computer_shots = calculate_shots(board) + return num_computer_shots + + +# +# Turn Control +# +###################################### + +###################### +# +# main game flow +# +###################### + +# initialize the player and computer +# boards +initialize_game() + +# execute turns until someone wins or we run +# out of squares to shoot + +game_over = False +while not game_over: + + # 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 diff --git a/00_Alternate_Languages/77_Salvo/ruby/README.md b/00_Alternate_Languages/77_Salvo/ruby/README.md new file mode 100644 index 00000000..fb32811e --- /dev/null +++ b/00_Alternate_Languages/77_Salvo/ruby/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Ruby](https://www.ruby-lang.org/en/) diff --git a/00_Alternate_Languages/77_Salvo/salvo.bas b/00_Alternate_Languages/77_Salvo/salvo.bas new file mode 100644 index 00000000..6a85d715 --- /dev/null +++ b/00_Alternate_Languages/77_Salvo/salvo.bas @@ -0,0 +1,329 @@ +1000 PRINT TAB(33);"SALVO" +1010 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +1020 PRINT:PRINT:PRINT +1030 REM +1040 DIM A(10,10),B(10,10),C(7),D(7),E(12),F(12),G(12),H(12),K(10,10) +1050 Z8=0 +1060 FOR W=1 TO 12 +1070 E(W)=-1 +1080 H(W)=-1 +1090 NEXT W +1100 FOR X=1 TO 10 +1110 FOR Y=1 TO 10 +1120 B(X,Y)=0 +1130 NEXT Y +1140 NEXT X +1150 FOR X=1 TO 12 +1160 F(X)=0 +1170 G(X)=0 +1180 NEXT X +1190 FOR X=1 TO 10 +1200 FOR Y=1 TO 10 +1210 A(X,Y)=0 +1220 NEXT Y +1230 NEXT X +1240 FOR K=4 TO 1 STEP -1 +1250 U6=0 +1260 GOSUB 2910 +1270 DEF FNA(K)=(5-K)*3-2*INT(K/4)+SGN(K-1)-1 +1280 DEF FNB(K)=K+INT(K/4)-SGN(K-1) +1290 IF V+V2+V*V2=0 THEN 1260 +1300 IF Y+V*FNB(K)>10 THEN 1260 +1310 IF Y+V*FNB(K)<1 THEN 1260 +1320 IF X+V2*FNB(K)>10 THEN 1260 +1330 IF X+V2*FNB(K)<1 THEN 1260 +1340 U6=U6+1 +1350 IF U6>25 THEN 1190 +1360 FOR Z=0 TO FNB(K) +1370 F(Z+FNA(K))=X+V2*Z +1380 G(Z+FNA(K))=Y+V*Z +1390 NEXT Z +1400 U8=FNA(K) +1405 IF U8>U8+FNB(K) THEN 1460 +1410 FOR Z2= U8 TO U8+FNB(K) +1415 IF U8<2 THEN 1450 +1420 FOR Z3=1 TO U8-1 +1430 IF SQR((F(Z3)-F(Z2))^2 + (G(Z3)-G(Z2))^2) < 3.59 THEN 1260 +1440 NEXT Z3 +1450 NEXT Z2 +1460 FOR Z=0 TO FNB(K) +1470 A(F(Z+U8),G(Z+U8))=.5+SGN(K-1)*(K-1.5) +1480 NEXT Z +1490 NEXT K +1500 PRINT "ENTER COORDINATES FOR..." +1510 PRINT "BATTLESHIP" +1520 FOR X=1 TO 5 +1530 INPUT Y,Z +1540 B(Y,Z)=3 +1550 NEXT X +1560 PRINT "CRUISER" +1570 FOR X=1 TO 3 +1580 INPUT Y,Z +1590 B(Y,Z)=2 +1600 NEXT X +1610 PRINT "DESTROYER" +1620 FOR X=1 TO 2 +1630 INPUT Y,Z +1640 B(Y,Z)=1 +1650 NEXT X +1660 PRINT "DESTROYER" +1670 FOR X=1 TO 2 +1680 INPUT Y,Z +1690 B(Y,Z)=.5 +1700 NEXT X +1710 PRINT "DO YOU WANT TO START"; +1720 INPUT J$ +1730 IF J$<>"WHERE ARE YOUR SHIPS?" THEN 1890 +1740 PRINT "BATTLESHIP" +1750 FOR Z=1 TO 5 +1760 PRINT F(Z);G(Z) +1770 NEXT Z +1780 PRINT "CRUISER" +1790 PRINT F(6);G(6) +1800 PRINT F(7);G(7) +1810 PRINT F(8);G(8) +1820 PRINT "DESTROYER" +1830 PRINT F(9);G(9) +1840 PRINT F(10);G(10) +1850 PRINT "DESTROYER" +1860 PRINT F(11);G(11) +1870 PRINT F(12);G(12) +1880 GOTO 1710 +1890 C=0 +1900 PRINT "DO YOU WANT TO SEE MY SHOTS"; +1910 INPUT K$ +1920 PRINT +1930 IF J$<>"YES" THEN 2620 +1940 REM*******************START +1950 IF J$<>"YES" THEN 1990 +1960 C=C+1 +1970 PRINT +1980 PRINT "TURN";C +1990 A=0 +2000 FOR W=.5 TO 3 STEP .5 +2010 FOR X=1 TO 10 +2020 FOR Y=1 TO 10 +2030 IF B(X,Y)=W THEN 2070 +2040 NEXT Y +2050 NEXT X +2060 GOTO 2080 +2070 A=A+INT(W+.5) +2080 NEXT W +2090 FOR W=1 TO 7 +2100 C(W)=0 +2110 D(W)=0 +2120 F(W)=0 +2130 G(W)=0 +2140 NEXT W +2150 P3=0 +2160 FOR X=1 TO 10 +2170 FOR Y=1 TO 10 +2180 IF A(X,Y)>10 THEN 2200 +2190 P3=P3+1 +2200 NEXT Y +2210 NEXT X +2220 PRINT "YOU HAVE";A;"SHOTS." +2230 IF P3>=A THEN 2260 +2240 PRINT "YOU HAVE MORE SHOTS THAN THERE ARE BLANK SQUARES." +2250 GOTO 2890 +2260 IF A<>0 THEN 2290 +2270 PRINT "I HAVE WON." +2280 STOP +2290 FOR W=1 TO A +2300 INPUT X,Y +2310 IF X<>INT(X) THEN 2370 +2320 IF X>10 THEN 2370 +2330 IF X<1 THEN 2370 +2340 IF Y<>INT(Y) THEN 2370 +2350 IF Y>10 THEN 2370 +2360 IF Y>=1 THEN 2390 +2370 PRINT "ILLEGAL, ENTER AGAIN." +2380 GOTO 2300 +2390 IF A(X,Y)>10 THEN 2440 +2400 C(W)=X +2410 D(W)=Y +2420 NEXT W +2430 GOTO 2460 +2440 PRINT "YOU SHOT THERE BEFORE ON TURN";A(X,Y)-10 +2450 GOTO 2300 +2460 FOR W=1 TO A +2470 IF A(C(W),D(W))=3 THEN 2540 +2480 IF A(C(W),D(W))=2 THEN 2560 +2490 IF A(C(W),D(W))=1 THEN 2580 +2500 IF A(C(W),D(W))=.5 THEN 2600 +2510 A(C(W),D(W))=10+C +2520 NEXT W +2530 GOTO 2620 +2540 PRINT "YOU HIT MY BATTLESHIP." +2550 GOTO 2510 +2560 PRINT "YOU HIT MY CRUISER." +2570 GOTO 2510 +2580 PRINT "YOU HIT MY DESTROYER." +2590 GOTO 2510 +2600 PRINT "YOU HIT MY DESTROYER." +2610 GOTO 2510 +2620 A=0 +2630 IF J$="YES" THEN 2670 +2640 C=C+1 +2650 PRINT +2660 PRINT "TURN";C +2670 A=0 +2680 FOR W=.5 TO 3 STEP .5 +2690 FOR X=1 TO 10 +2700 FOR Y=1 TO 10 +2710 IF A(X,Y)=W THEN 2750 +2720 NEXT Y +2730 NEXT X +2740 GOTO 2760 +2750 A=A+INT(W+.5) +2760 NEXT W +2770 P3=0 +2780 FOR X=1 TO 10 +2790 FOR Y=1 TO 10 +2800 IF A(X,Y)>10 THEN 2820 +2810 P3=P3+1 +2820 NEXT Y +2830 NEXT X +2840 PRINT "I HAVE";A;"SHOTS." +2850 IF P3>A THEN 2880 +2860 PRINT "I HAVE MORE SHOTS THAN BLANK SQUARES." +2870 GOTO 2270 +2880 IF A<>0 THEN 2960 +2890 PRINT "YOU HAVE WON." +2900 STOP +2910 X=INT(RND(1)*10+1) +2920 Y=INT(RND(1)*10+1) +2930 V=INT(3*RND(1)-1) +2940 V2=INT(3*RND(1)-1) +2950 RETURN +2960 FOR W=1 TO 12 +2970 IF H(W)>0 THEN 3800 +2980 NEXT W +2990 REM*******************RANDOM +3000 W=0 +3010 R3=0 +3020 GOSUB 2910 +3030 RESTORE +3040 R2=0 +3050 R3=R3+1 +3060 IF R3>100 THEN 3010 +3070 IF X>10 THEN 3110 +3080 IF X>0 THEN 3120 +3090 X=1+INT(RND(1)*2.5) +3100 GOTO 3120 +3110 X=10-INT(RND(1)*2.5) +3120 IF Y>10 THEN 3160 +3130 IF Y>0 THEN 3270 +3140 Y=1+INT(RND(1)*2.5) +3150 GOTO 3270 +3160 Y=10-INT(RND(1)*2.5) +3170 GOTO 3270 +3180 F(W)=X +3190 G(W)=Y +3200 IF W=A THEN 3380 +3210 IF R2=6 THEN 3030 +3220 READ X1,Y1 +3230 R2=R2+1 +3240 DATA 1,1,-1,1,1,-3,1,1,0,2,-1,1 +3250 X=X+X1 +3260 Y=Y+Y1 +3270 IF X>10 THEN 3210 +3280 IF X<1 THEN 3210 +3290 IF Y>10 THEN 3210 +3300 IF Y<1 THEN 3210 +3310 IF B(X,Y)>10 THEN 3210 +3320 FOR Q9=1 TO W +3330 IF F(Q9)<>X THEN 3350 +3340 IF G(Q9)=Y THEN 3210 +3350 NEXT Q9 +3360 W=W+1 +3370 GOTO 3180 +3380 IF K$<>"YES" THEN 3420 +3390 FOR Z5=1 TO A +3400 PRINT F(Z5);G(Z5) +3410 NEXT Z5 +3420 FOR W=1 TO A +3430 IF B(F(W),G(W))=3 THEN 3500 +3440 IF B(F(W),G(W))=2 THEN 3520 +3450 IF B(F(W),G(W))=1 THEN 3560 +3460 IF B(F(W),G(W))=.5 THEN 3540 +3470 B(F(W),G(W))=10+C +3480 NEXT W +3490 GOTO 1950 +3500 PRINT "I HIT YOUR BATTLESHIP" +3510 GOTO 3570 +3520 PRINT "I HIT YOUR CRUISER" +3530 GOTO 3570 +3540 PRINT "I HIT YOUR DESTROYER" +3550 GOTO 3570 +3560 PRINT "I HIT YOUR DESTROYER" +3570 FOR Q=1 TO 12 +3580 IF E(Q)<>-1 THEN 3730 +3590 E(Q)=10+C +3600 H(Q)=B(F(W),G(W)) +3610 M3=0 +3620 FOR M2=1 TO 12 +3630 IF H(M2)<>H(Q) THEN 3650 +3640 M3=M3+1 +3650 NEXT M2 +3660 IF M3<>INT(H(Q)+.5)+1+INT(INT(H(Q)+.5)/3) THEN 3470 +3670 FOR M2=1 TO 12 +3680 IF H(M2)<>H(Q) THEN 3710 +3690 E(M2)=-1 +3700 H(M2)=-1 +3710 NEXT M2 +3720 GOTO 3470 +3730 NEXT Q +3740 PRINT "PROGRAM ABORT:" +3750 FOR Q=1 TO 12 +3760 PRINT "E(";Q;") =";E(Q) +3770 PRINT "H(";Q;") =";H(Q) +3780 NEXT Q +3790 STOP +3800 REM************************USINGEARRAY +3810 FOR R=1 TO 10 +3820 FOR S=1 TO 10 +3830 K(R,S)=0 +3840 NEXT S +3850 NEXT R +3860 FOR U=1 TO 12 +3870 IF E(U)<10 THEN 4020 +3880 FOR R=1 TO 10 +3890 FOR S=1 TO 10 +3900 IF B(R,S)<10 THEN 3930 +3910 K(R,S)=-10000000 +3920 GOTO 4000 +3930 FOR M=SGN(1-R) TO SGN(10-R) +3940 FOR N=SGN(1-S) TO SGN(10-S) +3950 IF N+M+N*M=0 THEN 3980 +3960 IF B(R+M,S+N)<>E(U) THEN 3980 +3970 K(R,S)=K(R,S)+E(U)-S*INT(H(U)+.5) +3980 NEXT N +3990 NEXT M +4000 NEXT S +4010 NEXT R +4020 NEXT U +4030 FOR R=1 TO A +4040 F(R)=R +4050 G(R)=R +4060 NEXT R +4070 FOR R=1 TO 10 +4080 FOR S=1 TO 10 +4090 Q9=1 +4100 FOR M=1 TO A +4110 IF K(F(M),G(M))>=K(F(Q9),G(Q9)) THEN 4130 +4120 Q9=M +4130 NEXT M +4131 IF R>A THEN 4140 +4132 IF R=S THEN 4210 +4140 IF K(R,S)R THEN 4190 +4170 IF G(M)=S THEN 4210 +4180 NEXT M +4190 F(Q9)=R +4200 G(Q9)=S +4210 NEXT S +4220 NEXT R +4230 GOTO 3380 +4240 END diff --git a/00_Alternate_Languages/77_Salvo/vbnet/README.md b/00_Alternate_Languages/77_Salvo/vbnet/README.md new file mode 100644 index 00000000..98b702c7 --- /dev/null +++ b/00_Alternate_Languages/77_Salvo/vbnet/README.md @@ -0,0 +1,3 @@ +Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET) diff --git a/00_Alternate_Languages/77_Salvo/vbnet/Salvo.sln b/00_Alternate_Languages/77_Salvo/vbnet/Salvo.sln new file mode 100644 index 00000000..3acb9449 --- /dev/null +++ b/00_Alternate_Languages/77_Salvo/vbnet/Salvo.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Salvo", "Salvo.vbproj", "{849885BF-24BD-4FEB-A224-A9502742D4B0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {849885BF-24BD-4FEB-A224-A9502742D4B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {849885BF-24BD-4FEB-A224-A9502742D4B0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {849885BF-24BD-4FEB-A224-A9502742D4B0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {849885BF-24BD-4FEB-A224-A9502742D4B0}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/00_Alternate_Languages/77_Salvo/vbnet/Salvo.vbproj b/00_Alternate_Languages/77_Salvo/vbnet/Salvo.vbproj new file mode 100644 index 00000000..90ec0e38 --- /dev/null +++ b/00_Alternate_Languages/77_Salvo/vbnet/Salvo.vbproj @@ -0,0 +1,8 @@ + + + Exe + Salvo + net6.0 + 16.9 + + diff --git a/00_Alternate_Languages/78_Sine_Wave/README.md b/00_Alternate_Languages/78_Sine_Wave/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/78_Sine_Wave/csharp/Program.cs b/00_Alternate_Languages/78_Sine_Wave/csharp/Program.cs new file mode 100644 index 00000000..69b2dee6 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/csharp/Program.cs @@ -0,0 +1,15 @@ +using System; + +Console.WriteLine(Tab(30) + "Sine Wave"); +Console.WriteLine(Tab(15) + "Creative Computing Morristown, New Jersey\n\n\n\n\n"); + +bool isCreative = true; +for (double t = 0.0; t <= 40.0; t += 0.25) +{ + int a = (int)(26 + 25 * Math.Sin(t)); + string word = isCreative ? "Creative" : "Computing"; + Console.WriteLine($"{Tab(a)}{word}"); + isCreative = !isCreative; +} + +static string Tab(int n) => new string(' ', n); diff --git a/00_Alternate_Languages/78_Sine_Wave/csharp/README.md b/00_Alternate_Languages/78_Sine_Wave/csharp/README.md new file mode 100644 index 00000000..4daabb5c --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/csharp/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) diff --git a/00_Alternate_Languages/78_Sine_Wave/csharp/SineWave.csproj b/00_Alternate_Languages/78_Sine_Wave/csharp/SineWave.csproj new file mode 100644 index 00000000..20827042 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/csharp/SineWave.csproj @@ -0,0 +1,8 @@ + + + + Exe + net5.0 + + + diff --git a/00_Alternate_Languages/78_Sine_Wave/csharp/SineWave.sln b/00_Alternate_Languages/78_Sine_Wave/csharp/SineWave.sln new file mode 100644 index 00000000..adcc993f --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/csharp/SineWave.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("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SineWave", "SineWave.csproj", "{730FA2CC-5AA5-4BE2-8DF9-8E55FDC8FB30}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {730FA2CC-5AA5-4BE2-8DF9-8E55FDC8FB30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {730FA2CC-5AA5-4BE2-8DF9-8E55FDC8FB30}.Debug|Any CPU.Build.0 = Debug|Any CPU + {730FA2CC-5AA5-4BE2-8DF9-8E55FDC8FB30}.Release|Any CPU.ActiveCfg = Release|Any CPU + {730FA2CC-5AA5-4BE2-8DF9-8E55FDC8FB30}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {32A37343-2955-4124-8765-9143F6C529DC} + EndGlobalSection +EndGlobal diff --git a/00_Alternate_Languages/78_Sine_Wave/java/README.md b/00_Alternate_Languages/78_Sine_Wave/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/78_Sine_Wave/java/src/SineWave.java b/00_Alternate_Languages/78_Sine_Wave/java/src/SineWave.java new file mode 100644 index 00000000..0908791e --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/java/src/SineWave.java @@ -0,0 +1,28 @@ +/** + * Sine Wave + * + * Based on the Sine Wave program here + * https://github.com/coding-horror/basic-computer-games/blob/main/78%20Sine%20Wave/sinewave.bas + * + * Note: The idea was to create a version of the 1970's Basic program in Java, without introducing + * new features - no additional text, error checking, etc has been added. + */ +public class SineWave { + + public static void main(String[] args) { + System.out.println(""" + SINE WAVE + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + """); + var isCreative = true; + for(var t = 0d; t<40; t += .25) { + //Indent output + var indentations = 26 + (int) (25 * Math.sin(t)); + System.out.print(" ".repeat(indentations)); + //Change output every iteration + var word = isCreative ? "CREATIVE" : "COMPUTING"; + System.out.println(word); + isCreative = !isCreative ; + } + } +} diff --git a/00_Alternate_Languages/78_Sine_Wave/javascript/README.md b/00_Alternate_Languages/78_Sine_Wave/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/78_Sine_Wave/javascript/sinewave.js b/00_Alternate_Languages/78_Sine_Wave/javascript/sinewave.js new file mode 100644 index 00000000..3823273d --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/javascript/sinewave.js @@ -0,0 +1,22 @@ +print(tab(30), "SINE WAVE"); +print(tab(15), "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); +print("\n\n\n\n"); + +// REMARKABLE PROGRAM BY DAVID AHL +// Transliterated to Javascript by Les Orchard + +let toggleWord = true; + +for (let step = 0; step < 40; step += 0.25) { + let indent = Math.floor(26 + 25 * Math.sin(step)); + print(tab(indent), toggleWord ? "CREATIVE" : "COMPUTING"); + toggleWord = !toggleWord; +} + +function print(...messages) { + console.log(messages.join(" ")); +} + +function tab(count) { + return " ".repeat(count); +} diff --git a/53_King/pascal/README.md b/00_Alternate_Languages/78_Sine_Wave/pascal/README.md similarity index 100% rename from 53_King/pascal/README.md rename to 00_Alternate_Languages/78_Sine_Wave/pascal/README.md diff --git a/00_Alternate_Languages/78_Sine_Wave/perl/README.md b/00_Alternate_Languages/78_Sine_Wave/perl/README.md new file mode 100644 index 00000000..e69c8b81 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/perl/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Perl](https://www.perl.org/) diff --git a/00_Alternate_Languages/78_Sine_Wave/perl/sinewave.pl b/00_Alternate_Languages/78_Sine_Wave/perl/sinewave.pl new file mode 100644 index 00000000..a28d3865 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/perl/sinewave.pl @@ -0,0 +1,17 @@ +#!/usr/bin/perl +use strict; +use warnings; + +print ' ' x 30 ."SINE WAVE\n"; +print ' ' x 15 ."CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"; +print "\n\n\n\n\n"; + +my $B=0; + +for (my $T=0; $T<40; $T+=.25) { + my $A=int(26+25*sin($T)); + print ' ' x $A; + if ($B==0) { print "CREATIVE\n"; } + if ($B==1) { print "COMPUTING\n"; } + $B= !$B; #Toggle + } diff --git a/00_Alternate_Languages/78_Sine_Wave/python/README.md b/00_Alternate_Languages/78_Sine_Wave/python/README.md new file mode 100644 index 00000000..781945ec --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/python/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Python](https://www.python.org/about/) diff --git a/00_Alternate_Languages/78_Sine_Wave/python/sinewave.py b/00_Alternate_Languages/78_Sine_Wave/python/sinewave.py new file mode 100644 index 00000000..9ae639e6 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/python/sinewave.py @@ -0,0 +1,108 @@ +######################################################## +# +# Sine Wave +# +# From: BASIC Computer Games (1978) +# Edited by David H. Ahl +# +# "Did you ever go to a computer show and see a bunch of +# CRT terminals just sitting there waiting forlornly +# for someone to give a demo on them. It was one of +# those moments when I was at DEC that I decided there +# should be a little bit of background activity. And +# why not plot with words instead of the usual X's? +# Thus SINE WAVE was born and lives on in dozens of +# different versions. At least those CRTs don't look +# so lifeless anymore." +# +# Original BASIC version by David Ahl +# +# Python port by Jeff Jetton, 2019 +# +######################################################## + +import math +import time + +# Constants +STRINGS = ("Creative", "Computing") # Text to display +MAX_LINES = 160 +STEP_SIZE = 0.25 # Number of radians to increase at each +# line. Controls speed of horizontal +# printing movement. +CENTER = 26 # Controls left edge of "middle" string +DELAY = 0.05 # Amount of seconds to wait between lines + + +# Display "intro" text +print("\n Sine Wave") +print(" Creative Computing Morristown, New Jersey") +print("\n\n\n\n") +# "REMarkable program by David Ahl" + + +string_index = 0 +radians = 0 +width = CENTER - 1 + +# "Start long loop" +for line_num in range(MAX_LINES): + + # Get string to display on this line + curr_string = STRINGS[string_index] + + # Calculate how far over to print the text + sine = math.sin(radians) + padding = int(CENTER + width * sine) + print(curr_string.rjust(padding + len(curr_string))) + + # Increase radians and increment our tuple index + radians += STEP_SIZE + string_index += 1 + if string_index >= len(STRINGS): + string_index = 0 + + # Make sure the text doesn't fly by too fast... + time.sleep(DELAY) + + +######################################################## +# +# Porting Notes +# +# The original BASIC version hardcoded two words in +# the body of the code and then used a sentinel flag +# (flipping between 0 and 1) with IF statements to +# determine the word to display next. +# +# Here, the words have been moved to a Python tuple, +# which is iterated over without any assumptions about +# how long it is. The STRINGS tuple can therefore be +# modified to have to program print out any sequence +# of any number of lines of text. +# +# Since a modern computer running Python will print +# to the screen much more quickly than a '70s-era +# computer running BASIC would, a delay component +# has been introduced in this version to make the +# output more historically accurate. +# +# +# Ideas for Modifications +# +# Ask the user for desired number of lines (perhaps +# with an "infinite" option) and/or step size. +# +# Let the user input the text strings to display, +# rather than having it pre-defined in a constant. +# Calculate an appropriate CENTER based on length of +# longest string. +# +# Try changing STINGS so that it only includes a +# single string, just like this: +# +# STRINGS = ('Howdy!') +# +# What happens? Why? How would you fix it? +# +######################################################## diff --git a/00_Alternate_Languages/78_Sine_Wave/ruby/README.md b/00_Alternate_Languages/78_Sine_Wave/ruby/README.md new file mode 100644 index 00000000..fb32811e --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/ruby/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Ruby](https://www.ruby-lang.org/en/) diff --git a/00_Alternate_Languages/78_Sine_Wave/ruby/sinewave.rb b/00_Alternate_Languages/78_Sine_Wave/ruby/sinewave.rb new file mode 100644 index 00000000..6cb19cd9 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/ruby/sinewave.rb @@ -0,0 +1,15 @@ +def intro + puts " SINE WAVE + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n\n\n\n" +end + +def main + intro + (0..40).step(0.25).each do |t| + a = (26 + 25 * Math.sin(t)).to_i + text = (t % 0.5) == 0 ? "CREATIVE" : "COMPUTING" + puts " " * a + text + end +end + +main diff --git a/00_Alternate_Languages/78_Sine_Wave/rust/README.md b/00_Alternate_Languages/78_Sine_Wave/rust/README.md new file mode 100644 index 00000000..7e85f9a1 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/rust/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM) diff --git a/00_Alternate_Languages/78_Sine_Wave/rust/src/main.rs b/00_Alternate_Languages/78_Sine_Wave/rust/src/main.rs new file mode 100644 index 00000000..f8a1cece --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/rust/src/main.rs @@ -0,0 +1,37 @@ +fn main() { + let mut ticker:f64 = 0.0; + let mut spaces ; + + //pring welcome message + welcome(); + + //drawing loop + loop { + //print however many spaces + spaces = (26.0 + 25.0*ticker.sin()).round() as i32; + for _i in 0..=spaces{ + print!(" "); //print a space + } + + //print Creative or Computing + if (ticker.round() as i32) % 2 == 0 { + println!("CREATIVE"); + } else { + println!("COMPUTING"); + } + + //increment ticker + ticker += 0.25; + } + +} + +/** + * prints welcome message + */ +fn welcome() { + println!(" + SINE WAVE + CREATIVE COMPUTING MORRISTOWN, NEW JERSEY + "); +} \ No newline at end of file diff --git a/00_Alternate_Languages/78_Sine_Wave/sinewave.bas b/00_Alternate_Languages/78_Sine_Wave/sinewave.bas new file mode 100644 index 00000000..0e362acd --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/sinewave.bas @@ -0,0 +1,17 @@ +10 PRINT TAB(30);"SINE WAVE" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +30 PRINT: PRINT: PRINT: PRINT: PRINT +40 REMARKABLE PROGRAM BY DAVID AHL +50 B=0 +100 REM START LONG LOOP +110 FOR T=0 TO 40 STEP .25 +120 A=INT(26+25*SIN(T)) +130 PRINT TAB(A); +140 IF B=1 THEN 180 +150 PRINT "CREATIVE" +160 B=1 +170 GOTO 200 +180 PRINT "COMPUTING" +190 B=0 +200 NEXT T +999 END diff --git a/00_Alternate_Languages/78_Sine_Wave/vbnet/README.md b/00_Alternate_Languages/78_Sine_Wave/vbnet/README.md new file mode 100644 index 00000000..98b702c7 --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/vbnet/README.md @@ -0,0 +1,3 @@ +Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET) diff --git a/00_Alternate_Languages/78_Sine_Wave/vbnet/SineWave.sln b/00_Alternate_Languages/78_Sine_Wave/vbnet/SineWave.sln new file mode 100644 index 00000000..37f4bf7e --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/vbnet/SineWave.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SineWave", "SineWave.vbproj", "{204DD0CD-1DA5-4B4B-992F-1C3ED089A147}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {204DD0CD-1DA5-4B4B-992F-1C3ED089A147}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {204DD0CD-1DA5-4B4B-992F-1C3ED089A147}.Debug|Any CPU.Build.0 = Debug|Any CPU + {204DD0CD-1DA5-4B4B-992F-1C3ED089A147}.Release|Any CPU.ActiveCfg = Release|Any CPU + {204DD0CD-1DA5-4B4B-992F-1C3ED089A147}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/00_Alternate_Languages/78_Sine_Wave/vbnet/SineWave.vbproj b/00_Alternate_Languages/78_Sine_Wave/vbnet/SineWave.vbproj new file mode 100644 index 00000000..610c360f --- /dev/null +++ b/00_Alternate_Languages/78_Sine_Wave/vbnet/SineWave.vbproj @@ -0,0 +1,8 @@ + + + Exe + SineWave + net6.0 + 16.9 + + diff --git a/00_Alternate_Languages/79_Slalom/README.md b/00_Alternate_Languages/79_Slalom/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/79_Slalom/csharp/README.md b/00_Alternate_Languages/79_Slalom/csharp/README.md new file mode 100644 index 00000000..4daabb5c --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/csharp/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) diff --git a/00_Alternate_Languages/79_Slalom/csharp/Slalom.csproj b/00_Alternate_Languages/79_Slalom/csharp/Slalom.csproj new file mode 100644 index 00000000..d3fe4757 --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/csharp/Slalom.csproj @@ -0,0 +1,9 @@ + + + Exe + net6.0 + 10 + enable + enable + + diff --git a/00_Alternate_Languages/79_Slalom/csharp/Slalom.sln b/00_Alternate_Languages/79_Slalom/csharp/Slalom.sln new file mode 100644 index 00000000..c1621f2e --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/csharp/Slalom.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Slalom", "Slalom.csproj", "{6D0607CF-B01C-4E17-A4DE-D15514AE5F84}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {6D0607CF-B01C-4E17-A4DE-D15514AE5F84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6D0607CF-B01C-4E17-A4DE-D15514AE5F84}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6D0607CF-B01C-4E17-A4DE-D15514AE5F84}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6D0607CF-B01C-4E17-A4DE-D15514AE5F84}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/00_Alternate_Languages/79_Slalom/csharp/program.cs b/00_Alternate_Languages/79_Slalom/csharp/program.cs new file mode 100644 index 00000000..df70ba42 --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/csharp/program.cs @@ -0,0 +1,433 @@ +using System.Text; + +namespace Slalom +{ + class Slalom + { + private int[] GateMaxSpeed = { 14,18,26,29,18,25,28,32,29,20,29,29,25,21,26,29,20,21,20, + 18,26,25,33,31,22 }; + + private int GoldMedals = 0; + private int SilverMedals = 0; + private int BronzeMedals = 0; + private void DisplayIntro() + { + Console.WriteLine(""); + Console.WriteLine("SLALOM".PadLeft(23)); + Console.WriteLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + Console.WriteLine(""); + } + + private void DisplayInstructions() + { + Console.WriteLine(); + Console.WriteLine("*** Slalom: This is the 1976 Winter Olympic Giant Slalom. You are"); + Console.WriteLine(" the American team's only hope of a gold medal."); + Console.WriteLine(); + Console.WriteLine(" 0 -- Type this if you want to see how long you've taken."); + Console.WriteLine(" 1 -- Type this if you want to speed up a lot."); + Console.WriteLine(" 2 -- Type this if you want to speed up a little."); + Console.WriteLine(" 3 -- Type this if you want to speed up a teensy."); + Console.WriteLine(" 4 -- Type this if you want to keep going the same speed."); + Console.WriteLine(" 5 -- Type this if you want to check a teensy."); + Console.WriteLine(" 6 -- Type this if you want to check a litte."); + Console.WriteLine(" 7 -- Type this if you want to check a lot."); + Console.WriteLine(" 8 -- Type this if you want to cheat and try to skip a gate."); + Console.WriteLine(); + Console.WriteLine(" The place to use these options is when the computer asks:"); + Console.WriteLine(); + Console.WriteLine("Option?"); + Console.WriteLine(); + Console.WriteLine(" Good Luck!"); + Console.WriteLine(); + } + + private bool PromptYesNo(string Prompt) + { + bool Success = false; + + while (!Success) + { + Console.Write(Prompt); + string LineInput = Console.ReadLine().Trim().ToLower(); + + if (LineInput.Equals("yes")) + return true; + else if (LineInput.Equals("no")) + return false; + else + Console.WriteLine("Please type 'YES' or 'NO'"); + } + + return false; + } + + private int PromptForGates() + { + bool Success = false; + int NumberOfGates = 0; + + while (!Success) + { + Console.Write("How many gates does this course have (1 to 25) "); + string LineInput = Console.ReadLine().Trim().ToLower(); + + if (int.TryParse(LineInput, out NumberOfGates)) + { + if (NumberOfGates >= 1 && NumberOfGates <= 25) + { + Success = true; + } + else if (NumberOfGates < 1) + { + Console.WriteLine("Try again,"); + } + else // greater than 25 + { + Console.WriteLine("25 is the limit."); + NumberOfGates = 25; + Success = true; + } + } + else + { + Console.WriteLine("Try again,"); + } + } + + return NumberOfGates; + } + + private int PromptForRate() + { + bool Success = false; + int Rating = 0; + + while (!Success) + { + Console.Write("Rate yourself as a skier, (1=worst, 3=best) "); + string LineInput = Console.ReadLine().Trim().ToLower(); + + if (int.TryParse(LineInput, out Rating)) + { + if (Rating >= 1 && Rating <= 3) + { + Success = true; + } + else + { + Console.WriteLine("The bounds are 1-3"); + } + } + else + { + Console.WriteLine("The bounds are 1-3"); + } + } + + return Rating; + } + + private int PromptForOption() + { + bool Success = false; + int Option = 0; + + while (!Success) + { + Console.Write("Option? "); + string LineInput = Console.ReadLine().Trim().ToLower(); + + if (int.TryParse(LineInput, out Option)) + { + if (Option >= 0 && Option <= 8) + { + Success = true; + } + else if (Option > 8) + { + Console.WriteLine("What?"); + } + } + else + { + Console.WriteLine("What?"); + } + } + + return Option; + } + + private string PromptForCommand() + { + bool Success = false; + string Result = ""; + + Console.WriteLine(); + Console.WriteLine("Type \"INS\" for intructions"); + Console.WriteLine("Type \"MAX\" for approximate maximum speeds"); + Console.WriteLine("Type \"RUN\" for the beginning of the race"); + + while (!Success) + { + + Console.Write("Command--? "); + string LineInput = Console.ReadLine().Trim().ToLower(); + + if (LineInput.Equals("ins") || LineInput.Equals("max") || LineInput.Equals("run")) + { + Result = LineInput; + Success = true; + } + else + { + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine("\"{0}\" is an illegal command--retry", LineInput); + } + } + + return Result; + } + + private bool ExceedGateSpeed(double MaxGateSpeed, double MPH, double Time) + { + Random rand = new Random(); + + Console.WriteLine("{0:N0} M.P.H.", MPH); + if (MPH > MaxGateSpeed) + { + Console.Write("You went over the maximum speed "); + if (rand.NextDouble() < ((MPH - (double)MaxGateSpeed) * 0.1) + 0.2) + { + Console.WriteLine("and made it!"); + } + else + { + if (rand.NextDouble() < 0.5) + { + Console.WriteLine("snagged a flag!"); + } + else + { + Console.WriteLine("wiped out!"); + } + + Console.WriteLine("You took {0:N2} seconds", rand.NextDouble() + Time); + + return false; + } + } + else if (MPH > (MaxGateSpeed - 1)) + { + Console.WriteLine("Close one!"); + } + + return true; + } + private void DoARun(int NumberOfGates, int Rating) + { + Random rand = new Random(); + double MPH = 0; + double Time = 0; + int Option = 0; + double MaxGateSpeed = 0; // Q + double PreviousMPH = 0; + double Medals = 0; + + Console.WriteLine("The starter counts down...5...4...3...2...1...GO!"); + + MPH = rand.NextDouble() * (18-9)+9; + + Console.WriteLine(); + Console.WriteLine("You're off!"); + + for (int GateNumber = 1; GateNumber <= NumberOfGates; GateNumber++) + { + MaxGateSpeed = GateMaxSpeed[GateNumber-1]; + + Console.WriteLine(); + Console.WriteLine("Here comes Gate # {0}:", GateNumber); + Console.WriteLine("{0:N0} M.P.H.", MPH); + + PreviousMPH = MPH; + + Option = PromptForOption(); + while (Option == 0) + { + Console.WriteLine("You've taken {0:N2} seconds.", Time); + Option = PromptForOption(); + } + + switch (Option) + { + case 1: + MPH = MPH + (rand.NextDouble() * (10-5)+5); + if (ExceedGateSpeed(MaxGateSpeed, MPH, Time)) + break; + else + return; + case 2: + MPH = MPH + (rand.NextDouble() * (5-3)+3); + if (ExceedGateSpeed(MaxGateSpeed, MPH, Time)) + break; + else + return; + case 3: + MPH = MPH + (rand.NextDouble() * (4-1)+1); + if (ExceedGateSpeed(MaxGateSpeed, MPH, Time)) + break; + else + return; + case 4: + if (ExceedGateSpeed(MaxGateSpeed, MPH, Time)) + break; + else + return; + case 5: + MPH = MPH - (rand.NextDouble() * (4-1)+1); + if (ExceedGateSpeed(MaxGateSpeed, MPH, Time)) + break; + else + return; + case 6: + MPH = MPH - (rand.NextDouble() * (5-3)+3); + if (ExceedGateSpeed(MaxGateSpeed, MPH, Time)) + break; + else + return; + case 7: + MPH = MPH - (rand.NextDouble() * (10-5)+5); + if (ExceedGateSpeed(MaxGateSpeed, MPH, Time)) + break; + else + return; + case 8: // Cheat! + Console.WriteLine("***Cheat"); + if (rand.NextDouble() < 0.7) + { + Console.WriteLine("An official caught you!"); + Console.WriteLine("You took {0:N2} seconds.", Time); + + return; + } + else + { + Console.WriteLine("You made it!"); + Time = Time + 1.5; + } + break; + } + + if (MPH < 7) + { + Console.WriteLine("Let's be realistic, OK? Let's go back and try again..."); + MPH = PreviousMPH; + } + else + { + Time = Time + (MaxGateSpeed - MPH + 1); + if (MPH > MaxGateSpeed) + { + Time = Time + 0.5; + + } + } + } + + Console.WriteLine(); + Console.WriteLine("You took {0:N2} seconds.", Time); + + Medals = Time; + Medals = Medals / NumberOfGates; + + if (Medals < (1.5 - (Rating * 0.1))) + { + Console.WriteLine("You won a gold medal!"); + GoldMedals++; + } + else if (Medals < (2.9 - (Rating * 0.1))) + { + Console.WriteLine("You won a silver medal!"); + SilverMedals++; + } + else if (Medals < (4.4 - (Rating * 0.01))) + { + Console.WriteLine("You won a bronze medal!"); + BronzeMedals++; + } + } + + private void PlayOneRound() + { + int NumberOfGates = 0; + string Command = "first"; + bool KeepPlaying = false; + int Rating = 0; + + Console.WriteLine(""); + + NumberOfGates = PromptForGates(); + + while (!Command.Equals("")) + { + Command = PromptForCommand(); + + // Display instructions + if (Command.Equals("ins")) + { + DisplayInstructions(); + } + else if (Command.Equals("max")) + { + Console.WriteLine("Gate Max"); + Console.WriteLine(" # M.P.H."); + Console.WriteLine("----------"); + for (int i = 0; i < NumberOfGates; i++) + { + Console.WriteLine(" {0} {1}", i+1, GateMaxSpeed[i]); + } + } + else // do a run! + { + Rating = PromptForRate(); + + do + { + DoARun(NumberOfGates, Rating); + + KeepPlaying = PromptYesNo("Do you want to race again? "); + } + while (KeepPlaying); + + Console.WriteLine("Thanks for the race"); + + if (GoldMedals > 0) + Console.WriteLine("Gold Medals: {0}", GoldMedals); + if (SilverMedals > 0) + Console.WriteLine("Silver Medals: {0}", SilverMedals); + if (BronzeMedals > 0) + Console.WriteLine("Bronze Medals: {0}", BronzeMedals); + + return; + } + } + } + + public void PlayTheGame() + { + DisplayIntro(); + + PlayOneRound(); + } + } + class Program + { + static void Main(string[] args) + { + + new Slalom().PlayTheGame(); + + } + } +} diff --git a/00_Alternate_Languages/79_Slalom/java/README.md b/00_Alternate_Languages/79_Slalom/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/79_Slalom/java/Slalom.java b/00_Alternate_Languages/79_Slalom/java/Slalom.java new file mode 100644 index 00000000..608af058 --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/java/Slalom.java @@ -0,0 +1,373 @@ +import java.util.Arrays; +import java.util.InputMismatchException; +import java.util.Random; +import java.util.Scanner; + +/** + * Slalom + *

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + * + * There is a bug in the original version where the data pointer doesn't reset after a race is completed. This causes subsequent races to error at + * some future point on line "540 READ Q" + */ +public class Slalom { + + private static final int MAX_NUM_GATES = 25; + private static final int[] MAX_SPEED = { + 14, 18, 26, 29, 18, + 25, 28, 32, 29, 20, + 29, 29, 25, 21, 26, + 29, 20, 21, 20, 18, + 26, 25, 33, 31, 22 + }; + + public static void main(String[] args) { + var random = new Random(); + + printIntro(); + Scanner scanner = new Scanner(System.in); + + int numGates = readNumberOfGatesChoice(scanner); + + printMenu(); + MenuChoice menuChoice; + do { + menuChoice = readMenuOption(scanner); + switch (menuChoice) { + case INS: + printInstructions(); + break; + case MAX: + printApproxMaxSpeeds(numGates); + break; + case RUN: + run(numGates, scanner, random); + break; + } + } while (menuChoice != MenuChoice.RUN); + } + + private static void run(int numGates, Scanner scan, Random random) { + int rating = readSkierRating(scan); + boolean gameInProgress = true; + var medals = new Medals(0, 0, 0); + + while (gameInProgress) { + System.out.println("THE STARTER COUNTS DOWN...5...4...3...2...1...GO!"); + System.out.println("YOU'RE OFF!"); + + int speed = random.nextInt(18 - 9) + 9; + + float totalTimeTaken = 0; + try { + totalTimeTaken = runThroughGates(numGates, scan, random, speed); + System.out.printf("%nYOU TOOK %.2f SECONDS.%n", totalTimeTaken + random.nextFloat()); + + medals = evaluateAndUpdateMedals(totalTimeTaken, numGates, rating, medals); + } catch (WipedOutOrSnaggedAFlag | DisqualifiedException e) { + //end of this race! Print time taken and stop + System.out.printf("%nYOU TOOK %.2f SECONDS.%n", totalTimeTaken + random.nextFloat()); + } + + gameInProgress = readRaceAgainChoice(scan); + } + + System.out.println("THANKS FOR THE RACE"); + if (medals.getGold() >= 1) System.out.printf("GOLD MEDALS: %d%n", medals.getGold()); + if (medals.getSilver() >= 1) System.out.printf("SILVER MEDALS: %d%n", medals.getSilver()); + if (medals.getBronze() >= 1) System.out.printf("BRONZE MEDALS: %d%n", medals.getBronze()); + } + + private static Medals evaluateAndUpdateMedals(float totalTimeTaken, int numGates, int rating, + Medals medals) { + var m = totalTimeTaken; + m = m / numGates; + int goldMedals = medals.getGold(); + int silverMedals = medals.getSilver(); + int bronzeMedals = medals.getBronze(); + if (m < 1.5 - (rating * 0.1)) { + System.out.println("YOU WON A GOLD MEDAL!"); + goldMedals++; + } else if (m < 2.9 - rating * 0.1) { + System.out.println("YOU WON A SILVER MEDAL"); + silverMedals++; + } else if (m < 4.4 - rating * 0.01) { + System.out.println("YOU WON A BRONZE MEDAL"); + bronzeMedals++; + } + return new Medals(goldMedals, silverMedals, bronzeMedals); + } + + /** + * @return the total time taken through all the gates. + */ + private static float runThroughGates(int numGates, Scanner scan, Random random, int speed) throws DisqualifiedException, WipedOutOrSnaggedAFlag { + float totalTimeTaken = 0.0f; + for (int i = 0; i < numGates; i++) { + var gateNum = i + 1; + boolean stillInRace = true; + boolean gateCompleted = false; + while (!gateCompleted) { + System.out.printf("%nHERE COMES GATE # %d:%n", gateNum); + printSpeed(speed); + + var tmpSpeed = speed; + + int chosenOption = readOption(scan); + switch (chosenOption) { + case 0: + //how long + printHowLong(totalTimeTaken, random); + break; + case 1: + //speed up a lot + speed = speed + random.nextInt(10 - 5) + 5; + break; + case 2: + //speed up a little + speed = speed + random.nextInt(5 - 3) + 3; + break; + case 3: + //speed up a teensy + speed = speed + random.nextInt(4 - 1) + 1; + break; + case 4: + //keep going at the same speed + break; + case 5: + //check a teensy + speed = speed - random.nextInt(4 - 1) + 1; + break; + case 6: + //check a little + speed = speed - random.nextInt(5 - 3) + 3; + break; + case 7: + //check a lot + speed = speed - random.nextInt(10 - 5) + 5; + break; + case 8: + //cheat + System.out.println("***CHEAT"); + if (random.nextFloat() < 0.7) { + System.out.println("AN OFFICIAL CAUGHT YOU!"); + stillInRace = false; + } else { + System.out.println("YOU MADE IT!"); + totalTimeTaken = totalTimeTaken + 1.5f; + } + break; + } + + if (stillInRace) { + printSpeed(speed); + stillInRace = checkAndProcessIfOverMaxSpeed(random, speed, MAX_SPEED[i]); + if (!stillInRace) throw new WipedOutOrSnaggedAFlag(); + } else { + throw new DisqualifiedException();//we've been dis-qualified + } + + if (speed < 7) { + System.out.println("LET'S BE REALISTIC, OK? LET'S GO BACK AND TRY AGAIN..."); + speed = tmpSpeed; + gateCompleted = false; + } else { + totalTimeTaken = totalTimeTaken + (MAX_SPEED[i] - speed + 1); + if (speed > MAX_SPEED[i]) { + totalTimeTaken = totalTimeTaken + 0.5f; + } + gateCompleted = true; + } + } + + } + return totalTimeTaken; + } + + private static boolean checkAndProcessIfOverMaxSpeed(Random random, int speed, int maxSpeed) { + boolean stillInRace = true; + if (speed > maxSpeed) { + if (random.nextFloat() >= (speed - maxSpeed) * 0.1 + 0.2) { + System.out.println("YOU WENT OVER THE MAXIMUM SPEED AND MADE IT!"); + } else { + System.out.print("YOU WENT OVER THE MAXIMUM SPEED AND "); + if (random.nextBoolean()) { + System.out.println("WIPED OUT!"); + } else { + System.out.println("SNAGGED A FLAG!"); + } + stillInRace = false; + } + } else if (speed > maxSpeed - 1) { + System.out.println("CLOSE ONE!"); + } + return stillInRace; + } + + private static boolean readRaceAgainChoice(Scanner scan) { + System.out.print("\nDO YOU WANT TO RACE AGAIN? "); + String raceAgain = ""; + final String YES = "YES"; + final String NO = "NO"; + while (!YES.equals(raceAgain) && !NO.equals(raceAgain)) { + raceAgain = scan.nextLine(); + if (!(YES.equals(raceAgain) || NO.equals(raceAgain))) { + System.out.println("PLEASE TYPE 'YES' OR 'NO'"); + } + } + return raceAgain.equals(YES); + } + + private static void printSpeed(int speed) { + System.out.printf("%3d M.P.H.%n", speed); + } + + private static void printHowLong(float t, Random random) { + System.out.printf("YOU'VE TAKEN %.2f SECONDS.%n", t + random.nextFloat()); + } + + private static int readOption(Scanner scan) { + Integer option = null; + + while (option == null) { + System.out.print("OPTION? "); + try { + option = scan.nextInt(); + } catch (InputMismatchException ex) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE\n"); + } + scan.nextLine(); + if (option != null && (option > 8 || option < 0)) { + System.out.println("WHAT?"); + option = null; + } + } + return option; + } + + private static int readSkierRating(Scanner scan) { + int rating = 0; + + while (rating < 1 || rating > 3) { + System.out.print("RATE YOURSELF AS A SKIER, (1=WORST, 3=BEST)? "); + try { + rating = scan.nextInt(); + if (rating < 1 || rating > 3) { + System.out.println("THE BOUNDS ARE 1-3"); + } + } catch (InputMismatchException ex) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE\n"); + } + scan.nextLine(); + } + return rating; + } + + private static void printApproxMaxSpeeds(int numGates) { + System.out.println("GATE MAX"); + System.out.println(" # M.P.H."); + System.out.println("---------"); + for (int i = 0; i < numGates; i++) { + System.out.println((i+1) + " " + MAX_SPEED[i]); + } + } + + private static void printInstructions() { + System.out.println("\n*** SLALOM: THIS IS THE 1976 WINTER OLYMPIC GIANT SLALOM. YOU ARE"); + System.out.println(" THE AMERICAN TEAM'S ONLY HOPE OF A GOLD MEDAL."); + System.out.println(); + System.out.println(" 0 -- TYPE THIS IS YOU WANT TO SEE HOW LONG YOU'VE TAKEN."); + System.out.println(" 1 -- TYPE THIS IF YOU WANT TO SPEED UP A LOT."); + System.out.println(" 2 -- TYPE THIS IF YOU WANT TO SPEED UP A LITTLE."); + System.out.println(" 3 -- TYPE THIS IF YOU WANT TO SPEED UP A TEENSY."); + System.out.println(" 4 -- TYPE THIS IF YOU WANT TO KEEP GOING THE SAME SPEED."); + System.out.println(" 5 -- TYPE THIS IF YOU WANT TO CHECK A TEENSY."); + System.out.println(" 6 -- TYPE THIS IF YOU WANT TO CHECK A LITTLE."); + System.out.println(" 7 -- TYPE THIS IF YOU WANT TO CHECK A LOT."); + System.out.println(" 8 -- TYPE THIS IF YOU WANT TO CHEAT AND TRY TO SKIP A GATE."); + System.out.println(); + System.out.println(" THE PLACE TO USE THESE OPTIONS IS WHEN THE COMPUTER ASKS:"); + System.out.println(); + System.out.println("OPTION?"); + System.out.println(); + System.out.println(" GOOD LUCK!"); + } + + private static MenuChoice readMenuOption(Scanner scan) { + System.out.print("COMMAND--? "); + MenuChoice menuChoice = null; + + while (menuChoice == null) { + String choice = scan.next(); + if (Arrays.stream(MenuChoice.values()).anyMatch(a -> a.name().equals(choice))) { + menuChoice = MenuChoice.valueOf(choice); + } else { + System.out.print("\""+ choice + "\" IS AN ILLEGAL COMMAND--RETRY? "); + } + scan.nextLine(); + } + return menuChoice; + } + + private static void printMenu() { + System.out.println("TYPE INS FOR INSTRUCTIONS"); + System.out.println("TYPE MAX FOR APPROXIMATE MAXIMUM SPEEDS"); + System.out.println("TYPE RUN FOR THE BEGINNING OF THE RACE"); + } + + private static int readNumberOfGatesChoice(Scanner scan) { + int numGates = 0; + while (numGates < 1) { + System.out.print("HOW MANY GATES DOES THIS COURSE HAVE (1 TO 25)? "); + numGates = scan.nextInt(); + if (numGates > MAX_NUM_GATES) { + System.out.println(MAX_NUM_GATES + " IS THE LIMIT."); + numGates = MAX_NUM_GATES; + } + } + return numGates; + } + + private static void printIntro() { + System.out.println(" SLALOM"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + } + + private enum MenuChoice { + INS, MAX, RUN + } + + private static class DisqualifiedException extends Exception { + } + + private static class WipedOutOrSnaggedAFlag extends Exception { + } + + private static class Medals { + private int gold = 0; + private int silver = 0; + private int bronze = 0; + + public Medals(int gold, int silver, int bronze) { + this.gold = gold; + this.silver = silver; + this.bronze = bronze; + } + + public int getGold() { + return gold; + } + + public int getSilver() { + return silver; + } + + public int getBronze() { + return bronze; + } + } + + +} diff --git a/00_Alternate_Languages/79_Slalom/javascript/README.md b/00_Alternate_Languages/79_Slalom/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/79_Slalom/javascript/slalom.html b/00_Alternate_Languages/79_Slalom/javascript/slalom.html new file mode 100644 index 00000000..d91f71ad --- /dev/null +++ b/00_Alternate_Languages/79_Slalom/javascript/slalom.html @@ -0,0 +1,9 @@ + + +SLALOM + + +


+
+
+
diff --git a/00_Alternate_Languages/79_Slalom/javascript/slalom.js b/00_Alternate_Languages/79_Slalom/javascript/slalom.js
new file mode 100644
index 00000000..196ddb5d
--- /dev/null
+++ b/00_Alternate_Languages/79_Slalom/javascript/slalom.js
@@ -0,0 +1,260 @@
+// SLALOM
+//
+// 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 speed = [,14,18,26,29,18,
+             25,28,32,29,20,
+             29,29,25,21,26,
+             29,20,21,20,18,
+             26,25,33,31,22];
+
+function show_instructions()
+{
+    print("\n");
+    print("*** SLALOM: THIS IS THE 1976 WINTER OLYMPIC GIANT SLALOM.  YOU ARE\n");
+    print("            THE AMERICAN TEAM'S ONLY HOPE OF A GOLD MEDAL.\n");
+    print("\n");
+    print("     0 -- TYPE THIS IS YOU WANT TO SEE HOW LONG YOU'VE TAKEN.\n");
+    print("     1 -- TYPE THIS IF YOU WANT TO SPEED UP A LOT.\n");
+    print("     2 -- TYPE THIS IF YOU WANT TO SPEED UP A LITTLE.\n");
+    print("     3 -- TYPE THIS IF YOU WANT TO SPEED UP A TEENSY.\n");
+    print("     4 -- TYPE THIS IF YOU WANT TO KEEP GOING THE SAME SPEED.\n");
+    print("     5 -- TYPE THIS IF YOU WANT TO CHECK A TEENSY.\n");
+    print("     6 -- TYPE THIS IF YOU WANT TO CHECK A LITTLE.\n");
+    print("     7 -- TYPE THIS IF YOU WANT TO CHECK A LOT.\n");
+    print("     8 -- TYPE THIS IF YOU WANT TO CHEAT AND TRY TO SKIP A GATE.\n");
+    print("\n");
+    print(" THE PLACE TO USE THESE OPTIONS IS WHEN THE COMPUTER ASKS:\n");
+    print("\n");
+    print("OPTION?\n");
+    print("\n");
+    print("                GOOD LUCK!\n");
+    print("\n");
+}
+
+function show_speeds()
+{
+    print("GATE MAX\n");
+    print(" #  M.P.H.\n");
+    print("----------\n");
+    for (var b = 1; b <= v; b++) {
+        print(" " + b + "  " + speed[b] + "\n");
+    }
+}
+
+// Main program
+async function main()
+{
+    var gold = 0;
+    var silver = 0;
+    var bronze = 0;
+
+    print(tab(33) + "SLALOM\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    while (1) {
+        print("HOW MANY GATES DOES THIS COURSE HAVE (1 TO 25)");
+        v = parseInt(await input());
+        if (v >= 25) {
+            print("25 IS THE LIMIT\n");
+            v = 25;
+        } else if (v < 1) {
+            print("TRY AGAIN.\n");
+        } else {
+            break;
+        }
+    }
+    print("\n");
+    print("TYPE \"INS\" FOR INSTRUCTIONS\n");
+    print("TYPE \"MAX\" FOR APPROXIMATE MAXIMUM SPEEDS\n");
+    print("TYPE \"RUN\" FOR THE BEGINNING OF THE RACE\n");
+    while (1) {
+        print("COMMAND--");
+        str = await input();
+        if (str == "INS") {
+            show_instructions();
+        } else if (str == "MAX") {
+            show_speeds();
+        } else if (str == "RUN") {
+            break;
+        } else {
+            print("\"" + str + "\" IS AN ILLEGAL COMMAND--RETRY");
+        }
+    }
+    while (1) {
+        print("RATE YOURSELF AS A SKIER, (1=WORST, 3=BEST)");
+        a = parseInt(await input());
+        if (a < 1 || a > 3)
+            print("THE BOUNDS ARE 1-3\n");
+        else
+            break;
+    }
+    while (1) {
+        print("THE STARTER COUNTS DOWN...5...4...3...2...1...GO!");
+        t = 0;
+        s = Math.floor(Math.random(1) * (18 - 9) + 9);
+        print("\n");
+        print("YOU'RE OFF!\n");
+        for (o = 1; o <= v; o++) {
+            q = speed[o];
+            print("\n");
+            print("HERE COMES GATE #" + o + " :\n");
+            print(s + " M.P.H.\n");
+            s1 = s;
+            while (1) {
+                print("OPTION");
+                o1 = parseInt(await input());
+                if (o1 < 0 || o1 > 8)
+                    print("WHAT?\n");
+                else if (o1 == 0)
+                    print("YOU'VE TAKEN " + (t + Math.random()) + " SECONDS.\n");
+                else
+                    break;
+            }
+            finish = false;
+            switch (o1) {
+                case 1:
+                    s += Math.floor(Math.random() * (10 - 5) + 5);
+                    break;
+                case 2:
+                    s += Math.floor(Math.random() * (5 - 3) + 3);
+                    break;
+                case 3:
+                    s += Math.floor(Math.random() * (4 - 1) + 1);
+                    break;
+                case 4:
+                    break;
+                case 5:
+                    s -= Math.floor(Math.random() * (4 - 1) + 1);
+                    break;
+                case 6:
+                    s -= Math.floor(Math.random() * (5 - 3) + 3);
+                    break;
+                case 7:
+                    s -= Math.floor(Math.random() * (10 - 5) + 5);
+                    break;
+                case 8:
+                    print("***CHEAT\n");
+                    if (Math.random() >= 0.7) {
+                        print("YOU MADE IT!\n");
+                        t += 1.5;
+                    } else {
+                        print("AN OFFICIAL CAUGHT YOU!\n");
+                        print("YOU TOOK " + (t + Math.random()) + " SECONDS.\n");
+                        finish = true;
+                    }
+                    break;
+            }
+            if (!finish) {
+                if (o1 != 4)
+                    print(s + " M.P.H.\n");
+                if (s > q) {
+                    if (Math.random() < ((s - q) * 0.1) + 0.2) {
+                        print("YOU WENT OVER THE MAXIMUM SPEED AND ");
+                        if (Math.random() < 0.5) {
+                            print("SNAGGED A FLAG!\n");
+                        } else {
+                            print("WIPED OUT!\n");
+                        }
+                        print("YOU TOOK " + (t + Math.random()) + " SECONDS.\n");
+                        finish = true;
+                    } else {
+                        print("YOU WENT OVER THE MAXIMUM SPEED AND MADE IT!\n");
+                    }
+                } else if (s > q - 1) {
+                    print("CLOSE ONE!\n");
+                }
+            }
+            if (finish)
+                break;
+            if (s < 7) {
+                print("LET'S BE REALISTIC, OK?  LET'S GO BACK AND TRY AGAIN...\n");
+                s = s1;
+                o--;
+                continue;
+            }
+            t += q - s + 1;
+            if (s > q) {
+                t += 0.5;
+            }
+        }
+        if (!finish) {
+            print("\n");
+            print("YOU TOOK " + (t + Math.random()) + " SECONDS.\n");
+            m = t;
+            m /= v;
+            if (m < 1.5 - (a * 0.1)) {
+                print("YOU WON A GOLD MEDAL!\n");
+                gold++;
+            } else if (m < 2.9 - (a * 0.1)) {
+                print("YOU WON A SILVER MEDAL\n");
+                silver++;
+            } else if (m < 4.4 - (a * 0.1)) {
+                print("YOU WON A BRONZE MEDAL\n");
+                bronze++;
+            }
+        }
+        while (1) {
+            print("\n");
+            print("DO YOU WANT TO RACE AGAIN");
+            str = await input();
+            if (str != "YES" && str != "NO")
+                print("PLEASE TYPE 'YES' OR 'NO'\n");
+            else
+                break;
+        }
+        if (str != "YES")
+            break;
+    }
+    print("THANKS FOR THE RACE\n");
+    if (gold >= 1)
+        print("GOLD MEDALS: " + gold + "\n");
+    if (silver >= 1)
+        print("SILVER MEDALS: " + silver + "\n");
+    if (bronze >= 1)
+        print("BRONZE MEDALS: " + bronze + "\n");
+}
+
+main();
diff --git a/54_Letter/pascal/README.md b/00_Alternate_Languages/79_Slalom/pascal/README.md
similarity index 100%
rename from 54_Letter/pascal/README.md
rename to 00_Alternate_Languages/79_Slalom/pascal/README.md
diff --git a/00_Alternate_Languages/79_Slalom/perl/README.md b/00_Alternate_Languages/79_Slalom/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/79_Slalom/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/79_Slalom/python/README.md b/00_Alternate_Languages/79_Slalom/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/79_Slalom/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/79_Slalom/python/slalom.py b/00_Alternate_Languages/79_Slalom/python/slalom.py
new file mode 100644
index 00000000..4e361f26
--- /dev/null
+++ b/00_Alternate_Languages/79_Slalom/python/slalom.py
@@ -0,0 +1,198 @@
+from random import random
+
+print("Slalom".rjust(39))
+print("Creative Computing Morristown, New Jersey\n\n\n".rjust(57))
+
+medals = {
+    "gold": 0,
+    "silver": 0,
+    "bronze": 0,
+}
+max_speeds = [
+    14,
+    18,
+    26,
+    29,
+    18,
+    25,
+    28,
+    32,
+    29,
+    20,
+    29,
+    29,
+    25,
+    21,
+    26,
+    29,
+    20,
+    21,
+    20,
+    18,
+    26,
+    25,
+    33,
+    31,
+    22,
+]
+
+
+def ask(question):
+    print(question, end="? ")
+    return input().upper()
+
+
+def ask_int(question):
+    reply = ask(question)
+    return int(reply) if reply.isnumeric() else -1
+
+
+def pre_run():
+    print('\nType "INS" for instructions')
+    print('Type "MAX" for approximate maximum speeds')
+    print('Type "RUN" for the beginning of the race')
+    cmd = ask("Command--")
+    while cmd != "RUN":
+        if cmd == "INS":
+            print("\n*** Slalom: This is the 1976 Winter Olypic Giant Slalom.  You are")
+            print("            the American team's only hope for a gold medal.\n")
+            print("     0 -- Type this if you want to see how long you've taken.")
+            print("     1 -- Type this if you want to speed up a lot.")
+            print("     2 -- Type this if you want to speed up a little.")
+            print("     3 -- Type this if you want to speed up a teensy.")
+            print("     4 -- Type this if you want to keep going the same speed.")
+            print("     5 -- Type this if you want to check a teensy.")
+            print("     6 -- Type this if you want to check a little.")
+            print("     7 -- Type this if you want to check a lot.")
+            print("     8 -- Type this if you want to cheat and try to skip a gate.\n")
+            print(" The place to use these options is when the Computer asks:\n")
+            print("Option?\n")
+            print("                Good Luck!\n")
+            cmd = ask("Command--")
+        elif cmd == "MAX":
+            print("Gate Max")
+            print(" # M.P.H.")
+            print("----------")
+            for i in range(0, gates):
+                print(f" {i + 1}  {max_speeds[i]}")
+            cmd = ask("Command--")
+        else:
+            cmd = ask(f'"{cmd}" is an illegal command--Retry')
+
+
+def run():
+    global medals
+    print("The starter counts down...5...4...3...2...1...Go!")
+    time = 0
+    speed = int(random() * (18 - 9) + 9)
+    print("You're off")
+    for i in range(0, gates):
+        while True:
+            print(f"\nHere comes gate #{i + 1}:")
+            print(f" {int(speed)} M.P.H.")
+            old_speed = speed
+            opt = ask_int("Option")
+            while opt < 1 or opt > 8:
+                if opt == 0:
+                    print(f"You've taken {int(time)} seconds.")
+                else:
+                    print("What?")
+                opt = ask_int("Option")
+
+            if opt == 8:
+                print("***Cheat")
+                if random() < 0.7:
+                    print("An official caught you!")
+                    print(f"You took {int(time + random())} seconds.")
+                    return
+                else:
+                    print("You made it!")
+                    time += 1.5
+            else:
+                match opt:
+                    case 1:
+                        speed += int(random() * (10 - 5) + 5)
+
+                    case 2:
+                        speed += int(random() * (5 - 3) + 3)
+
+                    case 3:
+                        speed += int(random() * (4 - 1) + 1)
+
+                    case 5:
+                        speed -= int(random() * (4 - 1) + 1)
+
+                    case 6:
+                        speed -= int(random() * (5 - 3) + 3)
+
+                    case 7:
+                        speed -= int(random() * (10 - 5) + 5)
+                print(f" {int(speed)} M.P.H.")
+                if speed > max_speeds[i]:
+                    if random() < ((speed - max_speeds[i]) * 0.1) + 0.2:
+                        print(
+                            f"You went over the maximum speed and {'snagged a flag' if random() < .5 else 'wiped out'}!"
+                        )
+                        print(f"You took {int(time + random())} seconds")
+                        return
+                    else:
+                        print("You went over the maximum speed and made it!")
+                if speed > max_speeds[i] - 1:
+                    print("Close one!")
+            if speed < 7:
+                print("Let's be realistic, ok? Let's go back and try again...")
+                speed = old_speed
+            else:
+                time += max_speeds[i] - speed + 1
+                if speed > max_speeds[i]:
+                    time += 0.5
+                break
+    print(f"\nYou took {int(time + random())} seconds.")
+    avg = time / gates
+    if avg < 1.5 - (lvl * 0.1):
+        print("Yout won a gold medal!")
+        medals["gold"] += 1
+    elif avg < 2.9 - (lvl * 0.1):
+        print("You won a silver medal!")
+        medals["silver"] += 1
+    elif avg < 4.4 - (lvl * 0.01):
+        print("You won a bronze medal!")
+        medals["bronze"] += 1
+
+
+while True:
+    gates = ask_int("How many gates does this course have (1 to 25)")
+    if gates < 1:
+        print("Try again,")
+    else:
+        if gates > 25:
+            print("25 is the limit.")
+        break
+
+pre_run()
+
+while True:
+    lvl = ask_int("Rate yourself as a skier, (1=Worst, 3=Best)")
+    if lvl < 1 or lvl > 3:
+        print("The bounds are 1-3.")
+    else:
+        break
+
+while True:
+    run()
+    while True:
+        answer = ask("Do you want to play again?")
+        if answer == "YES" or answer == "NO":
+            break
+        else:
+            print('Please type "YES" or "NO"')
+    if answer == "NO":
+        break
+
+print("Thanks for the race")
+if medals["gold"] > 0:
+    print(f"Gold medals: {medals['gold']}")
+if medals["silver"] > 0:
+    print(f"Silver medals: {medals['silver']}")
+if medals["bronze"] > 0:
+    print(f"Bronze medals: {medals['bronze']}")
diff --git a/00_Alternate_Languages/79_Slalom/ruby/README.md b/00_Alternate_Languages/79_Slalom/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/79_Slalom/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/79_Slalom/slalom.bas b/00_Alternate_Languages/79_Slalom/slalom.bas
new file mode 100644
index 00000000..b46cc39b
--- /dev/null
+++ b/00_Alternate_Languages/79_Slalom/slalom.bas
@@ -0,0 +1,165 @@
+10 PRINT TAB(33);"SLALOM"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+310 PRINT "HOW MANY GATES DOES THIS COURSE HAVE (1 TO 25)";
+320 INPUT V
+330 IF V>25 THEN 360
+340 IF V<1 THEN 390
+350 GOTO 1440
+360 PRINT "25 IS THE LIMIT."
+370 LET V=25
+380 GOTO 1440
+390 PRINT "TRY AGAIN,"
+400 GOTO 310
+410 PRINT "RATE YOURSELF AS A SKIER, (1=WORST, 3=BEST)";
+420 INPUT A
+430 IF A<1 THEN 460
+440 IF A>3 THEN 460
+450 GOTO 480
+460 PRINT "THE BOUNDS ARE 1-3"
+470 GOTO 410
+480 PRINT"THE STARTER COUNTS DOWN...5...4...3...2...1...GO!";
+490 REM
+500 LET T=0
+510 LET S=INT(RND(1)*(18-9)+9)
+520 PRINT
+525 PRINT "YOU'RE OFF!"
+530 FOR O=1 TO V
+540    READ Q
+550    PRINT
+555    PRINT "HERE COMES GATE #";STR$(O);":"
+560    PRINT S;"M.P.H."
+570    LET S1=S
+580    PRINT "OPTION";
+590    INPUT O1
+600    IF O1=0 THEN 970
+610   IF O1>8 THEN 1420
+620    IF O1<1 THEN 1420
+630    GOSUB 990
+640    IF S<7 THEN 1390
+650    LET T=T+(Q-S+1)
+660    IF S>Q THEN 1630
+670 NEXT O
+680 PRINT:PRINT "YOU TOOK";(T+RND(1));"SECONDS."
+690 LET M=T
+700 LET M=M/V
+710 IF M<1.5-(A*.1) THEN 1650
+720 IF M<2.9-(A*.1) THEN 1680
+730 IF M<4.4-(A*.01) THEN 1710
+740 PRINT:PRINT "DO YOU WANT TO RACE AGAIN";
+750 INPUT B$
+760 REM
+770 IF B$="NO" THEN 1740
+780 IF B$="YES" THEN 480
+790 PRINT "PLEASE TYPE 'YES' OR 'NO'"
+800 GOTO 740
+810 STOP
+820 PRINT
+825 PRINT "*** SLALOM: THIS IS THE 1976 WINTER OLYMPIC GIANT SLALOM.  YOU ARE"
+830 PRINT "            THE AMERICAN TEAM'S ONLY HOPE OF A GOLD MEDAL."
+840 PRINT
+845 PRINT "     0 -- TYPE THIS IS YOU WANT TO SEE HOW LONG YOU'VE TAKEN."
+850 PRINT "     1 -- TYPE THIS IF YOU WANT TO SPEED UP A LOT."
+860 PRINT "     2 -- TYPE THIS IF YOU WANT TO SPEED UP A LITTLE."
+870 PRINT "     3 -- TYPE THIS IF YOU WANT TO SPEED UP A TEENSY."
+880 PRINT "     4 -- TYPE THIS IF YOU WANT TO KEEP GOING THE SAME SPEED."
+890 PRINT "     5 -- TYPE THIS IF YOU WANT TO CHECK A TEENSY."
+900 PRINT "     6 -- TYPE THIS IF YOU WANT TO CHECK A LITTLE."
+910 PRINT "     7 -- TYPE THIS IF YOU WANT TO CHECK A LOT."
+920 PRINT "     8 -- TYPE THIS IF YOU WANT TO CHEAT AND TRY TO SKIP A GATE."
+930 PRINT
+935 PRINT " THE PLACE TO USE THESE OPTIONS IS WHEN THE COMPUTER ASKS:"
+940 PRINT
+945 PRINT "OPTION?"
+950 PRINT
+955 PRINT "                GOOD LUCK!"
+957 PRINT
+960 GOTO 1470
+970 PRINT "YOU'VE TAKEN";(T+RND(1));"SECONDS."
+980 GOTO 580
+990 ON O1 GOTO 1130,1010,1170,1080,1190,1100,1150,1210
+1000 STOP
+1010 LET S=S+INT(RND(1)*(5-3)+3)
+1020 PRINT S;"M.P.H."
+1030 IF S>Q THEN 1290
+1040 IF S>Q-1 THEN 1060
+1050 RETURN
+1060 PRINT "CLOSE ONE!"
+1070 RETURN
+1080 PRINT S;"M.P.H."
+1090 GOTO 1030
+1100 LET S=S-INT(RND(1)*(5-3)+3)
+1110 PRINT S;"M.P.H."
+1120 GOTO 1030
+1130 LET S=S+INT(RND(1)*(10-5)+5)
+1140 GOTO 1080
+1150 LET S=S-INT(RND(1)*(10-5)+5)
+1160 GOTO 1110
+1170 LET S=S+INT(RND(1)*(4-1)+1)
+1180 GOTO 1110
+1190 LET S=S-INT(RND(1)*(4-1)+1)
+1200 GOTO 1110
+1210 PRINT "***CHEAT"
+1220 IF RND(1)<.7 THEN 1260
+1230 PRINT "YOU MADE IT!"
+1240 LET T=T+1.5
+1250 RETURN
+1260 PRINT "AN OFFICIAL CAUGHT YOU!"
+1270 PRINT "YOU TOOK";(T+RND(1));"SECONDS."
+1280 GOTO 740
+1290 IF RND(1)<((S-Q)*.1)+.2 THEN 1320
+1300 PRINT "YOU WENT OVER THE NAXIMUM SPEED AND MADE IT!"
+1310 RETURN
+1320 PRINT "YOU WENT OVER THE MAXIMUM SPEED AND ";
+1330 IF RND(1)<.5 THEN 1370
+1340 PRINT "WIPED OUT!"
+1350 PRINT "YOU TOOK";(T+RND(1));"SECONDS"
+1360 GOTO 740
+1370 PRINT "SNAGGED A FLAG!"
+1380 GOTO 1350
+1390 PRINT "LET'S BE REALISTIC, OK?  LET'S GO BACK AND TRY AGAIN..."
+1400 LET S=S1
+1410 GOTO 550
+1420 PRINT "WHAT?"
+1430 GOTO 580
+1440 PRINT
+1445 PRINT "TYPE ";CHR$(34);"INS";CHR$(34);" FOR INSTRUCTIONS"
+1450 PRINT "TYPE ";CHR$(34);"MAX";CHR$(34);" FOR APPROXIMATE MAXIMUM SPEEDS"
+1460 PRINT "TYPE ";CHR$(34);"RUN";CHR$(34);" FOR THE BEGINNING OF THE RACE"
+1470 PRINT "COMMAND--";
+1480 INPUT A$
+1490 REM
+1500 IF A$="INS" THEN 820
+1510 IF A$="MAX" THEN 1550
+1520 IF A$="RUN" THEN 410
+1530 PRINT CHR$(34);A$;CHR$(34);" IS AN ILLEGAL COMMAND--RETRY";
+1540 GOTO 1480
+1550 PRINT "GATE MAX"
+1560 PRINT " #  M.P.H."
+1570 PRINT"----------"
+1580 FOR B=1 TO V
+1590    READ Q
+1600    PRINT B;"  ";Q
+1610 NEXT B
+1620 GOTO 1470
+1630 LET T=T+.5
+1640 GOTO 670
+1650 PRINT "YOU WON A GOLD MEDAL!"
+1660 LET G(1)=G(1)+1
+1670 GOTO 1730
+1680 PRINT "YOU WON A SILVER MEDAL"
+1690 LET S(1)=S(1)+1
+1700 GOTO 1730
+1710 PRINT "YOU WON A BRONZE MEDAL"
+1720 LET B(1)=B(1)+1
+1730 GOTO 740
+1740 PRINT "THANKS FOR THE RACE"
+1750 IF G(1)<1 THEN 1770
+1760 PRINT "GOLD MEDALS:";G(1)
+1770 IF S(1)<1 THEN 1790
+1780 PRINT "SILVER MEDALS:";S(1)
+1790 IF B(1)<1 THEN 1830
+1800 PRINT "BRONZE MEDALS:";B(1)
+1810 DATA 14,18,26,29,18,25,28,32,29,20,29,29,25,21,26,29,20,21,20
+1820 DATA 18,26,25,33,31,22
+1830 END
diff --git a/00_Alternate_Languages/79_Slalom/vbnet/README.md b/00_Alternate_Languages/79_Slalom/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/79_Slalom/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/79_Slalom/vbnet/Slalom.sln b/00_Alternate_Languages/79_Slalom/vbnet/Slalom.sln
new file mode 100644
index 00000000..daa61623
--- /dev/null
+++ b/00_Alternate_Languages/79_Slalom/vbnet/Slalom.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Slalom", "Slalom.vbproj", "{9A7FDEAB-071F-404C-BBA4-91D77E797DF1}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9A7FDEAB-071F-404C-BBA4-91D77E797DF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9A7FDEAB-071F-404C-BBA4-91D77E797DF1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9A7FDEAB-071F-404C-BBA4-91D77E797DF1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9A7FDEAB-071F-404C-BBA4-91D77E797DF1}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/79_Slalom/vbnet/Slalom.vbproj b/00_Alternate_Languages/79_Slalom/vbnet/Slalom.vbproj
new file mode 100644
index 00000000..0622bcd9
--- /dev/null
+++ b/00_Alternate_Languages/79_Slalom/vbnet/Slalom.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Slalom
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/80_Slots/README.md b/00_Alternate_Languages/80_Slots/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/80_Slots/csharp/README.md b/00_Alternate_Languages/80_Slots/csharp/README.md
new file mode 100644
index 00000000..32f406f8
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/csharp/README.md
@@ -0,0 +1,18 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
+
+This C# implementation of slots was done using a [C# script](https://github.com/filipw/dotnet-script).
+
+# Required
+[.NET Core SDK (i.e., .NET 6.0)](https://dotnet.microsoft.com/en-us/download)
+
+Install dotnet-script.  On the command line run:
+```
+dotnet tool install -g dotnet-script
+```
+
+# Run
+```
+dotnet script .\slots.csx
+```
diff --git a/00_Alternate_Languages/80_Slots/csharp/Slots.csproj b/00_Alternate_Languages/80_Slots/csharp/Slots.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/csharp/Slots.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/80_Slots/csharp/Slots.sln b/00_Alternate_Languages/80_Slots/csharp/Slots.sln
new file mode 100644
index 00000000..60f90046
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/csharp/Slots.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Slots", "Slots.csproj", "{D855ECF3-DF8C-46DD-8BEF-2ADFF3AE7817}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D855ECF3-DF8C-46DD-8BEF-2ADFF3AE7817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D855ECF3-DF8C-46DD-8BEF-2ADFF3AE7817}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D855ECF3-DF8C-46DD-8BEF-2ADFF3AE7817}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D855ECF3-DF8C-46DD-8BEF-2ADFF3AE7817}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/80_Slots/java/README.md b/00_Alternate_Languages/80_Slots/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/80_Slots/java/src/Slots.java b/00_Alternate_Languages/80_Slots/java/src/Slots.java
new file mode 100644
index 00000000..9d96d94f
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/java/src/Slots.java
@@ -0,0 +1,297 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Slots
+ * 

+ * Based on the Basic game of Slots here + * https://github.com/coding-horror/basic-computer-games/blob/main/80%20Slots/slots.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. + */ +public class Slots { + + public static final String[] SLOT_SYMBOLS = {"BAR", "BELL", "ORANGE", "LEMON", "PLUM", "CHERRY"}; + + public static final int NUMBER_SYMBOLS = SLOT_SYMBOLS.length; + + // Jackpot symbol (BAR) + public static final int BAR_SYMBOL = 0; + + // Indicator that the current spin won nothing + public static final int NO_WINNER = -1; + + // Used for keyboard input + private final Scanner kbScanner; + + private enum GAME_STATE { + START_GAME, + ONE_SPIN, + RESULTS, + GAME_OVER + } + + // Current game state + private GAME_STATE gameState; + + // Different types of spin results + private enum WINNINGS { + JACKPOT(100), + TOP_DOLLAR(10), + DOUBLE_BAR(5), + REGULAR(2), + NO_WIN(0); + + private final int multiplier; + + WINNINGS(int mult) { + multiplier = mult; + } + + // No win returns the negative amount of net + // otherwise calculate winnings based on + // multiplier + public int calculateWinnings(int bet) { + + if (multiplier == 0) { + return -bet; + } else { + // Return original bet plus a multipler + // of the win type + return (multiplier * bet) + bet; + } + } + } + + private int playerBalance; + + public Slots() { + + kbScanner = new Scanner(System.in); + gameState = GAME_STATE.START_GAME; + } + + /** + * Main game loop + */ + public void play() { + + int[] slotReel = new int[3]; + + do { + // Results of a single spin + WINNINGS winnings; + + switch (gameState) { + + case START_GAME: + intro(); + playerBalance = 0; + gameState = GAME_STATE.ONE_SPIN; + break; + + case ONE_SPIN: + + int playerBet = displayTextAndGetNumber("YOUR BET? "); + + slotReel[0] = randomSymbol(); + slotReel[1] = randomSymbol(); + slotReel[2] = randomSymbol(); + + // Store which symbol (if any) matches at least one other reel + int whichSymbolWon = winningSymbol(slotReel[0], slotReel[1], slotReel[2]); + + // Display the three randomly drawn symbols + StringBuilder output = new StringBuilder(); + for (int i = 0; i < 3; i++) { + if (i > 0) { + output.append(" "); + } + output.append(SLOT_SYMBOLS[slotReel[i]]); + } + + System.out.println(output); + + // Calculate results + + if (whichSymbolWon == NO_WINNER) { + // No symbols match = nothing won + winnings = WINNINGS.NO_WIN; + } else if (slotReel[0] == slotReel[1] && slotReel[0] == slotReel[2]) { + // Top dollar, 3 matching symbols + winnings = WINNINGS.TOP_DOLLAR; + if (slotReel[0] == BAR_SYMBOL) { + // All 3 symbols are BAR. Jackpot! + winnings = WINNINGS.JACKPOT; + } + } else { + // At this point the remaining options are a regular win + // or a double, since the rest (including not winning) have already + // been checked above. + // Assume a regular win + winnings = WINNINGS.REGULAR; + + // But if it was the BAR symbol that matched, its a double bar + if (slotReel[0] == BAR_SYMBOL) { + winnings = WINNINGS.DOUBLE_BAR; + } + + } + + // Update the players balance with the amount won or lost on this spin + playerBalance += winnings.calculateWinnings(playerBet); + + System.out.println(); + + // Output what happened on this spin + switch (winnings) { + case NO_WIN: + System.out.println("YOU LOST."); + break; + + case REGULAR: + System.out.println("DOUBLE!!"); + System.out.println("YOU WON!"); + break; + + case DOUBLE_BAR: + System.out.println("*DOUBLE BAR*"); + System.out.println("YOU WON!"); + break; + + case TOP_DOLLAR: + System.out.println(); + System.out.println("**TOP DOLLAR**"); + System.out.println("YOU WON!"); + break; + + case JACKPOT: + System.out.println(); + System.out.println("***JACKPOT***"); + System.out.println("YOU WON!"); + break; + + } + + System.out.println("YOUR STANDINGS ARE $" + playerBalance); + + // If player does not elect to play again, show results of session + if (!yesEntered(displayTextAndGetInput("AGAIN? "))) { + gameState = GAME_STATE.RESULTS; + + } + break; + + case RESULTS: + if (playerBalance == 0) { + System.out.println("HEY, YOU BROKE EVEN."); + } else if (playerBalance > 0) { + System.out.println("COLLECT YOUR WINNINGS FROM THE H&M CASHIER."); + } else { + // Lost + System.out.println("PAY UP! PLEASE LEAVE YOUR MONEY ON THE TERMINAL."); + } + + gameState = GAME_STATE.GAME_OVER; + break; + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + private void intro() { + System.out.println(simulateTabs(30) + "SLOTS"); + System.out.println(simulateTabs(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("YOU ARE IN THE H&M CASINO,IN FRONT OF ONE OF OUR"); + System.out.println("ONE-ARM BANDITS. BET FROM $1 TO $100."); + System.out.println("TO PULL THE ARM, PUNCH THE RETURN KEY AFTER MAKING YOUR BET."); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to an Integer + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private int displayTextAndGetNumber(String text) { + return Integer.parseInt(displayTextAndGetInput(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + + /** + * Checks whether player entered Y or YES to a question. + * + * @param text player string from kb + * @return true of Y or YES was entered, otherwise false + */ + private boolean yesEntered(String text) { + return stringIsAnyValue(text, "Y", "YES"); + } + + /** + * Check whether a string equals one of a variable number of values + * Useful to check for Y or YES for example + * Comparison is case insensitive. + * + * @param text source string + * @param values a range of values to compare against the source string + * @return true if a comparison was found in one of the variable number of strings passed + */ + private boolean stringIsAnyValue(String text, String... values) { + + return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text)); + } + + /** + * Simulate the old basic tab(xx) command which indented text by xx spaces. + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String simulateTabs(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } + + /** + * Find the symbol that won this round i.e. the first reel that matched another reel + * + * @param reel1 reel1 spin result + * @param reel2 reel2 spin result + * @param reel3 reel3 spin result + * @return NO_WINNER if no reels match otherwise an int 0-2 to indicate the reel that matches another + */ + private int winningSymbol(int reel1, int reel2, int reel3) { + if (reel1 == reel2) { + return 0; + } else if (reel1 == reel3) { + return 0; + } else if (reel2 == reel3) { + return 1; + } else { + return NO_WINNER; + } + } + + /** + * Random symbol for a slot wheel + * + * @return number between 0-5 + */ + private int randomSymbol() { + return (int) (Math.random() * NUMBER_SYMBOLS); + } +} diff --git a/00_Alternate_Languages/80_Slots/java/src/SlotsGame.java b/00_Alternate_Languages/80_Slots/java/src/SlotsGame.java new file mode 100644 index 00000000..05617cf7 --- /dev/null +++ b/00_Alternate_Languages/80_Slots/java/src/SlotsGame.java @@ -0,0 +1,6 @@ +public class SlotsGame { + public static void main(String[] args) { + Slots slots = new Slots(); + slots.play(); + } +} diff --git a/00_Alternate_Languages/80_Slots/javascript/README.md b/00_Alternate_Languages/80_Slots/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/80_Slots/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/80_Slots/javascript/slots.html b/00_Alternate_Languages/80_Slots/javascript/slots.html new file mode 100644 index 00000000..33b8e73f --- /dev/null +++ b/00_Alternate_Languages/80_Slots/javascript/slots.html @@ -0,0 +1,9 @@ + + +SLOTS + + +


+
+
+
diff --git a/00_Alternate_Languages/80_Slots/javascript/slots.js b/00_Alternate_Languages/80_Slots/javascript/slots.js
new file mode 100644
index 00000000..93c860b4
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/javascript/slots.js
@@ -0,0 +1,135 @@
+// SLOTS
+//
+// 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 figures = [, "BAR", "BELL", "ORANGE", "LEMON", "PLUM", "CHERRY"];
+
+// Main program
+async function main()
+{
+    print(tab(30) + "SLOTS\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    // Produced by Fred Mirabelle and Bob Harper on Jan 29, 1973
+    // It simulates the slot machine.
+    print("YOU ARE IN THE H&M CASINO,IN FRONT ON ONE OF OUR\n");
+    print("ONE-ARM BANDITS. BET FROM $1 TO $100.\n");
+    print("TO PULL THE ARM, PUNCH THE RETURN KEY AFTER MAKING YOUR BET.\n");
+    p = 0;
+    while (1) {
+        while (1) {
+            print("\n");
+            print("YOUR BET");
+            m = parseInt(await input());
+            if (m > 100) {
+                print("HOUSE LIMITS ARE $100\n");
+            } else if (m < 1) {
+                print("MINIMUM BET IS $1\n");
+            } else {
+                break;
+            }
+        }
+        // Not implemented: GOSUB 1270 ten chimes
+        print("\n");
+        x = Math.floor(6 * Math.random() + 1);
+        y = Math.floor(6 * Math.random() + 1);
+        z = Math.floor(6 * Math.random() + 1);
+        print("\n");
+        // Not implemented: GOSUB 1310 seven chimes after figure x and y
+        print(figures[x] + " " + figures[y] + " " + figures[z] + "\n");
+        lost = false;
+        if (x == y && y == z) {  // Three figure
+            print("\n");
+            if (z != 1) {
+                print("**TOP DOLLAR**\n");
+                p += ((10 * m) + m);
+            } else {
+                print("***JACKPOT***\n");
+                p += ((100 * m) + m);
+            }
+            print("YOU WON!\n");
+        } else if (x == y || y == z || x == z) {
+            if (x == y)
+                c = x;
+            else
+                c = z;
+            if (c == 1) {
+                print("\n");
+                print("*DOUBLE BAR*\n");
+                print("YOU WON\n");
+                p += ((5 * m) + m);
+            } else if (x != z) {
+                print("\n");
+                print("DOUBLE!!\n");
+                print("YOU WON!\n");
+                p += ((2 * m) + m);
+            } else {
+                lost = true;
+            }
+        } else {
+            lost = true;
+        }
+        if (lost) {
+            print("\n");
+            print("YOU LOST.\n");
+            p -= m;
+        }
+        print("YOUR STANDINGS ARE $" + p + "\n");
+        print("AGAIN");
+        str = await input();
+        if (str.substr(0, 1) != "Y")
+            break;
+    }
+    print("\n");
+    if (p < 0) {
+        print("PAY UP!  PLEASE LEAVE YOUR MONEY ON THE TERMINAL.\n");
+    } else if (p == 0) {
+        print("HEY, YOU BROKE EVEN.\n");
+    } else {
+        print("COLLECT YOUR WINNINGS FROM THE H&M CASHIER.\n");
+    }
+}
+
+main();
diff --git a/55_Life/pascal/README.md b/00_Alternate_Languages/80_Slots/pascal/README.md
similarity index 100%
rename from 55_Life/pascal/README.md
rename to 00_Alternate_Languages/80_Slots/pascal/README.md
diff --git a/00_Alternate_Languages/80_Slots/perl/README.md b/00_Alternate_Languages/80_Slots/perl/README.md
new file mode 100644
index 00000000..3a14d6cf
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/perl/README.md
@@ -0,0 +1,23 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
+
+This Perl script is a port of slots, which is the 80th entry in Basic
+Computer Games.
+
+I know nothing about slot machines, and my research into them says to me
+that the payout tables can be fairly arbitrary. But I have taken the
+liberty of deeming the BASIC program's refusal to pay on LEMON CHERRY
+LEMON a bug, and made that case a double.
+
+My justification for this is that at the point where the BASIC has
+detected the double in the first and third reels it has already detected
+that there is no double in the first and second reels. After the check
+for a bar (and therefore a double bar) fails it goes back and checks for
+a double on the second and third reels. But we know this check will
+fail, since the check for a double on the first and second reels failed.
+So if a loss was intended at this point, why not just call it a loss?
+
+To restore the original behavior, comment out the entire line commented
+'# Bug fix?' (about line 75) and uncomment the line with the trailing
+comment '# Bug?' (about line 83).
diff --git a/00_Alternate_Languages/80_Slots/perl/slots.pl b/00_Alternate_Languages/80_Slots/perl/slots.pl
new file mode 100644
index 00000000..b6749606
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/perl/slots.pl
@@ -0,0 +1,242 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'state' and 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use List::Util qw{ shuffle };   # Shuffle an array.
+use Scalar::Util qw{ looks_like_number };
+use Term::ReadLine;     # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+print <<'EOD';
+                                 SLOTS
+               Creative Computing  Morristown, New Jersey
+
+
+
+You are in the H&M casino, in front of one of our
+one-arm bandits.  Bet from $1 to $100.
+To pull the arm, punch the return key after making your bet.
+EOD
+
+my $winnings = 0;  # Winnings
+
+while ( 1 ) {   # Iterate indefinitely
+
+    say '';
+
+    my $bet = get_input( 'Your bet? ',
+        sub { m/ \A [0-9]+ \z /smx },
+        'Please enter a whole number between 0 and 100',
+    );
+    if ( $bet > 100 ) {
+        say 'The house limit is $100';
+        next;
+    }
+    if ( $bet < 1 ) {
+        say 'The minimum bet is $1';
+        next;
+    }
+
+    say "\a" x 10;
+    my $reel_x = int( 6 * rand() );
+    my $reel_y = int( 6 * rand() );
+    my $reel_z = int( 6 * rand() );
+    foreach my $column ( $reel_x, $reel_y, $reel_z ) {
+        state $symbol = [ qw{ Bar Bell Orange Lemon Plum Cherry } ];
+        print $symbol->[$column], "\a" x 5, ' ';
+    }
+
+    use constant YOU_WON    => 'You won!';
+    use constant YOU_LOST   => 'You lost.';
+
+    say '';
+    if ( $reel_x == $reel_y ) {
+        if ( $reel_y == $reel_z ) {
+            if ( $reel_z ) {
+                say '** TOP DOLLAR **';
+                $winnings += 11 * $bet;
+            } else {
+                say '*** JACKPOT ***';
+                $winnings += 101 * $bet;
+            }
+            say YOU_WON;
+        } elsif ( $reel_y ) {
+            $winnings += double( $bet );
+        } else {
+            $winnings += double_bar( $bet );
+        }
+    } elsif ( $reel_x == $reel_z ) {
+        if ( $reel_z ) {
+            $winnings += double( $bet );        # Bug fix?
+            # NOTE that the below code is what is actually implemented
+            # in the basic, but it is implemented strangely enough (a
+            # GOTO a line that contains a test that, if I understand the
+            # control flow, must fail) that I wonder if it is an error.
+            # I know nothing about slot machines, but research suggests
+            # the payoff table is fairly arbitrary. The code above makes
+            # code above makes the game orthogonal.
+            # $winnings += you_lost( $bet );    # Bug?
+        } else {
+            $winnings += double_bar( $bet );
+        }
+    } elsif ( $reel_y == $reel_z ) {
+        if ( $reel_z ) {
+            $winnings += double( $bet );
+        } else {
+            $winnings += double_bar( $bet );
+        }
+    } else {
+        $winnings += you_lost( $bet );
+    }
+
+    say 'Your standings are $', $winnings;
+
+    last unless get_yes_no( 'Again' );
+
+}
+
+if ( $winnings < 0 ) {
+    say 'Pay up!  Please leave your money on the terminal.';
+} elsif ( $winnings > 0 ) {
+    say 'Collect your winnings from the H&M cashier.';
+} else {
+    say 'Hey, you broke even.';
+}
+
+sub double {
+    my ( $bet ) = @_;
+    say 'DOUBLE!';
+    say YOU_WON;
+    return 3 * $bet;
+}
+
+sub double_bar {
+    my ( $bet ) = @_;
+    say '* DOUBLE BAR *';
+    say YOU_WON;
+    return 6 * $bet;
+}
+
+sub you_lost {
+    my ( $bet ) = @_;
+    say YOU_LOST;
+    return -$bet;
+}
+
+# Get input from the user. The arguments are:
+# * The prompt
+# * A reference to validation code. This code receives the response in
+#   $ARG and returns true for a valid response.
+# * A warning to print if the response is not valid. This must end in a
+#   return.
+# The first valid response is returned. An end-of-file terminates the
+# script.
+sub get_input {
+    my ( $prompt, $validate, $warning ) = @ARG;
+
+    # If no validator is passed, default to one that always returns
+    # true.
+    $validate ||= sub { 1 };
+
+    # Create the readline object. The 'state' causes the variable to be
+    # initialized only once, no matter how many times this subroutine is
+    # called. The do { ... } is a compound statement used because we
+    # need to tweak the created object before we store it.
+    state $term = do {
+        my $obj = Term::ReadLine->new( 'reverse' );
+        $obj->ornaments( 0 );
+        $obj;
+    };
+
+    while ( 1 ) {   # Iterate indefinitely
+
+        # Read the input into the topic variable, localized to prevent
+        # Spooky Action at a Distance. We exit on undef, which signals
+        # end-of-file.
+        exit unless defined( local $ARG = $term->readline( $prompt ) );
+
+        # Return the input if it is valid.
+        return $ARG if $validate->();
+
+        # Issue the warning, and go around the merry-go-round again.
+        warn $warning;
+    }
+}
+
+# Get a yes-or-no answer. The argument is the prompt, which will have
+# '? [y/n]: ' appended. The donkey work is done by get_input(), which is
+# requested to validate the response as beginning with 'y' or 'n',
+# case-insensitive. The return is a true value for 'y' and a false value
+# for 'n'.
+sub get_yes_no {
+    my ( $prompt ) = @ARG;
+    state $map_answer = {
+        n   => 0,
+        y   => 1,
+    };
+    my $resp = lc get_input(
+        "$prompt? [y/n]: ",
+        sub { m/ \A [yn] /smxi },
+        "Please respond 'y' or 'n'\n",
+    );
+    return $map_answer->{ substr $resp, 0, 1 };
+}
+
+__END__
+
+=head1 TITLE
+
+slots - Play the game 'Slots' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ slots.pl
+
+=head1 DETAILS
+
+This Perl script is a port of C, which is the 80th entry in Basic
+Computer Games.
+
+I know nothing about slot machines, and my research into them says to me
+that the payout tables can be fairly arbitrary. But I have taken the
+liberty of deeming the BASIC program's refusal to pay on LEMON CHERRY
+LEMON a bug, and made that case a double.
+
+My justification for this is that at the point where the BASIC has
+detected the double in the first and third reels it has already detected
+that there is no double in the first and second reels. After the check
+for a bar (and therefore a double bar) fails it goes back and checks for
+a double on the second and third reels. But we know this check will
+fail, since the check for a double on the first and second reels failed.
+So if a loss was intended at this point, why not just call it a loss?
+
+To restore the original behavior, comment out the entire line commented
+C<'# Bug fix?'> (about line 75) and uncomment the line with the trailing
+comment C<'# Bug?'> (about line 83).
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :
diff --git a/00_Alternate_Languages/80_Slots/python/README.md b/00_Alternate_Languages/80_Slots/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/80_Slots/python/slots.py b/00_Alternate_Languages/80_Slots/python/slots.py
new file mode 100644
index 00000000..6af1bcbd
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/python/slots.py
@@ -0,0 +1,159 @@
+########################################################
+#
+# Slots
+#
+# From Basic Computer Games (1978)
+#
+#    "The slot machine or one-arm bandit is a mechanical
+#   device that will absorb coins just about as fast as
+#   you can feed it. After inserting a coin, you pull a
+#   handle that sets three indepent reels spining. If the
+#   reels stop with certain symbols appearing in the pay
+#   line, you get a certain payoff. The original slot
+#   machine, called the Liberty bell, was invented in 1895
+#   by Charles Fey in San Francisco. Fey refused to sell
+#   or lease the manufacturing rights, so H.S. Mills in
+#   Chicago built a similar, but much improved, machine
+#   called the Operators Bell. This has survived nearly
+#   unchanged to today.
+#     On the operators Bell and other standard slot
+#   machines, there are 20 symbols on each wheel but they
+#   are not distributed evenly among the objects(cherries,
+#   bar, apples, etc). Of the 8000 possible combinations,
+#   the expected payoff(to the player) is 7049 or $89.11
+#   for every $100.00 put in, one of the lowest expected
+#   payoffs of all casino games.
+#     In the program here, the payoff is considerably more
+#   liberal; indeed it appears to favor the player by 11%
+#   -- i.e., an expected payoff of $111 for each $100 bet."
+#     The program was originally written by Fred Mirabelle
+#   and Bob Harper
+#
+########################################################
+
+import sys
+from collections import Counter
+from random import choices
+
+
+def initial_message():
+    print(" " * 30 + "Slots")
+    print(" " * 15 + "Creative Computing Morrison, New Jersey")
+    print("\n" * 3)
+    print("You are in the H&M Casino, in front of one of our")
+    print("one-arm Bandits. Bet from $1 to $100.")
+    print("To pull the arm, punch the return key after making your bet.")
+
+
+def input_betting():
+    print("\n")
+    b = -1
+    while b < 1 or b > 100:
+        try:
+            b = int(input("Your bet:"))
+        except ValueError:
+            b = -1
+        if b > 100:
+            print("House limits are $100")
+        elif b < 1:
+            print("Minium bet is $1")
+    beeping()
+    return int(b)
+
+
+def beeping():
+    # Function to produce a beep sound.
+    # In the original program is the subroutine at line 1270
+    for _ in range(5):
+        sys.stdout.write("\a")
+        sys.stdout.flush()
+
+
+def spin_wheels():
+    possible_fruits = ["Bar", "Bell", "Orange", "Lemon", "Plum", "Cherry"]
+    wheel = choices(possible_fruits, k=3)
+
+    print(*wheel)
+    beeping()
+
+    return wheel
+
+
+def adjust_profits(wheel, m, profits):
+    # we remove the duplicates
+    s = set(wheel)
+
+    if len(s) == 1:
+        # the three fruits are the same
+        fruit = s.pop()
+
+        if fruit == "Bar":
+            print("\n***Jackpot***")
+            profits = ((100 * m) + m) + profits
+        else:
+            print("\n**Top Dollar**")
+            profits = ((10 * m) + m) + profits
+
+        print("You Won!")
+    elif len(s) == 2:
+        # two fruits are equal
+        c = Counter(wheel)
+        # we get the fruit that appears two times
+        fruit = sorted(c.items(), key=lambda x: x[1], reverse=True)[0][0]
+
+        if fruit == "Bar":
+            print("\n*Double Bar*")
+            profits = ((5 * m) + m) + profits
+        else:
+            print("\nDouble!!")
+            profits = ((2 * m) + m) + profits
+
+        print("You Won!")
+    else:
+        # three different fruits
+        print("\nYou Lost.")
+        profits = profits - m
+
+    return profits
+
+
+def final_message(profits):
+    if profits < 0:
+        print("Pay up!  Please leave your money on the terminal")
+    elif profits == 0:
+        print("Hey, You broke even.")
+    else:
+        print("Collect your winings from the H&M cashier.")
+
+
+profits = 0
+keep_betting = True
+
+initial_message()
+while keep_betting:
+    m = input_betting()
+    w = spin_wheels()
+    profits = adjust_profits(w, m, profits)
+
+    print(f"Your standings are ${profits}")
+    answer = input("Again?")
+
+    try:
+        if not answer[0].lower() == "y":
+            keep_betting = False
+    except IndexError:
+        keep_betting = False
+
+final_message(profits)
+
+
+######################################################################
+#
+# Porting notes
+#
+#   The selections of the fruits(Bar, apples, lemon, etc.) are made
+#   with equal probability, accordingly to random.choices documentation.
+#   It could be added a weights list to the function and therefore
+#   adjust the expected payoff
+#
+######################################################################
diff --git a/00_Alternate_Languages/80_Slots/ruby/README.md b/00_Alternate_Languages/80_Slots/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/80_Slots/ruby/slots.rb b/00_Alternate_Languages/80_Slots/ruby/slots.rb
new file mode 100644
index 00000000..1e6fc22d
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/ruby/slots.rb
@@ -0,0 +1,152 @@
+$pot = 0
+
+def greeting
+    puts "SLOTS".center(80)
+    puts "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".center(80)
+    puts "\n\n"
+
+    # PRODUCED BY FRED MIRABELLE AND BOB HARPER ON JAN 29, 1973
+    # IT SIMULATES THE SLOT MACHINE.
+
+    puts "You are in the H&M Casino, in front of one of our"
+    puts "one-arm bandits. You can bet from $1 to $100."
+    puts "To pull the arm, punch the return key after making your bet."
+    puts "\nBet zero to end the game."
+end
+
+def overLimit
+    puts "House Limit is $100"
+end
+
+def underMinimum
+    puts "Minimum Bet is $1"
+end
+
+# bells don't work on my machine. YMMV
+# I'm displaying dashes between the reels
+
+def tenBells
+    10.times do
+        # beep if you can
+        print "-"
+    end
+end
+
+def fiveBells
+    "-----"
+end
+
+def goodbye
+    puts "\n\n\n"
+    # end the game
+    exit
+end
+
+def payUp
+    puts "PAY UP!  PLEASE LEAVE YOUR MONEY ON THE TERMINAL."
+end
+
+def brokeEven
+    puts "HEY, YOU BROKE EVEN."
+end
+
+def collectWinnings
+    puts "COLLECT YOUR WINNINGS FROM THE H&M CASHIER."
+end
+
+def win winType, bet
+    case winType
+        when "jackpot"
+            winMessage = "***JACKPOT***"
+            winnings = 101
+        when "topDollar"
+            winMessage = "**TOP DOLLAR**"
+            winnings = 11
+        when "doubleBar"
+            winMessage = "*DOUBLE BAR!!*"
+            winnings = 6
+        when "double"
+            winMessage = "DOUBLE!!"
+            winnings = 3
+    end
+    puts "\nYou won: " + winMessage
+    $pot += (winnings * bet)
+end
+
+greeting
+
+#$pot = 0
+while true
+    reelArray = ["BAR","BELL","ORANGE","LEMON","PLUM","CHERRY"]
+    print "\nYOUR BET? "
+    # get input, remove leading and trailing whitespace, cast to integer
+    bet = gets.strip.to_i
+
+    if bet == 0 then
+        goodbye
+    elsif bet > 100 then
+        overLimit # error if more than $100
+    elsif bet < 1 then
+        underMinimum # have to bet at least a dollar
+    else
+        # valid bet, continue
+        tenBells # ding
+
+        # assign a random value from the array to each of the three reels
+        reel1 = reelArray[rand(5)]
+        reel2 = reelArray[rand(5)]
+        reel3 = reelArray[rand(5)]
+
+        # print the slot machine reels
+        puts "\n\n" + reel1 + fiveBells + reel2 + fiveBells + reel3
+
+        # see if we have a match in the first two reels
+        if reel1 == reel2 then
+            if reel2 == reel3 then
+                if reel3 == "BAR" then
+                    # all three reels are "BAR"
+                    win "jackpot", bet
+                 else
+                   # all three reels match but aren't "BAR"
+                   win "topDollar", bet
+                end
+            elsif reel2 == "BAR" then
+                # reels 1 and 2 are both "BAR"
+                win "doubleBar", bet
+             else
+                # reels 1 and 2 match but aren't "BAR"
+                win "double", bet
+            end
+        # otherwise see if there's a match in the remaining reels
+        elsif reel1 == reel3 or reel2 == reel3 then
+            if reel3 == "BAR" then
+                # two reels match, both "BAR"
+                win "doubleBar", bet
+            else
+                # two reels match, but not "BAR"
+                win "double", bet
+            end
+        else
+            # bad news - no matches
+            puts "\nYou lost"
+            # decrement your standings by the bet amount
+            $pot -= bet
+        end
+
+        puts "Your standings are: " + $pot.to_s
+        print "\nAgain? " # YES to continue
+        # get input, remove leading and trailing whitespace, make uppercase
+        again = gets.strip.upcase
+        if again != "Y" && again != "YES" then
+            # that's enough... evaluate the pot and quit
+            if $pot < 0 then
+                payUp
+            elsif $pot == 0 then
+                brokeEven
+            else # yay!
+                collectWinnings
+            end
+            goodbye
+        end
+    end
+end
diff --git a/00_Alternate_Languages/80_Slots/slots.bas b/00_Alternate_Languages/80_Slots/slots.bas
new file mode 100644
index 00000000..ef7ed841
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/slots.bas
@@ -0,0 +1,134 @@
+10 PRINT TAB(30);"SLOTS"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT: PRINT: PRINT
+100 REM PRODUCED BY FRED MIRABELLE AND BOB HARPER ON JAN 29, 1973
+110 REM IT SIMULATES THE SLOT MACHINE.
+120 PRINT "YOU ARE IN THE H&M CASINO,IN FRONT OF ONE OF OUR"
+130 PRINT "ONE-ARM BANDITS. BET FROM $1 TO $100."
+140 PRINT "TO PULL THE ARM, PUNCH THE RETURN KEY AFTER MAKING YOUR BET."
+150 LET P=0
+160 PRINT: PRINT"YOUR BET";
+170 INPUT M
+180 IF M>100 THEN 860
+190 IF M<1 THEN 880
+200 M=INT(M)
+210 GOSUB 1270
+220 PRINT
+230 LET X=INT(6*RND(1)+1)
+240 LET Y=INT(6*RND(1)+1)
+250 LET Z=INT(6*RND(1)+1)
+260 PRINT
+270 IF X=1 THEN 910
+280 IF X=2 THEN 930
+290 IF X=3 THEN 950
+300 IF X=4 THEN 970
+310 IF X=5 THEN 990
+320 IF X=6 THEN 1010
+330 IF Y=1 THEN 1030
+340 IF Y=2 THEN 1050
+350 IF Y=3 THEN 1070
+360 IF Y=4 THEN 1090
+370 IF Y=5 THEN 1110
+380 IF Y=6 THEN 1130
+390 IF Z=1 THEN 1150
+400 IF Z=2 THEN 1170
+410 IF Z=3 THEN 1190
+420 IF Z=4 THEN 1210
+430 IF Z=5 THEN 1230
+440 IF Z=6 THEN 1250
+450 IF X=Y THEN 600
+460 IF X=Z THEN 630
+470 IF Y=Z THEN 650
+480 PRINT
+490 PRINT "YOU LOST."
+500 LET P=P-M
+510 PRINT "YOUR STANDINGS ARE $"P
+520 PRINT "AGAIN";
+530 INPUT A$
+540 IF A$="Y" THEN 160
+550 PRINT
+560 IF P<0 THEN 670
+570 IF P=0 THEN 690
+580 IF P>0 THEN 710
+590 GOTO 1350
+600 IF Y=Z THEN 730
+610 IF Y=1 THEN 820
+620 GOTO 1341
+630 IF Z=1 THEN 820
+640 GOTO 470
+650 IF Z=1 THEN 820
+660 GOTO 1341
+670 PRINT "PAY UP!  PLEASE LEAVE YOUR MONEY ON THE TERMINAL."
+680 GOTO 1350
+690 PRINT"HEY, YOU BROKE EVEN."
+700 GOTO 1350
+710 PRINT "COLLECT YOUR WINNINGS FROM THE H&M CASHIER."
+720 GOTO 1350
+730 IF Z=1 THEN 780
+740 PRINT: PRINT"**TOP DOLLAR**"
+750 PRINT "YOU WON!"
+760 P=(((10*M)+M)+P)
+770 GOTO 510
+780 PRINT:PRINT"***JACKPOT***"
+790 PRINT "YOU WON!"
+800 P=(((100*M)+M)+P)
+810 GOTO 510
+820 PRINT:PRINT"*DOUBLE BAR*"
+830 PRINT"YOU WON!"
+840 P=(((5*M)+M)+P)
+850 GOTO 510
+860 PRINT"HOUSE LIMITS ARE $100"
+870 GOTO 160
+880 PRINT"MINIMUM BET IS $1"
+890 GOTO 160
+900 GOTO 220
+910 PRINT"BAR";:GOSUB 1310
+920 GOTO 330
+930 PRINT"BELL";:GOSUB 1310
+940 GOTO 330
+950 PRINT"ORANGE";:GOSUB 1310
+960 GOTO 330
+970 PRINT"LEMON";:GOSUB 1310
+980 GOTO 330
+990 PRINT"PLUM";:GOSUB 1310
+1000 GOTO 330
+1010 PRINT"CHERRY";:GOSUB 1310
+1020 GOTO 330
+1030 PRINT" BAR";:GOSUB 1310
+1040 GOTO 390
+1050 PRINT" BELL";:GOSUB 1310
+1060 GOTO 390
+1070 PRINT" ORANGE";:GOSUB 1310
+1080 GOTO 390
+1090 PRINT" LEMON";:GOSUB 1310
+1100 GOTO 390
+1110 PRINT" PLUM";:GOSUB 1310
+1120 GOTO 390
+1130 PRINT" CHERRY";:GOSUB 1310
+1140 GOTO 390
+1150 PRINT" BAR"
+1160 GOTO 450
+1170 PRINT" BELL"
+1180 GOTO 450
+1190 PRINT" ORANGE"
+1200 GOTO 450
+1210 PRINT" LEMON"
+1220 GOTO 450
+1230 PRINT" PLUM"
+1240 GOTO 450
+1250 PRINT" CHERRY"
+1260 GOTO 450
+1270 FOR Q4=1 TO 10
+1280 PRINT CHR$(7);
+1290 NEXT Q4
+1300 RETURN
+1310 FOR T8=1 TO 5
+1320 PRINT CHR$(7);
+1330 NEXT T8
+1340 RETURN
+1341 PRINT: PRINT "DOUBLE!!"
+1342 PRINT"YOU WON!"
+1343 P=(((2*M)+M)+P)
+1344 GOTO 510
+1350 STOP
+9999 END
diff --git a/00_Alternate_Languages/80_Slots/vbnet/README.md b/00_Alternate_Languages/80_Slots/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/80_Slots/vbnet/Slots.sln b/00_Alternate_Languages/80_Slots/vbnet/Slots.sln
new file mode 100644
index 00000000..1f493198
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/vbnet/Slots.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Slots", "Slots.vbproj", "{F64CB361-215F-4984-B154-304FF663A60C}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F64CB361-215F-4984-B154-304FF663A60C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F64CB361-215F-4984-B154-304FF663A60C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F64CB361-215F-4984-B154-304FF663A60C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F64CB361-215F-4984-B154-304FF663A60C}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/80_Slots/vbnet/Slots.vbproj b/00_Alternate_Languages/80_Slots/vbnet/Slots.vbproj
new file mode 100644
index 00000000..04f381a3
--- /dev/null
+++ b/00_Alternate_Languages/80_Slots/vbnet/Slots.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Slots
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/81_Splat/README.md b/00_Alternate_Languages/81_Splat/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/81_Splat/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/81_Splat/csharp/Program.cs b/00_Alternate_Languages/81_Splat/csharp/Program.cs
new file mode 100644
index 00000000..6ca973a4
--- /dev/null
+++ b/00_Alternate_Languages/81_Splat/csharp/Program.cs
@@ -0,0 +1,330 @@
+using System.Collections;
+using System.Text;
+
+namespace Splat
+{
+    class Splat
+    {
+        private ArrayList DistanceLog = new ArrayList();
+
+        private string[][] AccelerationData =
+        {
+            new string[] {"Fine. You're on Mercury. Acceleration={0} ft/sec/sec", "12.2"},
+            new string[] {"All right.  You're on Venus. Acceleration={0} ft/sec/sec", "28.3"},
+            new string[] {"Then you're on Earth. Acceleration={0} ft/sec/sec", "32.16"},
+            new string[] {"Fine. You're on the Moon. Acceleration={0} ft/sec/sec", "5.15"},
+            new string[] {"All right. You're on Mars. Acceleration={0} ft/sec/sec", "12.5"},
+            new string[] {"Then you're on Jupiter. Acceleration={0} ft/sec/sec", "85.2"},
+            new string[] {"Fine. You're on Saturn. Acceleration={0} ft/sec/sec", "37.6"},
+            new string[] {"All right. You're on Uranus. Acceleration={0} ft/sec/sec", "33.8"},
+            new string[] {"Then you're on Neptune. Acceleration={0} ft/sec/sec", "39.6"},
+            new string[] {"Fine. You're on the Sun. Acceleration={0} ft/sec/sec", "896"}
+        };
+
+        private void DisplayIntro()
+        {
+            Console.WriteLine("");
+            Console.WriteLine("SPLAT".PadLeft(23));
+            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine("");
+            Console.WriteLine("Welcome to 'Splat' -- the game that simulates a parachute");
+            Console.WriteLine("jump.  Try to open your chute at the last possible");
+            Console.WriteLine("moment without going splat.");
+            Console.WriteLine("");
+        }
+
+        private bool PromptYesNo(string Prompt)
+        {
+            bool Success = false;
+
+            while (!Success)
+            {
+                Console.Write(Prompt);
+                string LineInput = Console.ReadLine().Trim().ToLower();
+
+                if (LineInput.Equals("yes"))
+                    return true;
+                else if (LineInput.Equals("no"))
+                    return false;
+                else
+                    Console.WriteLine("Yes or No");
+            }
+
+            return false;
+        }
+
+        private void WriteRandomBadResult()
+        {
+           string[] BadResults = {"Requiescat in pace.","May the Angel of Heaven lead you into paradise.",
+                "Rest in peace.","Son-of-a-gun.","#$%&&%!$","A kick in the pants is a boost if you're headed right.",
+                "Hmmm. Should have picked a shorter time.","Mutter. Mutter. Mutter.","Pushing up daisies.",
+                "Easy come, easy go."};
+
+            Random rand = new Random();
+
+            Console.WriteLine(BadResults[rand.Next(BadResults.Length)]);
+        }
+
+        private void WriteColumnOutput(double Column1, double Column2)
+        {
+
+            Console.WriteLine("{0,-11:N3}    {1,-17:N2}", Column1, Column2);
+
+        }
+
+        private void WriteColumnOutput(double Column1, string Column2)
+        {
+
+            Console.WriteLine("{0,-11:N3}    {1,-17}", Column1, Column2);
+
+        }
+
+        private void WriteColumnOutput(string Column1, string Column2)
+        {
+
+            Console.WriteLine("{0,-11}    {1,-17}", Column1, Column2);
+
+        }
+
+        private void WriteSuccessfulResults(double Distance)
+        {
+            // Add new result
+            DistanceLog.Add(Distance);
+
+            // Sort by distance
+            DistanceLog.Sort();
+
+            int ArrayLength = DistanceLog.Count;
+
+            // If 1st, 2nd, or 3rd jump then write a special message
+            if (ArrayLength <= 3)
+            {
+                Console.Write("Amazing!!! Not bad for your ");
+                if (ArrayLength == 1)
+                    Console.Write("1st ");
+                else if (ArrayLength == 2)
+                    Console.Write("2nd ");
+                else
+                    Console.Write("3rd ");
+                Console.WriteLine("successful jump!!!");
+            }
+            // Otherwise write a message based on where this jump falls in the list
+            else
+            {
+                int JumpPosition = DistanceLog.IndexOf(Distance);
+
+
+                if (ArrayLength - JumpPosition <= .1 * ArrayLength)
+                {
+                    Console.WriteLine("Wow! That's some jumping. Of the {0} successful jumps", ArrayLength);
+                    Console.WriteLine("before yours, only {0} opened their chutes lower than", (ArrayLength - JumpPosition));
+                    Console.WriteLine("you did.");
+                }
+                else if (ArrayLength - JumpPosition <= .25 * ArrayLength)
+                {
+                    Console.WriteLine("Pretty good! {0} successful jumps preceded yours and only", ArrayLength - 1);
+                    Console.WriteLine("{0} of them got lower than you did before their chutes", (ArrayLength - 1 - JumpPosition));
+                    Console.WriteLine("opened.");
+                }
+                else if (ArrayLength - JumpPosition <= .5 * ArrayLength)
+                {
+                    Console.WriteLine("Not bad. There have been  {0} successful jumps before yours.", ArrayLength - 1);
+                    Console.WriteLine("You were beaten out by {0} of them.", (ArrayLength - 1 - JumpPosition));
+                }
+                else if (ArrayLength - JumpPosition <= .75 * ArrayLength)
+                {
+                    Console.WriteLine("Conservative aren't you? You ranked only {0} in the", (ArrayLength - JumpPosition));
+                    Console.WriteLine("{0} successful jumps before yours.", ArrayLength - 1);
+                }
+                else if (ArrayLength - JumpPosition <= .9 * ArrayLength)
+                {
+                    Console.WriteLine("Humph! Don't you have any sporting blood? There were");
+                    Console.WriteLine("{0} successful jumps before yours and you came in {1} jumps", ArrayLength - 1, JumpPosition);
+                    Console.WriteLine("better than the worst. Shape up!!!");
+                }
+                else
+                {
+                    Console.WriteLine("Hey! You pulled the rip cord much too soon. {0} successful", ArrayLength - 1);
+                    Console.WriteLine("jumps before yours and you came in number {0}! Get with it!", (ArrayLength - JumpPosition));
+                }
+            }
+
+        }
+
+        private void PlayOneRound()
+        {
+            bool InputSuccess = false;
+            Random rand = new Random();
+            double Velocity = 0;
+            double TerminalVelocity = 0;
+            double Acceleration = 0;
+            double AccelerationInput = 0;
+            double Altitude = ((9001 * rand.NextDouble()) + 1000);
+            double SecondsTimer = 0;
+            double Distance = 0;
+            bool TerminalVelocityReached = false;
+
+            Console.WriteLine("");
+
+            // Determine the terminal velocity (user or system)
+            if (PromptYesNo("Select your own terminal velocity (yes or no)? "))
+            {
+                // Prompt user to enter the terminal velocity of their choice
+                while (!InputSuccess)
+                {
+                    Console.Write("What terminal velocity (mi/hr)? ");
+                    string Input = Console.ReadLine().Trim();
+                    InputSuccess = double.TryParse(Input, out TerminalVelocity);
+                    if (!InputSuccess)
+                        Console.WriteLine("*** Please enter a valid number ***");
+                 }
+            }
+            else
+            {
+                TerminalVelocity = rand.NextDouble() * 1000;
+                Console.WriteLine("OK.  Terminal Velocity = {0:N0} mi/hr", (TerminalVelocity));
+            }
+
+            // Convert Terminal Velocity to ft/sec
+            TerminalVelocity = TerminalVelocity * 5280 / 3600;
+
+            // Not sure what this calculation is
+            Velocity = TerminalVelocity + ((TerminalVelocity * rand.NextDouble()) / 20) - ((TerminalVelocity * rand.NextDouble()) / 20);
+
+            // Determine acceleration due to gravity (user or system)
+            if (PromptYesNo("Want to select acceleration due to gravity (yes or no)? "))
+            {
+                 // Prompt user to enter the acceleration of their choice
+                InputSuccess = false;
+                while (!InputSuccess)
+                {
+                    Console.Write("What acceleration (ft/sec/sec)? ");
+                    string Input = Console.ReadLine().Trim();
+                    InputSuccess = double.TryParse(Input, out AccelerationInput);
+                    if (!InputSuccess)
+                        Console.WriteLine("*** Please enter a valid number ***");
+                 }
+            }
+            else
+            {
+                // Choose a random acceleration entry from the data array
+                int Index = rand.Next(0, AccelerationData.Length);
+                Double.TryParse(AccelerationData[Index][1], out AccelerationInput);
+
+                // Display the corresponding planet this acceleration exists on and the value
+                Console.WriteLine(AccelerationData[Index][0], AccelerationInput.ToString());
+            }
+
+            Acceleration = AccelerationInput + ((AccelerationInput * rand.NextDouble()) / 20) - ((AccelerationInput * rand.NextDouble()) / 20);
+
+            Console.WriteLine("");
+            Console.WriteLine("    Altitude         = {0:N0} ft", Altitude);
+            Console.WriteLine("    Term. Velocity   = {0:N3} ft/sec +/-5%", TerminalVelocity);
+            Console.WriteLine("    Acceleration     = {0:N2} ft/sec/sec +/-5%", AccelerationInput);
+            Console.WriteLine("Set the timer for your freefall.");
+
+            // Prompt for how many seconds the fall should be before opening the chute
+            InputSuccess = false;
+            while (!InputSuccess)
+            {
+                Console.Write("How many seconds? ");
+                string Input = Console.ReadLine().Trim();
+                InputSuccess = double.TryParse(Input, out SecondsTimer);
+                if (!InputSuccess)
+                    Console.WriteLine("*** Please enter a valid number ***");
+            }
+
+            // Begin the drop!
+            Console.WriteLine("Here we go.");
+            Console.WriteLine("");
+
+            WriteColumnOutput("Time (sec)", "Dist to Fall (ft)");
+            WriteColumnOutput("==========", "=================");
+
+            // Loop through the number of seconds stepping by 8 intervals
+            for (double i = 0; i < SecondsTimer; i+=(SecondsTimer/8))
+            {
+                if (i > (Velocity / Acceleration))
+                {
+                    // Terminal Velocity achieved.  Only print out the warning once.
+                    if (TerminalVelocityReached == false)
+                        Console.WriteLine("Terminal velocity reached at T plus {0:N4} seconds.", (Velocity / Acceleration));
+
+                    TerminalVelocityReached = true;
+                }
+
+                // Calculate distance dependent upon whether terminal velocity has been reached
+                if (TerminalVelocityReached)
+                {
+                    Distance = Altitude - ((Math.Pow(Velocity,2) / (2 * Acceleration)) + (Velocity * (i - (Velocity / Acceleration))));
+                }
+                else
+                {
+                    Distance = Altitude - ((Acceleration / 2) * Math.Pow(i,2));
+                }
+
+                // Was the ground hit?  If so, then SPLAT!
+                if (Distance <= 0)
+                {
+                    if (TerminalVelocityReached)
+                    {
+                        WriteColumnOutput((Velocity / Acceleration) + ((Altitude - (Math.Pow(Velocity,2) / (2 * Acceleration))) / Velocity).ToString(), "SPLAT");
+                    }
+                    else
+                    {
+                        WriteColumnOutput(Math.Sqrt(2 * Altitude / Acceleration), "SPLAT");
+                    }
+
+                    WriteRandomBadResult();
+
+                    Console.WriteLine("I'll give you another chance.");
+                    break;
+                }
+                else
+                {
+                    WriteColumnOutput(i, Distance);
+                }
+            }
+
+            // If the number of seconds of drop ended and we are still above ground then success!
+            if (Distance > 0)
+            {
+                // We made it!  Chutes open!
+                Console.WriteLine("Chute Open");
+
+                // Store succesful jump and write out a fun message
+                WriteSuccessfulResults(Distance);
+            }
+
+        }
+
+        public void PlayTheGame()
+        {
+            bool ContinuePlay = false;
+
+            DisplayIntro();
+
+            do
+            {
+                PlayOneRound();
+
+                ContinuePlay = PromptYesNo("Do you want to play again? ");
+                if (!ContinuePlay)
+                    ContinuePlay = PromptYesNo("Please? ");
+            }
+            while (ContinuePlay);
+
+            Console.WriteLine("SSSSSSSSSS.");
+
+        }
+    }
+    class Program
+    {
+        static void Main(string[] args)
+        {
+
+            new Splat().PlayTheGame();
+
+        }
+    }
+}
diff --git a/00_Alternate_Languages/81_Splat/csharp/README.md b/00_Alternate_Languages/81_Splat/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/81_Splat/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/81_Splat/csharp/Splat.csproj b/00_Alternate_Languages/81_Splat/csharp/Splat.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/81_Splat/csharp/Splat.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/81_Splat/csharp/Splat.sln b/00_Alternate_Languages/81_Splat/csharp/Splat.sln
new file mode 100644
index 00000000..d7184859
--- /dev/null
+++ b/00_Alternate_Languages/81_Splat/csharp/Splat.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Splat", "Splat.csproj", "{95640CEE-A1A6-4824-A2C7-CF72CADA40FB}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{95640CEE-A1A6-4824-A2C7-CF72CADA40FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{95640CEE-A1A6-4824-A2C7-CF72CADA40FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{95640CEE-A1A6-4824-A2C7-CF72CADA40FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{95640CEE-A1A6-4824-A2C7-CF72CADA40FB}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/81_Splat/java/README.md b/00_Alternate_Languages/81_Splat/java/README.md
new file mode 100644
index 00000000..b8998fa6
--- /dev/null
+++ b/00_Alternate_Languages/81_Splat/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/81_Splat/java/src/Splat.java b/00_Alternate_Languages/81_Splat/java/src/Splat.java
new file mode 100644
index 00000000..e28a2bb8
--- /dev/null
+++ b/00_Alternate_Languages/81_Splat/java/src/Splat.java
@@ -0,0 +1,357 @@
+import java.util.*;
+
+/**
+ * SPLAT simulates a parachute jump in which you try to open your parachute at the last possible moment without going
+ * splat! You may select your own terminal velocity or let the computer do it for you. You many also select the
+ * acceleration due to gravity or, again, let the computer do it in which case you might wind up on any of eight
+ * planets (out to Neptune), the moon, or the sun.
+ * 

+ * The computer then tells you the height you’re jumping from and asks for the seconds of free fall. It then divides + * your free fall time into eight intervals and gives you progress reports on your way down. The computer also keeps + * track of all prior jumps in the array A and lets you know how you compared with previous successful jumps. If you + * want to recall information from previous runs, then you should store array A in a disk or take file and read it + * before each run. + *

+ * John Yegge created this program while at the Oak Ridge Associated Universities. + *

+ * Ported from BASIC by jason plumb (@breedx2) + *

+ */ +public class Splat { + private static final Random random = new Random(); + private final Scanner scanner = new Scanner(System.in); + private final List pastSuccessfulJumpDistances = new ArrayList<>(); + + public static void main(String[] args) { + new Splat().run(); + } + + public void run() { + showIntroduction(); + + while (true) { + + InitialJumpConditions initial = buildInitialConditions(); + + System.out.println(); + System.out.printf(" ALTITUDE = %d FT\n", initial.getAltitude()); + System.out.printf(" TERM. VELOCITY = %.2f FT/SEC +/-5%%\n", initial.getOriginalTerminalVelocity()); + System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", initial.getOriginalAcceleration()); + + System.out.println("SET THE TIMER FOR YOUR FREEFALL."); + float freefallTime = promptFloat("HOW MANY SECONDS "); + System.out.println("HERE WE GO.\n"); + System.out.println("TIME (SEC) DIST TO FALL (FT)"); + System.out.println("========== ================="); + + JumpResult jump = executeJump(initial, freefallTime); + showJumpResults(initial, jump); + + if (!playAgain()) { + System.out.println("SSSSSSSSSS."); + return; + } + } + } + + private void showIntroduction() { + System.out.printf("%33s%s\n", " ", "SPLAT"); + System.out.printf("%15s%s\n", " ", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.print("\n\n\n"); + System.out.println("WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE"); + System.out.println("JUMP. TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE"); + System.out.println("MOMENT WITHOUT GOING SPLAT."); + } + + private InitialJumpConditions buildInitialConditions() { + System.out.print("\n\n"); + float terminalVelocity = promptTerminalVelocity(); + float acceleration = promptGravitationalAcceleration(); + return InitialJumpConditions.create(terminalVelocity, acceleration); + } + + private float promptTerminalVelocity() { + if (askYesNo("SELECT YOUR OWN TERMINAL VELOCITY")) { + float terminalVelocity = promptFloat("WHAT TERMINAL VELOCITY (MI/HR) "); + return mphToFeetPerSec(terminalVelocity); + } + float terminalVelocity = (int) (1000 * random.nextFloat()); + System.out.printf("OK. TERMINAL VELOCITY = %.2f MI/HR\n", terminalVelocity); + return mphToFeetPerSec(terminalVelocity); + } + + private float promptFloat(String prompt){ + while(true){ + System.out.print(prompt); + try { + return scanner.nextFloat(); + } catch (Exception e) { + scanner.next(); // clear current input + } + } + } + + private float promptGravitationalAcceleration() { + if (askYesNo("WANT TO SELECT ACCELERATION DUE TO GRAVITY")) { + return promptFloat("WHAT ACCELERATION (FT/SEC/SEC) "); + } + return chooseRandomAcceleration(); + } + + private JumpResult executeJump(InitialJumpConditions initial, float chuteOpenTime) { + JumpResult jump = new JumpResult(initial.getAltitude()); + for (float time = 0.0f; time < chuteOpenTime; time += chuteOpenTime / 8) { + if (!jump.hasReachedTerminalVelocity() && time > initial.getTimeOfTerminalAccelerationReached()) { + jump.setReachedTerminalVelocity(); + System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", initial.getTimeOfTerminalAccelerationReached()); + } + float newDistance = computeDistance(initial, time, jump.hasReachedTerminalVelocity()); + jump.setDistance(newDistance); + + if (jump.isSplat()) { + return jump; + } + System.out.printf("%10.2f %f\n", time, jump.getDistance()); + } + return jump; + } + + private float computeDistance(InitialJumpConditions initial, float i, boolean hasReachedTerminalVelocity) { + final float V = initial.getTerminalVelocity(); + final float A = initial.getAcceleration(); + if (hasReachedTerminalVelocity) { + return initial.getAltitude() - ((V * V / (2 * A)) + (V * (i - (V / A)))); + } + return initial.getAltitude() - ((A / 2) * i * i); + } + + private void showJumpResults(InitialJumpConditions initial, JumpResult jump) { + if (jump.isSplat()) { + showSplatMessage(initial, jump); + showCleverSplatMessage(); + return; + } + System.out.println("CHUTE OPEN"); + int worseJumpCount = countWorseHistoricalJumps(jump); + int successfulJumpCt = pastSuccessfulJumpDistances.size(); + pastSuccessfulJumpDistances.add(jump.getDistance()); + + if (pastSuccessfulJumpDistances.size() <= 2) { + List ordinals = Arrays.asList("1ST", "2ND", "3RD"); + System.out.printf("AMAZING!!! NOT BAD FOR YOUR %s SUCCESSFUL JUMP!!!\n", ordinals.get(successfulJumpCt)); + return; + } + + int betterThanCount = successfulJumpCt - worseJumpCount; + if (betterThanCount <= 0.1 * successfulJumpCt) { + System.out.printf("WOW! THAT'S SOME JUMPING. OF THE %d SUCCESSFUL JUMPS\n", successfulJumpCt); + System.out.printf("BEFORE YOURS, ONLY %d OPENED THEIR CHUTES LOWER THAN\n", betterThanCount); + System.out.println("YOU DID."); + } else if (betterThanCount <= 0.25 * successfulJumpCt) { + System.out.printf("PRETTY GOOD! %d SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\n", successfulJumpCt); + System.out.printf("%d OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\n", betterThanCount); + System.out.println("OPENED."); + } else if (betterThanCount <= 0.5 * successfulJumpCt) { + System.out.printf("NOT BAD. THERE HAVE BEEN %d SUCCESSFUL JUMPS BEFORE YOURS.\n", successfulJumpCt); + System.out.printf("YOU WERE BEATEN OUT BY %d OF THEM.\n", betterThanCount); + } else if (betterThanCount <= 0.75 * successfulJumpCt) { + System.out.printf("CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY %d IN THE\n", betterThanCount); + System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS.\n", successfulJumpCt); + } else if (betterThanCount <= -0.9 * successfulJumpCt) { + System.out.println("HUMPH! DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE"); + System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN %d JUMPS\n", successfulJumpCt, worseJumpCount); + System.out.println("BETTER THAN THE WORST. SHAPE UP!!!\n"); + } else { + System.out.printf("HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. %d SUCCESSFUL\n", successfulJumpCt); + System.out.printf("JUMPS BEFORE YOURS AND YOU CAME IN NUMBER %d! GET WITH IT!\n", betterThanCount); + } + } + + private void showSplatMessage(InitialJumpConditions initial, JumpResult jump) { + double timeOfSplat = computeTimeOfSplat(initial, jump); + System.out.printf("%10.2f SPLAT\n", timeOfSplat); + } + + /** + * Returns the number of jumps for which this jump was better + */ + private double computeTimeOfSplat(InitialJumpConditions initial, JumpResult jump) { + final float V = initial.getTerminalVelocity(); + final float A = initial.getAcceleration(); + if (jump.hasReachedTerminalVelocity()) { + return (V / A) + ((initial.getAltitude() - (V * V / (2 * A))) / V); + } + return Math.sqrt(2 * initial.getAltitude() / A); + } + + private int countWorseHistoricalJumps(JumpResult jump) { + return (int) pastSuccessfulJumpDistances.stream() + .filter(distance -> jump.getDistance() < distance) + .count(); + } + + private void showCleverSplatMessage() { + List messages = Arrays.asList( + "REQUIESCAT IN PACE.", + "MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.", + "REST IN PEACE.", + "SON-OF-A-GUN.", + "#$%&&%!$", + "A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.", + "HMMM. SHOULD HAVE PICKED A SHORTER TIME.", + "MUTTER. MUTTER. MUTTER.", + "PUSHING UP DAISIES.", + "EASY COME, EASY GO." + ); + System.out.println(messages.get(random.nextInt(10))); + } + + private boolean playAgain() { + if (askYesNo("DO YOU WANT TO PLAY AGAIN ")) { + return true; + } + return askYesNo("PLEASE"); + } + + private float mphToFeetPerSec(float speed) { + return speed * (5280.0f / 3600.0f); + } + + private boolean askYesNo(String prompt) { + System.out.printf("%s (YES OR NO) ", prompt); + while (true) { + String answer = scanner.next(); + switch (answer) { + case "YES": + return true; + case "NO": + return false; + default: + System.out.print("YES OR NO "); + } + } + } + + private float chooseRandomAcceleration() { + Planet planet = Planet.pickRandom(); + System.out.printf("%s %s. ACCELERATION=%.2f FT/SEC/SEC.\n", planet.getMessage(), planet.name(), planet.getAcceleration()); + return planet.getAcceleration(); + } + + enum Planet { + MERCURY("FINE. YOU'RE ON", 12.2f), + VENUS("ALL RIGHT. YOU'RE ON", 28.3f), + EARTH("THEN YOU'RE ON", 32.16f), + MOON("FINE. YOU'RE ON THE", 5.15f), + MARS("ALL RIGHT. YOU'RE ON", 12.5f), + JUPITER("THEN YOU'RE ON", 85.2f), + SATURN("FINE. YOU'RE ON", 37.6f), + URANUS("ALL RIGHT. YOU'RE ON", 33.8f), + NEPTUNE("THEN YOU'RE ON", 39.6f), + SUN("FINE. YOU'RE ON THE", 896.0f); + + private static final Random random = new Random(); + private final String message; + private final float acceleration; + + Planet(String message, float acceleration) { + this.message = message; + this.acceleration = acceleration; + } + + static Planet pickRandom() { + return values()[random.nextInt(Planet.values().length)]; + } + + String getMessage() { + return message; + } + + float getAcceleration() { + return acceleration; + } + } + + // Mutable + static class JumpResult { + private boolean reachedTerminalVelocity = false; + private float distance; // from the ground + + public JumpResult(float distance) { + this.distance = distance; + } + + boolean isSplat() { + return distance <= 0; + } + + boolean hasReachedTerminalVelocity() { + return reachedTerminalVelocity; + } + + float getDistance() { + return distance; + } + + void setDistance(float distance) { + this.distance = distance; + } + + void setReachedTerminalVelocity() { + reachedTerminalVelocity = true; + } + } + + // Immutable + static class InitialJumpConditions { + private final float originalTerminalVelocity; + private final float originalAcceleration; + private final float terminalVelocity; + private final float acceleration; + private final int altitude; + + private InitialJumpConditions(float originalTerminalVelocity, float originalAcceleration, + float terminalVelocity, float acceleration, int altitude) { + this.originalTerminalVelocity = originalTerminalVelocity; + this.originalAcceleration = originalAcceleration; + this.terminalVelocity = terminalVelocity; + this.acceleration = acceleration; + this.altitude = altitude; + } + + // Create initial jump conditions with adjusted velocity/acceleration and a random initial altitude + private static InitialJumpConditions create(float terminalVelocity, float gravitationalAcceleration) { + final int altitude = (int) (9001.0f * random.nextFloat() + 1000); + return new InitialJumpConditions(terminalVelocity, gravitationalAcceleration, + plusMinus5Percent(terminalVelocity), plusMinus5Percent(gravitationalAcceleration), altitude); + } + + private static float plusMinus5Percent(float value) { + return value + ((value * random.nextFloat()) / 20.0f) - ((value * random.nextFloat()) / 20.0f); + } + + float getOriginalTerminalVelocity() { + return originalTerminalVelocity; + } + + float getOriginalAcceleration() { + return originalAcceleration; + } + + float getTerminalVelocity() { + return terminalVelocity; + } + + float getAcceleration() { + return acceleration; + } + + int getAltitude() { + return altitude; + } + + float getTimeOfTerminalAccelerationReached() { + return terminalVelocity / acceleration; + } + } +} diff --git a/00_Alternate_Languages/81_Splat/javascript/README.md b/00_Alternate_Languages/81_Splat/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/81_Splat/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/81_Splat/javascript/splat.html b/00_Alternate_Languages/81_Splat/javascript/splat.html new file mode 100644 index 00000000..19503973 --- /dev/null +++ b/00_Alternate_Languages/81_Splat/javascript/splat.html @@ -0,0 +1,9 @@ + + +SPLAT + + +

+
+
+
diff --git a/00_Alternate_Languages/81_Splat/javascript/splat.js b/00_Alternate_Languages/81_Splat/javascript/splat.js
new file mode 100644
index 00000000..8b51786b
--- /dev/null
+++ b/00_Alternate_Languages/81_Splat/javascript/splat.js
@@ -0,0 +1,283 @@
+// SPLAT
+//
+// 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 aa = [];
+
+// Main program
+async function main()
+{
+    print(tab(33) + "SPLAT\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    for (i = 0; i <= 42; i++)
+        aa[i] = 0;
+    print("WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE\n");
+    print("JUMP.  TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE\n");
+    print("MOMENT WITHOUT GOING SPLAT.\n");
+    while (1) {
+        print("\n");
+        print("\n");
+        d1 = 0;
+        v = 0;
+        a = 0;
+        n = 0;
+        m = 0;
+        d1 = Math.floor(9001 * Math.random() + 1000);
+        print("SELECT YOUR OWN TERMINAL VELOCITY (YES OR NO)");
+        while (1) {
+            a1s = await input();
+            if (a1s == "YES" || a1s == "NO")
+                break;
+            print("YES OR NO");
+        }
+        if (a1s == "YES") {
+            print("WHAT TERMINAL VELOCITY (MI/HR)");
+            v1 = parseFloat(await input());
+            v1 = v1 * (5280 / 3600);
+        } else {
+            v1 = Math.floor(1000 * Math.random());
+            print("OK.  TERMINAL VELOCITY = " + v1 + " MI/HR\n");
+        }
+        v = v1 + ((v1 * Math.random()) / 20) - ((v1 * Math.random()) / 20);
+        print("WANT TO SELECT ACCELERATION DUE TO GRAVITY (YES OR NO)");
+        while (1) {
+            b1s = await input();
+            if (b1s == "YES" || b1s == "NO")
+                break;
+            print("YES OR NO");
+        }
+        if (b1s == "YES") {
+            print("WHAT ACCELERATION (FT/SEC/SEC)");
+            a2 = parseFloat(await input());
+        } else {
+            switch (Math.floor(1 + (10 * Math.random()))) {
+                case 1:
+                    print("FINE. YOU'RE ON MERCURY. ACCELERATION=12.2 FT/SEC/SEC.\n");
+                    a2 = 12.2;
+                    break;
+                case 2:
+                    print("ALL RIGHT. YOU'RE ON VENUS. ACCELERATION=28.3 FT/SEC/SEC.\n");
+                    a2 = 28.3;
+                    break;
+                case 3:
+                    print("THEN YOU'RE ON EARTH. ACCELERATION=32.16 FT/SEC/SEC.\n");
+                    a2 = 32.16;
+                    break;
+                case 4:
+                    print("FINE. YOU'RE ON THE MOON. ACCELERATION=5.15 FT/SEC/SEC.\n");
+                    a2 = 5.15;
+                    break;
+                case 5:
+                    print("ALL RIGHT. YOU'RE ON MARS. ACCELERATION=12.5 FT/SEC/SEC.\n");
+                    a2 = 12.5;
+                    break;
+                case 6:
+                    print("THEN YOU'RE ON JUPITER. ACCELERATION=85.2 FT/SEC/SEC.\n");
+                    a2 = 85.2;
+                    break;
+                case 7:
+                    print("FINE. YOU'RE ON SATURN. ACCELERATION=37.6 FT/SEC/SEC.\n");
+                    a2 = 37.6;
+                    break;
+                case 8:
+                    print("ALL RIGHT. YOU'RE ON URANUS. ACCELERATION=33.8 FT/SEC/SEC.\n");
+                    a2 = 33.8;
+                    break;
+                case 9:
+                    print("THEN YOU'RE ON NEPTUNE. ACCELERATION=39.6 FT/SEC/SEC.\n");
+                    a2 = 39.6;
+                    break;
+                case 10:
+                    print("FINE. YOU'RE ON THE SUN. ACCELERATION=896 FT/SEC/SEC.\n");
+                    a2 = 896;
+                    break;
+            }
+        }
+        a = a2 + ((a2 * Math.random()) / 20) - ((a2 * Math.random()) / 20);
+        print("\n");
+        print("    ALTITUDE         = " + d1 + " FT\n");
+        print("    TERM. VELOCITY   = " + v1 + " FT/SEC +/-5%\n");
+        print("    ACCELERATION     = " + a2 + " FT/SEC/SEC +/-5%\n");
+        print("SET THE TIMER FOR YOUR FREEFALL.\n");
+        print("HOW MANY SECONDS");
+        t = parseFloat(await input());
+        print("HERE WE GO.\n");
+        print("\n");
+        print("TIME (SEC)\tDIST TO FALL (FT)\n");
+        print("==========\t=================\n");
+        terminal = false;
+        crash = false;
+        for (i = 0; i <= t; i += t / 8) {
+            if (i > v / a) {
+                terminal = true;
+                break;
+            }
+            d = d1 - ((a / 2) * Math.pow(i, 2));
+            if (d <= 0) {
+                print(Math.sqrt(2 * d1 / a) + "\tSPLAT\n");
+                crash = true;
+                break;
+            }
+            print(i + "\t" + d + "\n");
+        }
+        if (terminal) {
+            print("TERMINAL VELOCITY REACHED AT T PLUS " + v/a + " SECONDS.\n");
+            for (; i <= t; i += t / 8) {
+                d = d1 - ((Math.pow(v, 2) / (2 * a)) + (v * (i - (v / a))));
+                if (d <= 0) {
+                    print(((v / a) + ((d1 - (Math.pow(v, 2) / (2 * a))) / v)) + "\tSPLAT\n");
+                    crash = true;
+                    break;
+                }
+                print(i + "\t" + d + "\n");
+            }
+        }
+        if (!crash) {
+            print("CHUTE OPEN\n");
+            k = 0;
+            k1 = 0;
+            for (j = 0; j <= 42; j++) {
+                if (aa[j] == 0)
+                    break;
+                k++;
+                if (d < aa[j])
+                    k1++;
+            }
+            // In original jumps to line 540 (undefined) when table is full
+            aa[j] = d;
+            if (j <= 2) {
+                print("AMAZING!!! NOT BAD FOR YOUR ");
+                if (j == 0)
+                    print("1ST ");
+                else if (j == 1)
+                    print("2ND ");
+                else
+                    print("3RD ");
+                print("SUCCESSFUL JUMP!!!\n");
+            } else {
+                if (k - k1 <= 0.1 * k) {
+                    print("WOW!  THAT'S SOME JUMPING.  OF THE " + k + " SUCCESSFUL JUMPS\n");
+                    print("BEFORE YOURS, ONLY " + (k - k1) + " OPENED THEIR CHUTES LOWER THAN\n");
+                    print("YOU DID.\n");
+                } else if (k - k1 <= 0.25 * k) {
+                    print("PRETTY GOOD! " + k + " SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\n");
+                    print((k - k1) + " OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\n");
+                    print("OPENED.\n");
+                } else if (k - k1 <= 0.5 * k) {
+                    print("NOT BAD.  THERE HAVE BEEN " + k + " SUCCESSFUL JUMPS BEFORE YOURS.\n");
+                    print("YOU WERE BEATEN OUT BY " + (k - k1) + " OF THEM.\n");
+                } else if (k - k1 <= 0.75 * k) {
+                    print("CONSERVATIVE, AREN'T YOU?  YOU RANKED ONLY " + (k - k1) + " IN THE\n");
+                    print(k + " SUCCESSFUL JUMPS BEFORE YOURS.\n");
+                } else if (k - k1 <= 0.9 * k) {
+                    print("HUMPH!  DON'T YOU HAVE ANY SPORTING BLOOD?  THERE WERE\n");
+                    print(k + " SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN " + k1 + "JUMPS\n");
+                    print("BETTER THAN THE WORST.  SHAPE UP!!!\n");
+                } else {
+                    print("HEY!  YOU PULLED THE RIP CORD MUCH TOO SOON.  " + k + " SUCCESSFUL\n");
+                    print("JUMPS BEFORE YOURS AND YOU CAME IN NUMBER " + (k - k1) + "!  GET WITH IT!\n");
+                }
+            }
+        } else {
+            switch (Math.floor(1 + 10 * Math.random())) {
+                case 1:
+                    print("REQUIESCAT IN PACE.\n");
+                    break;
+                case 2:
+                    print("MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.\n");
+                    break;
+                case 3:
+                    print("REST IN PEACE.\n");
+                    break;
+                case 4:
+                    print("SON-OF-A-GUN.\n");
+                    break;
+                case 5:
+                    print("#%&&%!$\n");
+                    break;
+                case 6:
+                    print("A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.\n");
+                    break;
+                case 7:
+                    print("HMMM. SHOULD HAVE PICKED A SHORTER TIME.\n");
+                    break;
+                case 8:
+                    print("MUTTER. MUTTER. MUTTER.\n");
+                    break;
+                case 9:
+                    print("PUSHING UP DAISIES.\n");
+                    break;
+                case 10:
+                    print("EASY COME, EASY GO.\n");
+                    break;
+            }
+            print("I'LL GIVE YOU ANOTHER CHANCE.\n");
+        }
+        while (1) {
+            print("DO YOU WANT TO PLAY AGAIN");
+            str = await input();
+            if (str == "YES" || str == "NO")
+                break;
+            print("YES OR NO\n");
+        }
+        if (str == "YES")
+            continue;
+        print("PLEASE");
+        while (1) {
+            str = await input();
+            if (str == "YES" || str == "NO")
+                break;
+            print("YES OR NO");
+        }
+        if (str == "YES")
+            continue;
+        break;
+    }
+    print("SSSSSSSSSS.\n");
+    print("\n");
+}
+
+main();
diff --git a/56_Life_for_Two/pascal/README.md b/00_Alternate_Languages/81_Splat/pascal/README.md
similarity index 100%
rename from 56_Life_for_Two/pascal/README.md
rename to 00_Alternate_Languages/81_Splat/pascal/README.md
diff --git a/00_Alternate_Languages/81_Splat/perl/README.md b/00_Alternate_Languages/81_Splat/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/81_Splat/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/81_Splat/perl/splat.pl b/00_Alternate_Languages/81_Splat/perl/splat.pl
new file mode 100644
index 00000000..6114e7fc
--- /dev/null
+++ b/00_Alternate_Languages/81_Splat/perl/splat.pl
@@ -0,0 +1,336 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'state' and 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use List::Util qw{ shuffle };   # Shuffle an array.
+use Scalar::Util qw{ looks_like_number };
+use Term::ReadLine;     # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+use constant ROW_TPLT => ( '%4d' x 8 ) . "\n";
+
+print <<'EOD';
+                                 SPLAT
+               Creative Computing  Morristown, New Jersey
+
+
+
+Welcome to 'Splat' -- the game that simulates a parachute
+jump.  Try to open your chute at the last possible
+moment without going splat.
+EOD
+
+while ( 1 ) {
+    say '';
+    my $initial_altitude = int( 9001 * rand() + 1000 );
+
+    my $nominal_terminal_velocity;
+    if ( get_yes_no( 'Select your own terminal velocity' ) ) {
+        $nominal_terminal_velocity = get_input(
+            'What terminal velocity (mi/hr)? ',
+            sub { looks_like_number( $ARG ) && $ARG > 0 },
+            'Please enter a positive number',
+        );
+        # Convert miles per hour to feet per second
+        $nominal_terminal_velocity = $nominal_terminal_velocity * 5280 / 3600;
+    } else {
+        $nominal_terminal_velocity = int( 1000 * rand() );
+        say "OK.  Terminal velocity = $nominal_terminal_velocity mi/hr"
+    }
+    my $terminal_velocity = dither( $nominal_terminal_velocity );
+
+    my $nominal_gravity; # Acceleration due to gravity
+    if ( get_yes_no( 'Want to select acceleration due to gravity' ) ) {
+    } else {
+        state $body = [
+            [ q,
+                12.2 ],
+            [ q,
+                28.3 ],
+            [ q,
+                32.16 ],
+            [ q,
+                5.15 ],
+            [ q,
+                12.5 ],
+            [ q,
+                85.2 ],
+            [ q,
+                37.6 ],
+            [ q,
+                33.8  ],
+            [ q,
+                39.6 ],
+            [ q,
+                896 ],
+        ];
+        my $pick = $body->[ rand scalar @{ $body } ];
+        say $pick->[0];
+        $nominal_gravity = $pick->[1];
+    }
+    my $gravity = dither( $nominal_gravity );
+
+    print <<"EOD";
+
+    Altitude        = $initial_altitude ft
+    Term. velocity  = $nominal_terminal_velocity ft/sec +/- 5%
+    Acceleration    = $nominal_gravity ft/sec/sec +/- 5%
+Set the timer for your freefall
+EOD
+
+    my $drop_time = get_input(
+        'How many seconds? ',
+        sub { m/ \A [0-9]+ \z /smx },
+        "Please enter an unsigned integer\n",
+    );
+
+    print <<'EOD';
+Here we go.
+
+Time (sec)      Dist to fall (ft)
+==========      =================
+EOD
+
+    if ( defined( my $altitude = make_jump(
+                $initial_altitude,
+                $gravity,
+                $terminal_velocity,
+                $drop_time ) )
+    ) {
+        # Successful jump
+        state $succesful = [];
+        state $ordinal = [ qw{ 1st 2nd 3rd } ];
+        if ( defined( my $ord = $ordinal->[ @{ $succesful } ] ) ) {
+            say "Amazing!!! Not nad for your $ord successful jump!!!";
+        } else {
+            my $jumps = @{ $succesful };
+            my $worse = grep { $_ > $altitude } @{ $succesful };
+            my $fractile = 1 - $worse / $jumps;
+            my $better = $jumps - $worse;
+            if ( $fractile <= 0.1 ) {
+                print <<"EOD";
+Wow!  That's some jumping.  Of the $jumps successful jumps
+before yours, only $better opened their chutes lower than
+you did.
+EOD
+            } elsif ( $fractile <= 0.25 ) {
+                print <<"EOD";
+Pretty good! $jumps successful jumps preceded yours and only
+$better of them got lower than you did before their chutes
+opened.
+EOD
+            } elsif ( $fractile <= 0.5 ) {
+                print <<"EOD";
+Not bad.  There have been $jumps successful jumps before yours.
+You were beaten out by $better of them.
+EOD
+            } elsif ( $fractile <= 0.75 ) {
+                print <<"EOD";
+Conservative, aren't you?  You ranked only $better in the
+$jumps successful jumps before yours.
+EOD
+            } elsif ( $fractile <= 0.9 ) {
+                print <<"EOD";
+Humph!  Don't you have any sporting blood?  There were
+$jumps successful jumps before yours and you came in $worse jumps
+better than the worst.  Shape up!!!
+EOD
+            } else {
+                print <<"EOD";
+Hey!  You pulled the rip cord much too soon.  $jumps successful
+jumps before yours and you came in number $better!  Get with it!
+EOD
+            }
+        }
+        push @{ $succesful }, $altitude;
+    } else {
+        # Splat
+
+        say q;
+    }
+
+    next if get_yes_no( 'Do you want to play again' );
+    next if get_yes_no( 'Please' );
+
+    print <<'EOD';
+Ssssssssss.
+
+EOD
+    last;
+
+}
+
+# Return the first argument modified by up to plus or minus some
+# fraction specified by the second argument (default 0.05)
+sub dither {
+    my ( $arg, $fract ) = @_;
+    $fract //= 1 / 20;
+    return $arg + ( $arg * rand() * $fract ) - ( $arg * rand() * $fract );
+}
+
+use constant FORMAT_FALL    => "%10.1f      %10d\n";
+use constant FORMAT_SPLAT   => "%10.1f      %s\n";
+sub make_jump {
+    my ( $initial_altitude, $gravity, $terminal_velocity, $drop_time ) = @_;
+    my $altitude;
+    foreach my $step ( 0 .. 8 ) {
+        my $time = $step * $drop_time / 8;
+        if ( $time > $terminal_velocity / $gravity ) {
+            # Terminal velocity reached
+            printf "Terminal velocity reached at T plus %.2f seconds.\n",
+                $terminal_velocity / $gravity;
+            for my $step ( $step .. 8 ) {
+                my $time = $step * $drop_time / 8;
+                $altitude = $initial_altitude - (
+                    $terminal_velocity * $terminal_velocity /
+                    ( 2 * $gravity ) + $terminal_velocity * (
+                        $time - $terminal_velocity / $gravity ) );
+                if ( $altitude > 0 ) {
+                    printf FORMAT_FALL, $time, $altitude;
+                } else {
+                    splat(
+                        $terminal_velocity / $gravity + (
+                            $initial_altitude -
+                            $terminal_velocity * $terminal_velocity /
+                            ( 2 * $gravity ) ) / $terminal_velocity,
+                    );
+                    return;
+                }
+            }
+            last;
+        } else {
+            $altitude = $initial_altitude - $gravity / 2 * $time * $time;
+            if ( $altitude > 0 ) {
+                printf FORMAT_FALL, $time, $altitude;
+            } else {
+                splat( sqrt( 2 * $initial_altitude / $gravity ) );
+                return;
+            }
+        }
+    }
+
+    say 'Chute open.';
+    return $altitude;
+}
+
+sub splat {
+    my ( $time ) = @_;
+    printf FORMAT_SPLAT, $time, 'Splat!';
+    state $rip = [
+        q,
+        q,
+        q,
+        q,
+        q<#$%&&%!$>,
+        q
, + q, + q, + q, + q, + ]; + say $rip->[ rand scalar @{ $rip } ]; + return; +} + +# Get input from the user. The arguments are: +# * The prompt +# * A reference to validation code. This code receives the response in +# $ARG and returns true for a valid response. +# * A warning to print if the response is not valid. This must end in a +# return. +# The first valid response is returned. An end-of-file terminates the +# script. +sub get_input { + my ( $prompt, $validate, $warning ) = @ARG; + + # If no validator is passed, default to one that always returns + # true. + $validate ||= sub { 1 }; + + # Create the readline object. The 'state' causes the variable to be + # initialized only once, no matter how many times this subroutine is + # called. The do { ... } is a compound statement used because we + # need to tweak the created object before we store it. + state $term = do { + my $obj = Term::ReadLine->new( 'reverse' ); + $obj->ornaments( 0 ); + $obj; + }; + + while ( 1 ) { # Iterate indefinitely + + # Read the input into the topic variable, localized to prevent + # Spooky Action at a Distance. We exit on undef, which signals + # end-of-file. + exit unless defined( local $ARG = $term->readline( $prompt ) ); + + # Return the input if it is valid. + return $ARG if $validate->(); + + # Issue the warning, and go around the merry-go-round again. + warn $warning; + } +} + +# Get a yes-or-no answer. The argument is the prompt, which will have +# '? [y/n]: ' appended. The donkey work is done by get_input(), which is +# requested to validate the response as beginning with 'y' or 'n', +# case-insensitive. The return is a true value for 'y' and a false value +# for 'n'. +sub get_yes_no { + my ( $prompt ) = @ARG; + state $map_answer = { + n => 0, + y => 1, + }; + my $resp = lc get_input( + "$prompt? [y/n]: ", + sub { m/ \A [yn] /smxi }, + "Please respond 'y' or 'n'\n", + ); + return $map_answer->{ substr $resp, 0, 1 }; +} + +__END__ + +=head1 TITLE + +splat.pl - Play the game 'splat' from Basic Computer Games + +=head1 SYNOPSIS + + splat.pl + +=head1 DETAILS + +This Perl script is a port of C, which is the 73rd entry in +Basic Computer Games. + +This is a very basic port. All I really did was untangle the spaghetti. + +=head1 PORTED BY + +Thomas R. Wyant, III F + +=head1 COPYRIGHT AND LICENSE + +Copyright (C) 2022 by Thomas R. Wyant, III + +This program is free software; you can redistribute it and/or modify it +under the same terms as Perl 5.10.0. For more details, see the Artistic +License 1.0 at +L, and/or the +Gnu GPL at L. + +This program is distributed in the hope that it will be useful, but +without any warranty; without even the implied warranty of +merchantability or fitness for a particular purpose. + +=cut + +# ex: set expandtab tabstop=4 textwidth=72 : diff --git a/00_Alternate_Languages/81_Splat/python/README.md b/00_Alternate_Languages/81_Splat/python/README.md new file mode 100644 index 00000000..781945ec --- /dev/null +++ b/00_Alternate_Languages/81_Splat/python/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Python](https://www.python.org/about/) diff --git a/00_Alternate_Languages/81_Splat/python/splat.py b/00_Alternate_Languages/81_Splat/python/splat.py new file mode 100644 index 00000000..909151e2 --- /dev/null +++ b/00_Alternate_Languages/81_Splat/python/splat.py @@ -0,0 +1,319 @@ +""" +SPLAT + +Splat similates a parachute jump in which you try to open your parachute +at the last possible moment without going splat! You may select your own +terminal velocity or let the computer do it for you. You may also select +the acceleration due to gravity or, again, let the computer do it +in which case you might wind up on any one of the eight planets (out to +Neptune), the moon, or the sun. + +The computer then tells you the height you're jumping from and asks for +the seconds of free fall. It then divides your free fall time into eight +intervals and gives you progress reports on the way down. The computer +also keeps track of all prior jumps and lets you know how you compared +with previous successful jumps. If you want to recall information from +previous runs, then you should store the array `successful_jumps` on +disk and read it before each run. + +John Yegge created this program while at the Oak Ridge Associated +Universities. + +Ported in 2021 by Jonas Nockert / @lemonad + +""" +from math import sqrt +from random import choice, random, uniform + +PAGE_WIDTH = 72 + + +def numeric_input(question, default=0): + """Ask user for a numeric value.""" + while True: + answer = input(f"{question} [{default}]: ").strip() or default + try: + return float(answer) + except ValueError: + pass + + +def yes_no_input(question, default="YES"): + """Ask user a yes/no question and returns True if yes, otherwise False.""" + answer = input(f"{question} (YES OR NO) [{default}]: ").strip() or default + while answer.lower() not in ["n", "no", "y", "yes"]: + answer = input(f"YES OR NO [{default}]: ").strip() or default + return answer.lower() in ["y", "yes"] + + +def get_terminal_velocity(): + """Terminal velocity by user or picked by computer.""" + if yes_no_input("SELECT YOUR OWN TERMINAL VELOCITY", default="NO"): + v1 = numeric_input("WHAT TERMINAL VELOCITY (MI/HR)", default=100) + else: + # Computer picks 0-1000 terminal velocity. + v1 = int(1000 * random()) + print(f"OK. TERMINAL VELOCITY = {v1} MI/HR") + + # Convert miles/h to feet/s. + return v1 * (5280 / 3600) + + +def get_acceleration(): + """Acceleration due to gravity by user or picked by computer.""" + if yes_no_input("WANT TO SELECT ACCELERATION DUE TO GRAVITY", default="NO"): + a2 = numeric_input("WHAT ACCELERATION (FT/SEC/SEC)", default=32.16) + else: + body, a2 = pick_random_celestial_body() + print(f"FINE. YOU'RE ON {body}. ACCELERATION={a2} FT/SEC/SEC.") + return a2 + + +def get_freefall_time(): + """User-guessed freefall time. + + The idea of the game is to pick a freefall time, given initial + altitude, terminal velocity and acceleration, so the parachute + as close to the ground as possible without going splat. + """ + t_freefall = 0 + # A zero or negative freefall time is not handled by the motion + # equations during the jump. + while t_freefall <= 0: + t_freefall = numeric_input("HOW MANY SECONDS", default=10) + return t_freefall + + +def jump(): + """Simulate a jump and returns the altitude where the chute opened. + + The idea is to open the chute as late as possible -- but not too late. + """ + v = 0 # Terminal velocity. + a = 0 # Acceleration. + initial_altitude = int(9001 * random() + 1000) + + v1 = get_terminal_velocity() + # Actual terminal velocity is +/-5% of v1. + v = v1 * uniform(0.95, 1.05) + + a2 = get_acceleration() + # Actual acceleration is +/-5% of a2. + a = a2 * uniform(0.95, 1.05) + + print( + "\n" + f" ALTITUDE = {initial_altitude} FT\n" + f" TERM. VELOCITY = {v1:.2f} FT/SEC +/-5%\n" + f" ACCELERATION = {a2:.2f} FT/SEC/SEC +/-5%\n" + "SET THE TIMER FOR YOUR FREEFALL." + ) + t_freefall = get_freefall_time() + print( + "HERE WE GO.\n\n" + "TIME (SEC)\tDIST TO FALL (FT)\n" + "==========\t=================" + ) + + terminal_velocity_reached = False + is_splat = False + for i in range(9): + # Divide time for freefall into 8 intervals. + t = i * (t_freefall / 8) + # From the first equation of motion, v = v_0 + a * delta_t, with + # initial velocity v_0 = 0, we can get the time when terminal velocity + # is reached: delta_t = v / a. + if t > v / a: + if not terminal_velocity_reached: + print(f"TERMINAL VELOCITY REACHED AT T PLUS {v / a:.2f} SECONDS.") + terminal_velocity_reached = True + # After having reached terminal velocity, the displacement is + # composed of two parts: + # 1. Displacement up to reaching terminal velocity: + # From the third equation of motion, v^2 = v_0^2 + 2 * a * d, + # with v_0 = 0, we can get the displacement using + # d1 = v^2 / (2 * a). + # 2. Displacement beyond having reached terminal velocity: + # here, the displacement is just a function of the terminal + # velocity and the time passed after having reached terminal + # velocity: d2 = v * (t - t_reached_term_vel) + d1 = (v**2) / (2 * a) + d2 = v * (t - (v / a)) + altitude = initial_altitude - (d1 + d2) + if altitude <= 0: + # Time taken for an object to fall to the ground given + # an initial altitude is composed of two parts after having + # reached terminal velocity: + # 1. time up to reaching terminal velocity: t1 = v / a + # 2. time beyond having reached terminal velocity: + # here, the altitude that remains after having reached + # terminal velocity can just be divided by the constant + # terminal velocity to get the time it takes to reach the + # ground: t2 = altitude_remaining / v + t1 = v / a + t2 = (initial_altitude - d1) / v + print_splat(t1 + t2) + is_splat = True + break + else: + # 1. Displacement before reaching terminal velocity: + # From the second equation of motion, + # d = v_0 * t + 0.5 * a * t^2, with v_0 = 0, we can get + # the displacement using d1 = a / 2 * t^2 + d1 = (a / 2) * (t**2) + altitude = initial_altitude - d1 + if altitude <= 0: + # Time taken for an object to fall to the ground given that + # it never reaches terminal velocity can be calculated by + # using the second equation of motion: + # d = v_0 * t + 0.5 * a * t^2, with v_0 = 0, which + # when solved for t becomes + # t1 = sqrt(2 * d / a). + t1 = sqrt(2 * initial_altitude / a) + print_splat(t1) + is_splat = True + break + print(f"{t:.2f}\t\t{altitude:.1f}") + + if not is_splat: + print("CHUTE OPEN") + return altitude + + +def pick_random_celestial_body(): + """Pick a random planet, the moon, or the sun with associated gravity.""" + body, gravity = choice( + [ + ("MERCURY", 12.2), + ("VENUS", 28.3), + ("EARTH", 32.16), + ("THE MOON", 5.15), + ("MARS", 12.5), + ("JUPITER", 85.2), + ("SATURN", 37.6), + ("URANUS", 33.8), + ("NEPTUNE", 39.6), + ("THE SUN", 896.0), + ] + ) + return body, gravity + + +def jump_stats(previous_jumps, chute_altitude): + """Compare altitude when chute opened with previous successful jumps. + + Return the number of previous jumps and the number of times + the current jump is better. + """ + n_previous_jumps = len(previous_jumps) + n_better = sum(1 for pj in previous_jumps if chute_altitude < pj) + return n_previous_jumps, n_better + + +def print_splat(time_on_impact): + """Parachute opened too late!""" + print(f"{time_on_impact:.2f}\t\tSPLAT") + print( + choice( + [ + "REQUIESCAT IN PACE.", + "MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.", + "REST IN PEACE.", + "SON-OF-A-GUN.", + "#$%&&%!$", + "A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.", + "HMMM. SHOULD HAVE PICKED A SHORTER TIME.", + "MUTTER. MUTTER. MUTTER.", + "PUSHING UP DAISIES.", + "EASY COME, EASY GO.", + ] + ) + ) + + +def print_results(n_previous_jumps, n_better): + """Compare current jump to previous successful jumps.""" + k = n_previous_jumps + k1 = n_better + n_jumps = k + 1 + if n_jumps <= 3: + order = ["1ST", "2ND", "3RD"] + nth = order[n_jumps - 1] + print(f"AMAZING!!! NOT BAD FOR YOUR {nth} SUCCESSFUL JUMP!!!") + elif k - k1 <= 0.1 * k: + print( + f"WOW! THAT'S SOME JUMPING. OF THE {k} SUCCESSFUL JUMPS\n" + f"BEFORE YOURS, ONLY {k - k1} OPENED THEIR CHUTES LOWER THAN\n" + "YOU DID." + ) + elif k - k1 <= 0.25 * k: + print( + f"PRETTY GOOD! {k} SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\n" + f"{k - k1} OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\n" + "OPENED." + ) + elif k - k1 <= 0.5 * k: + print( + f"NOT BAD. THERE HAVE BEEN {k} SUCCESSFUL JUMPS BEFORE YOURS.\n" + f"YOU WERE BEATEN OUT BY {k - k1} OF THEM." + ) + elif k - k1 <= 0.75 * k: + print( + f"CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY {k - k1} IN THE\n" + f"{k} SUCCESSFUL JUMPS BEFORE YOURS." + ) + elif k - k1 <= 0.9 * k: + print( + "HUMPH! DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE\n" + f"{k} SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN {k1} JUMPS\n" + "BETTER THAN THE WORST. SHAPE UP!!!" + ) + else: + print( + f"HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. {k} SUCCESSFUL\n" + f"JUMPS BEFORE YOURS AND YOU CAME IN NUMBER {k - k1}!" + " GET WITH IT!" + ) + + +def print_centered(msg): + """Print centered text.""" + spaces = " " * ((PAGE_WIDTH - len(msg)) // 2) + print(spaces + msg) + + +def print_header(): + print_centered("SPLAT") + print_centered("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY") + print( + "\n\n\n" + "WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE\n" + "JUMP. TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE\n" + "MOMENT WITHOUT GOING SPLAT.\n\n" + ) + + +# +# Main program. +# + +print_header() + +successful_jumps = [] +while True: + chute_altitude = jump() + if chute_altitude > 0: + # We want the statistics on previous jumps (i.e. not including the + # current jump.) + n_previous_jumps, n_better = jump_stats(successful_jumps, chute_altitude) + successful_jumps.append(chute_altitude) + print_results(n_previous_jumps, n_better) + else: + # Splat! + print("I'LL GIVE YOU ANOTHER CHANCE.") + z = yes_no_input("DO YOU WANT TO PLAY AGAIN") + if not z: + z = yes_no_input("PLEASE") + if not z: + print("SSSSSSSSSS.") + break diff --git a/00_Alternate_Languages/81_Splat/ruby/README.md b/00_Alternate_Languages/81_Splat/ruby/README.md new file mode 100644 index 00000000..fb32811e --- /dev/null +++ b/00_Alternate_Languages/81_Splat/ruby/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Ruby](https://www.ruby-lang.org/en/) diff --git a/00_Alternate_Languages/81_Splat/splat.bas b/00_Alternate_Languages/81_Splat/splat.bas new file mode 100644 index 00000000..8561f634 --- /dev/null +++ b/00_Alternate_Languages/81_Splat/splat.bas @@ -0,0 +1,128 @@ +10 PRINT TAB(33);"SPLAT" +20 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY" +40 PRINT:PRINT:PRINT +50 DIM A(42) +95 PRINT "WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE" +96 PRINT "JUMP. TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE" +97 PRINT "MOMENT WITHOUT GOING SPLAT." +118 PRINT:PRINT:D1=0:V=0:A=0:N=0:M=0:D1=INT(9001*RND(1)+1000) +119 PRINT "SELECT YOUR OWN TERMINAL VELOCITY (YES OR NO)";:INPUT A1$ +120 IF A1$="NO" THEN 128 +121 IF A1$<>"YES" THEN PRINT "YES OR NO";:INPUT A1$:GOTO 120 +123 PRINT "WHAT TERMINAL VELOCITY (MI/HR)";:INPUT V1 +125 V1=V1*(5280/3600):V=V1+((V1*RND(1))/20)-((V1*RND(1))/20):GOTO 135 +128 V1=INT(1000*RND(1)) +130 PRINT "OK. TERMINAL VELOCITY ="V1"MI/HR" +131 V1=V1*(5280/3600):V=V1+((V1*RND(1))/20)-((V1*RND(1))/20) +135 PRINT "WANT TO SELECT ACCELERATION DUE TO GRAVITY (YES OR NO)"; +136 INPUT B1$ +140 IF B1$="NO" THEN 150 +141 IF B1$<>"YES" THEN PRINT "YES OR NO";:INPUT B1$:GOTO 140 +143 PRINT "WHAT ACCELERATION (FT/SEC/SEC)";:INPUT A2 +145 A=A2+((A2*RND(1))/20)-((A2*RND(1))/20):GOTO 205 +150 ON INT(1+(10*RND(1)))GOTO 151,152,153,154,155,156,157,158,159,160 +151 PRINT"FINE. YOU'RE ON MERCURY. ACCELERATION=12.2 FT/SEC/SEC.":GOTO 161 +152 PRINT"ALL RIGHT. YOU'RE ON VENUS. ACCELERATION=28.3 FT/SEC/SEC.":GOTO 162 +153 PRINT "THEN YOU'RE ON EARTH. ACCELERATION=32.16 FT/SEC/SEC.":GOTO 163 +154 PRINT"FINE. YOU'RE ON THE MOON. ACCELERATION=5.15 FT/SEC/SEC.":GOTO 164 +155 PRINT"ALL RIGHT. YOU'RE ON MARS. ACCELERATION=12.5 FT/SEC/SEC.":GOTO 165 +156 PRINT"THEN YOU'RE ON JUPITER. ACCELERATION=85.2 FT/SEC/SEC.":GOTO 166 +157 PRINT"FINE. YOU'RE ON SATURN. ACCELERATION=37.6 FT/SEC/SEC.":GOTO 167 +158 PRINT"ALL RIGHT. YOU'RE ON URANUS. ACCELERATION=33.8 FT/SEC/SEC.":GOTO 168 +159 PRINT"THEN YOU'RE ON NEPTUNE. ACCELERATION=39.6 FT/SEC/SEC.":GOTO 169 +160 PRINT"FINE. YOU'RE ON THE SUN. ACCELERATION=896 FT/SEC/SEC.":GOTO 170 +161 A2=12.2:GOTO 145 +162 A2=28.3:GOTO 145 +163 A2=32.16:GOTO 145 +164 A2=5.15:GOTO 145 +165 A2=12.5:GOTO 145 +166 A2=85.2:GOTO 145 +167 A2=37.6:GOTO 145 +168 A2=33.8 :GOTO 145 +169 A2=39.6:GOTO 145 +170 A2=896:GOTO 145 +205 PRINT +206 PRINT " ALTITUDE ="D1"FT" +207 PRINT " TERM. VELOCITY ="V1"FT/SEC +/-5%" +208 PRINT " ACCELERATION ="A2"FT/SEC/SEC +/-5%" +210 PRINT "SET THE TIMER FOR YOUR FREEFALL." +211 PRINT "HOW MANY SECONDS";:INPUT T +215 PRINT "HERE WE GO." +217 PRINT +218 PRINT "TIME (SEC)","DIST TO FALL (FT)" +219 PRINT "==========","=================" +300 FOR I=0 TO T STEP (T/8) +310 IF I>V/A THEN 400 +320 D=D1-((A/2)*I^2) +330 IF D<=0 THEN 1000 +340 PRINT I,D +350 NEXT I +360 GOTO 500 +400 PRINT "TERMINAL VELOCITY REACHED AT T PLUS"V/A"SECONDS." +405 FOR I=I TO T STEP (T/8) +410 D=D1-((V^2/(2*A))+(V*(I-(V/A)))) +420 IF D<=0 THEN 1010 +430 PRINT I,D +440 NEXT I +500 PRINT "CHUTE OPEN" +510 K=0:K1=0 +550 FOR J=0 TO 42 +555 IF A(J)=0 THEN 620 +560 K=K+1 +570 IF D>=A(J) THEN 600 +580 K1=K1+1 +600 NEXT J +610 GOTO 540 +620 A(J)=D +630 IF J>2 THEN 650 +635 PRINT "AMAZING!!! NOT BAD FOR YOUR "; +636 IF J=0 THEN PRINT "1ST "; +637 IF J=1 THEN PRINT "2ND "; +638 IF J=2 THEN PRINT "3RD "; +639 PRINT "SUCCESSFUL JUMP!!!":GOTO 2000 +650 IF K-K1<=.1*K THEN 700 +660 IF K-K1<=.25*K THEN 710 +670 IF K-K1<=.5*K THEN 720 +680 IF K-K1<=.75*K THEN 730 +690 IF K-K1<=.9*K THEN 740 +695 GOTO 750 +700 PRINT "WOW! THAT'S SOME JUMPING. OF THE"K"SUCCESSFUL JUMPS" +701 PRINT "BEFORE YOURS, ONLY"K-K1"OPENED THEIR CHUTES LOWER THAN" +702 PRINT "YOU DID." +703 GOTO 2000 +710 PRINT "PRETTY GOOD! " K"SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY" +711 PRINT K-K1" OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES" +712 PRINT "OPENED." :GOTO 2000 +720 PRINT "NOT BAD. THERE HAVE BEEN"K"SUCCESSFUL JUMPS BEFORE YOURS." +721 PRINT"YOU WERE BEATEN OUT BY"K-K1"OF THEM.":GOTO 2000 +730 PRINT "CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY"K-K1"IN THE" +731 PRINT K"SUCCESSFUL JUMPS BEFORE YOURS.":GOTO 2000 +740 PRINT "HUMPH! DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE" +741 PRINT K"SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN"K1"JUMPS" +742 PRINT "BETTER THAN THE WORST. SHAPE UP!!!":GOTO 2000 +750 PRINT "HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. "K"SUCCESSFUL" +751 PRINT "JUMPS BEFORE YOURS AND YOU CAME IN NUMBER"K-K1"! GET WITH IT!" +752 GOTO 2000 +800 PRINT "REQUIESCAT IN PACE.":GOTO 1950 +801 PRINT "MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.":GOTO 1950 +802 PRINT "REST IN PEACE.":GOTO 1950 +803 PRINT "SON-OF-A-GUN.":GOTO 1950 +804 PRINT "#$%&&%!$":GOTO 1950 +805 PRINT "A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.":GOTO 1950 +806 PRINT "HMMM. SHOULD HAVE PICKED A SHORTER TIME.":GOTO 1950 +807 PRINT "MUTTER. MUTTER. MUTTER.":GOTO 1950 +808 PRINT "PUSHING UP DAISIES.":GOTO 1950 +809 PRINT "EASY COME, EASY GO.":GOTO 1950 +1000 PRINT SQR(2*D1/A),"SPLAT" +1005 ON INT(1+(10*RND(1)))GOTO 800,801,802,803,804,805,806,807,808,809 +1010 PRINT (V/A)+((D1-(V^2/(2*A)))/V),"SPLAT" +1020 GOTO 1005 +1950 PRINT "I'LL GIVE YOU ANOTHER CHANCE.":GOTO 2000 +2000 PRINT "DO YOU WANT TO PLAY AGAIN";:INPUT Z$ +2001 IF Z$="YES" THEN 118 +2002 IF Z$="NO" THEN 2005 +2003 PRINT "YES OR NO":GOTO 2000 +2005 PRINT "PLEASE";:INPUT Z$:IF Z$="YES" THEN 118 +2006 IF Z$<>"NO" THEN PRINT "YES OR NO ";:GOTO 2005 +2007 PRINT "SSSSSSSSSS.":PRINT:GOTO 2046 +2046 END diff --git a/00_Alternate_Languages/81_Splat/vbnet/README.md b/00_Alternate_Languages/81_Splat/vbnet/README.md new file mode 100644 index 00000000..98b702c7 --- /dev/null +++ b/00_Alternate_Languages/81_Splat/vbnet/README.md @@ -0,0 +1,3 @@ +Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET) diff --git a/00_Alternate_Languages/81_Splat/vbnet/Splat.sln b/00_Alternate_Languages/81_Splat/vbnet/Splat.sln new file mode 100644 index 00000000..b132583d --- /dev/null +++ b/00_Alternate_Languages/81_Splat/vbnet/Splat.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Splat", "Splat.vbproj", "{62FD7167-97B2-4EA7-8BC8-CBC5765DF721}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {62FD7167-97B2-4EA7-8BC8-CBC5765DF721}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {62FD7167-97B2-4EA7-8BC8-CBC5765DF721}.Debug|Any CPU.Build.0 = Debug|Any CPU + {62FD7167-97B2-4EA7-8BC8-CBC5765DF721}.Release|Any CPU.ActiveCfg = Release|Any CPU + {62FD7167-97B2-4EA7-8BC8-CBC5765DF721}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/00_Alternate_Languages/81_Splat/vbnet/Splat.vbproj b/00_Alternate_Languages/81_Splat/vbnet/Splat.vbproj new file mode 100644 index 00000000..daf6de3c --- /dev/null +++ b/00_Alternate_Languages/81_Splat/vbnet/Splat.vbproj @@ -0,0 +1,8 @@ + + + Exe + Splat + net6.0 + 16.9 + + diff --git a/00_Alternate_Languages/82_Stars/README.md b/00_Alternate_Languages/82_Stars/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/82_Stars/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/82_Stars/csharp/Game.cs b/00_Alternate_Languages/82_Stars/csharp/Game.cs new file mode 100644 index 00000000..9711dd82 --- /dev/null +++ b/00_Alternate_Languages/82_Stars/csharp/Game.cs @@ -0,0 +1,94 @@ +using System; + +namespace Stars +{ + internal class Game + { + private readonly int _maxNumber; + private readonly int _maxGuessCount; + private readonly Random _random; + + public Game(int maxNumber, int maxGuessCount) + { + _maxNumber = maxNumber; + _maxGuessCount = maxGuessCount; + _random = new Random(); + } + + internal void DisplayInstructions() + { + if (Input.GetString("Do you want instructions? ").Equals("N", StringComparison.InvariantCultureIgnoreCase)) + { + return; + } + + Console.WriteLine($"I am thinking of a number between 1 and {_maxNumber}."); + Console.WriteLine("Try to guess my number. After you guess, I"); + Console.WriteLine("will type one or more stars (*). The more"); + Console.WriteLine("stars I type, the close you are to my number."); + Console.WriteLine("One star (*) means far away, seven stars (*******)"); + Console.WriteLine($"means really close! You get {_maxGuessCount} guesses."); + } + + internal void Play() + { + Console.WriteLine(); + Console.WriteLine(); + + var target = _random.Next(_maxNumber) + 1; + + Console.WriteLine("Ok, I am thinking of a number. Start guessing."); + + AcceptGuesses(target); + } + + private void AcceptGuesses(int target) + { + for (int guessCount = 1; guessCount <= _maxGuessCount; guessCount++) + { + Console.WriteLine(); + var guess = Input.GetNumber("Your guess? "); + + if (guess == target) + { + DisplayWin(guessCount); + return; + } + + DisplayStars(target, guess); + } + + DisplayLoss(target); + } + + private static void DisplayStars(int target, float guess) + { + var stars = Math.Abs(guess - target) switch + { + >= 64 => "*", + >= 32 => "**", + >= 16 => "***", + >= 8 => "****", + >= 4 => "*****", + >= 2 => "******", + _ => "*******" + }; + + Console.WriteLine(stars); + } + + private static void DisplayWin(int guessCount) + { + Console.WriteLine(); + Console.WriteLine(new string('*', 79)); + Console.WriteLine(); + Console.WriteLine($"You got it in {guessCount} guesses!!! Let's play again..."); + } + + private void DisplayLoss(int target) + { + Console.WriteLine(); + Console.WriteLine($"Sorry, that's {_maxGuessCount} guesses. The number was {target}."); + } + } +} diff --git a/00_Alternate_Languages/82_Stars/csharp/Input.cs b/00_Alternate_Languages/82_Stars/csharp/Input.cs new file mode 100644 index 00000000..6ba6e3a1 --- /dev/null +++ b/00_Alternate_Languages/82_Stars/csharp/Input.cs @@ -0,0 +1,31 @@ +using System; + +namespace Stars +{ + internal static class Input + { + // Float, because that's what the BASIC input operation returns + internal static float GetNumber(string prompt) + { + Console.Write(prompt); + + while (true) + { + var response = Console.ReadLine(); + if (float.TryParse(response, out var value)) + { + return value; + } + + Console.WriteLine("!Number expected - retry input line"); + Console.Write("? "); + } + } + + internal static string GetString(string prompt) + { + Console.Write(prompt); + return Console.ReadLine(); + } + } +} diff --git a/00_Alternate_Languages/82_Stars/csharp/Program.cs b/00_Alternate_Languages/82_Stars/csharp/Program.cs new file mode 100644 index 00000000..b072595c --- /dev/null +++ b/00_Alternate_Languages/82_Stars/csharp/Program.cs @@ -0,0 +1,30 @@ +using System; + +namespace Stars +{ + class Program + { + static void Main(string[] args) + { + DisplayTitle(); + + var game = new Game(maxNumber: 100, maxGuessCount: 7); + + game.DisplayInstructions(); + + while (true) + { + game.Play(); + } + } + + private static void DisplayTitle() + { + Console.WriteLine(" Stars"); + Console.WriteLine(" Creative Computing Morristown, New Jersey"); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); + } + } +} diff --git a/00_Alternate_Languages/82_Stars/csharp/README.md b/00_Alternate_Languages/82_Stars/csharp/README.md new file mode 100644 index 00000000..4daabb5c --- /dev/null +++ b/00_Alternate_Languages/82_Stars/csharp/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) diff --git a/00_Alternate_Languages/82_Stars/csharp/Stars.csproj b/00_Alternate_Languages/82_Stars/csharp/Stars.csproj new file mode 100644 index 00000000..20827042 --- /dev/null +++ b/00_Alternate_Languages/82_Stars/csharp/Stars.csproj @@ -0,0 +1,8 @@ + + + + Exe + net5.0 + + + diff --git a/00_Alternate_Languages/82_Stars/csharp/Stars.sln b/00_Alternate_Languages/82_Stars/csharp/Stars.sln new file mode 100644 index 00000000..19c3a265 --- /dev/null +++ b/00_Alternate_Languages/82_Stars/csharp/Stars.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.32014.148 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Stars", "Stars.csproj", "{F03C19DA-0F5D-45F4-B85E-E3ABCA197D4B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F03C19DA-0F5D-45F4-B85E-E3ABCA197D4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F03C19DA-0F5D-45F4-B85E-E3ABCA197D4B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F03C19DA-0F5D-45F4-B85E-E3ABCA197D4B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F03C19DA-0F5D-45F4-B85E-E3ABCA197D4B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0752CA22-85F0-43AE-8B79-7A611531CAF7} + EndGlobalSection +EndGlobal diff --git a/00_Alternate_Languages/82_Stars/java/README.md b/00_Alternate_Languages/82_Stars/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/82_Stars/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/82_Stars/java/src/Stars.java b/00_Alternate_Languages/82_Stars/java/src/Stars.java new file mode 100644 index 00000000..b9cf641a --- /dev/null +++ b/00_Alternate_Languages/82_Stars/java/src/Stars.java @@ -0,0 +1,242 @@ +import java.util.Arrays; +import java.util.Scanner; + +/** + * Game of Stars + * + * Based on the Basic game of Stars here + * https://github.com/coding-horror/basic-computer-games/blob/main/82%20Stars/stars.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. + */ +public class Stars { + + public static final int HIGH_NUMBER_RANGE = 100; + public static final int MAX_GUESSES = 7; + + private enum GAME_STATE { + STARTING, + INSTRUCTIONS, + START_GAME, + GUESSING, + WON, + LOST, + GAME_OVER + } + + // Used for keyboard input + private final Scanner kbScanner; + + // Current game state + private GAME_STATE gameState; + + // Players guess count; + private int playerTotalGuesses; + + // Players current guess + private int playerCurrentGuess; + + // Computers random number + private int computersNumber; + + public Stars() { + + gameState = GAME_STATE.STARTING; + + // Initialise kb scanner + kbScanner = new Scanner(System.in); + } + + /** + * Main game loop + * + */ + public void play() { + + do { + switch (gameState) { + + // Show an introduction the first time the game is played. + case STARTING: + intro(); + gameState = GAME_STATE.INSTRUCTIONS; + break; + + // Ask if instructions are needed and display if yes + case INSTRUCTIONS: + if(yesEntered(displayTextAndGetInput("DO YOU WANT INSTRUCTIONS? "))) { + instructions(); + } + gameState = GAME_STATE.START_GAME; + break; + + // Generate computers number for player to guess, etc. + case START_GAME: + init(); + System.out.println("OK, I AM THINKING OF A NUMBER, START GUESSING."); + gameState = GAME_STATE.GUESSING; + break; + + // Player guesses the number until they get it or run out of guesses + case GUESSING: + playerCurrentGuess = playerGuess(); + + // Check if the player guessed the number + if(playerCurrentGuess == computersNumber) { + gameState = GAME_STATE.WON; + } else { + // incorrect guess + showStars(); + playerTotalGuesses++; + // Ran out of guesses? + if (playerTotalGuesses > MAX_GUESSES) { + gameState = GAME_STATE.LOST; + } + } + break; + + // Won game. + case WON: + + System.out.println(stars(79)); + System.out.println("YOU GOT IT IN " + playerTotalGuesses + + " GUESSES!!! LET'S PLAY AGAIN..."); + gameState = GAME_STATE.START_GAME; + break; + + // Lost game by running out of guesses + case LOST: + System.out.println("SORRY, THAT'S " + MAX_GUESSES + + " GUESSES. THE NUMBER WAS " + computersNumber); + gameState = GAME_STATE.START_GAME; + break; + } + // Endless loop since the original code did not allow the player to exit + } while (gameState != GAME_STATE.GAME_OVER); + } + + /** + * Shows how close a players guess is to the computers number by + * showing a series of stars - the more stars the closer to the + * number. + * + */ + private void showStars() { + int d = Math.abs(playerCurrentGuess - computersNumber); + int starsToShow; + if(d >=64) { + starsToShow = 1; + } else if(d >=32) { + starsToShow = 2; + } else if (d >= 16) { + starsToShow = 3; + } else if (d >=8) { + starsToShow = 4; + } else if( d>= 4) { + starsToShow = 5; + } else if(d>= 2) { + starsToShow = 6; + } else { + starsToShow = 7; + } + System.out.println(stars(starsToShow)); + } + + /** + * Show a number of stars (asterisks) + * @param number the number of stars needed + * @return the string encoded with the number of required stars + */ + private String stars(int number) { + char[] stars = new char[number]; + Arrays.fill(stars, '*'); + return new String(stars); + } + + /** + * Initialise variables before each new game + * + */ + private void init() { + playerTotalGuesses = 1; + computersNumber = randomNumber(); + } + + public void instructions() { + System.out.println("I AM THINKING OF A WHOLE NUMBER FROM 1 TO " + HIGH_NUMBER_RANGE); + System.out.println("TRY TO GUESS MY NUMBER. AFTER YOU GUESS, I"); + System.out.println("WILL TYPE ONE OR MORE STARS (*). THE MORE"); + System.out.println("STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER."); + System.out.println("ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)"); + System.out.println("MEANS REALLY CLOSE! YOU GET " + MAX_GUESSES + " GUESSES."); + } + + public void intro() { + System.out.println("STARS"); + System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + } + + /** + * Get players guess from kb + * + * @return players guess as an int + */ + private int playerGuess() { + return Integer.parseInt((displayTextAndGetInput("YOUR GUESS? "))); + } + + /** + * Checks whether player entered Y or YES to a question. + * + * @param text player string from kb + * @return true of Y or YES was entered, otherwise false + */ + private boolean yesEntered(String text) { + return stringIsAnyValue(text, "Y", "YES"); + } + + /** + * Check whether a string equals one of a variable number of values + * Useful to check for Y or YES for example + * Comparison is case insensitive. + * + * @param text source string + * @param values a range of values to compare against the source string + * @return true if a comparison was found in one of the variable number of strings passed + */ + private boolean stringIsAnyValue(String text, String... values) { + + // Cycle through the variable number of values and test each + for(String val:values) { + if(text.equalsIgnoreCase(val)) { + return true; + } + } + + // no matches + return false; + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + + /** + * Generate random number + * + * @return random number + */ + private int randomNumber() { + return (int) (Math.random() + * (HIGH_NUMBER_RANGE) + 1); + } +} diff --git a/00_Alternate_Languages/82_Stars/java/src/StarsGame.java b/00_Alternate_Languages/82_Stars/java/src/StarsGame.java new file mode 100644 index 00000000..4e1a9058 --- /dev/null +++ b/00_Alternate_Languages/82_Stars/java/src/StarsGame.java @@ -0,0 +1,9 @@ +import java.lang.reflect.AnnotatedType; + +public class StarsGame { + + public static void main(String[] args) { + Stars stars = new Stars(); + stars.play(); + } +} diff --git a/00_Alternate_Languages/82_Stars/javascript/README.md b/00_Alternate_Languages/82_Stars/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/82_Stars/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/82_Stars/javascript/stars.html b/00_Alternate_Languages/82_Stars/javascript/stars.html new file mode 100644 index 00000000..c63aeb0d --- /dev/null +++ b/00_Alternate_Languages/82_Stars/javascript/stars.html @@ -0,0 +1,9 @@ + + +STARS + + +

+
+
+
diff --git a/00_Alternate_Languages/82_Stars/javascript/stars.js b/00_Alternate_Languages/82_Stars/javascript/stars.js
new file mode 100644
index 00000000..15a92ca1
--- /dev/null
+++ b/00_Alternate_Languages/82_Stars/javascript/stars.js
@@ -0,0 +1,108 @@
+// STARS
+//
+// Converted from BASIC to Javascript by Qursch
+//
+
+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 guesses = 7;
+var limit = 100;
+
+// Main program
+async function main()
+{
+    print(tab(33) + "STARS\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n\n\n");
+
+    // Instructions
+    print("DO YOU WANT INSTRUCTIONS? (Y/N)");
+    var instructions = await input();
+    if(instructions.toLowerCase()[0] == "y") {
+        print(`I AM THINKING OF A WHOLE NUMBER FROM 1 TO ${limit}\n`);
+        print("TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I\n");
+        print("WILL TYPE ONE OR MORE STARS (*).  THE MORE\n");
+        print("STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER.\n");
+        print("ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)\n");
+        print(`MEANS REALLY CLOSE!  YOU GET ${guesses} GUESSES.\n\n\n`);
+    }
+
+    // Game loop
+    while (true) {
+
+        var randomNum = Math.floor(Math.random() * limit) + 1;
+        var loss = true;
+
+        print("\nOK, I AM THINKING OF A NUMBER, START GUESSING.\n\n");
+
+        for(var guessNum=1; guessNum <= guesses; guessNum++) {
+
+            // Input guess
+            print("YOUR GUESS");
+            var guess = parseInt(await input());
+
+            // Check if guess is correct
+            if(guess == randomNum) {
+                loss = false;
+                print("\n\n" + "*".repeat(50) + "!!!\n");
+                print(`YOU GOT IT IN ${guessNum} GUESSES!!! LET'S PLAY AGAIN...\n`);
+                break;
+            }
+
+            // Output distance in stars
+            var dist = Math.abs(guess - randomNum);
+            if(isNaN(dist)) print("*");
+            else if(dist >= 64) print("*");
+            else if(dist >= 32) print("**");
+            else if(dist >= 16) print("***");
+            else if(dist >= 8) print("****");
+            else if(dist >= 4) print("*****");
+            else if(dist >= 2) print("******");
+            else print("*******")
+            print("\n\n")
+        }
+
+        if(loss) {
+            print(`SORRY, THAT'S ${guesses} GUESSES. THE NUMBER WAS ${randomNum}\n`);
+        }
+    }
+}
+
+main();
diff --git a/57_Literature_Quiz/pascal/README.md b/00_Alternate_Languages/82_Stars/pascal/README.md
similarity index 100%
rename from 57_Literature_Quiz/pascal/README.md
rename to 00_Alternate_Languages/82_Stars/pascal/README.md
diff --git a/00_Alternate_Languages/82_Stars/perl/README.md b/00_Alternate_Languages/82_Stars/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/82_Stars/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/82_Stars/perl/stars.pl b/00_Alternate_Languages/82_Stars/perl/stars.pl
new file mode 100644
index 00000000..6c1b5392
--- /dev/null
+++ b/00_Alternate_Languages/82_Stars/perl/stars.pl
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+
+use v5.11; # for say and use strict
+use warnings;
+
+my $MAX_NUMBER = 100;
+my $MAX_GUESSES = 7;
+
+print<<__END_OF_INTRO;
+                                  Stars
+               Creative Computing  Morristown, New Jersey
+
+
+
+__END_OF_INTRO
+
+print "Do you want instructions? ";
+chomp( my $answer = <> );
+if ( $answer !~ /^N/i ) {
+  print<<__END_OF_INSTRUCTIONS;
+I am thinking of a whole number from 1 to $MAX_NUMBER
+Try to guess my number.  After you guess, I
+will type one or more stars (*).  The more
+stars I type, the closer you are to my number.
+One star (*) means far away, seven stars (*******)
+means really close!  You get $MAX_GUESSES guesses.
+__END_OF_INSTRUCTIONS
+}
+
+
+while (1) {
+  my $number_to_guess = int(rand($MAX_NUMBER) + 1);
+  say "\n\nOK, I am thinking of a number, start guessing.";
+
+  my $guess_number = 1;
+  while ( $guess_number <= $MAX_GUESSES ) {
+    print "\nYour Guess? ";
+    chomp( my $guess = <> );
+    last if $guess == $number_to_guess;
+    $guess_number++;
+    my $difference = abs $guess - $number_to_guess;
+    print '*' if $difference < 2;
+    print '*' if $difference < 4;
+    print '*' if $difference < 8;
+    print '*' if $difference < 16;
+    print '*' if $difference < 32;
+    print '*' if $difference < 64;
+    print "*\n";
+  }
+  if ( $guess_number > $MAX_GUESSES ) { # didn't guess
+    say "\nSorry, that's $MAX_GUESSES guesses, number was $number_to_guess";
+  } else { # winner!
+    say '*' x 50, '!!!';
+    say "You got it in $guess_number guesses!!!  Let's play again...";
+  }
+}
diff --git a/00_Alternate_Languages/82_Stars/python/README.md b/00_Alternate_Languages/82_Stars/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/82_Stars/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/82_Stars/python/stars.py b/00_Alternate_Languages/82_Stars/python/stars.py
new file mode 100644
index 00000000..7024d2d3
--- /dev/null
+++ b/00_Alternate_Languages/82_Stars/python/stars.py
@@ -0,0 +1,128 @@
+"""
+Stars
+
+From: BASIC Computer Games (1978)
+      Edited by David H. Ahl
+
+"In this game, the computer selects a random number from 1 to 100
+ (or any value you set [for MAX_NUM]).  You try to guess the number
+ and the computer gives you clues to tell you how close you're
+ getting.  One star (*) means you're far away from the number; seven
+ stars (*******) means you're really close.  You get 7  guesses.
+
+"On the surface this game is very similar to GUESS; however, the
+ guessing strategy is quite different.  See if you can come up with
+ one or more approaches to finding the mystery number.
+
+"Bob Albrecht of People's Computer Company created this game."
+
+
+Python port by Jeff Jetton, 2019
+"""
+
+
+import random
+
+# Some contants
+MAX_NUM = 100
+MAX_GUESSES = 7
+
+
+def print_instructions():
+    """Instructions on how to play"""
+    print("I am thinking of a whole number from 1 to %d" % MAX_NUM)
+    print("Try to guess my number.  After you guess, I")
+    print("will type one or more stars (*).  The more")
+    print("stars I type, the closer you are to my number.")
+    print("one star (*) means far away, seven stars (*******)")
+    print("means really close!  You get %d guesses." % MAX_GUESSES)
+
+
+def print_stars(secret_number, guess):
+    diff = abs(guess - secret_number)
+    stars = ""
+    for i in range(8):
+        if diff < 2**i:
+            stars += "*"
+    print(stars)
+
+
+def get_guess():
+    valid_response = False
+    while not valid_response:
+        guess = input("Your guess? ")
+        if guess.isdigit():
+            valid_response = True
+            guess = int(guess)
+    return guess
+
+
+# Display intro text
+print("\n                   Stars")
+print("Creative Computing  Morristown, New Jersey")
+print("\n\n")
+# "*** Stars - People's Computer Center, MenloPark, CA"
+
+response = input("Do you want instructions? ")
+if response.upper()[0] == "Y":
+    print_instructions()
+
+still_playing = True
+while still_playing:
+
+    # "*** Computer thinks of a number"
+    secret_number = random.randint(1, MAX_NUM)
+    print("\n\nOK, I am thinking of a number, start guessing.")
+
+    # Init/start guess loop
+    guess_number = 0
+    player_has_won = False
+    while (guess_number < MAX_GUESSES) and not player_has_won:
+
+        print("")
+        guess = get_guess()
+        guess_number += 1
+
+        if guess == secret_number:
+            # "*** We have a winner"
+            player_has_won = True
+            print("**************************************************!!!")
+            print(f"You got it in {guess_number} guesses!!!")
+
+        else:
+            print_stars(secret_number, guess)
+
+        # End of guess loop
+
+    # "*** Did not guess in [MAX_GUESS] guesses"
+    if not player_has_won:
+        print(f"\nSorry, that's {guess_number} guesses, number was {secret_number}")
+
+    # Keep playing?
+    response = input("\nPlay again? ")
+    if response.upper()[0] != "Y":
+        still_playing = False
+
+
+######################################################################
+#
+# Porting Notes
+#
+#   The original program never exited--it just kept playing rounds
+#   over and over.  This version asks to continue each time.
+#
+#
+# Ideas for Modifications
+#
+#   Let the player know how many guesses they have remaining after
+#   each incorrect guess.
+#
+#   Ask the player to select a skill level at the start of the game,
+#   which will affect the values of MAX_NUM and MAX_GUESSES.
+#   For example:
+#
+#       Easy   = 8 guesses, 1 to 50
+#       Medium = 7 guesses, 1 to 100
+#       Hard   = 6 guesses, 1 to 200
+#
+######################################################################
diff --git a/00_Alternate_Languages/82_Stars/ruby/README.md b/00_Alternate_Languages/82_Stars/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/82_Stars/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/82_Stars/stars.bas b/00_Alternate_Languages/82_Stars/stars.bas
new file mode 100644
index 00000000..0536ed3a
--- /dev/null
+++ b/00_Alternate_Languages/82_Stars/stars.bas
@@ -0,0 +1,54 @@
+10 PRINT TAB(34);"STARS"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+100 REM *** STARS - PEOPLE'S COMPUTER CENTER, MENLO PARK, CA
+140 REM *** A IS LIMIT ON NUMBER, M IS NUMBER OF GUESSES
+150 A=100:M=7
+170 INPUT "DO YOU WANT INSTRUCTIONS";A$
+190 IF LEFT$(A$,1)="N" THEN 280
+200 REM *** INSTRUCTIONS ON HOW TO PLAY
+210 PRINT "I AM THINKING OF A WHOLE NUMBER FROM 1 TO";A
+220 PRINT "TRY TO GUESS MY NUMBER.  AFTER YOU GUESS, I"
+230 PRINT "WILL TYPE ONE OR MORE STARS (*).  THE MORE"
+240 PRINT "STARS I TYPE, THE CLOSER YOU ARE TO MY NUMBER."
+250 PRINT "ONE STAR (*) MEANS FAR AWAY, SEVEN STARS (*******)"
+260 PRINT "MEANS REALLY CLOSE!  YOU GET";M;"GUESSES."
+270 REM *** COMPUTER THINKS OF A NUMBER
+280 PRINT
+290 PRINT
+300 X=INT(A*RND(1)+1)
+310 PRINT "OK, I AM THINKING OF A NUMBER, START GUESSING."
+320 REM *** GUESSING BEGINS, HUMAN GETS M GUESSES
+330 FOR K=1 TO M
+340 PRINT
+350 PRINT "YOUR GUESS";
+360 INPUT G
+370 IF G=X THEN 600
+380 D=ABS(G-X)
+390 IF D>=64 THEN 510
+400 IF D>=32 THEN 500
+410 IF D>=16 THEN 490
+420 IF D>=8 THEN 480
+430 IF D>=4 THEN 470
+440 IF D>=2 THEN 460
+450 PRINT "*";
+460 PRINT "*";
+470 PRINT "*";
+480 PRINT "*";
+490 PRINT "*";
+500 PRINT "*";
+510 PRINT "*";
+520 PRINT
+530 NEXT K
+540 REM *** DID NOT GUESS IN M GUESSES
+550 PRINT
+560 PRINT "SORRY, THAT'S";M;"GUESSES. THE NUMBER WAS";X
+580 GOTO 650
+590 REM *** WE HAVE A WINNER
+600 PRINT:FOR N=1 TO 79
+610 PRINT "*";
+620 NEXT N
+630 PRINT:PRINT
+640 PRINT "YOU GOT IT IN";K;"GUESSES!!!  LET'S PLAY AGAIN..."
+650 GOTO 280
+660 END
diff --git a/00_Alternate_Languages/82_Stars/vbnet/README.md b/00_Alternate_Languages/82_Stars/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/82_Stars/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/82_Stars/vbnet/Stars.sln b/00_Alternate_Languages/82_Stars/vbnet/Stars.sln
new file mode 100644
index 00000000..edb5e587
--- /dev/null
+++ b/00_Alternate_Languages/82_Stars/vbnet/Stars.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Stars", "Stars.vbproj", "{181B70F5-C2CB-4A73-9982-30C16DE89240}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{181B70F5-C2CB-4A73-9982-30C16DE89240}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{181B70F5-C2CB-4A73-9982-30C16DE89240}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{181B70F5-C2CB-4A73-9982-30C16DE89240}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{181B70F5-C2CB-4A73-9982-30C16DE89240}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/82_Stars/vbnet/Stars.vbproj b/00_Alternate_Languages/82_Stars/vbnet/Stars.vbproj
new file mode 100644
index 00000000..caad7d6e
--- /dev/null
+++ b/00_Alternate_Languages/82_Stars/vbnet/Stars.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Stars
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/83_Stock_Market/README.md b/00_Alternate_Languages/83_Stock_Market/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/Assets.cs b/00_Alternate_Languages/83_Stock_Market/csharp/Assets.cs
new file mode 100644
index 00000000..ecb2eafe
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/Assets.cs
@@ -0,0 +1,20 @@
+using System.Collections.Immutable;
+
+namespace Game
+{
+    /// 
+    /// Stores the player's assets.
+    /// 
+    public record Assets
+    {
+        /// 
+        /// Gets the player's amount of cash.
+        /// 
+        public double Cash { get; init; }
+
+        /// 
+        /// Gets the number of stocks owned of each company.
+        /// 
+        public ImmutableArray Portfolio { get; init; }
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/Broker.cs b/00_Alternate_Languages/83_Stock_Market/csharp/Broker.cs
new file mode 100644
index 00000000..dc0abb9e
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/Broker.cs
@@ -0,0 +1,60 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+
+namespace Game
+{
+    /// 
+    /// Contains functions for exchanging assets.
+    /// 
+    public static class Broker
+    {
+        /// 
+        /// Applies the given set of transactions to the given set of assets.
+        /// 
+        /// 
+        /// The assets to update.
+        /// 
+        /// 
+        /// The set of stocks to purchase or sell.  Positive values indicate
+        /// purchaes and negative values indicate sales.
+        /// 
+        /// 
+        /// The collection of companies.
+        /// 
+        /// 
+        /// Returns the sellers new assets and a code indicating the result
+        /// of the transaction.
+        /// 
+        public static (Assets newAssets, TransactionResult result) Apply(Assets assets, IEnumerable transactions, IEnumerable companies)
+        {
+            var (netCost, transactionSize) = Enumerable.Zip(
+                    transactions,
+                    companies,
+                    (amount, company) => (amount * company.SharePrice))
+                .Aggregate(
+                    (netCost: 0.0, transactionSize: 0.0),
+                    (accumulated, amount) => (accumulated.netCost + amount, accumulated.transactionSize + Math.Abs(amount)));
+
+            var brokerageFee = 0.01 * transactionSize;
+
+            var newAssets = assets with
+            {
+                Cash      = assets.Cash - netCost - brokerageFee,
+                Portfolio = ImmutableArray.CreateRange(Enumerable.Zip(
+                    assets.Portfolio,
+                    transactions,
+                    (sharesOwned, delta) => sharesOwned + delta))
+            };
+
+            if (newAssets.Portfolio.Any(amount => amount < 0))
+                return (newAssets, TransactionResult.Oversold);
+            else
+            if (newAssets.Cash < 0)
+                return (newAssets, TransactionResult.Overspent);
+            else
+                return (newAssets, TransactionResult.Ok);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/Company.cs b/00_Alternate_Languages/83_Stock_Market/csharp/Company.cs
new file mode 100644
index 00000000..86c4e4ba
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/Company.cs
@@ -0,0 +1,29 @@
+namespace Game
+{
+    /// 
+    /// Represents a company.
+    /// 
+    public record Company
+    {
+        /// 
+        /// Gets the company's name.
+        /// 
+        public string Name { get; }
+
+        /// 
+        /// Gets the company's three letter stock symbol.
+        /// 
+        public string StockSymbol { get; }
+
+        /// 
+        /// Gets the company's current share price.
+        /// 
+        public double SharePrice { get; init; }
+
+        /// 
+        /// Initializes a new Company record.
+        /// 
+        public Company(string name, string stockSymbol, double sharePrice) =>
+            (Name, StockSymbol, SharePrice) = (name, stockSymbol, sharePrice);
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/Controller.cs b/00_Alternate_Languages/83_Stock_Market/csharp/Controller.cs
new file mode 100644
index 00000000..87a1dc7d
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/Controller.cs
@@ -0,0 +1,112 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Game
+{
+    public static class Controller
+    {
+        /// 
+        /// Manages the initial interaction with the user.
+        /// 
+        public static void StartGame()
+        {
+            View.ShowBanner();
+
+            var showInstructions = GetYesOrNo(View.PromptShowInstructions);
+            View.ShowSeparator();
+            if (showInstructions)
+                View.ShowInstructions();
+
+            View.ShowSeparator();
+        }
+
+        /// 
+        /// Gets a yes or no answer from the user.
+        /// 
+        /// 
+        /// Displays the prompt.
+        /// 
+        /// 
+        /// True if the user answered yes and false if he or she answered no.
+        /// 
+        public static bool GetYesOrNo(Action prompt)
+        {
+            prompt();
+
+            var response = default(char);
+            do
+            {
+                response = Console.ReadKey(intercept: true).KeyChar;
+            }
+            while (response != '0' && response != '1');
+
+            View.ShowChar(response);
+            return response == '1';
+        }
+
+        /// 
+        /// Gets a transaction amount for each company in the given collection
+        /// of companies and returns the updated assets.
+        /// 
+        /// 
+        /// The assets to update.
+        /// 
+        /// 
+        /// The collection of companies.
+        /// 
+        /// 
+        /// The updated assets.
+        /// 
+        public static Assets UpdateAssets(Assets assets, IEnumerable companies)
+        {
+            while (true)
+            {
+                View.PromptEnterTransactions();
+
+                var result = Broker.Apply (
+                    assets,
+                    companies.Select(GetTransactionAmount).ToList(),
+                    companies);
+
+                switch (result)
+                {
+                    case (Assets newAssets, TransactionResult.Ok):
+                        return newAssets;
+                    case (_, TransactionResult.Oversold):
+                        View.ShowOversold();
+                        break;
+                    case (Assets newAssets, TransactionResult.Overspent):
+                        View.ShowOverspent(-newAssets.Cash);
+                        break;
+                }
+            }
+        }
+
+        /// 
+        /// Gets a transaction amount for the given company.
+        /// 
+        /// 
+        /// The company to buy or sell.
+        /// 
+        /// 
+        /// The number of shares to buy or sell.
+        /// 
+        public static int GetTransactionAmount(Company company)
+        {
+            while (true)
+            {
+                View.PromptBuySellCompany(company);
+
+                var input = Console.ReadLine();
+                if (input is null)
+                    Environment.Exit(0);
+                else
+                if (!Int32.TryParse(input, out var amount))
+                    View.PromptValidInteger();
+                else
+                    return amount;
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/Extensions/EnumerableExtensions.cs b/00_Alternate_Languages/83_Stock_Market/csharp/Extensions/EnumerableExtensions.cs
new file mode 100644
index 00000000..11de50a9
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/Extensions/EnumerableExtensions.cs
@@ -0,0 +1,116 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Game.Extensions
+{
+    /// 
+    /// Provides additional methods for the 
+    /// interface.
+    /// 
+    public static class EnumerableExtensions
+    {
+        /// 
+        /// Simultaneously projects each element of a sequence and applies
+        /// the result of the previous projection.
+        /// 
+        /// 
+        /// The type of elements in the source sequence.
+        /// 
+        /// 
+        /// The type of elements in the result sequence.
+        /// 
+        /// 
+        /// The source sequence.
+        /// 
+        /// 
+        /// The seed value for the aggregation component.  This value is
+        /// passed to the first call to .
+        /// 
+        /// 
+        /// The projection function.  This function is supplied with a value
+        /// from the source sequence and the result of the projection on the
+        /// previous value in the source sequence.
+        /// 
+        /// 
+        /// The resulting sequence.
+        /// 
+        public static IEnumerable SelectAndAggregate(
+            this IEnumerable source,
+            TResult seed,
+            Func selector)
+        {
+            foreach (var element in source)
+            {
+                seed = selector(element, seed);
+                yield return seed;
+            }
+        }
+
+        /// 
+        /// Combines the results of three distinct sequences into a single
+        /// sequence.
+        /// 
+        /// 
+        /// The element type of the first sequence.
+        /// 
+        /// 
+        /// The element type of the second sequence.
+        /// 
+        /// 
+        /// The element type of the third sequence.
+        /// 
+        /// 
+        /// The element type of the resulting sequence.
+        /// 
+        /// 
+        /// The first source sequence.
+        /// 
+        /// 
+        /// The second source sequence.
+        /// 
+        /// 
+        /// The third source sequence.
+        /// 
+        /// 
+        /// Function that combines results from each source sequence into a
+        /// final result.
+        /// 
+        /// 
+        /// A sequence of combined values.
+        /// 
+        /// 
+        /// 
+        /// This function works identically to Enumerable.Zip except that it
+        /// combines three sequences instead of two.
+        /// 
+        /// 
+        /// We have defined this as an extension method for consistency with
+        /// the similar LINQ methods in the  class.
+        /// However, since there is nothing special about the first sequence,
+        /// it is often more clear to call this as a regular function.  For
+        /// example:
+        /// 
+        /// 
+        /// EnumerableExtensions.Zip(
+        ///     sequence1,
+        ///     sequence2,
+        ///     sequence3,
+        ///     (a, b, c) => GetResult (a, b, c));
+        /// 
+        /// 
+        public static IEnumerable Zip(
+            this IEnumerable first,
+            IEnumerable second,
+            IEnumerable third,
+            Func resultSelector)
+        {
+            using var enumerator1 = first.GetEnumerator();
+            using var enumerator2 = second.GetEnumerator();
+            using var enumerator3 = third.GetEnumerator();
+
+            while (enumerator1.MoveNext() && enumerator2.MoveNext() && enumerator3.MoveNext())
+                yield return resultSelector(enumerator1.Current, enumerator2.Current, enumerator3.Current);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/Extensions/ImmutableArrayExtensions.cs b/00_Alternate_Languages/83_Stock_Market/csharp/Extensions/ImmutableArrayExtensions.cs
new file mode 100644
index 00000000..544c7625
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/Extensions/ImmutableArrayExtensions.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Immutable;
+
+namespace Game.Extensions
+{
+    /// 
+    /// Provides additional methods for the  class.
+    /// 
+    public static class ImmutableArrayExtensions
+    {
+        /// 
+        /// Maps each element in an immutable array to a new value.
+        /// 
+        /// 
+        /// The type of elements in the source array.
+        /// 
+        /// 
+        /// The type of elements in the resulting array.
+        /// 
+        /// 
+        /// The source array.
+        /// 
+        /// 
+        /// Function which receives an element from the source array and its
+        /// index and returns the resulting element.
+        /// 
+        public static ImmutableArray Map(this ImmutableArray source, Func selector)
+        {
+            var builder = ImmutableArray.CreateBuilder(source.Length);
+
+            for (var i = 0; i < source.Length; ++i)
+                builder.Add(selector(source[i], i));
+
+            return builder.MoveToImmutable();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/Extensions/RandomExtensions.cs b/00_Alternate_Languages/83_Stock_Market/csharp/Extensions/RandomExtensions.cs
new file mode 100644
index 00000000..0c3a4230
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/Extensions/RandomExtensions.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+
+namespace Game.Extensions
+{
+    /// 
+    /// Provides additional methods for the  class.
+    /// 
+    public static class RandomExtensions
+    {
+        /// 
+        /// Generates an infinite sequence of random numbers.
+        /// 
+        /// 
+        /// The random number generator.
+        /// 
+        /// 
+        /// The inclusive lower bound of the range to generate.
+        /// 
+        /// 
+        /// The exclusive upper bound of the range to generate.
+        /// 
+        /// 
+        /// An infinite sequence of random integers in the range [min, max).
+        /// 
+        /// 
+        /// 
+        /// We use an exclusive upper bound, even though it's a little
+        /// confusing, for the sake of consistency with Random.Next.
+        /// 
+        /// 
+        /// Since the sequence is infinite, a typical usage would be to cap
+        /// the results with a function like Enumerable.Take.  For example,
+        /// to sum the results of rolling three six sided dice, we could do:
+        /// 
+        /// 
+        /// random.Integers(1, 7).Take(3).Sum()
+        /// 
+        /// 
+        public static IEnumerable Integers(this Random random, int min, int max)
+        {
+            while (true)
+                yield return random.Next(min, max);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/Program.cs b/00_Alternate_Languages/83_Stock_Market/csharp/Program.cs
new file mode 100644
index 00000000..a7ab841a
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/Program.cs
@@ -0,0 +1,52 @@
+using System;
+using System.Collections.Immutable;
+using System.Linq;
+
+namespace Game
+{
+    class Program
+    {
+        /// 
+        /// Defines the set of companies that will be simulated in the game.
+        /// 
+        private readonly static ImmutableArray Companies = ImmutableArray.CreateRange(new[]
+        {
+            new Company("INT. BALLISTIC MISSILES",     "IBM", sharePrice:100),
+            new Company("RED CROSS OF AMERICA",        "RCA", sharePrice:85 ),
+            new Company("LICHTENSTEIN, BUMRAP & JOKE", "LBJ", sharePrice:150),
+            new Company("AMERICAN BANKRUPT CO.",       "ABC", sharePrice:140),
+            new Company("CENSURED BOOKS STORE",        "CBS", sharePrice:110)
+        });
+
+        static void Main()
+        {
+            var assets = new Assets
+            {
+                Cash      = 10000.0,
+                Portfolio = ImmutableArray.CreateRange(Enumerable.Repeat(0, Companies.Length))
+            };
+
+            var previousDay = default(TradingDay);
+
+            Controller.StartGame();
+
+            foreach (var day in StockMarket.Simulate(Companies))
+            {
+                if (previousDay is null)
+                    View.ShowCompanies(day.Companies);
+                else
+                    View.ShowTradeResults(day, previousDay, assets);
+
+                View.ShowAssets(assets, day.Companies);
+
+                if (previousDay is not null && !Controller.GetYesOrNo(View.PromptContinue))
+                    break;
+
+                assets      = Controller.UpdateAssets(assets, day.Companies);
+                previousDay = day;
+            }
+
+            View.ShowFarewell();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/README.md b/00_Alternate_Languages/83_Stock_Market/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/StockMarket.cs b/00_Alternate_Languages/83_Stock_Market/csharp/StockMarket.cs
new file mode 100644
index 00000000..36201074
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/StockMarket.cs
@@ -0,0 +1,149 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Game.Extensions;
+
+namespace Game
+{
+    /// 
+    /// Provides a method for simulating a stock market.
+    /// 
+    public static class StockMarket
+    {
+        /// 
+        /// Simulates changes in the stock market over time.
+        /// 
+        /// 
+        /// The collection of companies that will participate in the market.
+        /// 
+        /// 
+        /// An infinite sequence of trading days.  Each day represents the
+        /// state of the stock market at the start of that day.
+        /// 
+        public static IEnumerable Simulate(ImmutableArray companies)
+        {
+            var random = new Random();
+
+            var cyclicParameters = EnumerableExtensions.Zip(
+                Trends(random, 1, 5),
+                PriceSpikes(random, companies.Length, 1, 5),
+                PriceSpikes(random, companies.Length, 1, 5),
+                (trend, company1, company2) => (trend, positiveSpike: company1, negativeSpike: company2));
+
+            return cyclicParameters.SelectAndAggregate(
+                new TradingDay
+                {
+                    Companies = companies
+                },
+                (parameters, previousDay) => previousDay with
+                {
+                    Companies = previousDay.Companies.Map(
+                        (company, index) => AdjustSharePrice(
+                            random,
+                            company,
+                            parameters.trend,
+                            parameters.positiveSpike == index,
+                            parameters.negativeSpike == index))
+                });
+        }
+
+        /// 
+        /// Creates a copy of a company with a randomly adjusted share price,
+        /// based on the given parameters.
+        /// 
+        /// 
+        /// The random number generator.
+        /// 
+        /// 
+        /// The company to adjust.
+        /// 
+        /// 
+        /// The slope of the overall market price trend.
+        /// 
+        /// 
+        /// True if the function should simulate a positive spike in the
+        /// company's share price.
+        /// 
+        /// 
+        /// True if the function should simulate a negative spike in the
+        /// company's share price.
+        /// 
+        /// 
+        /// The adjusted company.
+        /// 
+        private static Company AdjustSharePrice(Random random, Company company, double trend, bool positiveSpike, bool negativeSpike)
+        {
+            var boost = random.Next(4) * 0.25;
+
+            var spikeAmount = 0.0;
+
+            if (positiveSpike)
+                spikeAmount = 10;
+
+            if (negativeSpike)
+                spikeAmount = spikeAmount - 10;
+
+            var priceChange = (int)(trend * company.SharePrice) + boost + (int)(3.5 - (6 * random.NextDouble())) + spikeAmount;
+
+            var newPrice = company.SharePrice + priceChange;
+            if (newPrice < 0)
+                newPrice = 0;
+
+            return company with { SharePrice = newPrice };
+        }
+
+        /// 
+        /// Generates an infinite sequence of market trends.
+        /// 
+        /// 
+        /// The random number generator.
+        /// 
+        /// 
+        /// The minimum number of days each trend should last.
+        /// 
+        /// 
+        /// The maximum number of days each trend should last.
+        /// 
+        public static IEnumerable Trends(Random random, int minDays, int maxDays) =>
+            random.Integers(minDays, maxDays + 1).SelectMany(daysInCycle => Enumerable.Repeat(GenerateTrend(random), daysInCycle));
+
+        /// 
+        /// Generates a random value for the market trend.
+        /// 
+        /// 
+        /// The random number generator.
+        /// 
+        /// 
+        /// A trend value in the range [-0.1, 0.1].
+        /// 
+        private static double GenerateTrend(Random random) =>
+            ((int)(random.NextDouble() * 10 + 0.5) / 100.0) * (random.Next(2) == 0 ? 1 : -1) ;
+
+        /// 
+        /// Generates an infinite sequence of price spikes.
+        /// 
+        /// 
+        /// The random number generator.
+        /// 
+        /// 
+        /// The number of companies.
+        /// 
+        /// 
+        /// The minimum number of days in between price spikes.
+        /// 
+        /// 
+        /// The maximum number of days in between price spikes.
+        /// 
+        /// 
+        /// An infinite sequence of random company indexes and null values.
+        /// A non-null value means that the corresponding company should
+        /// experience a price spike.
+        /// 
+        private static IEnumerable PriceSpikes(Random random, int companyCount, int minDays, int maxDays) =>
+            random.Integers(minDays, maxDays + 1)
+                .SelectMany(
+                    daysInCycle => Enumerable.Range(0, daysInCycle),
+                    (daysInCycle, dayNumber) => dayNumber == 0 ? random.Next(companyCount) : default(int?));
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/StockMarket.csproj b/00_Alternate_Languages/83_Stock_Market/csharp/StockMarket.csproj
new file mode 100644
index 00000000..849a99d4
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/StockMarket.csproj
@@ -0,0 +1,7 @@
+
+  
+    Exe
+    net5.0
+    enable
+  
+
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/StockMarket.sln b/00_Alternate_Languages/83_Stock_Market/csharp/StockMarket.sln
new file mode 100644
index 00000000..ab159a5b
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/StockMarket.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StockMarket", "StockMarket.csproj", "{B4C15C31-EB2D-4AAF-8380-5F2EBC0DD9D0}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B4C15C31-EB2D-4AAF-8380-5F2EBC0DD9D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B4C15C31-EB2D-4AAF-8380-5F2EBC0DD9D0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B4C15C31-EB2D-4AAF-8380-5F2EBC0DD9D0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B4C15C31-EB2D-4AAF-8380-5F2EBC0DD9D0}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {C78DBA4A-87E2-4B31-A261-4AEF5E4C3B12}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/TradingDay.cs b/00_Alternate_Languages/83_Stock_Market/csharp/TradingDay.cs
new file mode 100644
index 00000000..4e9d93f4
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/TradingDay.cs
@@ -0,0 +1,24 @@
+using System.Collections.Immutable;
+using System.Linq;
+
+namespace Game
+{
+    /// 
+    /// Represents a single trading day.
+    /// 
+    public record TradingDay
+    {
+        /// 
+        /// Gets the average share price of all companies in the market this
+        /// day.
+        /// 
+        public double AverageSharePrice =>
+            Companies.Average (company => company.SharePrice);
+
+        /// 
+        /// Gets the collection of public listed companies in the stock market
+        /// this day.
+        /// 
+        public ImmutableArray Companies { get; init; }
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/TransactionResult.cs b/00_Alternate_Languages/83_Stock_Market/csharp/TransactionResult.cs
new file mode 100644
index 00000000..23ee8831
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/TransactionResult.cs
@@ -0,0 +1,25 @@
+namespace Game
+{
+    /// 
+    /// Enumerates the different possible outcomes of applying a transaction.
+    /// 
+    public enum TransactionResult
+    {
+        /// 
+        /// The transaction was successful.
+        /// 
+        Ok,
+
+        /// 
+        /// The transaction failed because the seller tried to sell more shares
+        /// than he or she owns.
+        /// 
+        Oversold,
+
+        /// 
+        /// The transaction failed because the net cost was greater than the
+        /// seller's available cash.
+        /// 
+        Overspent
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/csharp/View.cs b/00_Alternate_Languages/83_Stock_Market/csharp/View.cs
new file mode 100644
index 00000000..28426b98
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/csharp/View.cs
@@ -0,0 +1,157 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Game.Extensions;
+
+namespace Game
+{
+    /// 
+    /// Contains functions for displaying information to the user.
+    /// 
+    public static class View
+    {
+        public static void ShowBanner()
+        {
+            Console.WriteLine("                             STOCK MARKET");
+            Console.WriteLine("               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+        }
+
+        public static void ShowInstructions()
+        {
+            Console.WriteLine("THIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN");
+            Console.WriteLine("$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL");
+            Console.WriteLine("BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT");
+            Console.WriteLine("REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE");
+            Console.WriteLine("OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES");
+            Console.WriteLine("IN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE");
+            Console.WriteLine("INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION");
+            Console.WriteLine("MARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK");
+            Console.WriteLine("TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE");
+            Console.WriteLine("NUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED");
+            Console.WriteLine("ON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS");
+            Console.WriteLine("TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU");
+            Console.WriteLine("HAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS.");
+            Console.WriteLine("(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST");
+            Console.WriteLine("10 DAYS)");
+            Console.WriteLine("-----GOOD LUCK!-----");
+        }
+
+        public static void ShowCompanies(IEnumerable companies)
+        {
+            var maxNameLength = companies.Max(company => company.Name.Length);
+
+            Console.WriteLine($"{"STOCK".PadRight(maxNameLength)} INITIALS      PRICE/SHARE");
+            foreach (var company in companies)
+                Console.WriteLine($"{company.Name.PadRight(maxNameLength)}   {company.StockSymbol}          {company.SharePrice:0.00}");
+
+            Console.WriteLine();
+            Console.WriteLine($"NEW YORK STOCK EXCHANGE AVERAGE: {companies.Average(company => company.SharePrice):0.00}");
+            Console.WriteLine();
+        }
+
+        public static void ShowTradeResults(TradingDay day, TradingDay previousDay, Assets assets)
+        {
+            var results = EnumerableExtensions.Zip(
+                day.Companies,
+                previousDay.Companies,
+                assets.Portfolio,
+                (company, previous, shares) =>
+                (
+                    stockSymbol: company.StockSymbol,
+                    price: company.SharePrice,
+                    shares,
+                    value: shares * company.SharePrice,
+                    change: company.SharePrice - previous.SharePrice
+                )).ToList();
+
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("**********     END OF DAY'S TRADING     **********");
+            Console.WriteLine();
+            Console.WriteLine();
+
+            Console.WriteLine("STOCK\tPRICE/SHARE\tHOLDINGS\tVALUE\tNET PRICE CHANGE");
+            foreach (var result in results)
+                Console.WriteLine($"{result.stockSymbol}\t{result.price}\t\t{result.shares}\t\t{result.value:0.00}\t\t{result.change:0.00}");
+
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+
+            var averagePrice = day.AverageSharePrice;
+            var averagePriceChange = averagePrice - previousDay.AverageSharePrice;
+
+            Console.WriteLine($"NEW YORK STOCK EXCHANGE AVERAGE: {averagePrice:0.00} NET CHANGE {averagePriceChange:0.00}");
+            Console.WriteLine();
+        }
+
+        public static void ShowAssets(Assets assets, IEnumerable companies)
+        {
+            var totalStockValue = Enumerable.Zip(
+                assets.Portfolio,
+                companies,
+                (shares, company) => shares * company.SharePrice).Sum();
+
+            Console.WriteLine($"TOTAL STOCK ASSETS ARE   ${totalStockValue:0.00}");
+            Console.WriteLine($"TOTAL CASH ASSETS ARE    ${assets.Cash:0.00}");
+            Console.WriteLine($"TOTAL ASSETS ARE         ${totalStockValue + assets.Cash:0.00}");
+            Console.WriteLine();
+        }
+
+        public static void ShowOversold()
+        {
+            Console.WriteLine();
+            Console.WriteLine("YOU HAVE OVERSOLD A STOCK; TRY AGAIN.");
+        }
+
+        public static void ShowOverspent(double amount)
+        {
+            Console.WriteLine();
+            Console.WriteLine($"YOU HAVE USED ${amount:0.00} MORE THAN YOU HAVE.");
+        }
+
+        public static void ShowFarewell()
+        {
+            Console.WriteLine("HOPE YOU HAD FUN!!");
+        }
+
+        public static void ShowSeparator()
+        {
+            Console.WriteLine();
+            Console.WriteLine();
+        }
+
+        public static void ShowChar(char c)
+        {
+            Console.WriteLine(c);
+        }
+
+        public static void PromptShowInstructions()
+        {
+            Console.Write("DO YOU WANT THE INSTRUCTIONS (YES-TYPE 1, NO-TYPE 0)? ");
+        }
+
+        public static void PromptContinue()
+        {
+            Console.Write("DO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)? ");
+        }
+
+        public static void PromptEnterTransactions()
+        {
+            Console.WriteLine("WHAT IS YOUR TRANSACTION IN");
+        }
+
+        public static void PromptBuySellCompany(Company company)
+        {
+            Console.Write($"{company.StockSymbol}? ");
+        }
+
+        public static void PromptValidInteger()
+        {
+            Console.WriteLine("PLEASE ENTER A VALID INTEGER");
+        }
+    }
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/java/README.md b/00_Alternate_Languages/83_Stock_Market/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/83_Stock_Market/java/StockMarket.java b/00_Alternate_Languages/83_Stock_Market/java/StockMarket.java
new file mode 100644
index 00000000..3eb883e9
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/java/StockMarket.java
@@ -0,0 +1,426 @@
+import java.util.ArrayList;
+import java.util.InputMismatchException;
+import java.util.List;
+import java.util.Random;
+import java.util.Scanner;
+
+/**
+ * Stock Market Simulation
+ *
+ * Some of the original program's variables' documentation and their equivalent in this program:
+ * A-MRKT TRND SLP;             marketTrendSlope
+ * B5-BRKRGE FEE;               brokerageFee
+ * C-TTL CSH ASSTS;             cashAssets
+ * C5-TTL CSH ASSTS (TEMP);     tmpCashAssets
+ * C(I)-CHNG IN STK VAL;        changeStockValue
+ * D-TTL ASSTS;                 assets
+ * E1,E2-LRG CHNG MISC;         largeChange1, largeChange2
+ * I1,I2-STCKS W LRG CHNG;      randomStockIndex1, randomStockIndex2
+ * N1,N2-LRG CHNG DAY CNTS;     largeChangeNumberDays1, largeChangeNumberDays2
+ * P5-TTL DAYS PRCHSS;          totalDaysPurchases
+ * P(I)-PRTFL CNTNTS;           portfolioContents
+ * Q9-NEW CYCL?;                newCycle
+ * S4-SGN OF A;                 slopeSign
+ * S5-TTL DYS SLS;              totalDaysSales
+ * S(I)-VALUE/SHR;              stockValue
+ * T-TTL STCK ASSTS;            totalStockAssets
+ * T5-TTL VAL OF TRNSCTNS;      totalValueOfTransactions
+ * W3-LRG CHNG;                 bigChange
+ * X1-SMLL CHNG(<$1);           smallChange
+ * Z4,Z5,Z6-NYSE AVE.;          tmpNyseAverage, nyseAverage, nyseAverageChange
+ * Z(I)-TRNSCT                  transactionQuantity
+ *
+ * new price = old price + (trend x old price) + (small random price
+ * change) + (possible large price change)
+ *
+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)
+ */
+public class StockMarket {
+
+	private static final Random random = new Random();
+
+	public static void main(String[] args) {
+
+		Scanner scan = new Scanner(System.in);
+
+		printIntro();
+		printGameHelp(scan);
+
+		final List stocks = initStocks();
+
+		double marketTrendSlope = Math.floor((random.nextFloat() / 10) * 100 + 0.5)/100f;
+		double totalValueOfTransactions;
+		int largeChangeNumberDays1 = 0;
+		int largeChangeNumberDays2 = 0;
+
+		//DAYS FOR FIRST TREND SLOPE (A)
+		var t8 = randomNumber(1, 6);
+
+		//RANDOMIZE SIGN OF FIRST TREND SLOPE (A)
+		if (random.nextFloat() <= 0.5) {
+			marketTrendSlope = -marketTrendSlope;
+		}
+
+		// INITIALIZE CASH ASSETS:C
+		double cashAssets = 10000;
+		boolean largeChange1 = false;
+		boolean largeChange2 = false;
+		double tmpNyseAverage;
+		double nyseAverage = 0;
+		boolean inProgress = true;
+		var firstRound = true;
+
+		while (inProgress) {
+
+			/* Original documentation:
+			RANDOMLY PRODUCE NEW STOCK VALUES BASED ON PREVIOUS DAY'S VALUES
+			N1,N2 ARE RANDOM NUMBERS OF DAYS WHICH RESPECTIVELY
+			DETERMINE WHEN STOCK I1 WILL INCREASE 10 PTS. AND STOCK
+			I2 WILL DECREASE 10 PTS.
+			IF N1 DAYS HAVE PASSED, PICK AN I1, SET E1, DETERMINE NEW N1
+			*/
+			int randomStockIndex1 = 0;
+			int randomStockIndex2 = 0;
+
+			if (largeChangeNumberDays1 <= 0) {
+				randomStockIndex1 = randomNumber(0, stocks.size());
+				largeChangeNumberDays1 = randomNumber(1, 6);
+				largeChange1 = true;
+			}
+			if (largeChangeNumberDays2 <= 0) {
+				randomStockIndex2 = randomNumber(0, stocks.size());
+				largeChangeNumberDays2 = randomNumber(1, 6);
+				largeChange2 = true;
+			}
+			adjustAllStockValues(stocks, largeChange1, largeChange2, marketTrendSlope, stocks.get(randomStockIndex1), stocks.get(randomStockIndex2));
+
+			//reset largeChange flags
+			largeChange1 = false;
+			largeChange2 = false;
+			largeChangeNumberDays1--;
+			largeChangeNumberDays2--;
+
+			//AFTER T8 DAYS RANDOMLY CHANGE TREND SIGN AND SLOPE
+			t8 = t8 - 1;
+			if (t8 < 1) {
+				marketTrendSlope = newMarketTrendSlope();
+				t8 = randomNumber(1, 6);
+			}
+
+			//PRINT PORTFOLIO
+			printPortfolio(firstRound, stocks);
+
+			tmpNyseAverage = nyseAverage;
+			nyseAverage = 0;
+			double totalStockAssets = 0;
+			for (Stock stock : stocks) {
+				nyseAverage = nyseAverage + stock.getStockValue();
+				totalStockAssets = totalStockAssets + stock.getStockValue() * stock.getPortfolioContents();
+			}
+			nyseAverage = Math.floor(100 * (nyseAverage / 5) + .5) / 100f;
+			double nyseAverageChange = Math.floor((nyseAverage - tmpNyseAverage) * 100 + .5) / 100f;
+
+			// TOTAL ASSETS:D
+			double assets = totalStockAssets + cashAssets;
+			if (firstRound) {
+				System.out.printf("\n\nNEW YORK STOCK EXCHANGE AVERAGE: %.2f", nyseAverage);
+			} else {
+				System.out.printf("\n\nNEW YORK STOCK EXCHANGE AVERAGE: %.2f NET CHANGE %.2f", nyseAverage, nyseAverageChange);
+			}
+
+			totalStockAssets = Math.floor(100 * totalStockAssets + 0.5) / 100d;
+			System.out.printf("\n\nTOTAL STOCK ASSETS ARE   $ %.2f", totalStockAssets);
+       		cashAssets = Math.floor(100 * cashAssets + 0.5) / 100d;
+			System.out.printf("\nTOTAL CASH ASSETS ARE    $ %.2f", cashAssets);
+			assets = Math.floor(100 * assets + .5) / 100d;
+			System.out.printf("\nTOTAL ASSETS ARE         $ %.2f\n", assets);
+
+			if (!firstRound) {
+				System.out.print("\nDO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)? ");
+				var newCycle = readANumber(scan);
+				if (newCycle < 1) {
+					System.out.println("HOPE YOU HAD FUN!!");
+					inProgress = false;
+				}
+			}
+
+			if (inProgress) {
+				boolean validTransaction = false;
+				//    TOTAL DAY'S PURCHASES IN $:P5
+				double totalDaysPurchases = 0;
+				//    TOTAL DAY'S SALES IN $:S5
+				double totalDaysSales = 0;
+				double tmpCashAssets;
+				while (!validTransaction) {
+					//INPUT TRANSACTIONS
+					readStockTransactions(stocks, scan);
+					totalDaysPurchases = 0;
+					totalDaysSales = 0;
+
+					validTransaction = true;
+					for (Stock stock : stocks) {
+						stock.setTransactionQuantity(Math.floor(stock.getTransactionQuantity() + 0.5));
+						if (stock.getTransactionQuantity() > 0) {
+							totalDaysPurchases = totalDaysPurchases + stock.getTransactionQuantity() * stock.getStockValue();
+						} else {
+							totalDaysSales = totalDaysSales - stock.getTransactionQuantity() * stock.getStockValue();
+							if (-stock.getTransactionQuantity() > stock.getPortfolioContents()) {
+								System.out.println("YOU HAVE OVERSOLD A STOCK; TRY AGAIN.");
+								validTransaction = false;
+								break;
+							}
+						}
+					}
+
+					//TOTAL VALUE OF TRANSACTIONS:T5
+					totalValueOfTransactions = totalDaysPurchases + totalDaysSales;
+					// BROKERAGE FEE:B5
+					var brokerageFee = Math.floor(0.01 * totalValueOfTransactions * 100 + .5) / 100d;
+					// CASH ASSETS=OLD CASH ASSETS-TOTAL PURCHASES
+					//-BROKERAGE FEES+TOTAL SALES:C5
+					tmpCashAssets = cashAssets - totalDaysPurchases - brokerageFee + totalDaysSales;
+					if (tmpCashAssets < 0) {
+						System.out.printf("\nYOU HAVE USED $%.2f MORE THAN YOU HAVE.", -tmpCashAssets);
+						validTransaction = false;
+					} else {
+						cashAssets = tmpCashAssets;
+					}
+				}
+
+				// CALCULATE NEW PORTFOLIO
+				for (Stock stock : stocks) {
+					stock.setPortfolioContents(stock.getPortfolioContents() + stock.getTransactionQuantity());
+				}
+
+				firstRound = false;
+			}
+
+		}
+	}
+
+	/**
+	 * Random int between lowerBound(inclusive) and upperBound(exclusive)
+	 */
+	private static int randomNumber(int lowerBound, int upperBound) {
+		return random.nextInt((upperBound - lowerBound)) + lowerBound;
+	}
+
+	private static double newMarketTrendSlope() {
+		return randomlyChangeTrendSignAndSlopeAndDuration();
+	}
+
+	private static void printPortfolio(boolean firstRound, List stocks) {
+		//BELL RINGING-DIFFERENT ON MANY COMPUTERS
+		if (firstRound) {
+			System.out.printf("%n%-30s\t%12s\t%12s", "STOCK", "INITIALS", "PRICE/SHARE");
+			for (Stock stock : stocks) {
+				System.out.printf("%n%-30s\t%12s\t%12.2f ------ %12.2f", stock.getStockName(), stock.getStockCode(),
+						stock.getStockValue(), stock.getChangeStockValue());
+			}
+			System.out.println("");
+		} else {
+			System.out.println("\n**********     END OF DAY'S TRADING     **********\n\n");
+			System.out.printf("%n%-12s\t%-12s\t%-12s\t%-12s\t%-20s", "STOCK", "PRICE/SHARE",
+					"HOLDINGS", "VALUE", "NET PRICE CHANGE");
+			for (Stock stock : stocks) {
+				System.out.printf("%n%-12s\t%-12.2f\t%-12.0f\t%-12.2f\t%-20.2f",
+						stock.getStockCode(), stock.getStockValue(), stock.getPortfolioContents(),
+						stock.getStockValue() * stock.getPortfolioContents(), stock.getChangeStockValue());
+			}
+		}
+	}
+
+	private static void readStockTransactions(List stocks, Scanner scan) {
+		System.out.println("\n\nWHAT IS YOUR TRANSACTION IN");
+		for (Stock stock : stocks) {
+			System.out.printf("%s? ", stock.getStockCode());
+
+			stock.setTransactionQuantity(readANumber(scan));
+		}
+	}
+
+	private static int readANumber(Scanner scan) {
+		int choice = 0;
+
+		boolean validInput = false;
+		while (!validInput) {
+			try {
+				choice = scan.nextInt();
+				validInput = true;
+			} catch (InputMismatchException ex) {
+				System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE");
+			} finally {
+				scan.nextLine();
+			}
+		}
+
+		return choice;
+	}
+
+	private static void adjustAllStockValues(List stocks, boolean largeChange1,
+			boolean largeChange2,
+			double marketTrendSlope,
+			Stock stockForLargeChange1, Stock stockForLargeChange2
+	) {
+		//LOOP THROUGH ALL STOCKS
+		for (Stock stock : stocks) {
+			double smallChange = random.nextFloat();
+
+			if (smallChange <= 0.25) {
+				smallChange = 0.25;
+			} else if (smallChange <= 0.5) {
+				smallChange = 0.5;
+			} else if (smallChange <= 0.75) {
+				smallChange = 0.75;
+			} else {
+				smallChange = 0;
+			}
+
+			//BIG CHANGE CONSTANT:W3  (SET TO ZERO INITIALLY)
+			var bigChange = 0;
+			if (largeChange1) {
+				if (stock.getStockCode().equals(stockForLargeChange1.getStockCode())) {
+					//ADD 10 PTS. TO THIS STOCK;  RESET E1
+					bigChange = 10;
+				}
+			}
+
+			if (largeChange2) {
+				if (stock.getStockCode().equals(stockForLargeChange2.getStockCode())) {
+					//SUBTRACT 10 PTS. FROM THIS STOCK;  RESET E2
+					bigChange = bigChange - 10;
+				}
+			}
+
+			stock.setChangeStockValue(Math.floor(marketTrendSlope * stock.stockValue) + smallChange +
+					Math.floor(3 - 6 * random.nextFloat() + .5) + bigChange);
+			stock.setChangeStockValue(Math.floor(100 * stock.getChangeStockValue() + .5) / 100d);
+			stock.stockValue += stock.getChangeStockValue();
+
+			if (stock.stockValue > 0) {
+				stock.stockValue = Math.floor(100 * stock.stockValue + 0.5) / 100d;
+			} else {
+				stock.setChangeStockValue(0);
+				stock.stockValue = 0;
+			}
+		}
+	}
+
+	private static double randomlyChangeTrendSignAndSlopeAndDuration() {
+		// RANDOMLY CHANGE TREND SIGN AND SLOPE (A), AND DURATION
+		var newTrend = Math.floor((random.nextFloat() / 10) * 100 + .5) / 100d;
+		var slopeSign = random.nextFloat();
+		if (slopeSign > 0.5) {
+			newTrend = -newTrend;
+		}
+		return newTrend;
+	}
+
+	private static List initStocks() {
+		List stocks = new ArrayList<>();
+		stocks.add(new Stock(100, "INT. BALLISTIC MISSILES", "IBM"));
+		stocks.add(new Stock(85, "RED CROSS OF AMERICA", "RCA"));
+		stocks.add(new Stock(150, "LICHTENSTEIN, BUMRAP & JOKE", "LBJ"));
+		stocks.add(new Stock(140, "AMERICAN BANKRUPT CO.", "ABC"));
+		stocks.add(new Stock(110, "CENSURED BOOKS STORE", "CBS"));
+		return stocks;
+	}
+
+	private static void printGameHelp(Scanner scan) {
+		System.out.print("DO YOU WANT THE INSTRUCTIONS (YES-TYPE 1, NO-TYPE 0) ? ");
+		int choice = scan.nextInt();
+		if (choice >= 1) {
+			System.out.println("");
+			System.out.println("THIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN");
+			System.out.println("$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL");
+			System.out.println("BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT");
+			System.out.println("REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE");
+			System.out.println("OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES");
+			System.out.println("IN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE");
+			System.out.println("INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION");
+			System.out.println("MARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK");
+			System.out.println("TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE");
+			System.out.println("NUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED");
+			System.out.println("ON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS");
+			System.out.println("TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU");
+			System.out.println("HAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS.");
+			System.out.println("(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST");
+			System.out.println("10 DAYS)");
+			System.out.println("-----GOOD LUCK!-----");
+		}
+		System.out.println("\n\n");
+	}
+
+	private static void printIntro() {
+		System.out.println("                                STOCK MARKET");
+		System.out.println("              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+		System.out.println("\n\n");
+	}
+
+	/**
+	 * Stock class also storing the stock information and other related information for simplicity
+	 */
+	private static class Stock {
+
+		private final String stockName;
+		private final String stockCode;
+		private double stockValue;
+		private double portfolioContents = 0;
+		private double transactionQuantity = 0;
+		private double changeStockValue = 0;
+
+		public Stock(double stockValue, String stockName, String stockCode) {
+			this.stockValue = stockValue;
+			this.stockName = stockName;
+			this.stockCode = stockCode;
+		}
+
+		public String getStockName() {
+			return stockName;
+		}
+
+		public String getStockCode() {
+			return stockCode;
+		}
+
+		public double getStockValue() {
+			return stockValue;
+		}
+
+		public double getPortfolioContents() {
+			return portfolioContents;
+		}
+
+		public void setPortfolioContents(double portfolioContents) {
+			this.portfolioContents = portfolioContents;
+		}
+
+		public double getTransactionQuantity() {
+			return transactionQuantity;
+		}
+
+		public void setTransactionQuantity(double transactionQuantity) {
+			this.transactionQuantity = transactionQuantity;
+		}
+
+		public double getChangeStockValue() {
+			return changeStockValue;
+		}
+
+		public void setChangeStockValue(double changeStockValue) {
+			this.changeStockValue = changeStockValue;
+		}
+
+		@Override
+		public String toString() {
+			return "Stock{" +
+					"stockValue=" + stockValue +
+					", stockCode='" + stockCode + '\'' +
+					", portfolioContents=" + portfolioContents +
+					", transactionQuantity=" + transactionQuantity +
+					", changeStockValue=" + changeStockValue +
+					'}';
+		}
+	}
+
+}
diff --git a/00_Alternate_Languages/83_Stock_Market/javascript/README.md b/00_Alternate_Languages/83_Stock_Market/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/83_Stock_Market/javascript/stockmarket.html b/00_Alternate_Languages/83_Stock_Market/javascript/stockmarket.html
new file mode 100644
index 00000000..6a6188ef
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/javascript/stockmarket.html
@@ -0,0 +1,9 @@
+
+
+STOCKMARKET
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/83_Stock_Market/javascript/stockmarket.js b/00_Alternate_Languages/83_Stock_Market/javascript/stockmarket.js
new file mode 100644
index 00000000..69af32f9
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/javascript/stockmarket.js
@@ -0,0 +1,317 @@
+// STOCKMARKET
+//
+// 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 = [];
+var pa = [];
+var za = [];
+var ca = [];
+var i1;
+var n1;
+var e1;
+var i2;
+var n2;
+var e2;
+var x1;
+var w3;
+var t8;
+var a;
+var s4;
+
+// New stock values - subroutine
+function randomize_initial()
+{
+    // RANDOMLY PRODUCE NEW STOCK VALUES BASED ON PREVIOUS
+    // DAY'S VALUES
+    // N1,N2 ARE RANDOM NUMBERS OF DAYS WHICH RESPECTIVELY
+    // DETERMINE WHEN STOCK I1 WILL INCREASE 10 PTS. AND STOCK
+    // I2 WILL DECREASE 10 PTS.
+    // IF N1 DAYS HAVE PASSED, PICK AN I1, SET E1, DETERMINE NEW N1
+    if (n1 <= 0) {
+        i1 = Math.floor(4.99 * Math.random() + 1);
+        n1 = Math.floor(4.99 * Math.random() + 1);
+        e1 = 1;
+    }
+    // IF N2 DAYS HAVE PASSED, PICK AN I2, SET E2, DETERMINE NEW N2
+    if (n2 <= 0) {
+        i2 = Math.floor(4.99 * Math.random() + 1);
+        n2 = Math.floor(4.99 * Math.random() + 1);
+        e2 = 1;
+    }
+    // DEDUCT ONE DAY FROM N1 AND N2
+    n1--;
+    n2--;
+    // LOOP THROUGH ALL STOCKS
+    for (i = 1; i <= 5; i++) {
+        x1 = Math.random();
+        if (x1 < 0.25) {
+            x1 = 0.25;
+        } else if (x1 < 0.5) {
+            x1 = 0.5;
+        } else if (x1 < 0.75) {
+            x1 = 0.75;
+        } else {
+            x1 = 0.0;
+        }
+        // BIG CHANGE CONSTANT:W3  (SET TO ZERO INITIALLY)
+        w3 = 0;
+        if (e1 >= 1 && Math.floor(i1 + 0.5) == Math.floor(i + 0.5)) {
+            // ADD 10 PTS. TO THIS STOCK;  RESET E1
+            w3 = 10;
+            e1 = 0;
+        }
+        if (e2 >= 1 && Math.floor(i2 + 0.5) == Math.floor(i + 0.5)) {
+            // SUBTRACT 10 PTS. FROM THIS STOCK;  RESET E2
+            w3 -= 10;
+            e2 = 0;
+        }
+        // C(I) IS CHANGE IN STOCK VALUE
+        ca[i] = Math.floor(a * sa[i]) + x1 + Math.floor(3 - 6 * Math.random() + 0.5) + w3;
+        ca[i] = Math.floor(100 * ca[i] + 0.5) / 100;
+        sa[i] += ca[i];
+        if (sa[i] <= 0) {
+            ca[i] = 0;
+            sa[i] = 0;
+        } else {
+            sa[i] = Math.floor(100 * sa[i] + 0.5) / 100;
+        }
+    }
+    // AFTER T8 DAYS RANDOMLY CHANGE TREND SIGN AND SLOPE
+    if (--t8 < 1) {
+        // RANDOMLY CHANGE TREND SIGN AND SLOPE (A), AND DURATION
+        // OF TREND (T8)
+        t8 = Math.floor(4.99 * Math.random() + 1);
+        a = Math.floor((Math.random() / 10) * 100 + 0.5) / 100;
+        s4 = Math.random();
+        if (s4 > 0.5)
+            a = -a;
+    }
+}
+
+// Main program
+async function main()
+{
+    print(tab(30) + "STOCK MARKET\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    // STOCK MARKET SIMULATION     -STOCK-
+    // REVISED 8/18/70 (D. PESSEL, L. BRAUN, C. LOSIK)
+    // IMP VRBLS: A-MRKT TRND SLP; B5-BRKRGE FEE; C-TTL CSH ASSTS;
+    // C5-TTL CSH ASSTS (TEMP); C(I)-CHNG IN STK VAL; D-TTL ASSTS;
+    // E1,E2-LRG CHNG MISC; I-STCK #; I1,I2-STCKS W LRG CHNG;
+    // N1,N2-LRG CHNG DAY CNTS; P5-TTL DAYS PRCHSS; P(I)-PRTFL CNTNTS;
+    // Q9-NEW CYCL?; S4-SGN OF A; S5-TTL DYS SLS; S(I)-VALUE/SHR;
+    // T-TTL STCK ASSTS; T5-TTL VAL OF TRNSCTNS;
+    // W3-LRG CHNG; X1-SMLL CHNG(<$1); Z4,Z5,Z6-NYSE AVE.; Z(I)-TRNSCT
+    // SLOPE OF MARKET TREND:A  (SAME FOR ALL STOCKS)
+    x = 1;
+    a = Math.floor(Math.random() / 10 * 100 + 0.5) / 100;
+    t5 = 0;
+    x9 = 0;
+    n1 = 0;
+    n2 = 0;
+    e1 = 0;
+    e2 = 0;
+    // INTRODUCTION
+    print("DO YOU WANT THE INSTRUCTIONS (YES-TYPE 1, NO-TYPE 0)");
+    z9 = parseInt(await input());
+    print("\n");
+    print("\n");
+    if (z9 >= 1) {
+        print("THIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN\n");
+        print("$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL\n");
+        print("BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT\n");
+        print("REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE\n");
+        print("OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES\n");
+        print("IN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE\n");
+        print("INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION\n");
+        print("MARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK\n");
+        print("TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE\n");
+        print("NUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED\n");
+        print("ON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS\n");
+        print("TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU\n");
+        print("HAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS.\n");
+        print("(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST\n");
+        print("10 DAYS)\n");
+        print("-----GOOD LUCK!-----\n");
+    }
+    // GENERATION OF STOCK TABLE: INPUT REQUESTS
+    // INITIAL STOCK VALUES
+    sa[1] = 100;
+    sa[2] = 85;
+    sa[3] = 150;
+    sa[4] = 140;
+    sa[5] = 110;
+    // INITIAL T8 - # DAYS FOR FIRST TREND SLOPE (A)
+    t8 = Math.floor(4.99 * Math.random() + 1);
+    // RANDOMIZE SIGN OF FIRST TREND SLOPE (A)
+    if (Math.random() <= 0.5)
+        a -= a;
+    // RANDOMIZE INITIAL VALUES
+    randomize_initial();
+    // INITIAL PORTFOLIO CONTENTS
+    for (i = 1; i <= 5; i++) {
+        pa[i] = 0;
+        za[i] = 0;
+    }
+    print("\n");
+    print("\n");
+    // INITIALIZE CASH ASSETS:C
+    c = 10000;
+    z5 = 0;
+    // PRINT INITIAL PORTFOLIO
+    print("STOCK\t \t\t\tINITIALS\tPRICE/SHARE\n");
+    print("INT. BALLISTIC MISSILES\t\t  IBM\t\t" + sa[1] + "\n");
+    print("RED CROSS OF AMERICA\t\t  RCA\t\t" + sa[2] + "\n");
+    print("LICHTENSTEIN, BUMRAP & JOKE\t  LBJ\t\t" + sa[3] + "\n");
+    print("AMERICAN BANKRUPT CO.\t\t  ABC\t\t" + sa[4] + "\n");
+    print("CENSURED BOOKS STORE\t\t  CBS\t\t" + sa[5] + "\n");
+    while (1) {
+        print("\n");
+        // NYSE AVERAGE:Z5; TEMP. VALUE:Z4; NET CHANGE:Z6
+        z4 = z5;
+        z5 = 0;
+        t = 0;
+        for (i = 1; i <= 5; i++) {
+            z5 += sa[i];
+            t += sa[i] * pa[i];
+        }
+        z5 = Math.floor(100 * (z5 / 5) + 0.5) / 100;
+        z6 = Math.floor((z5 - z4) * 100 + 0.5) / 100;
+        // TOTAL ASSETS:D
+        d = t + c;
+        if (x9 <= 0) {
+            print("NEW YORK STOCK EXCHANGE AVERAGE: " + z5 + "\n");
+        } else {
+            print("NEW YORK STOCK EXCHANGE AVERAGE: " + z5 + " NET CHANGE " + z6 + "\n");
+        }
+        print("\n");
+        t = Math.floor(100 * t + 0.5) / 100;
+        print("TOTAL STOCK ASSETS ARE   $" + t + "\n");
+        c = Math.floor(100 * c + 0.5) / 100;
+        print("TOTAL CASH ASSETS ARE    $" + c + "\n");
+        d = Math.floor(100 * d + 0.5) / 100;
+        print("TOTAL ASSETS ARE         $" + d + "\n");
+        print("\n");
+        if (x9 != 0) {
+            print("DO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)");
+            q9 = parseInt(await input());
+            if (q9 < 1) {
+                print("HOPE YOU HAD FUN!!\n");
+                return;
+            }
+        }
+        // INPUT TRANSACTIONS
+        while (1) {
+            print("WHAT IS YOUR TRANSACTION IN\n");
+            print("IBM");
+            za[1] = parseInt(await input());
+            print("RCA");
+            za[2] = parseInt(await input());
+            print("LBJ");
+            za[3] = parseInt(await input());
+            print("ABC");
+            za[4] = parseInt(await input());
+            print("CBS");
+            za[5] = parseInt(await input());
+            print("\n");
+            // TOTAL DAY'S PURCHASES IN $:P5
+            p5 = 0;
+            // TOTAL DAY'S SALES IN $:S5
+            s5 = 0;
+            for (i = 1; i <= 5; i++) {
+                za[i] = Math.floor(za[i] + 0.5);
+                if (za[i] > 0) {
+                    p5 += za[i] * sa[i];
+                } else {
+                    s5 -= za[i] * sa[i];
+                    if (-za[i] > pa[i]) {
+                        print("YOU HAVE OVERSOLD A STOCK; TRY AGAIN.\n");
+                        break;
+                    }
+                }
+            }
+            if (i <= 5)
+                contine;
+            // TOTAL VALUE OF TRANSACTIONS:T5
+            t5 = p5 + s5;
+            // BROKERAGE FEE:B5
+            b5 = Math.floor(0.01 * t5 * 100 + 0.5) / 100;
+            // CASH ASSETS=OLD CASH ASSETS-TOTAL PURCHASES
+            // -BROKERAGE FEES+TOTAL SALES:C5
+            c5 = c - p5 - b5 + s5;
+            if (c5 < 0) {
+                print("YOU HAVE USED $" + (-c5) + " MORE THAN YOU HAVE.\n");
+                continue;
+            }
+            break;
+        }
+        c = c5;
+        // CALCULATE NEW PORTFOLIO
+        for (i = 1; i <= 5; i++) {
+            pa[i] += za[i];
+        }
+        // CALCULATE NEW STOCK VALUES
+        randomize_initial();
+        // PRINT PORTFOLIO
+        // BELL RINGING-DIFFERENT ON MANY COMPUTERS
+        print("\n");
+        print("**********     END OF DAY'S TRADING     **********\n");
+        print("\n");
+        print("\n");
+        if (x9 >= 1) ;
+        print("STOCK\tPRICE/SHARE\tHOLDINGS\tVALUE\tNET PRICE CHANGE\n");
+        print("IBM\t" + sa[1] + "\t\t" + pa[1] + "\t\t" + sa[1] * pa[1] + "\t" + ca[1] + "\n");
+        print("RCA\t" + sa[2] + "\t\t" + pa[2] + "\t\t" + sa[2] * pa[2] + "\t" + ca[2] + "\n");
+        print("LBJ\t" + sa[3] + "\t\t" + pa[3] + "\t\t" + sa[3] * pa[3] + "\t" + ca[3] + "\n");
+        print("ABC\t" + sa[4] + "\t\t" + pa[4] + "\t\t" + sa[4] * pa[4] + "\t" + ca[4] + "\n");
+        print("CBS\t" + sa[5] + "\t\t" + pa[5] + "\t\t" + sa[5] * pa[5] + "\t" + ca[5] + "\n");
+        x9 = 1;
+        print("\n");
+        print("\n");
+    }
+}
+
+main();
diff --git a/58_Love/pascal/README.md b/00_Alternate_Languages/83_Stock_Market/pascal/README.md
similarity index 100%
rename from 58_Love/pascal/README.md
rename to 00_Alternate_Languages/83_Stock_Market/pascal/README.md
diff --git a/00_Alternate_Languages/83_Stock_Market/perl/README.md b/00_Alternate_Languages/83_Stock_Market/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/83_Stock_Market/python/README.md b/00_Alternate_Languages/83_Stock_Market/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/83_Stock_Market/python/Stock_Market.py b/00_Alternate_Languages/83_Stock_Market/python/Stock_Market.py
new file mode 100644
index 00000000..4d7d63a8
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/python/Stock_Market.py
@@ -0,0 +1,228 @@
+import random
+
+
+# Stock_Market
+class Stock_Market:
+    def __init__(self):
+
+        # Hard Coded Names
+        short_names = ["IBM", "RCA", "LBJ", "ABC", "CBS"]
+        full_names = [
+            "INT. BALLISTIC MISSLES",
+            "RED CROSS OF AMERICA",
+            "LICHTENSTEIN, BUMRAP & JOKE",
+            "AMERICAN BANKRUPT CO.",
+            "CENSURED BOOKS STORE",
+        ]
+
+        # Initializing Dictionary to hold all the information systematically
+        self.data = {}
+        for sn, fn in zip(short_names, full_names):
+            # A dictionary for each stock
+            temp = {"Name": fn, "Price": None, "Holdings": 0}
+            # Nested outer dictionary for all stocks
+            self.data[sn] = temp
+
+        # Initializing Randomly generated initial prices
+        for stock in self.data.values():
+            stock["Price"] = round(random.uniform(80, 120), 2)  # Price b/w 60 and 120
+
+        # Initialize Assets
+        self.cash_assets = 10000
+        self.stock_assets = 0
+
+    def total_assets(self):
+
+        return self.cash_assets + self.stock_assets
+
+    def _generate_day_change(self):
+
+        self.changes = []
+        for _ in range(len(self.data)):
+            self.changes.append(
+                round(random.uniform(-5, 5), 2)
+            )  # Random % Change b/w -5 and 5
+
+    def update_prices(self):
+
+        self._generate_day_change()
+        for stock, change in zip(self.data.values(), self.changes):
+            stock["Price"] = round(stock["Price"] + (change / 100) * stock["Price"], 2)
+
+    def print_exchange_average(self):
+
+        sum = 0
+        for stock in self.data.values():
+            sum += stock["Price"]
+
+        print(f"\nNEW YORK STOCK EXCHANGE AVERAGE: ${sum / 5:.2f}")
+
+    def get_average_change(self):
+
+        sum = 0
+        for change in self.changes:
+            sum += change
+
+        return round(sum / 5, 2)
+
+    def print_first_day(self):
+
+        print("\nSTOCK\t\t\t\t\tINITIALS\tPRICE/SHARE($)")
+        for stock, data in self.data.items():
+            if stock != "LBJ":
+                print("{}\t\t\t{}\t\t{}".format(data["Name"], stock, data["Price"]))
+            else:
+                print("{}\t\t{}\t\t{}".format(data["Name"], stock, data["Price"]))
+
+        self.print_exchange_average()
+        self.print_assets()
+
+    def take_inputs(self):
+
+        print("\nWHAT IS YOUR TRANSACTION IN")
+        flag = False
+        while not flag:
+            new_holdings = []
+            for stock in self.data.keys():
+                try:
+                    new_holdings.append(int(input(f"{stock}? ")))
+                except Exception:
+                    print("\nINVALID ENTRY, TRY AGAIN\n")
+                    break
+            if len(new_holdings) == 5:
+                flag = self._check_transaction(new_holdings)
+
+        return new_holdings
+
+    def print_trading_day(self):
+
+        print("STOCK\tPRICE/SHARE\tHOLDINGS\tNET. Value\tPRICE CHANGE")
+        for stock, data, change in zip(
+            self.data.keys(), self.data.values(), self.changes
+        ):
+            value = data["Price"] * data["Holdings"]
+            print(
+                "{}\t{}\t\t{}\t\t{:.2f}\t\t{}".format(
+                    stock, data["Price"], data["Holdings"], value, change
+                )
+            )
+
+    def update_cash_assets(self, new_holdings):
+
+        sell = 0
+        buy = 0
+        for stock, holding in zip(self.data.values(), new_holdings):
+            if holding > 0:
+                buy += stock["Price"] * holding
+
+            elif holding < 0:
+                sell += stock["Price"] * abs(holding)
+
+        self.cash_assets = self.cash_assets + sell - buy
+
+    def update_stock_assets(self):
+
+        sum = 0
+        for data in self.data.values():
+            sum += data["Price"] * data["Holdings"]
+
+        self.stock_assets = round(sum, 2)
+
+    def print_assets(self):
+
+        print(f"\nTOTAL STOCK ASSETS ARE: ${self.stock_assets:.2f}")
+        print(f"TOTAL CASH ASSETS ARE: ${self.cash_assets:.2f}")
+        print(f"TOTAL ASSETS ARE: ${self.total_assets():.2f}")
+
+    def _check_transaction(self, new_holdings):
+
+        sum = 0
+        for stock, holding in zip(self.data.values(), new_holdings):
+            if holding > 0:
+                sum += stock["Price"] * holding
+
+            elif holding < 0:
+                if abs(holding) > stock["Holdings"]:
+                    print("\nYOU HAVE OVERSOLD SOME STOCKS, TRY AGAIN\n")
+                    return False
+
+        if sum > self.cash_assets:
+            print(
+                "\nYOU HAVE USED ${:.2f} MORE THAN YOU HAVE, TRY AGAIN\n".format(
+                    sum - self.cash_assets
+                )
+            )
+            return False
+
+        return True
+
+    def update_holdings(self, new_holdings):
+
+        for stock, new_holding in zip(self.data.values(), new_holdings):
+            stock["Holdings"] += new_holding
+
+
+def print_instruction():
+
+    print(
+        """
+THIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN
+$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL
+BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT
+REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE
+OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES
+IN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE
+INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION
+MARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK
+TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE
+NUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED
+ON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS
+TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU
+HAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS.
+(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST
+10 DAYS)
+          ------------GOOD LUCK!------------\n
+    """
+    )
+
+
+if __name__ == "__main__":
+
+    print("\t\t      STOCK MARKET")
+    help = input("\nDO YOU WANT INSTRUCTIONS(YES OR NO)? ")
+
+    # Printing Instruction
+    if help == "YES" or help == "yes" or help == "Yes":
+        print_instruction()
+
+    # Initialize Game
+    Game = Stock_Market()
+
+    # Do first day
+    Game.print_first_day()
+    new_holdings = Game.take_inputs()
+    Game.update_holdings(new_holdings)
+    Game.update_cash_assets(new_holdings)
+    print("\n------------END OF TRADING DAY--------------\n")
+
+    response = 1
+    while response == 1:
+
+        # Simulate a DAY
+        Game.update_prices()
+        Game.print_trading_day()
+        Game.print_exchange_average()
+        Game.update_stock_assets()
+        Game.print_assets()
+
+        response = int(input("\nDO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)? "))
+        if response == 0:
+            break
+
+        new_holdings = Game.take_inputs()
+        Game.update_holdings(new_holdings)
+        Game.update_cash_assets(new_holdings)
+        print("\n------------END OF TRADING DAY--------------\n")
+
+    print("\nHOPE YOU HAD FUN!!!!")
+    input("")
diff --git a/00_Alternate_Languages/83_Stock_Market/ruby/README.md b/00_Alternate_Languages/83_Stock_Market/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/83_Stock_Market/stockmarket.bas b/00_Alternate_Languages/83_Stock_Market/stockmarket.bas
new file mode 100644
index 00000000..402b6360
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/stockmarket.bas
@@ -0,0 +1,232 @@
+10 PRINT TAB(30);"STOCK MARKET"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT: PRINT: PRINT
+100 REM STOCK MARKET SIMULATION     -STOCK-
+101 REM REVISED 8/18/70 (D. PESSEL, L. BRAUN, C. LOSIK)
+102 REM IMP VRBLS: A-MRKT TRND SLP; B5-BRKRGE FEE; C-TTL CSH ASSTS;
+103 REM C5-TTL CSH ASSTS (TEMP); C(I)-CHNG IN STK VAL; D-TTL ASSTS;
+104 REM E1,E2-LRG CHNG MISC; I-STCK #; I1,I2-STCKS W LRG CHNG;
+105 REM N1,N2-LRG CHNG DAY CNTS; P5-TTL DAYS PRCHSS; P(I)-PRTFL CNTNTS;
+106 REM Q9-NEW CYCL?; S4-SGN OF A; S5-TTL DYS SLS; S(I)-VALUE/SHR;
+107 REM T-TTL STCK ASSTS; T5-TTL VAL OF TRNSCTNS;
+108 REM W3-LRG CHNG; X1-SMLL CHNG(<$1); Z4,Z5,Z6-NYSE AVE.; Z(I)-TRNSCT
+110 DIM S(5),P(5),Z(5),C(5)
+112 REM SLOPE OF MARKET TREND:A  (SAME FOR ALL STOCKS)
+113 LET X=1
+114 LET A=INT((RND(X)/10)*100+.5)/100
+115 LET T5=0
+116 LET X9=0
+117 LET N1=0
+118 LET N2=0
+119 LET E1=0
+120 LET E2=0
+121 REM INTRODUCTION
+122 PRINT "DO YOU WANT THE INSTRUCTIONS (YES-TYPE 1, NO-TYPE 0)";
+123 INPUT Z9
+124 PRINT
+125 PRINT
+126 IF Z9<1 THEN 200
+130 PRINT "THIS PROGRAM PLAYS THE STOCK MARKET.  YOU WILL BE GIVEN"
+132 PRINT "$10,000 AND MAY BUY OR SELL STOCKS.  THE STOCK PRICES WILL"
+134 PRINT "BE GENERATED RANDOMLY AND THEREFORE THIS MODEL DOES NOT"
+135 PRINT "REPRESENT EXACTLY WHAT HAPPENS ON THE EXCHANGE.  A TABLE"
+136 PRINT "OF AVAILABLE STOCKS, THEIR PRICES, AND THE NUMBER OF SHARES"
+137 PRINT "IN YOUR PORTFOLIO WILL BE PRINTED.  FOLLOWING THIS, THE"
+138 PRINT "INITIALS OF EACH STOCK WILL BE PRINTED WITH A QUESTION"
+139 PRINT "MARK.  HERE YOU INDICATE A TRANSACTION.  TO BUY A STOCK"
+140 PRINT "TYPE +NNN, TO SELL A STOCK TYPE -NNN, WHERE NNN IS THE"
+141 PRINT "NUMBER OF SHARES.  A BROKERAGE FEE OF 1% WILL BE CHARGED"
+142 PRINT "ON ALL TRANSACTIONS.  NOTE THAT IF A STOCK'S VALUE DROPS"
+143 PRINT "TO ZERO IT MAY REBOUND TO A POSITIVE VALUE AGAIN.  YOU"
+144 PRINT "HAVE $10,000 TO INVEST.  USE INTEGERS FOR ALL YOUR INPUTS."
+145 PRINT "(NOTE:  TO GET A 'FEEL' FOR THE MARKET RUN FOR AT LEAST"
+146 PRINT "10 DAYS)"
+147 PRINT "-----GOOD LUCK!-----"
+200 REM GENERATION OF STOCK TABLE; INPUT REQUESTS
+210 REM INITIAL STOCK VALUES
+220 LET S(1)=100
+230 LET S(2)=85
+240 LET S(3)=150
+250 LET S(4)=140
+260 LET S(5)=110
+265 REM INITIAL T8 - # DAYS FOR FIRST TREND SLOPE (A)
+266 LET T8=INT(4.99*RND(X)+1)
+267 REM RANDOMIZE SIGN OF FIRST TREND SLOPE (A)
+268 IF RND(X)>.5 THEN 270
+269 LET A=-A
+270 REM RANDOMIZE INITIAL VALUES
+280 GOSUB 830
+285 REM INITIAL PORTFOLIO CONTENTS
+290 FOR I=1 TO 5
+300 LET P(I)=0
+305 LET Z(I)=0
+310 NEXT I
+320 PRINT
+330 PRINT
+333 REM INITIALIZE CASH ASSETS:C
+335 LET C=10000
+338 REM PRINT INITIAL PORTFOLIO
+340 PRINT "STOCK"," ","INITIALS","PRICE/SHARE"
+350 PRINT "INT. BALLISTIC MISSILES","  IBM",S(1)
+352 PRINT "RED CROSS OF AMERICA","  RCA",S(2)
+354 PRINT "LICHTENSTEIN, BUMRAP & JOKE","  LBJ",S(3)
+356 PRINT "AMERICAN BANKRUPT CO.","  ABC",S(4)
+358 PRINT "CENSURED BOOKS STORE","  CBS",S(5)
+360 PRINT
+361 REM NYSE AVERAGE:Z5; TEMP. VALUE:Z4; NET CHANGE:Z6
+363 LET Z4=Z5
+364 LET Z5=0
+365 LET T=0
+370 FOR I=1 TO 5
+375 LET Z5=Z5+S(I)
+380 LET T=T+S(I)*P(I)
+390 NEXT I
+391 LET Z5=INT(100*(Z5/5)+.5)/100
+392 LET Z6=INT((Z5-Z4)*100+.5)/100
+393 REM TOTAL ASSETS:D
+394 LET D=T+C
+395 IF X9>0 THEN 398
+396 PRINT "NEW YORK STOCK EXCHANGE AVERAGE: "Z5
+397 GOTO 399
+398 PRINT "NEW YORK STOCK EXCHANGE AVERAGE: "Z5"NET CHANGE"Z6
+399 PRINT
+400 LET T=INT(100*T+.5)/100
+401 PRINT "TOTAL STOCK ASSETS ARE   $";T
+403 LET C=INT(100*C+.5)/100
+405 PRINT "TOTAL CASH ASSETS ARE    $";C
+407 LET D=INT(100*D+.5)/100
+408 PRINT "TOTAL ASSETS ARE         $";D
+410 PRINT
+411 IF X9=0 THEN 416
+412 PRINT "DO YOU WISH TO CONTINUE (YES-TYPE 1, NO-TYPE 0)";
+413 INPUT Q9
+414 IF Q9<1 THEN 998
+416 REM INPUT TRANSACTIONS
+420 PRINT "WHAT IS YOUR TRANSACTION IN"
+430 PRINT "IBM";
+440 INPUT Z(1)
+450 PRINT "RCA";
+460 INPUT Z(2)
+470 PRINT "LBJ";
+480 INPUT Z(3)
+490 PRINT "ABC";
+500 INPUT Z(4)
+510 PRINT "CBS";
+520 INPUT Z(5)
+525 PRINT
+530 REM TOTAL DAY'S PURCHASES IN $:P5
+540 LET P5=0
+550 REM TOTAL DAY'S SALES IN $:S5
+560 LET S5=0
+570 FOR I=1 TO 5
+575 LET Z(I)=INT(Z(I)+.5)
+580 IF Z(I)<=0 THEN 610
+590 LET P5=P5+Z(I)*S(I)
+600 GOTO 620
+610 LET S5=S5-Z(I)*S(I)
+612 IF -Z(I)<=P(I) THEN 620
+614 PRINT "YOU HAVE OVERSOLD A STOCK; TRY AGAIN."
+616 GOTO 420
+620 NEXT I
+622 REM TOTAL VALUE OF TRANSACTIONS:T5
+625 LET T5=P5+S5
+630 REM BROKERAGE FEE:B5
+640 LET B5=INT(.01*T5*100+.5)/100
+650 REM CASH ASSETS=OLD CASH ASSETS-TOTAL PURCHASES
+652 REM -BROKERAGE FEES+TOTAL SALES:C5
+654 LET C5=C-P5-B5+S5
+656 IF C5>=0 THEN 674
+658 PRINT "YOU HAVE USED $"-C5" MORE THAN YOU HAVE."
+660 GOTO 420
+674 LET C=C5
+675 REM CALCULATE NEW PORTFOLIO
+680 FOR I=1 TO 5
+690 LET P(I)=P(I)+Z(I)
+700 NEXT I
+710 REM CALCULATE NEW STOCK VALUES
+720 GOSUB 830
+750 REM PRINT PORTFOLIO
+751 REM BELL RINGING-DIFFERENT ON MANY COMPUTERS
+755 PRINT
+756 PRINT "**********     END OF DAY'S TRADING     **********"
+757 PRINT
+758 PRINT
+759 IF X9<1 THEN 769
+769 PRINT "STOCK","PRICE/SHARE","HOLDINGS", "VALUE", "NET PRICE CHANGE"
+770 PRINT "IBM", S(1), P(1), S(1)*P(1), C(1)
+771 PRINT "RCA", S(2), P(2), S(2)*P(2), C(2)
+772 PRINT "LBJ", S(3), P(3), S(3)*P(3), C(3)
+773 PRINT "ABC", S(4), P(4), S(4)*P(4), C(4)
+774 PRINT "CBS", S(5), P(5), S(5)*P(5), C(5)
+775 LET X9=1
+780 PRINT
+790 PRINT
+810 GOTO 360
+829 REM NEW STOCK VALUES - SUBROUTINE
+830 REM RANDOMLY PRODUCE NEW STOCK VALUES BASED ON PREVIOUS
+831 REM DAY'S VALUES
+832 REM N1,N2 ARE RANDOM NUMBERS OF DAYS WHICH RESPECTIVELY
+833 REM DETERMINE WHEN STOCK I1 WILL INCREASE 10 PTS. AND STOCK
+834 REM I2 WILL DECREASE 10 PTS.
+840 REM IF N1 DAYS HAVE PASSED, PICK AN I1, SET E1, DETERMINE NEW N1
+841 IF N1>0 THEN 850
+845 LET I1=INT(4.99*RND(X)+1)
+846 LET N1=INT(4.99*RND(X)+1)
+847 LET E1=1
+850 REM IF N2 DAYS HAVE PASSED, PICK AN I2, SET E2, DETERMINE NEW N2
+851 IF N2>0 THEN 860
+855 LET I2=INT(4.99*RND(X)+1)
+856 LET N2=INT(4.99*RND(X)+1)
+857 LET E2=1
+860 REM DEDUCT ONE DAY FROM N1 AND N2
+861 LET N1=N1-1
+862 LET N2=N2-1
+890 REM LOOP THROUGH ALL STOCKS
+900 FOR I=1 TO 5
+910 LET X1=RND(X)
+915 IF X1>.25 THEN 920
+916 LET X1=.25
+917 GOTO 935
+920 IF X1>.5 THEN 925
+921 LET X1=.5
+922 GOTO 935
+925 IF X1>.75 THEN 930
+926 LET X1=.75
+927 GOTO 935
+930 LET X1=0.0
+931 REM BIG CHANGE CONSTANT:W3  (SET TO ZERO INITIALLY)
+935 LET W3=0
+936 IF E1<1 THEN 945
+937 IF INT(I1+.5)<>INT(I+.5) THEN 945
+938 REM ADD 10 PTS. TO THIS STOCK;  RESET E1
+939 LET W3=10
+943 LET E1=0
+945 IF E2<1 THEN 955
+947 IF INT(I2+.5)<>INT(I+.5) THEN 955
+948 REM SUBTRACT 10 PTS. FROM THIS STOCK;  RESET E2
+949 LET W3=W3-10
+953 LET E2=0
+954 REM C(I) IS CHANGE IN STOCK VALUE
+955 LET C(I)=INT(A*S(I))+X1+INT(3-6*RND(X)+.5)+W3
+956 LET C(I)=INT(100*C(I)+.5)/100
+957 LET S(I)=S(I)+C(I)
+960 IF S(I)>0 THEN 967
+964 LET C(I)=0
+965 LET S(I)=0
+966 GOTO 970
+967 LET S(I)=INT(100*S(I)+.5)/100
+970 NEXT I
+972 REM AFTER T8 DAYS RANDOMLY CHANGE TREND SIGN AND SLOPE
+973 LET T8=T8-1
+974 IF T8<1 THEN 985
+980 RETURN
+985 REM RANDOMLY CHANGE TREND SIGN AND SLOPE (A), AND DURATION
+986 REM OF TREND (T8)
+990 LET T8=INT(4.99*RND(X)+1)
+992 LET A=INT((RND(X)/10)*100+.5)/100
+993 LET S4=RND(X)
+994 IF S4<=.5 THEN 997
+995 LET A=-A
+997 RETURN
+998 PRINT "HOPE YOU HAD FUN!!"
+999 END
diff --git a/00_Alternate_Languages/83_Stock_Market/vbnet/README.md b/00_Alternate_Languages/83_Stock_Market/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/83_Stock_Market/vbnet/StockMarket.sln b/00_Alternate_Languages/83_Stock_Market/vbnet/StockMarket.sln
new file mode 100644
index 00000000..00c39242
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/vbnet/StockMarket.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "StockMarket", "StockMarket.vbproj", "{BF9F62B1-4F0E-40F0-AE76-D1055F0A2F31}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{BF9F62B1-4F0E-40F0-AE76-D1055F0A2F31}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BF9F62B1-4F0E-40F0-AE76-D1055F0A2F31}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BF9F62B1-4F0E-40F0-AE76-D1055F0A2F31}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BF9F62B1-4F0E-40F0-AE76-D1055F0A2F31}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/83_Stock_Market/vbnet/StockMarket.vbproj b/00_Alternate_Languages/83_Stock_Market/vbnet/StockMarket.vbproj
new file mode 100644
index 00000000..1404eb48
--- /dev/null
+++ b/00_Alternate_Languages/83_Stock_Market/vbnet/StockMarket.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    StockMarket
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/README.md b/00_Alternate_Languages/84_Super_Star_Trek/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Commands/Command.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Commands/Command.cs
new file mode 100644
index 00000000..f0d569f8
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Commands/Command.cs
@@ -0,0 +1,34 @@
+using System.ComponentModel;
+
+namespace SuperStarTrek.Commands
+{
+    internal enum Command
+    {
+        [Description("To set course")]
+        NAV,
+
+        [Description("For short range sensor scan")]
+        SRS,
+
+        [Description("For long range sensor scan")]
+        LRS,
+
+        [Description("To fire phasers")]
+        PHA,
+
+        [Description("To fire photon torpedoes")]
+        TOR,
+
+        [Description("To raise or lower shields")]
+        SHE,
+
+        [Description("For damage control reports")]
+        DAM,
+
+        [Description("To call on library-computer")]
+        COM,
+
+        [Description("To resign your command")]
+        XXX
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Commands/CommandExtensions.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Commands/CommandExtensions.cs
new file mode 100644
index 00000000..f8f7e9da
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Commands/CommandExtensions.cs
@@ -0,0 +1,14 @@
+using System.Reflection;
+using System.ComponentModel;
+
+namespace SuperStarTrek.Commands
+{
+    internal static class CommandExtensions
+    {
+        internal static string GetDescription(this Command command) =>
+            typeof(Command)
+                .GetField(command.ToString())
+                .GetCustomAttribute()
+                .Description;
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Commands/CommandResult.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Commands/CommandResult.cs
new file mode 100644
index 00000000..1b02780c
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Commands/CommandResult.cs
@@ -0,0 +1,23 @@
+namespace SuperStarTrek.Commands
+{
+    internal class CommandResult
+    {
+        public static readonly CommandResult Ok = new(false);
+        public static readonly CommandResult GameOver = new(true);
+
+        private CommandResult(bool isGameOver)
+        {
+            IsGameOver = isGameOver;
+        }
+
+        private CommandResult(float timeElapsed)
+        {
+            TimeElapsed = timeElapsed;
+        }
+
+        public bool IsGameOver { get; }
+        public float TimeElapsed { get; }
+
+        public static CommandResult Elapsed(float timeElapsed) => new(timeElapsed);
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Game.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Game.cs
new file mode 100644
index 00000000..274e2948
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Game.cs
@@ -0,0 +1,131 @@
+using System;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+using SuperStarTrek.Systems;
+using SuperStarTrek.Systems.ComputerFunctions;
+
+namespace SuperStarTrek
+{
+    internal class Game
+    {
+        private readonly Output _output;
+        private readonly Input _input;
+        private readonly Random _random;
+
+        private int _initialStardate;
+        private int _finalStarDate;
+        private float _currentStardate;
+        private Coordinates _currentQuadrant;
+        private Galaxy _galaxy;
+        private int _initialKlingonCount;
+        private Enterprise _enterprise;
+
+        internal Game(Output output, Input input, Random random)
+        {
+            _output = output;
+            _input = input;
+            _random = random;
+        }
+
+        internal float Stardate => _currentStardate;
+
+        internal float StardatesRemaining => _finalStarDate - _currentStardate;
+
+        internal void DoIntroduction()
+        {
+            _output.Write(Strings.Title);
+
+            if (_input.GetYesNo("Do you need instructions", Input.YesNoMode.FalseOnN))
+            {
+                _output.Write(Strings.Instructions);
+
+                _input.WaitForAnyKeyButEnter("to continue");
+            }
+        }
+
+        internal void Play()
+        {
+            Initialise();
+            var gameOver = false;
+
+            while (!gameOver)
+            {
+                var command = _input.GetCommand();
+
+                var result = _enterprise.Execute(command);
+
+                gameOver = result.IsGameOver || CheckIfStranded();
+                _currentStardate += result.TimeElapsed;
+                gameOver |= _currentStardate > _finalStarDate;
+            }
+
+            if (_galaxy.KlingonCount > 0)
+            {
+                _output.Write(Strings.EndOfMission, _currentStardate, _galaxy.KlingonCount);
+            }
+            else
+            {
+                _output.Write(Strings.Congratulations, GetEfficiency());
+            }
+        }
+
+        private void Initialise()
+        {
+            _currentStardate = _initialStardate = _random.GetInt(20, 40) * 100;
+            _finalStarDate = _initialStardate + _random.GetInt(25, 35);
+
+            _currentQuadrant = _random.GetCoordinate();
+
+            _galaxy = new Galaxy(_random);
+            _initialKlingonCount = _galaxy.KlingonCount;
+
+            _enterprise = new Enterprise(3000, _random.GetCoordinate(), _output, _random, _input);
+            _enterprise
+                .Add(new WarpEngines(_enterprise, _output, _input))
+                .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output))
+                .Add(new LongRangeSensors(_galaxy, _output))
+                .Add(new PhaserControl(_enterprise, _output, _input, _random))
+                .Add(new PhotonTubes(10, _enterprise, _output, _input))
+                .Add(new ShieldControl(_enterprise, _output, _input))
+                .Add(new DamageControl(_enterprise, _output))
+                .Add(new LibraryComputer(
+                    _output,
+                    _input,
+                    new CumulativeGalacticRecord(_output, _galaxy),
+                    new StatusReport(this, _galaxy, _enterprise, _output),
+                    new TorpedoDataCalculator(_enterprise, _output),
+                    new StarbaseDataCalculator(_enterprise, _output),
+                    new DirectionDistanceCalculator(_enterprise, _output, _input),
+                    new GalaxyRegionMap(_output, _galaxy)));
+
+            _output.Write(Strings.Enterprise);
+            _output.Write(
+                Strings.Orders,
+                _galaxy.KlingonCount,
+                _finalStarDate,
+                _finalStarDate - _initialStardate,
+                _galaxy.StarbaseCount > 1 ? "are" : "is",
+                _galaxy.StarbaseCount,
+                _galaxy.StarbaseCount > 1 ? "s" : "");
+
+            _input.WaitForAnyKeyButEnter("when ready to accept command");
+
+            _enterprise.StartIn(BuildCurrentQuadrant());
+        }
+
+        private Quadrant BuildCurrentQuadrant() =>
+           new Quadrant(_galaxy[_currentQuadrant], _enterprise, _random, _galaxy, _input, _output);
+
+        internal bool Replay() => _galaxy.StarbaseCount > 0 && _input.GetString(Strings.ReplayPrompt, "Aye");
+
+        private bool CheckIfStranded()
+        {
+            if (_enterprise.IsStranded) { _output.Write(Strings.Stranded); }
+            return _enterprise.IsStranded;
+        }
+
+        private float GetEfficiency() =>
+            1000 * (float)Math.Pow(_initialKlingonCount / (_currentStardate - _initialStardate), 2);
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Input.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Input.cs
new file mode 100644
index 00000000..2b37b2ba
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Input.cs
@@ -0,0 +1,159 @@
+using System;
+using System.Linq;
+using SuperStarTrek.Commands;
+using SuperStarTrek.Space;
+using static System.StringComparison;
+
+namespace SuperStarTrek
+{
+    internal class Input
+    {
+        private readonly Output _output;
+
+        internal Input(Output output)
+        {
+            _output = output;
+        }
+
+        internal void WaitForAnyKeyButEnter(string prompt)
+        {
+            _output.Write($"Hit any key but Enter {prompt} ");
+            while (Console.ReadKey(intercept: true).Key == ConsoleKey.Enter);
+        }
+
+        internal string GetString(string prompt)
+        {
+            _output.Prompt(prompt);
+            return Console.ReadLine();
+        }
+
+        internal float GetNumber(string prompt)
+        {
+            _output.Prompt(prompt);
+
+            while (true)
+            {
+                var response = Console.ReadLine();
+                if (float.TryParse(response, out var value))
+                {
+                    return value;
+                }
+
+                _output.WriteLine("!Number expected - retry input line");
+                _output.Prompt();
+            }
+        }
+
+        internal (float X, float Y) GetCoordinates(string prompt)
+        {
+            _output.Prompt($"{prompt} (X,Y)");
+            var responses = ReadNumbers(2);
+            return (responses[0], responses[1]);
+        }
+
+        internal bool TryGetNumber(string prompt, float minValue, float maxValue, out float value)
+        {
+            value = GetNumber($"{prompt} ({minValue}-{maxValue})");
+
+            return value >= minValue && value <= maxValue;
+        }
+
+        internal bool GetString(string replayPrompt, string trueValue) =>
+            GetString(replayPrompt).Equals(trueValue, InvariantCultureIgnoreCase);
+
+        internal Command GetCommand()
+        {
+            while(true)
+            {
+                var response = GetString("Command");
+
+                if (response.Length >= 3 &&
+                    Enum.TryParse(response.Substring(0, 3), ignoreCase: true, out Command parsedCommand))
+                {
+                    return parsedCommand;
+                }
+
+                _output.WriteLine("Enter one of the following:");
+                foreach (var command in Enum.GetValues(typeof(Command)).OfType())
+                {
+                    _output.WriteLine($"  {command}  ({command.GetDescription()})");
+                }
+                _output.WriteLine();
+            }
+        }
+
+        internal bool TryGetCourse(string prompt, string officer, out Course course)
+        {
+            if (!TryGetNumber(prompt, 1, 9, out var direction))
+            {
+                _output.WriteLine($"{officer} reports, 'Incorrect course data, sir!'");
+                course = default;
+                return false;
+            }
+
+            course = new Course(direction);
+            return true;
+        }
+
+        internal bool GetYesNo(string prompt, YesNoMode mode)
+        {
+            _output.Prompt($"{prompt} (Y/N)");
+            var response = Console.ReadLine().ToUpperInvariant();
+
+            return (mode, response) switch
+            {
+                (YesNoMode.FalseOnN, "N") => false,
+                (YesNoMode.FalseOnN, _) => true,
+                (YesNoMode.TrueOnY, "Y") => true,
+                (YesNoMode.TrueOnY, _) => false,
+                _ => throw new ArgumentOutOfRangeException(nameof(mode), mode, "Invalid value")
+            };
+        }
+
+        private float[] ReadNumbers(int quantity)
+        {
+            var numbers = new float[quantity];
+            var index = 0;
+            bool tryAgain;
+
+            do
+            {
+                tryAgain = false;
+                var responses = Console.ReadLine().Split(',');
+                if (responses.Length > quantity)
+                {
+                    _output.WriteLine("!Extra input ingored");
+                }
+
+                for (; index < responses.Length; index++)
+                {
+                    if (!float.TryParse(responses[index], out numbers[index]))
+                    {
+                        _output.WriteLine("!Number expected - retry input line");
+                        _output.Prompt();
+                        tryAgain = true;
+                        break;
+                    }
+                }
+            } while (tryAgain);
+
+            if (index < quantity)
+            {
+                _output.Prompt("?");
+                var responses = ReadNumbers(quantity - index);
+                for (int i = 0; i < responses.Length; i++, index++)
+                {
+                    numbers[index] = responses[i];
+                }
+            }
+
+            return numbers;
+        }
+
+        internal enum YesNoMode
+        {
+            TrueOnY,
+            FalseOnN
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Enterprise.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Enterprise.cs
new file mode 100644
index 00000000..ac9e8112
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Enterprise.cs
@@ -0,0 +1,231 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SuperStarTrek.Commands;
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+using SuperStarTrek.Systems;
+
+namespace SuperStarTrek.Objects
+{
+    internal class Enterprise
+    {
+        private readonly int _maxEnergy;
+        private readonly Output _output;
+        private readonly List _systems;
+        private readonly Dictionary _commandExecutors;
+        private readonly Random _random;
+        private readonly Input _input;
+        private Quadrant _quadrant;
+
+        public Enterprise(int maxEnergy, Coordinates sector, Output output, Random random, Input input)
+        {
+            SectorCoordinates = sector;
+            TotalEnergy = _maxEnergy = maxEnergy;
+
+            _systems = new List();
+            _commandExecutors = new Dictionary();
+            _output = output;
+            _random = random;
+            _input = input;
+        }
+
+        internal Quadrant Quadrant => _quadrant;
+
+        internal Coordinates QuadrantCoordinates => _quadrant.Coordinates;
+
+        internal Coordinates SectorCoordinates { get; private set; }
+
+        internal string Condition => GetCondition();
+
+        internal LibraryComputer Computer => (LibraryComputer)_commandExecutors[Command.COM];
+
+        internal ShieldControl ShieldControl => (ShieldControl)_commandExecutors[Command.SHE];
+
+        internal float Energy => TotalEnergy - ShieldControl.ShieldEnergy;
+
+        internal float TotalEnergy { get; private set; }
+
+        internal int DamagedSystemCount => _systems.Count(s => s.IsDamaged);
+
+        internal IEnumerable Systems => _systems;
+
+        internal PhotonTubes PhotonTubes => (PhotonTubes)_commandExecutors[Command.TOR];
+
+        internal bool IsDocked => _quadrant.EnterpriseIsNextToStarbase;
+
+        internal bool IsStranded => TotalEnergy < 10 || Energy < 10 && ShieldControl.IsDamaged;
+
+        internal Enterprise Add(Subsystem system)
+        {
+            _systems.Add(system);
+            _commandExecutors[system.Command] = system;
+
+            return this;
+        }
+
+        internal void StartIn(Quadrant quadrant)
+        {
+            _quadrant = quadrant;
+            quadrant.Display(Strings.StartText);
+        }
+
+        private string GetCondition() =>
+            IsDocked switch
+            {
+                true => "Docked",
+                false when _quadrant.HasKlingons => "*Red*",
+                false when Energy / _maxEnergy < 0.1f => "Yellow",
+                false => "Green"
+            };
+
+        internal CommandResult Execute(Command command)
+        {
+            if (command == Command.XXX) { return CommandResult.GameOver; }
+
+            return _commandExecutors[command].ExecuteCommand(_quadrant);
+        }
+
+        internal void Refuel() => TotalEnergy = _maxEnergy;
+
+        public override string ToString() => "<*>";
+
+        internal void UseEnergy(float amountUsed)
+        {
+            TotalEnergy -= amountUsed;
+        }
+
+        internal CommandResult TakeHit(Coordinates sector, int hitStrength)
+        {
+            _output.WriteLine($"{hitStrength} unit hit on Enterprise from sector {sector}");
+            ShieldControl.AbsorbHit(hitStrength);
+
+            if (ShieldControl.ShieldEnergy <= 0)
+            {
+                _output.WriteLine(Strings.Destroyed);
+                return CommandResult.GameOver;
+            }
+
+            _output.WriteLine($"      ");
+
+            if (hitStrength >= 20)
+            {
+                TakeDamage(hitStrength);
+            }
+
+            return CommandResult.Ok;
+        }
+
+        private void TakeDamage(float hitStrength)
+        {
+            var hitShieldRatio = hitStrength / ShieldControl.ShieldEnergy;
+            if (_random.GetFloat() > 0.6 || hitShieldRatio <= 0.02f)
+            {
+                return;
+            }
+
+            var system = _systems[_random.Get1To8Inclusive() - 1];
+            system.TakeDamage(hitShieldRatio + 0.5f * _random.GetFloat());
+            _output.WriteLine($"Damage Control reports, '{system.Name} damaged by the hit.'");
+        }
+
+        internal void RepairSystems(float repairWorkDone)
+        {
+            var repairedSystems = new List();
+
+            foreach (var system in _systems.Where(s => s.IsDamaged))
+            {
+                if (system.Repair(repairWorkDone))
+                {
+                    repairedSystems.Add(system.Name);
+                }
+            }
+
+            if (repairedSystems.Any())
+            {
+                _output.WriteLine("Damage Control report:");
+                foreach (var systemName in repairedSystems)
+                {
+                    _output.WriteLine($"        {systemName} repair completed.");
+                }
+            }
+        }
+
+        internal void VaryConditionOfRandomSystem()
+        {
+            if (_random.GetFloat() > 0.2f) { return; }
+
+            var system = _systems[_random.Get1To8Inclusive() - 1];
+            _output.Write($"Damage Control report:  {system.Name} ");
+            if (_random.GetFloat() >= 0.6)
+            {
+                system.Repair(_random.GetFloat() * 3 + 1);
+                _output.WriteLine("state of repair improved");
+            }
+            else
+            {
+                system.TakeDamage(_random.GetFloat() * 5 + 1);
+                _output.WriteLine("damaged");
+            }
+        }
+
+        internal float Move(Course course, float warpFactor, int distance)
+        {
+            var (quadrant, sector) = MoveWithinQuadrant(course, distance) ?? MoveBeyondQuadrant(course, distance);
+
+            if (quadrant != _quadrant.Coordinates)
+            {
+                _quadrant = new Quadrant(_quadrant.Galaxy[quadrant], this, _random, _quadrant.Galaxy, _input, _output);
+            }
+            _quadrant.SetEnterpriseSector(sector);
+            SectorCoordinates = sector;
+
+            TotalEnergy -= distance + 10;
+            if (Energy < 0)
+            {
+                _output.WriteLine("Shield Control supplies energy to complete the maneuver.");
+                ShieldControl.ShieldEnergy = Math.Max(0, TotalEnergy);
+            }
+
+            return GetTimeElapsed(quadrant, warpFactor);
+        }
+
+        private (Coordinates, Coordinates)? MoveWithinQuadrant(Course course, int distance)
+        {
+            var currentSector = SectorCoordinates;
+            foreach (var (sector, index) in course.GetSectorsFrom(SectorCoordinates).Select((s, i) => (s, i)))
+            {
+                if (distance == 0) { break; }
+
+                if (_quadrant.HasObjectAt(sector))
+                {
+                    _output.WriteLine($"Warp engines shut down at sector {currentSector} dues to bad navigation");
+                    distance = 0;
+                    break;
+                }
+
+                currentSector = sector;
+                distance -= 1;
+            }
+
+            return distance == 0 ? (_quadrant.Coordinates, currentSector) : null;
+        }
+
+        private (Coordinates, Coordinates) MoveBeyondQuadrant(Course course, int distance)
+        {
+            var (complete, quadrant, sector) = course.GetDestination(QuadrantCoordinates, SectorCoordinates, distance);
+
+            if (!complete)
+            {
+                _output.Write(Strings.PermissionDenied, sector, quadrant);
+            }
+
+            return (quadrant, sector);
+        }
+
+        private float GetTimeElapsed(Coordinates finalQuadrant, float warpFactor) =>
+            finalQuadrant == _quadrant.Coordinates
+                ? Math.Min(1, (float)Math.Round(warpFactor, 1, MidpointRounding.ToZero))
+                : 1;
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Klingon.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Klingon.cs
new file mode 100644
index 00000000..1b55940a
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Klingon.cs
@@ -0,0 +1,43 @@
+using SuperStarTrek.Commands;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Objects
+{
+    internal class Klingon
+    {
+        private readonly Random _random;
+
+        internal Klingon(Coordinates sector, Random random)
+        {
+            Sector = sector;
+            _random = random;
+            Energy = _random.GetFloat(100, 300);
+        }
+
+        internal float Energy { get; private set; }
+
+        internal Coordinates Sector { get; private set; }
+
+        public override string ToString() => "+K+";
+
+        internal CommandResult FireOn(Enterprise enterprise)
+        {
+            var attackStrength = _random.GetFloat();
+            var distanceToEnterprise = Sector.GetDistanceTo(enterprise.SectorCoordinates);
+            var hitStrength = (int)(Energy * (2 + attackStrength) / distanceToEnterprise);
+            Energy /= 3 + attackStrength;
+
+            return enterprise.TakeHit(Sector, hitStrength);
+        }
+
+        internal bool TakeHit(int hitStrength)
+        {
+            if (hitStrength < 0.15 * Energy) { return false; }
+
+            Energy -= hitStrength;
+            return true;
+        }
+
+        internal void MoveTo(Coordinates newSector) => Sector = newSector;
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Star.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Star.cs
new file mode 100644
index 00000000..1d9eef6f
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Star.cs
@@ -0,0 +1,7 @@
+namespace SuperStarTrek.Objects
+{
+    internal class Star
+    {
+        public override string ToString() => " * ";
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Starbase.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Starbase.cs
new file mode 100644
index 00000000..c9abb870
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Objects/Starbase.cs
@@ -0,0 +1,45 @@
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Objects
+{
+    internal class Starbase
+    {
+        private readonly Input _input;
+        private readonly Output _output;
+        private readonly float _repairDelay;
+
+        internal Starbase(Coordinates sector, Random random, Input input, Output output)
+        {
+            Sector = sector;
+            _repairDelay = random.GetFloat() * 0.5f;
+            _input = input;
+            _output = output;
+        }
+
+        internal Coordinates Sector { get; }
+
+        public override string ToString() => ">!<";
+
+        internal bool TryRepair(Enterprise enterprise, out float repairTime)
+        {
+            repairTime = enterprise.DamagedSystemCount * 0.1f + _repairDelay;
+            if (repairTime >= 1) { repairTime = 0.9f; }
+
+            _output.Write(Strings.RepairEstimate, repairTime);
+            if (_input.GetYesNo(Strings.RepairPrompt, Input.YesNoMode.TrueOnY))
+            {
+                foreach (var system in enterprise.Systems)
+                {
+                    system.Repair();
+                }
+                return true;
+            }
+
+            repairTime = 0;
+            return false;
+        }
+
+        internal void ProtectEnterprise() => _output.WriteLine(Strings.Protected);
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Output.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Output.cs
new file mode 100644
index 00000000..6a377bce
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Output.cs
@@ -0,0 +1,40 @@
+using System;
+
+namespace SuperStarTrek
+{
+    internal class Output
+    {
+        internal Output Write(string text)
+        {
+            Console.Write(text);
+            return this;
+        }
+
+        internal Output Write(string format, params object[] args)
+        {
+            Console.Write(format, args);
+            return this;
+        }
+
+        internal Output WriteLine(string text = "")
+        {
+            Console.WriteLine(text);
+            return this;
+        }
+
+
+        internal Output NextLine()
+        {
+            Console.WriteLine();
+            return this;
+        }
+
+
+        internal Output Prompt(string text = "")
+        {
+            Console.Write($"{text}? ");
+            return this;
+        }
+
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Program.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Program.cs
new file mode 100644
index 00000000..7080df29
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Program.cs
@@ -0,0 +1,46 @@
+// SUPER STARTREK - MAY 16,1978 - REQUIRES 24K MEMORY
+//
+// ****         **** STAR TREK ****        ****
+// ****  SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,
+// ****  AS SEEN ON THE STAR TREK TV SHOW.
+// ****  ORIGIONAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION
+// ****  PUBLISHED IN DEC'S "101 BASIC GAMES", BY DAVE AHL.
+// ****  MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB
+// ****  LEEDOM - APRIL & DECEMBER 1974,
+// ****  WITH A LITTLE HELP FROM HIS FRIENDS . . .
+// ****  COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED --
+// ****  SEND TO:  R. C. LEEDOM
+// ****            WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR.
+// ****            BOX 746, M.S. 338
+// ****            BALTIMORE, MD  21203
+// ****
+// ****  CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN GORDERS
+// ****  LINE NUMBERS FROM VERSION STREK7 OF 1/12/75 PRESERVED AS
+// ****  MUCH AS POSSIBLE WHILE USING MULTIPLE STATEMENTS PER LINE
+// ****  SOME LINES ARE LONGER THAN 72 CHARACTERS; THIS WAS DONE
+// ****  BY USING "?" INSTEAD OF "PRINT" WHEN ENTERING LINES
+// ****
+// ****  CONVERTED TO MICROSOFT C# 2/20/21 BY ANDREW COOPER
+// ****
+
+namespace SuperStarTrek
+{
+    internal class Program
+    {
+        static void Main()
+        {
+            var output = new Output();
+            var input = new Input(output);
+            var random = new Random();
+
+            var game = new Game(output, input, random);
+
+            game.DoIntroduction();
+
+            do
+            {
+                game.Play();
+            } while (game.Replay());
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/README.md b/00_Alternate_Languages/84_Super_Star_Trek/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Random.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Random.cs
new file mode 100644
index 00000000..cd0ef230
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Random.cs
@@ -0,0 +1,25 @@
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek
+{
+    internal class Random
+    {
+        private readonly System.Random _random = new();
+
+        internal Coordinates GetCoordinate() => new Coordinates(Get1To8Inclusive() - 1, Get1To8Inclusive() - 1);
+
+        // Duplicates the algorithm used in the original code to get an integer value from 1 to 8, inclusive:
+        //     475 DEF FNR(R)=INT(RND(R)*7.98+1.01)
+        // Returns a value from 1 to 8, inclusive.
+        // Note there's a slight bias away from the extreme values, 1 and 8.
+        internal int Get1To8Inclusive() => (int)(GetFloat() * 7.98 + 1.01);
+
+        internal int GetInt(int inclusiveMinValue, int exclusiveMaxValue) =>
+            _random.Next(inclusiveMinValue, exclusiveMaxValue);
+
+        internal float GetFloat() => (float)_random.NextDouble();
+
+        internal float GetFloat(float inclusiveMinValue, float exclusiveMaxValue)
+            => GetFloat() * (exclusiveMaxValue - inclusiveMinValue) + inclusiveMinValue;
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/CombatArea.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/CombatArea.txt
new file mode 100644
index 00000000..ea27a826
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/CombatArea.txt
@@ -0,0 +1 @@
+COMBAT AREA      CONDITION RED
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Congratulations.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Congratulations.txt
new file mode 100644
index 00000000..767f8653
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Congratulations.txt
@@ -0,0 +1,4 @@
+Congratulations, Captain!  The last Klingon battle cruiser
+menacing the Federation has been destroyed.
+
+Your efficiency rating is {0}.
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/CourtMartial.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/CourtMartial.txt
new file mode 100644
index 00000000..a6c5285e
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/CourtMartial.txt
@@ -0,0 +1,3 @@
+
+Starfleet Command reviewing your record to consider
+court martial!
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Destroyed.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Destroyed.txt
new file mode 100644
index 00000000..881d7b49
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Destroyed.txt
@@ -0,0 +1 @@
+The Enterprise has been destroyed.  The Federation will be conquered.
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/EndOfMission.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/EndOfMission.txt
new file mode 100644
index 00000000..f6995e31
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/EndOfMission.txt
@@ -0,0 +1,3 @@
+Is is stardate {0}.
+There were {1} Klingon battle cruisers left at
+the end of your mission.
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Enterprise.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Enterprise.txt
new file mode 100644
index 00000000..a47156a5
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Enterprise.txt
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+                                    ,------*------,
+                    ,-------------   '---  ------'
+                     '-------- --'      / /
+                         ,---' '-------/ /--,
+                          '----------------'
+
+                    THE USS ENTERPRISE --- NCC-1701
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Instructions.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Instructions.txt
new file mode 100644
index 00000000..72ded5ce
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Instructions.txt
@@ -0,0 +1,106 @@
+
+      INSTRUCTIONS FOR 'SUPER STAR TREK'
+
+1. When you see "Command ?" printed, enter one of the legal
+     commands (NAV, SRS, LRS, PHA, TOR, SHE, DAM, COM, OR XXX).
+2. If you should type in an illegal command, you'll get a short
+     list of the legal commands printed out.
+3. Some commands require you to enter data (for example, the
+     'NAV' command comes back with 'Course (1-9) ?'.)  If you
+     type in illegal data (like negative numbers), then command
+     will be aborted.
+
+     The galaxy is divided into an 8 X 8 quadrant grid,
+and each quadrant is further divided into an 8 X 8 sector grid.
+
+     You will be assigned a starting point somewhere in the
+galaxy to begin a tour of duty as commander of the starship
+Enterprise; your mission: to seek and destroy the fleet of
+Klingon warships which are menacing the United Federation of
+Planets.
+
+     You have the following commands available to you as captain
+of the starship Enterprise:
+
+NAV command = Warp Engine Control
+     Course is in a circular numerical      4  3  2
+     vector arrangement as shown             . . .
+     integer and real values may be           ...
+     used.  (Thus course 1.5 is half-     5 ---*--- 1
+     way between 1 and 2.                     ...
+                                             . . .
+     Values may approach 9.0, which         6  7  8
+     itself is equivalent to 1.0
+                                            COURSE
+     One warp factor is the size of
+     one quadrant.  Therefore, to get
+     from quadrant 6,5 to 5,5, you WOULD
+     use course 3, warp factor 1.
+
+SRS command = Short Range Sensor Scan
+     Shows you a scan of your present quadrant.
+
+     Symbology on your sensor screen is as follows:
+        <*> = Your starship's position
+        +K+ = Klingon battle cruiser
+        >!< = Federation starbase (refuel/repair/re-arm here!)
+         *  = Star
+
+     A condensed 'status report' will also be presented.
+
+LRS command = Long Range Sensor Scan
+     Shows conditions in space for one quadrant on each side
+     of the Enterprise (which is in the middle of the scan).
+     The scan is coded in the form ###, where the units digit
+     is the number of stars, the tens digit is the number of
+     starbases, and the hundreds digit is the number of
+     Klingons.
+
+     Example - 207 = 2 Klingons, No starbases, & 7 stars.
+
+PHA command = Phaser Control
+     Allows you to destroy the Klingon battle cruisers by
+     zapping them with suitably large units of energy to
+     deplete their shield power.  (Remember, Klingons have
+     phasers, too!)
+
+TOR command = Photon Torpedo Control
+     Torpedo course is the same as used in warp engine control.
+     If you hit the Klingon vessel, he is destroyed and
+     cannot fire back at you.  If you miss, you are subject to
+     his phaser fire.  In either case, you are also subject to
+     the phaser fire of all other Klingons in the quadrant.
+
+     The library-computer (COM command) has an option to
+     compute torpedo trajectory for you (Option 2).
+
+SHE command = Shield Control
+     Defines the number of energy units to be assigned to the
+     shields.  Energy is taken from total ship's energy.  Note
+     that the status display total energy includes shield energy.
+
+DAM command = Damage Control Report
+     Gives the state of repair of all devices.  Where a negative
+     'state of repair' shows that the device is temporarily
+     damaged.
+
+COM command = Library-Computer
+     The library-computer contains six options:
+     Option 0 = Cumulative Galactic Record
+        This option shows computer memory of the results of all
+        previous short and long range sensor scans.
+     Option 1 = Status Report
+        This option shows the number of Klingons, Stardates,
+        and starbases remaining in the game.
+     Option 2 = Photon Torpedo Data
+        Which gives directions and distance from the Enterprise
+        to all Klingons in your quadrant.
+     Option 3 = Starbase Nav Data
+        This option gives direction and distance to any
+        starbase within your quadrant.
+     Option 4 = Direction/Distance Calculator
+        This option allows you to enter coordinates for
+        direction/distance calculations.
+     Option 5 = Galactic Region Name Map
+        This option prints the names of the sixteen major
+        galactic regions referred to in the game.
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/LowShields.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/LowShields.txt
new file mode 100644
index 00000000..b449b6eb
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/LowShields.txt
@@ -0,0 +1 @@
+   SHIELDS DANGEROUSLY LOW
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/NoEnemyShips.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/NoEnemyShips.txt
new file mode 100644
index 00000000..d4b2efb2
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/NoEnemyShips.txt
@@ -0,0 +1,2 @@
+Science Officer Spock reports, 'Sensors show no enemy ships
+                                in this quadrant'
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/NoStarbase.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/NoStarbase.txt
new file mode 100644
index 00000000..59c991ec
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/NoStarbase.txt
@@ -0,0 +1 @@
+Mr. Spock reports, 'Sensors show no starbases in this quadrant.'
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/NowEntering.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/NowEntering.txt
new file mode 100644
index 00000000..6e770a71
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/NowEntering.txt
@@ -0,0 +1,2 @@
+
+Now entering {0} quadrant . . .
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Orders.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Orders.txt
new file mode 100644
index 00000000..7dd142e5
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Orders.txt
@@ -0,0 +1,5 @@
+Your orders are as follows:
+    Destroy the {0} Klingon warships which have invaded
+  the galaxy before they can attack federation headquarters
+  on stardate {1}. This gives you {2} days. There {3}
+  {4} starbase{5} in the galaxy for resupplying your ship.
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/PermissionDenied.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/PermissionDenied.txt
new file mode 100644
index 00000000..c24d9da7
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/PermissionDenied.txt
@@ -0,0 +1,5 @@
+Lt. Uhura report message from Starfleet Command:
+  'Permission to attempt crossing of galactic perimeter
+  is hereby *Denied*. Shut down your engines.'
+Chief Engineer Scott reports, 'Warp engines shut down
+  at sector {0} of quadrant {1}.'
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Protected.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Protected.txt
new file mode 100644
index 00000000..fe23b63b
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Protected.txt
@@ -0,0 +1 @@
+Starbase shields protect the Enterprise
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RegionNames.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RegionNames.txt
new file mode 100644
index 00000000..7556a9f8
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RegionNames.txt
@@ -0,0 +1,8 @@
+      Antares                  Sirius
+       Rigel                   Deneb
+      Procyon                 Capella
+        Vega                 Betelgeuse
+      Canopus                Aldebaran
+       Altair                 Regulus
+    Sagittarius               Arcturus
+       Pollux                  Spica
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RelievedOfCommand.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RelievedOfCommand.txt
new file mode 100644
index 00000000..31f398ba
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RelievedOfCommand.txt
@@ -0,0 +1,3 @@
+
+That does it, Captain!!  You are hereby relieved of command
+and sentenced to 99 stardates at hard labor on Cygnus 12!!
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RepairEstimate.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RepairEstimate.txt
new file mode 100644
index 00000000..12e167a5
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RepairEstimate.txt
@@ -0,0 +1,2 @@
+Technicians standing by to effect repairs to your ship;
+Estimated time to repair: {0} stardates.
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RepairPrompt.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RepairPrompt.txt
new file mode 100644
index 00000000..36428e30
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/RepairPrompt.txt
@@ -0,0 +1 @@
+Will you authorize the repair order (Y/N)
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ReplayPrompt.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ReplayPrompt.txt
new file mode 100644
index 00000000..8f9c2d54
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ReplayPrompt.txt
@@ -0,0 +1,5 @@
+
+
+The Federation is in need of a new starship commander
+for a similar mission -- if there is a volunteer
+let him step forward and enter 'Aye'
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ShieldsDropped.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ShieldsDropped.txt
new file mode 100644
index 00000000..acc87f59
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ShieldsDropped.txt
@@ -0,0 +1 @@
+Shields dropped for docking purposes
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ShieldsSet.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ShieldsSet.txt
new file mode 100644
index 00000000..e3d7efda
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ShieldsSet.txt
@@ -0,0 +1,2 @@
+Deflector control room report:
+  'Shields now at {0} units per your command.'
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ShortRangeSensorsOut.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ShortRangeSensorsOut.txt
new file mode 100644
index 00000000..1c958cab
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/ShortRangeSensorsOut.txt
@@ -0,0 +1 @@
+*** Short Range Sensors are out ***
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/StartText.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/StartText.txt
new file mode 100644
index 00000000..c599a2e2
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/StartText.txt
@@ -0,0 +1,4 @@
+
+
+Your mission begins with your starship located
+in the galactic quadrant, '{0}'.
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Stranded.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Stranded.txt
new file mode 100644
index 00000000..07c37952
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Stranded.txt
@@ -0,0 +1,3 @@
+** FATAL ERROR **   You've just stranded your ship in space
+You have insufficient maneuvering energy, and shield control
+is presently incapable of cross-circuiting to engine room!!
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Strings.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Strings.cs
new file mode 100644
index 00000000..b6cd5486
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Strings.cs
@@ -0,0 +1,68 @@
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace SuperStarTrek.Resources
+{
+    internal static class Strings
+    {
+        internal static string CombatArea => GetResource();
+
+        internal static string Congratulations => GetResource();
+
+        internal static string CourtMartial => GetResource();
+
+        internal static string Destroyed => GetResource();
+
+        internal static string EndOfMission => GetResource();
+
+        internal static string Enterprise => GetResource();
+
+        internal static string Instructions => GetResource();
+
+        internal static string LowShields => GetResource();
+
+        internal static string NoEnemyShips => GetResource();
+
+        internal static string NoStarbase => GetResource();
+
+        internal static string NowEntering => GetResource();
+
+        internal static string Orders => GetResource();
+
+        internal static string PermissionDenied => GetResource();
+
+        internal static string Protected => GetResource();
+
+        internal static string RegionNames => GetResource();
+
+        internal static string RelievedOfCommand => GetResource();
+
+        internal static string RepairEstimate => GetResource();
+
+        internal static string RepairPrompt => GetResource();
+
+        internal static string ReplayPrompt => GetResource();
+
+        internal static string ShieldsDropped => GetResource();
+
+        internal static string ShieldsSet => GetResource();
+
+        internal static string ShortRangeSensorsOut => GetResource();
+
+        internal static string StartText => GetResource();
+
+        internal static string Stranded => GetResource();
+
+        internal static string Title => GetResource();
+
+        private static string GetResource([CallerMemberName] string name = "")
+        {
+            var streamName = $"SuperStarTrek.Resources.{name}.txt";
+            using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(streamName);
+            using var reader = new StreamReader(stream);
+
+            return reader.ReadToEnd();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Title.txt b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Title.txt
new file mode 100644
index 00000000..edee3578
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Resources/Title.txt
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+          *************************************
+          *                                   *
+          *                                   *
+          *      * * SUPER STAR TREK * *      *
+          *                                   *
+          *                                   *
+          *************************************
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Coordinates.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Coordinates.cs
new file mode 100644
index 00000000..4768d2c2
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Coordinates.cs
@@ -0,0 +1,70 @@
+using System;
+using SuperStarTrek.Utils;
+
+namespace SuperStarTrek.Space
+{
+    // Represents the corrdintate of a quadrant in the galaxy, or a sector in a quadrant.
+    // Note that the origin is top-left, x increase downwards, and y increases to the right.
+    internal record Coordinates
+    {
+        internal Coordinates(int x, int y)
+        {
+            X = Validated(x, nameof(x));
+            Y = Validated(y, nameof(y));
+
+            RegionIndex = (X << 1) + (Y >> 2);
+            SubRegionIndex = Y % 4;
+        }
+
+        internal int X { get; }
+
+        internal int Y { get; }
+
+        internal int RegionIndex { get; }
+
+        internal int SubRegionIndex { get; }
+
+        private static int Validated(int value, string argumentName)
+        {
+            if (value >= 0 && value <= 7) { return value; }
+
+            throw new ArgumentOutOfRangeException(argumentName, value, "Must be 0 to 7 inclusive");
+        }
+
+        private static bool IsValid(int value) => value >= 0 && value <= 7;
+
+        public override string ToString() => $"{X+1} , {Y+1}";
+
+        internal void Deconstruct(out int x, out int y)
+        {
+            x = X;
+            y = Y;
+        }
+
+        internal static bool TryCreate(float x, float y, out Coordinates coordinates)
+        {
+            var roundedX = Round(x);
+            var roundedY = Round(y);
+
+            if (IsValid(roundedX) && IsValid(roundedY))
+            {
+                coordinates = new Coordinates(roundedX, roundedY);
+                return true;
+            }
+
+            coordinates = default;
+            return false;
+
+            static int Round(float value) => (int)Math.Round(value, MidpointRounding.AwayFromZero);
+        }
+
+        internal (float Direction, float Distance) GetDirectionAndDistanceTo(Coordinates destination) =>
+            DirectionAndDistance.From(this).To(destination);
+
+        internal float GetDistanceTo(Coordinates destination)
+        {
+            var (_, distance) = GetDirectionAndDistanceTo(destination);
+            return distance;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Course.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Course.cs
new file mode 100644
index 00000000..6b9dfc31
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Course.cs
@@ -0,0 +1,98 @@
+using System;
+using System.Collections.Generic;
+
+namespace SuperStarTrek.Space
+{
+    // Implements the course calculations from the original code:
+    //     530 FORI=1TO9:C(I,1)=0:C(I,2)=0:NEXTI
+    //     540 C(3,1)=-1:C(2,1)=-1:C(4,1)=-1:C(4,2)=-1:C(5,2)=-1:C(6,2)=-1
+    //     600 C(1,2)=1:C(2,2)=1:C(6,1)=1:C(7,1)=1:C(8,1)=1:C(8,2)=1:C(9,2)=1
+    //
+    //     3110 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1))
+    //     3140 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1))
+    internal class Course
+    {
+        private static readonly (int DeltaX, int DeltaY)[] cardinals = new[]
+        {
+            (0, 1),
+            (-1, 1),
+            (-1, 0),
+            (-1, -1),
+            (0, -1),
+            (1, -1),
+            (1, 0),
+            (1, 1),
+            (0, 1)
+        };
+
+        internal Course(float direction)
+        {
+            if (direction < 1 || direction > 9)
+            {
+                throw new ArgumentOutOfRangeException(
+                    nameof(direction),
+                    direction,
+                    "Must be between 1 and 9, inclusive.");
+            }
+
+            var cardinalDirection = (int)(direction - 1) % 8;
+            var fractionalDirection = direction - (int)direction;
+
+            var baseCardinal = cardinals[cardinalDirection];
+            var nextCardinal = cardinals[cardinalDirection + 1];
+
+            DeltaX = baseCardinal.DeltaX + (nextCardinal.DeltaX - baseCardinal.DeltaX) * fractionalDirection;
+            DeltaY = baseCardinal.DeltaY + (nextCardinal.DeltaY - baseCardinal.DeltaY) * fractionalDirection;
+        }
+
+        internal float DeltaX { get; }
+
+        internal float DeltaY { get; }
+
+        internal IEnumerable GetSectorsFrom(Coordinates start)
+        {
+            (float x, float y) = start;
+
+            while(true)
+            {
+                x += DeltaX;
+                y += DeltaY;
+
+                if (!Coordinates.TryCreate(x, y, out var coordinates))
+                {
+                    yield break;
+                }
+
+                yield return coordinates;
+            }
+        }
+
+        internal (bool, Coordinates, Coordinates) GetDestination(Coordinates quadrant, Coordinates sector, int distance)
+        {
+            var (xComplete, quadrantX, sectorX) = GetNewCoordinate(quadrant.X, sector.X, DeltaX * distance);
+            var (yComplete, quadrantY, sectorY) = GetNewCoordinate(quadrant.Y, sector.Y, DeltaY * distance);
+
+            return (xComplete && yComplete, new Coordinates(quadrantX, quadrantY), new Coordinates(sectorX, sectorY));
+        }
+
+        private static (bool, int, int) GetNewCoordinate(int quadrant, int sector, float sectorsTravelled)
+        {
+            var galacticCoordinate = quadrant * 8 + sector + sectorsTravelled;
+            var newQuadrant = (int)(galacticCoordinate / 8);
+            var newSector = (int)(galacticCoordinate - newQuadrant * 8);
+
+            if (newSector < 0)
+            {
+                newQuadrant -= 1;
+                newSector += 8;
+            }
+
+            return newQuadrant switch
+            {
+                < 0 => (false, 0, 0),
+                > 7 => (false, 7, 7),
+                _ => (true, newQuadrant, newSector)
+            };
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Galaxy.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Galaxy.cs
new file mode 100644
index 00000000..0b348b06
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Galaxy.cs
@@ -0,0 +1,64 @@
+using System.Collections.Generic;
+using System.Linq;
+using SuperStarTrek.Resources;
+
+using static System.StringSplitOptions;
+
+namespace SuperStarTrek.Space
+{
+    internal class Galaxy
+    {
+        private static readonly string[] _regionNames;
+        private static readonly string[] _subRegionIdentifiers;
+        private readonly QuadrantInfo[][] _quadrants;
+
+        static Galaxy()
+        {
+            _regionNames = Strings.RegionNames.Split(new[] { ' ', '\n' }, RemoveEmptyEntries | TrimEntries);
+            _subRegionIdentifiers = new[] { "I", "II", "III", "IV" };
+        }
+
+        internal Galaxy(Random random)
+        {
+            _quadrants = Enumerable
+                .Range(0, 8)
+                .Select(x => Enumerable
+                    .Range(0, 8)
+                    .Select(y => new Coordinates(x, y))
+                    .Select(c => QuadrantInfo.Create(c, GetQuadrantName(c), random))
+                    .ToArray())
+                .ToArray();
+
+            if (StarbaseCount == 0)
+            {
+                var randomQuadrant = this[random.GetCoordinate()];
+                randomQuadrant.AddStarbase();
+
+                if (randomQuadrant.KlingonCount < 2)
+                {
+                    randomQuadrant.AddKlingon();
+                }
+            }
+        }
+
+        internal QuadrantInfo this[Coordinates coordinate] => _quadrants[coordinate.X][coordinate.Y];
+
+        internal int KlingonCount => _quadrants.SelectMany(q => q).Sum(q => q.KlingonCount);
+
+        internal int StarbaseCount => _quadrants.SelectMany(q => q).Count(q => q.HasStarbase);
+
+        internal IEnumerable> Quadrants => _quadrants;
+
+        private static string GetQuadrantName(Coordinates coordinates) =>
+            $"{_regionNames[coordinates.RegionIndex]} {_subRegionIdentifiers[coordinates.SubRegionIndex]}";
+
+        internal IEnumerable> GetNeighborhood(Quadrant quadrant) =>
+            Enumerable.Range(-1, 3)
+                .Select(dx => dx + quadrant.Coordinates.X)
+                .Select(x => GetNeighborhoodRow(quadrant, x));
+        private IEnumerable GetNeighborhoodRow(Quadrant quadrant, int x) =>
+            Enumerable.Range(-1, 3)
+                .Select(dy => dy + quadrant.Coordinates.Y)
+                .Select(y => y < 0 || y > 7 || x < 0 || x > 7 ? null : _quadrants[x][y]);
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Quadrant.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Quadrant.cs
new file mode 100644
index 00000000..694f7fc8
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/Quadrant.cs
@@ -0,0 +1,192 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SuperStarTrek.Commands;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Resources;
+
+namespace SuperStarTrek.Space
+{
+    internal class Quadrant
+    {
+        private readonly QuadrantInfo _info;
+        private readonly Random _random;
+        private readonly Dictionary _sectors;
+        private readonly Enterprise _enterprise;
+        private readonly Output _output;
+        private bool _entered = false;
+
+        internal Quadrant(
+            QuadrantInfo info,
+            Enterprise enterprise,
+            Random random,
+            Galaxy galaxy,
+            Input input,
+            Output output)
+        {
+            _info = info;
+            _random = random;
+            _output = output;
+            Galaxy = galaxy;
+
+            info.MarkAsKnown();
+            _sectors = new() { [enterprise.SectorCoordinates] = _enterprise = enterprise };
+            PositionObject(sector => new Klingon(sector, _random), _info.KlingonCount);
+            if (_info.HasStarbase)
+            {
+                Starbase = PositionObject(sector => new Starbase(sector, _random, input, output));
+            }
+            PositionObject(_ => new Star(), _info.StarCount);
+        }
+
+        internal Coordinates Coordinates => _info.Coordinates;
+
+        internal bool HasKlingons => _info.KlingonCount > 0;
+
+        internal int KlingonCount => _info.KlingonCount;
+
+        internal bool HasStarbase => _info.HasStarbase;
+
+        internal Starbase Starbase { get; }
+
+        internal Galaxy Galaxy { get; }
+
+        internal bool EnterpriseIsNextToStarbase =>
+            _info.HasStarbase &&
+            Math.Abs(_enterprise.SectorCoordinates.X - Starbase.Sector.X) <= 1 &&
+            Math.Abs(_enterprise.SectorCoordinates.Y - Starbase.Sector.Y) <= 1;
+
+        internal IEnumerable Klingons => _sectors.Values.OfType();
+
+        public override string ToString() => _info.Name;
+
+        private T PositionObject(Func objectFactory)
+        {
+            var sector = GetRandomEmptySector();
+            _sectors[sector] = objectFactory.Invoke(sector);
+            return (T)_sectors[sector];
+        }
+
+        private void PositionObject(Func objectFactory, int count)
+        {
+            for (int i = 0; i < count; i++)
+            {
+                PositionObject(objectFactory);
+            }
+        }
+
+        internal void Display(string textFormat)
+        {
+            if (!_entered)
+            {
+                _output.Write(textFormat, this);
+                _entered = true;
+            }
+
+            if (_info.KlingonCount > 0)
+            {
+                _output.Write(Strings.CombatArea);
+                if (_enterprise.ShieldControl.ShieldEnergy <= 200) { _output.Write(Strings.LowShields); }
+            }
+
+            _enterprise.Execute(Command.SRS);
+        }
+
+        internal bool HasObjectAt(Coordinates coordinates) => _sectors.ContainsKey(coordinates);
+
+        internal bool TorpedoCollisionAt(Coordinates coordinates, out string message, out bool gameOver)
+        {
+            gameOver = false;
+            message = default;
+
+            switch (_sectors.GetValueOrDefault(coordinates))
+            {
+                case Klingon klingon:
+                    message = Remove(klingon);
+                    gameOver = Galaxy.KlingonCount == 0;
+                    return true;
+
+                case Star _:
+                    message = $"Star at {coordinates} absorbed torpedo energy.";
+                    return true;
+
+                case Starbase _:
+                    _sectors.Remove(coordinates);
+                    _info.RemoveStarbase();
+                    message = "*** Starbase destroyed ***" +
+                        (Galaxy.StarbaseCount > 0 ? Strings.CourtMartial : Strings.RelievedOfCommand);
+                    gameOver = Galaxy.StarbaseCount == 0;
+                    return true;
+
+                default:
+                    return false;
+            }
+        }
+
+        internal string Remove(Klingon klingon)
+        {
+            _sectors.Remove(klingon.Sector);
+            _info.RemoveKlingon();
+            return "*** Klingon destroyed ***";
+        }
+
+        internal CommandResult KlingonsMoveAndFire()
+        {
+            foreach (var klingon in Klingons.ToList())
+            {
+                var newSector = GetRandomEmptySector();
+                _sectors.Remove(klingon.Sector);
+                _sectors[newSector] = klingon;
+                klingon.MoveTo(newSector);
+            }
+
+            return KlingonsFireOnEnterprise();
+        }
+
+        internal CommandResult KlingonsFireOnEnterprise()
+        {
+            if (EnterpriseIsNextToStarbase && Klingons.Any())
+            {
+                Starbase.ProtectEnterprise();
+                return CommandResult.Ok;
+            }
+
+            foreach (var klingon in Klingons)
+            {
+                var result = klingon.FireOn(_enterprise);
+                if (result.IsGameOver) { return result; }
+            }
+
+            return CommandResult.Ok;
+        }
+
+        private Coordinates GetRandomEmptySector()
+        {
+            while (true)
+            {
+                var sector = _random.GetCoordinate();
+                if (!_sectors.ContainsKey(sector))
+                {
+                    return sector;
+                }
+            }
+        }
+
+        internal IEnumerable GetDisplayLines() => Enumerable.Range(0, 8).Select(x => GetDisplayLine(x));
+
+        private string GetDisplayLine(int x) =>
+            string.Join(
+                " ",
+                Enumerable
+                    .Range(0, 8)
+                    .Select(y => new Coordinates(x, y))
+                    .Select(c => _sectors.GetValueOrDefault(c))
+                    .Select(o => o?.ToString() ?? "   "));
+
+        internal void SetEnterpriseSector(Coordinates sector)
+        {
+            _sectors.Remove(_enterprise.SectorCoordinates);
+            _sectors[sector] = _enterprise;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/QuadrantInfo.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/QuadrantInfo.cs
new file mode 100644
index 00000000..6a403c2e
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Space/QuadrantInfo.cs
@@ -0,0 +1,65 @@
+namespace SuperStarTrek.Space
+{
+    internal class QuadrantInfo
+    {
+        private bool _isKnown;
+
+        private QuadrantInfo(Coordinates coordinates, string name, int klingonCount, int starCount, bool hasStarbase)
+        {
+            Coordinates = coordinates;
+            Name = name;
+            KlingonCount = klingonCount;
+            StarCount = starCount;
+            HasStarbase = hasStarbase;
+        }
+
+        internal Coordinates Coordinates { get; }
+
+        internal string Name { get; }
+
+        internal int KlingonCount { get; private set; }
+
+        internal bool HasStarbase { get; private set; }
+
+        internal int StarCount { get; }
+
+        internal static QuadrantInfo Create(Coordinates coordinates, string name, Random random)
+        {
+            var klingonCount = random.GetFloat() switch
+            {
+                > 0.98f => 3,
+                > 0.95f => 2,
+                > 0.80f => 1,
+                _ => 0
+            };
+            var hasStarbase = random.GetFloat() > 0.96f;
+            var starCount = random.Get1To8Inclusive();
+
+            return new QuadrantInfo(coordinates, name, klingonCount, starCount, hasStarbase);
+        }
+
+        internal void AddKlingon() => KlingonCount += 1;
+
+        internal void AddStarbase() => HasStarbase = true;
+
+        internal void MarkAsKnown() => _isKnown = true;
+
+        internal string Scan()
+        {
+            _isKnown = true;
+            return ToString();
+        }
+
+        public override string ToString() => _isKnown ? $"{KlingonCount}{(HasStarbase ? 1 : 0)}{StarCount}" : "***";
+
+        internal void RemoveKlingon()
+        {
+            if (KlingonCount > 0)
+            {
+                KlingonCount -= 1;
+            }
+        }
+
+        internal void RemoveStarbase() => HasStarbase = false;
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/StringExtensions.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/StringExtensions.cs
new file mode 100644
index 00000000..4e77291a
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/StringExtensions.cs
@@ -0,0 +1,7 @@
+namespace SuperStarTrek
+{
+    internal static class StringExtensions
+    {
+        internal static string Pluralize(this string singular, int quantity) => singular + (quantity > 1 ? "s" : "");
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/SuperStarTrek.csproj b/00_Alternate_Languages/84_Super_Star_Trek/csharp/SuperStarTrek.csproj
new file mode 100644
index 00000000..c0de0594
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/SuperStarTrek.csproj
@@ -0,0 +1,12 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+  
+    
+  
+
+
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/SuperStarTrek.sln b/00_Alternate_Languages/84_Super_Star_Trek/csharp/SuperStarTrek.sln
new file mode 100644
index 00000000..7a17477a
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/SuperStarTrek.sln
@@ -0,0 +1,34 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26124.0
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SuperStarTrek", "SuperStarTrek.csproj", "{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|x64.Build.0 = Debug|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Debug|x86.Build.0 = Debug|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|x64.ActiveCfg = Release|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|x64.Build.0 = Release|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|x86.ActiveCfg = Release|Any CPU
+		{ACB0A7F5-A4DC-4A2F-8D3D-104E83A0417F}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs
new file mode 100644
index 00000000..43553bd7
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs
@@ -0,0 +1,19 @@
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems.ComputerFunctions
+{
+    internal abstract class ComputerFunction
+    {
+        protected ComputerFunction(string description, Output output)
+        {
+            Description = description;
+            Output = output;
+        }
+
+        internal string Description { get; }
+
+        protected Output Output { get; }
+
+        internal abstract void Execute(Quadrant quadrant);
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/CumulativeGalacticRecord.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/CumulativeGalacticRecord.cs
new file mode 100644
index 00000000..920fbcca
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/CumulativeGalacticRecord.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems.ComputerFunctions
+{
+    internal class CumulativeGalacticRecord : GalacticReport
+    {
+        internal CumulativeGalacticRecord(Output output, Galaxy galaxy)
+            : base("Cumulative galactic record", output, galaxy)
+        {
+        }
+
+        protected override void WriteHeader(Quadrant quadrant) =>
+            Output.NextLine().WriteLine($"Computer record of galaxy for quadrant {quadrant.Coordinates}").NextLine();
+
+        protected override IEnumerable GetRowData() =>
+            Galaxy.Quadrants.Select(row => " " + string.Join("   ", row));
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs
new file mode 100644
index 00000000..3e9965db
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs
@@ -0,0 +1,30 @@
+using SuperStarTrek.Objects;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems.ComputerFunctions
+{
+    internal class DirectionDistanceCalculator : NavigationCalculator
+    {
+        private readonly Enterprise _enterprise;
+        private readonly Input _input;
+
+        internal DirectionDistanceCalculator(Enterprise enterprise, Output output, Input input)
+            : base("Direction/distance calculator", output)
+        {
+            _enterprise = enterprise;
+            _input = input;
+        }
+
+        internal override void Execute(Quadrant quadrant)
+        {
+            Output.WriteLine("Direction/distance calculator:")
+                .Write($"You are at quadrant {_enterprise.QuadrantCoordinates}")
+                .WriteLine($" sector {_enterprise.SectorCoordinates}")
+                .WriteLine("Please enter");
+
+            WriteDirectionAndDistance(
+                _input.GetCoordinates("  Initial coordinates"),
+                _input.GetCoordinates("  Final coordinates"));
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/GalacticReport.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/GalacticReport.cs
new file mode 100644
index 00000000..1e8d5f23
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/GalacticReport.cs
@@ -0,0 +1,34 @@
+using System.Collections.Generic;
+using System.Linq;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems.ComputerFunctions
+{
+    internal abstract class GalacticReport : ComputerFunction
+    {
+        internal GalacticReport(string description, Output output, Galaxy galaxy)
+            : base(description, output)
+        {
+            Galaxy = galaxy;
+        }
+
+        protected Galaxy Galaxy { get; }
+
+        protected abstract void WriteHeader(Quadrant quadrant);
+
+        protected abstract IEnumerable GetRowData();
+
+        internal sealed override void Execute(Quadrant quadrant)
+        {
+            WriteHeader(quadrant);
+            Output.WriteLine("       1     2     3     4     5     6     7     8")
+                .WriteLine("     ----- ----- ----- ----- ----- ----- ----- -----");
+
+            foreach (var (row, index) in GetRowData().Select((r, i) => (r, i)))
+            {
+                Output.WriteLine($" {index+1}   {row}")
+                    .WriteLine("     ----- ----- ----- ----- ----- ----- ----- -----");
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/GalaxyRegionMap.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/GalaxyRegionMap.cs
new file mode 100644
index 00000000..12ff204b
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/GalaxyRegionMap.cs
@@ -0,0 +1,21 @@
+using System.Collections.Generic;
+using System.Linq;
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems.ComputerFunctions
+{
+    internal class GalaxyRegionMap : GalacticReport
+    {
+        internal GalaxyRegionMap(Output output, Galaxy galaxy)
+            : base("Galaxy 'region name' map", output, galaxy)
+        {
+        }
+
+        protected override void WriteHeader(Quadrant quadrant) =>
+            Output.WriteLine("                        The Galaxy");
+
+        protected override IEnumerable GetRowData() =>
+            Strings.RegionNames.Split('\n').Select(n => n.TrimEnd('\r'));
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/NavigationCalculator.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/NavigationCalculator.cs
new file mode 100644
index 00000000..ef35f8c3
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/NavigationCalculator.cs
@@ -0,0 +1,29 @@
+using SuperStarTrek.Space;
+using SuperStarTrek.Utils;
+
+namespace SuperStarTrek.Systems.ComputerFunctions
+{
+    internal abstract class NavigationCalculator : ComputerFunction
+    {
+        protected NavigationCalculator(string description, Output output)
+            : base(description, output)
+        {
+        }
+
+        protected void WriteDirectionAndDistance(Coordinates from, Coordinates to)
+        {
+            var (direction, distance) = from.GetDirectionAndDistanceTo(to);
+            Write(direction, distance);
+        }
+
+        protected void WriteDirectionAndDistance((float X, float Y) from, (float X, float Y) to)
+        {
+            var (direction, distance) = DirectionAndDistance.From(from.X, from.Y).To(to.X, to.Y);
+            Write(direction, distance);
+        }
+
+        private void Write(float direction, float distance) =>
+            Output.WriteLine($"Direction = {direction}")
+                .WriteLine($"Distance = {distance}");
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs
new file mode 100644
index 00000000..07f2119b
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs
@@ -0,0 +1,30 @@
+using SuperStarTrek.Objects;
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems.ComputerFunctions
+{
+    internal class StarbaseDataCalculator : NavigationCalculator
+    {
+        private readonly Enterprise _enterprise;
+
+        internal StarbaseDataCalculator(Enterprise enterprise, Output output)
+            : base("Starbase nav data", output)
+        {
+            _enterprise = enterprise;
+        }
+
+        internal override void Execute(Quadrant quadrant)
+        {
+            if (!quadrant.HasStarbase)
+            {
+                Output.WriteLine(Strings.NoStarbase);
+                return;
+            }
+
+            Output.WriteLine("From Enterprise to Starbase:");
+
+            WriteDirectionAndDistance(_enterprise.SectorCoordinates, quadrant.Starbase.Sector);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/StatusReport.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/StatusReport.cs
new file mode 100644
index 00000000..6e6bf6f1
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/StatusReport.cs
@@ -0,0 +1,41 @@
+using SuperStarTrek.Commands;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems.ComputerFunctions
+{
+    internal class StatusReport : ComputerFunction
+    {
+        private readonly Game _game;
+        private readonly Galaxy _galaxy;
+        private readonly Enterprise _enterprise;
+
+        internal StatusReport(Game game, Galaxy galaxy, Enterprise enterprise, Output output)
+            : base("Status report", output)
+        {
+            _game = game;
+            _galaxy = galaxy;
+            _enterprise = enterprise;
+        }
+
+        internal override void Execute(Quadrant quadrant)
+        {
+            Output.WriteLine("   Status report:")
+                .Write("Klingon".Pluralize(_galaxy.KlingonCount)).WriteLine($" left:  {_galaxy.KlingonCount}")
+                .WriteLine($"Mission must be completed in {_game.StardatesRemaining:0.#} stardates.");
+
+            if (_galaxy.StarbaseCount > 0)
+            {
+                Output.Write($"The Federation is maintaining {_galaxy.StarbaseCount} ")
+                   .Write("starbase".Pluralize(_galaxy.StarbaseCount)).WriteLine(" in the galaxy.");
+            }
+            else
+            {
+                Output.WriteLine("Your stupidity has left you on your own in")
+                    .WriteLine("  the galaxy -- you have no starbases left!");
+            }
+
+            _enterprise.Execute(Command.DAM);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs
new file mode 100644
index 00000000..94f8ae9a
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs
@@ -0,0 +1,33 @@
+using SuperStarTrek.Objects;
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems.ComputerFunctions
+{
+    internal class TorpedoDataCalculator : NavigationCalculator
+    {
+        private readonly Enterprise _enterprise;
+
+        internal TorpedoDataCalculator(Enterprise enterprise, Output output)
+            : base("Photon torpedo data", output)
+        {
+            _enterprise = enterprise;
+        }
+
+        internal override void Execute(Quadrant quadrant)
+        {
+            if (!quadrant.HasKlingons)
+            {
+                Output.WriteLine(Strings.NoEnemyShips);
+                return;
+            }
+
+            Output.WriteLine("From Enterprise to Klingon battle cruiser".Pluralize(quadrant.KlingonCount));
+
+            foreach (var klingon in quadrant.Klingons)
+            {
+                WriteDirectionAndDistance(_enterprise.SectorCoordinates, klingon.Sector);
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/DamageControl.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/DamageControl.cs
new file mode 100644
index 00000000..8fbf21d3
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/DamageControl.cs
@@ -0,0 +1,54 @@
+using SuperStarTrek.Commands;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems
+{
+    internal class DamageControl : Subsystem
+    {
+        private readonly Enterprise _enterprise;
+        private readonly Output _output;
+
+        internal DamageControl(Enterprise enterprise, Output output)
+            : base("Damage Control", Command.DAM, output)
+        {
+            _enterprise = enterprise;
+            _output = output;
+        }
+
+        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
+        {
+            if (IsDamaged)
+            {
+                _output.WriteLine("Damage Control report not available");
+            }
+            else
+            {
+                _output.NextLine();
+                WriteDamageReport();
+            }
+
+            if (_enterprise.DamagedSystemCount > 0 && _enterprise.IsDocked)
+            {
+                if (quadrant.Starbase.TryRepair(_enterprise, out var repairTime))
+                {
+                    WriteDamageReport();
+                    return CommandResult.Elapsed(repairTime);
+                }
+            }
+
+            return CommandResult.Ok;
+        }
+
+        internal void WriteDamageReport()
+        {
+            _output.NextLine().WriteLine("Device             State of Repair");
+            foreach (var system in _enterprise.Systems)
+            {
+                _output.Write(system.Name.PadRight(25))
+                    .WriteLine(((int)(system.Condition * 100) * 0.01).ToString(" 0.##;-0.##"));
+            }
+            _output.NextLine();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/LibraryComputer.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/LibraryComputer.cs
new file mode 100644
index 00000000..df5c6868
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/LibraryComputer.cs
@@ -0,0 +1,47 @@
+using SuperStarTrek.Commands;
+using SuperStarTrek.Space;
+using SuperStarTrek.Systems.ComputerFunctions;
+
+namespace SuperStarTrek.Systems
+{
+    internal class LibraryComputer : Subsystem
+    {
+        private readonly Output _output;
+        private readonly Input _input;
+        private readonly ComputerFunction[] _functions;
+
+        internal LibraryComputer(Output output, Input input, params ComputerFunction[] functions)
+            : base("Library-Computer", Command.COM, output)
+        {
+            _output = output;
+            _input = input;
+            _functions = functions;
+        }
+
+        protected override bool CanExecuteCommand() => IsOperational("Computer disabled");
+
+        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
+        {
+            var index = GetFunctionIndex();
+            _output.NextLine();
+
+            _functions[index].Execute(quadrant);
+
+            return CommandResult.Ok;
+        }
+
+        private int GetFunctionIndex()
+        {
+            while (true)
+            {
+                var index = (int)_input.GetNumber("Computer active and waiting command");
+                if (index >= 0 && index <= 5) { return index; }
+
+                for (int i = 0; i < _functions.Length; i++)
+                {
+                    _output.WriteLine($"   {i} = {_functions[i].Description}");
+                }
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/LongRangeSensors.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/LongRangeSensors.cs
new file mode 100644
index 00000000..a873eeba
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/LongRangeSensors.cs
@@ -0,0 +1,34 @@
+using System.Linq;
+using SuperStarTrek.Commands;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems
+{
+    internal class LongRangeSensors : Subsystem
+    {
+        private readonly Galaxy _galaxy;
+        private readonly Output _output;
+
+        internal LongRangeSensors(Galaxy galaxy, Output output)
+            : base("Long Range Sensors", Command.LRS, output)
+        {
+            _galaxy = galaxy;
+            _output = output;
+        }
+
+        protected override bool CanExecuteCommand() => IsOperational("{name} are inoperable");
+
+        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
+        {
+            _output.WriteLine($"Long range scan for quadrant {quadrant.Coordinates}");
+            _output.WriteLine("-------------------");
+            foreach (var quadrants in _galaxy.GetNeighborhood(quadrant))
+            {
+                _output.WriteLine(": " + string.Join(" : ", quadrants.Select(q => q?.Scan() ?? "***")) + " :");
+                _output.WriteLine("-------------------");
+            }
+
+            return CommandResult.Ok;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/PhaserControl.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/PhaserControl.cs
new file mode 100644
index 00000000..9207ad94
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/PhaserControl.cs
@@ -0,0 +1,97 @@
+using System.Linq;
+using SuperStarTrek.Commands;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems
+{
+    internal class PhaserControl : Subsystem
+    {
+        private readonly Enterprise _enterprise;
+        private readonly Output _output;
+        private readonly Input _input;
+        private readonly Random _random;
+
+        internal PhaserControl(Enterprise enterprise, Output output, Input input, Random random)
+            : base("Phaser Control", Command.PHA, output)
+        {
+            _enterprise = enterprise;
+            _output = output;
+            _input = input;
+            _random = random;
+        }
+
+        protected override bool CanExecuteCommand() => IsOperational("Phasers inoperative");
+
+        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
+        {
+            if (!quadrant.HasKlingons)
+            {
+                _output.WriteLine(Strings.NoEnemyShips);
+                return CommandResult.Ok;
+            }
+
+            if (_enterprise.Computer.IsDamaged)
+            {
+                _output.WriteLine("Computer failure hampers accuracy");
+            }
+
+            _output.Write($"Phasers locked on target;  ");
+
+            var phaserStrength = GetPhaserStrength();
+            if (phaserStrength < 0) { return CommandResult.Ok; }
+
+            _enterprise.UseEnergy(phaserStrength);
+
+            var perEnemyStrength = GetPerTargetPhaserStrength(phaserStrength, quadrant.KlingonCount);
+
+            foreach (var klingon in quadrant.Klingons.ToList())
+            {
+                ResolveHitOn(klingon, perEnemyStrength, quadrant);
+            }
+
+            return quadrant.KlingonsFireOnEnterprise();
+        }
+
+        private float GetPhaserStrength()
+        {
+            while (true)
+            {
+                _output.WriteLine($"Energy available = {_enterprise.Energy} units");
+                var phaserStrength = _input.GetNumber("Number of units to fire");
+
+                if (phaserStrength <= _enterprise.Energy) { return phaserStrength; }
+            }
+        }
+
+        private float GetPerTargetPhaserStrength(float phaserStrength, int targetCount)
+        {
+            if (_enterprise.Computer.IsDamaged)
+            {
+                phaserStrength *= _random.GetFloat();
+            }
+
+            return phaserStrength / targetCount;
+        }
+
+        private void ResolveHitOn(Klingon klingon, float perEnemyStrength, Quadrant quadrant)
+        {
+            var distance = _enterprise.SectorCoordinates.GetDistanceTo(klingon.Sector);
+            var hitStrength = (int)(perEnemyStrength / distance * (2 + _random.GetFloat()));
+
+            if (klingon.TakeHit(hitStrength))
+            {
+                _output.WriteLine($"{hitStrength} unit hit on Klingon at sector {klingon.Sector}");
+                _output.WriteLine(
+                    klingon.Energy <= 0
+                        ? quadrant.Remove(klingon)
+                        : $"   (sensors show {klingon.Energy} units remaining)");
+            }
+            else
+            {
+                _output.WriteLine($"Sensors show no damage to enemy at {klingon.Sector}");
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/PhotonTubes.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/PhotonTubes.cs
new file mode 100644
index 00000000..37613037
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/PhotonTubes.cs
@@ -0,0 +1,66 @@
+using SuperStarTrek.Commands;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems
+{
+    internal class PhotonTubes : Subsystem
+    {
+        private readonly int _tubeCount;
+        private readonly Enterprise _enterprise;
+        private readonly Output _output;
+        private readonly Input _input;
+
+        internal PhotonTubes(int tubeCount, Enterprise enterprise, Output output, Input input)
+            : base("Photon Tubes", Command.TOR, output)
+        {
+            TorpedoCount = _tubeCount = tubeCount;
+            _enterprise = enterprise;
+            _output = output;
+            _input = input;
+        }
+
+        internal int TorpedoCount { get; private set; }
+
+        protected override bool CanExecuteCommand() => HasTorpedoes() && IsOperational("{name} are not operational");
+
+        private bool HasTorpedoes()
+        {
+            if (TorpedoCount > 0) { return true; }
+
+            _output.WriteLine("All photon torpedoes expended");
+            return false;
+        }
+
+        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
+        {
+            if (!_input.TryGetCourse("Photon torpedo course", "Ensign Chekov", out var course))
+            {
+                return CommandResult.Ok;
+            }
+
+            TorpedoCount -= 1;
+
+            var isHit = false;
+            _output.WriteLine("Torpedo track:");
+            foreach (var sector in course.GetSectorsFrom(_enterprise.SectorCoordinates))
+            {
+                _output.WriteLine($"                {sector}");
+
+                if (quadrant.TorpedoCollisionAt(sector, out var message, out var gameOver))
+                {
+                    _output.WriteLine(message);
+                    isHit = true;
+                    if (gameOver) { return CommandResult.GameOver; }
+                    break;
+                }
+            }
+
+            if (!isHit) { _output.WriteLine("Torpedo missed!"); }
+
+            return quadrant.KlingonsFireOnEnterprise();
+        }
+
+        internal void ReplenishTorpedoes() => TorpedoCount = _tubeCount;
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ShieldControl.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ShieldControl.cs
new file mode 100644
index 00000000..de4f44d9
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ShieldControl.cs
@@ -0,0 +1,59 @@
+using SuperStarTrek.Commands;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems
+{
+    internal class ShieldControl : Subsystem
+    {
+        private readonly Enterprise _enterprise;
+        private readonly Output _output;
+        private readonly Input _input;
+
+        internal ShieldControl(Enterprise enterprise, Output output, Input input)
+            : base("Shield Control", Command.SHE, output)
+        {
+            _enterprise = enterprise;
+            _output = output;
+            _input = input;
+        }
+
+        internal float ShieldEnergy { get; set; }
+
+        protected override bool CanExecuteCommand() => IsOperational("{name} inoperable");
+
+        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
+        {
+            _output.WriteLine($"Energy available = {_enterprise.TotalEnergy}");
+            var requested = _input.GetNumber($"Number of units to shields");
+
+            if (Validate(requested))
+            {
+                ShieldEnergy = requested;
+                _output.Write(Strings.ShieldsSet, requested);
+            }
+            else
+            {
+                _output.WriteLine("");
+            }
+
+            return CommandResult.Ok;
+        }
+
+        private bool Validate(float requested)
+        {
+            if (requested > _enterprise.TotalEnergy)
+            {
+                _output.WriteLine("Shield Control reports, 'This is not the Federation Treasury.'");
+                return false;
+            }
+
+            return requested >= 0 && requested != ShieldEnergy;
+        }
+
+        internal void AbsorbHit(int hitStrength) => ShieldEnergy -= hitStrength;
+
+        internal void DropShields() => ShieldEnergy = 0;
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ShortRangeSensors.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ShortRangeSensors.cs
new file mode 100644
index 00000000..c37028cb
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/ShortRangeSensors.cs
@@ -0,0 +1,62 @@
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SuperStarTrek.Commands;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems
+{
+    internal class ShortRangeSensors : Subsystem
+    {
+        private readonly Enterprise _enterprise;
+        private readonly Galaxy _galaxy;
+        private readonly Game _game;
+        private readonly Output _output;
+
+        internal ShortRangeSensors(Enterprise enterprise, Galaxy galaxy, Game game, Output output)
+            : base("Short Range Sensors", Command.SRS, output)
+        {
+            _enterprise = enterprise;
+            _galaxy = galaxy;
+            _game = game;
+            _output = output;
+        }
+
+        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
+        {
+            if (_enterprise.IsDocked)
+            {
+                _output.WriteLine(Strings.ShieldsDropped);
+            }
+
+            if (Condition < 0)
+            {
+                _output.WriteLine(Strings.ShortRangeSensorsOut);
+            }
+
+            _output.WriteLine("---------------------------------");
+            quadrant.GetDisplayLines()
+                .Zip(GetStatusLines(), (sectors, status) => $" {sectors}         {status}")
+                .ToList()
+                .ForEach(l => _output.WriteLine(l));
+            _output.WriteLine("---------------------------------");
+
+            return CommandResult.Ok;
+        }
+
+        internal IEnumerable GetStatusLines()
+        {
+            yield return $"Stardate           {_game.Stardate}";
+            yield return $"Condition          {_enterprise.Condition}";
+            yield return $"Quadrant           {_enterprise.QuadrantCoordinates}";
+            yield return $"Sector             {_enterprise.SectorCoordinates}";
+            yield return $"Photon torpedoes   {_enterprise.PhotonTubes.TorpedoCount}";
+            yield return $"Total energy       {Math.Ceiling(_enterprise.TotalEnergy)}";
+            yield return $"Shields            {(int)_enterprise.ShieldControl.ShieldEnergy}";
+            yield return $"Klingons remaining {_galaxy.KlingonCount}";
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/Subsystem.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/Subsystem.cs
new file mode 100644
index 00000000..5c11e656
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/Subsystem.cs
@@ -0,0 +1,68 @@
+using SuperStarTrek.Commands;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems
+{
+    internal abstract class Subsystem
+    {
+        private readonly Output _output;
+
+        protected Subsystem(string name, Command command, Output output)
+        {
+            Name = name;
+            Command = command;
+            Condition = 0;
+            _output = output;
+        }
+
+        internal string Name { get; }
+
+        internal float Condition { get; private set; }
+
+        internal bool IsDamaged => Condition < 0;
+
+        internal Command Command { get; }
+
+        protected virtual bool CanExecuteCommand() => true;
+
+        protected bool IsOperational(string notOperationalMessage)
+        {
+            if (IsDamaged)
+            {
+                _output.WriteLine(notOperationalMessage.Replace("{name}", Name));
+                return false;
+            }
+
+            return true;
+        }
+
+        internal CommandResult ExecuteCommand(Quadrant quadrant)
+            => CanExecuteCommand() ? ExecuteCommandCore(quadrant) : CommandResult.Ok;
+
+        protected abstract CommandResult ExecuteCommandCore(Quadrant quadrant);
+
+        internal virtual void Repair()
+        {
+            if (IsDamaged)
+            {
+                Condition = 0;
+            }
+        }
+
+        internal virtual bool Repair(float repairWorkDone)
+        {
+            if (IsDamaged)
+            {
+                Condition += repairWorkDone;
+                if (Condition > -0.1f && Condition < 0)
+                {
+                    Condition = -0.1f;
+                }
+            }
+
+            return !IsDamaged;
+        }
+
+        internal void TakeDamage(float damage) => Condition -= damage;
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/WarpEngines.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/WarpEngines.cs
new file mode 100644
index 00000000..096d0e43
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Systems/WarpEngines.cs
@@ -0,0 +1,85 @@
+using System;
+using SuperStarTrek.Commands;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems
+{
+    internal class WarpEngines : Subsystem
+    {
+        private readonly Enterprise _enterprise;
+        private readonly Output _output;
+        private readonly Input _input;
+
+        internal WarpEngines(Enterprise enterprise, Output output, Input input)
+            : base("Warp Engines", Command.NAV, output)
+        {
+            _enterprise = enterprise;
+            _output = output;
+            _input = input;
+        }
+
+        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
+        {
+            if (_input.TryGetCourse("Course", "   Lt. Sulu", out var course) &&
+                TryGetWarpFactor(out var warpFactor) &&
+                TryGetDistanceToMove(warpFactor, out var distanceToMove))
+            {
+                var result = quadrant.KlingonsMoveAndFire();
+                if (result.IsGameOver) { return result; }
+
+                _enterprise.RepairSystems(warpFactor);
+                _enterprise.VaryConditionOfRandomSystem();
+                var timeElapsed = _enterprise.Move(course, warpFactor, distanceToMove);
+
+                if (_enterprise.IsDocked)
+                {
+                    _enterprise.ShieldControl.DropShields();
+                    _enterprise.Refuel();
+                    _enterprise.PhotonTubes.ReplenishTorpedoes();
+                }
+
+                _enterprise.Quadrant.Display(Strings.NowEntering);
+
+                return CommandResult.Elapsed(timeElapsed);
+            }
+
+            return CommandResult.Ok;
+        }
+
+        private bool TryGetWarpFactor(out float warpFactor)
+        {
+            var maximumWarp = IsDamaged ? 0.2f : 8;
+            if (_input.TryGetNumber("Warp Factor", 0, maximumWarp, out warpFactor))
+            {
+                return warpFactor > 0;
+            }
+
+            _output.WriteLine(
+                IsDamaged && warpFactor > maximumWarp
+                    ? "Warp engines are damaged.  Maximum speed = warp 0.2"
+                    : $"  Chief Engineer Scott reports, 'The engines won't take warp {warpFactor} !'");
+
+            return false;
+        }
+
+        private bool TryGetDistanceToMove(float warpFactor, out int distanceToTravel)
+        {
+            distanceToTravel = (int)Math.Round(warpFactor * 8, MidpointRounding.AwayFromZero);
+            if (distanceToTravel <= _enterprise.Energy) { return true; }
+
+            _output.WriteLine("Engineering reports, 'Insufficient energy available")
+                .WriteLine($"                      for maneuvering at warp {warpFactor} !'");
+
+            if (distanceToTravel <= _enterprise.TotalEnergy && !_enterprise.ShieldControl.IsDamaged)
+            {
+                _output.Write($"Deflector control room acknowledges {_enterprise.ShieldControl.ShieldEnergy} ")
+                    .WriteLine("units of energy")
+                    .WriteLine("                         presently deployed to shields.");
+            }
+
+            return false;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/csharp/Utils/DirectionAndDistance.cs b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Utils/DirectionAndDistance.cs
new file mode 100644
index 00000000..a2d3f09b
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/csharp/Utils/DirectionAndDistance.cs
@@ -0,0 +1,65 @@
+using System;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Utils
+{
+    internal class DirectionAndDistance
+    {
+        private readonly float _fromX;
+        private readonly float _fromY;
+
+        private DirectionAndDistance(float fromX, float fromY)
+        {
+            _fromX = fromX;
+            _fromY = fromY;
+        }
+
+        internal static DirectionAndDistance From(Coordinates coordinates) => From(coordinates.X, coordinates.Y);
+
+        internal static DirectionAndDistance From(float x, float y) => new DirectionAndDistance(x, y);
+
+        internal (float Direction, float Distance) To(Coordinates coordinates) => To(coordinates.X, coordinates.Y);
+
+        internal (float Direction, float Distance) To(float x, float y)
+        {
+            var deltaX = x - _fromX;
+            var deltaY = y - _fromY;
+
+            return (GetDirection(deltaX, deltaY), GetDistance(deltaX, deltaY));
+        }
+
+        // The algorithm here is mathematically equivalent to the following code in the original,
+        // where X is deltaY and A is deltaX
+        //     8220 X=X-A:A=C1-W1:IFX<0THEN8350
+        //     8250 IFA<0THEN8410
+        //     8260 IFX>0THEN8280
+        //     8270 IFA=0THENC1=5:GOTO8290
+        //     8280 C1=1
+        //     8290 IFABS(A)<=ABS(X)THEN8330
+        //     8310 PRINT"DIRECTION =";C1+(((ABS(A)-ABS(X))+ABS(A))/ABS(A)):GOTO8460
+        //     8330 PRINT"DIRECTION =";C1+(ABS(A)/ABS(X)):GOTO8460
+        //     8350 IFA>0THENC1=3:GOTO8420
+        //     8360 IFX<>0THENC1=5:GOTO8290
+        //     8410 C1=7
+        //     8420 IFABS(A)>=ABS(X)THEN8450
+        //     8430 PRINT"DIRECTION =";C1+(((ABS(X)-ABS(A))+ABS(X))/ABS(X)):GOTO8460
+        //     8450 PRINT"DIRECTION =";C1+(ABS(X)/ABS(A))
+        //     8460 PRINT"DISTANCE =";SQR(X^2+A^2):IFH8=1THEN1990
+        private static float GetDirection(float deltaX, float deltaY)
+        {
+            var deltaXDominant = Math.Abs(deltaX) > Math.Abs(deltaY);
+            var fractionalPart = deltaXDominant ? deltaY / deltaX : -deltaX / deltaY;
+            var nearestCardinal = deltaXDominant switch
+            {
+                true => deltaX > 0 ? 7 : 3,
+                false => deltaY > 0 ? 1 : 5
+            };
+
+            var direction = nearestCardinal + fractionalPart;
+            return direction < 1 ? direction + 8 : direction;
+        }
+
+        private static float GetDistance(float deltaX, float deltaY) =>
+            (float)Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2));
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/instructions.txt b/00_Alternate_Languages/84_Super_Star_Trek/instructions.txt
new file mode 100644
index 00000000..59124d9d
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/instructions.txt
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+*************************************
+*                                   *
+*                                   *
+*      * * SUPER STAR TREK * *      *
+*                                   *
+*                                   *
+*************************************
+
+
+
+
+
+
+
+
+      INSTRUCTIONS FOR 'SUPER STAR TREK'
+
+1. WHEN YOU SEE \COMMAND ?\ PRINTED, ENTER ONE OF THE LEGAL
+     COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).
+2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT
+     LIST OF THE LEGAL COMMANDS PRINTED OUT.
+3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE
+     'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.)  IF YOU
+     TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND
+     WILL BE ABORTED
+
+     THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,
+AND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.
+
+     YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE
+GALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP
+\ENTERPRISE\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF
+KLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF
+PLANETS.
+
+     YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN
+OF THE STARSHIP ENTERPRISE:
+
+\NAV\ COMMAND = WARP ENGINE CONTROL --
+     COURSE IS IN A CIRCULAR NUMERICAL      4  3  2
+     VECTOR ARRANGEMENT AS SHOWN             . . .
+     INTEGER AND REAL VALUES MAY BE           ...
+     USED.  (THUS COURSE 1.5 IS HALF-     5 ---*--- 1
+     WAY BETWEEN 1 AND 2                      ...
+                                             . . .
+     VALUES MAY APPROACH 9.0, WHICH         6  7  8
+     ITSELF IS EQUIVALENT TO 1.0"
+                                            COURSE
+     ONE WARP FACTOR IS THE SIZE OF
+     ONE QUADTANT.  THEREFORE, TO GET
+     FROM QUADRANT 6,5 TO 5,5, YOU WOULD
+     USE COURSE 3, WARP FACTOR 1.
+
+\SRS\ COMMAND = SHORT RANGE SENSOR SCAN
+     SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.
+
+     SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:
+        <*> = YOUR STARSHIP'S POSITION
+        +K+ = KLINGON BATTLE CRUISER
+        >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)
+         *  = STAR
+
+     A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.
+
+\LRS\ COMMAND = LONG RANGE SENSOR SCAN
+     SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE
+     OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)
+     THE SCAN IS CODED IN THE FORM \###\, WHERE TH UNITS DIGIT
+     IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF
+     STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF
+     KLINGONS.
+
+     EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.
+
+\PHA\ COMMAND = PHASER CONTROL.
+     ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY
+     ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO
+     DEPLETE THEIR SHIELD POWER.  (REMEMBER, KLINGONS HAVE
+     PHASERS TOO!)
+
+\TOR\ COMMAND = PHOTON TORPEDO CONTROL
+     TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL
+     IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND
+     CANNOT FIRE BACK AT YOU.  IF YOU MISS, YOU ARE SUBJECT TO
+     HIS PHASER FIRE.  IN EITHER CASE, YOU ARE ALSO SUBJECT TO
+     THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.
+
+     THE LIBRARY-COMPUTER (\COM\ COMMAND) HAS AN OPTION TO
+     COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)
+
+\SHE\ COMMAND = SHIELD CONTROL
+     DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE
+     SHIELDS.  ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY.  NOTE
+     THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY
+
+\DAM\ COMMAND = DAMMAGE CONTROL REPORT
+     GIVES THE STATE OF REPAIR OF ALL DEVICES.  WHERE A NEGATIVE
+     'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY
+     DAMAGED.
+
+\COM\ COMMAND = LIBRARY-COMPUTER
+     THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:
+     OPTION 0 = CUMULATIVE GALACTIC RECORD
+        THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL
+        PREVIOUS SHORT AND LONG RANGE SENSOR SCANS
+     OPTION 1 = STATUS REPORT
+        THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,
+        AND STARBASES REMAINING IN THE GAME.
+     OPTION 2 = PHOTON TORPEDO DATA
+        WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE
+        TO ALL KLINGONS IN YOUR QUADRANT
+     OPTION 3 = STARBASE NAV DATA
+        THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY
+        STARBASE WITHIN YOUR QUADRANT
+     OPTION 4 = DIRECTION/DISTANCE CALCULATOR
+        THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR
+        DIRECTION/DISTANCE CALCULATIONS
+     OPTION 5 = GALACTIC /REGION NAME/ MAP
+        THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR
+        GALACTIC REGIONS REFERRED TO IN THE GAME.
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/java/README.md b/00_Alternate_Languages/84_Super_Star_Trek/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/java/SuperStarTrekGame.java b/00_Alternate_Languages/84_Super_Star_Trek/java/SuperStarTrekGame.java
new file mode 100644
index 00000000..b8ecb934
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/java/SuperStarTrekGame.java
@@ -0,0 +1,1239 @@
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Random;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * SUPER STARTREK - MAY 16,1978
+ * ****        **** STAR TREK ****        ****
+ * **** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE,
+ * **** AS SEEN ON THE STAR TREK TV SHOW.
+ * **** ORIGINAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION
+ * **** PUBLISHED IN DEC'S "101 BASIC GAMES", BY DAVE AHL.
+ * **** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB
+ * *** LEEDOM - APRIL & DECEMBER 1974,
+ * *** WITH A LITTLE HELP FROM HIS FRIENDS . . .
+ *
+ * Ported to Java in Jan-Feb 2022 by
+ * Taciano Dreckmann Perez (taciano.perez@gmail.com)
+ */
+public class SuperStarTrekGame {
+
+    // markers
+    static final String MARKER_EMPTY = "   ";
+    static final String MARKER_ENTERPRISE = "<*>";
+    static final String MARKER_KLINGON = "+K+";
+    static final String MARKER_STARBASE = ">!<";
+    static final String MARKER_STAR = " * ";
+
+    // commands
+    static final int COMMAND_NAV = 1;
+    static final int COMMAND_SRS = 2;
+    static final int COMMAND_LRS = 3;
+    static final int COMMAND_PHA = 4;
+    static final int COMMAND_TOR = 5;
+    static final int COMMAND_SHE = 6;
+    static final int COMMAND_DAM = 7;
+    static final int COMMAND_COM = 8;
+    static final int COMMAND_XXX = 9;
+
+    // computer commands
+    static final int COMPUTER_COMMAND_CUMULATIVE_GALACTIC_RECORD = 1;
+    static final int COMPUTER_COMMAND_STATUS_REPORT = 2;
+    static final int COMPUTER_COMMAND_PHOTON_TORPEDO_DATA = 3;
+    static final int COMPUTER_COMMAND_STARBASE_NAV_DATA = 4;
+    static final int COMPUTER_COMMAND_DIR_DIST_CALC = 5;
+    static final int COMPUTER_COMMAND_GALAXY_MAP = 6;
+
+    // devices
+    static final int DEVICE_WARP_ENGINES = 1;
+    static final int DEVICE_SHORT_RANGE_SENSORS = 2;
+    static final int DEVICE_LONG_RANGE_SENSORS = 3;
+    static final int DEVICE_PHASER_CONTROL = 4;
+    static final int DEVICE_PHOTON_TUBES = 5;
+    static final int DEVICE_DAMAGE_CONTROL = 6;
+    static final int DEVICE_SHIELD_CONTROL = 7;
+    static final int DEVICE_LIBRARY_COMPUTER = 8;
+
+    // other constants
+    static final String QUADRANT_ROW = "                         ";
+    static final String COMMANDS = "NAVSRSLRSPHATORSHEDAMCOMXXX";
+    static final Random random = new Random();
+
+    // game state
+    final int galaxy[][] = new int[9][9];    // 8x8 galaxy map G
+    final int cardinalDirections[][] = new int[10][3];   // 9x2 vectors in cardinal directions C
+    final int klingonQuadrants[][] = new int[4][4];    // 3x3 position of klingons K
+    final int chartedGalaxy[][] = new int[9][9];    // 8x8 charted galaxy map Z
+    final double deviceStatus[] = new double[9];   // 8  device damage stats D
+    String quadrantMap = QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + leftStr(QUADRANT_ROW, 17);       // current quadrant map
+    double stardate = toInt(random() * 20 + 20); // T
+    int energy = 3000;   // E
+    boolean shipDocked = false;  // D0
+    int torpedoes = 10;     // P
+    int shields = 0;      // S
+    int missionDuration = 25 + toInt(random() * 10);    // T9 (mission duration in stardates)
+    int basesInGalaxy = 0;   // B9
+    int remainingKlingons;     // K7
+    int klingonsInGalaxy = 0;   // K9
+    int quadrantX;         // Q1
+    int quadrantY;         // Q2
+    int sectorX;         // S1
+    int sectorY;         // S2
+    int klingons = 0; //K3
+    int starbases = 0;   // B3
+    int stars = 0;   // S3
+    int starbaseX = 0;   // X coordinate of starbase
+    int starbaseY = 0; // Y coord of starbase
+    double repairCost;  // damage repair cost D4
+    boolean restart = false;
+
+    // initial values
+    final double initialStardate = stardate;   // T0
+    final int initialEnergy = energy;      // E0
+    final int initialTorpedoes = torpedoes;        // P0
+    final int avgKlingonShieldEnergy = 200; // S9
+
+    public static void main(String[] args) {
+        final SuperStarTrekGame game = new SuperStarTrekGame();
+        printBanner();
+        while (true) {
+            game.setup();
+            game.enterNewQuadrant();
+            game.restart = false;
+            game.commandLoop();
+        }
+    }
+
+    static void printBanner() {     // 220
+        IntStream.range(1, 10).forEach(i -> {
+            println("");
+        });
+        println(
+                """
+                                                            ,------*------,
+                                            ,-------------   '---  ------'
+                                             '-------- --'      / /
+                                                 ,---' '-------/ /--,
+                                                  '----------------'
+
+                                            THE USS ENTERPRISE --- NCC-1701"
+
+                        """
+        );
+    }
+
+    double fnd(int i) { // 470
+        return Math.sqrt((klingonQuadrants[i][1] - sectorX) ^ 2 + (klingonQuadrants[i][2] - sectorY) ^ 2);
+    }
+
+    static int fnr() {    // 475
+        // Generate a random integer from 1 to 8 inclusive.
+        return toInt(random() * 7 + 1);
+    }
+
+    void setup() {
+        this.initEnterprisePosition();
+        this.setupWhatExistsInTheGalaxy();
+    }
+
+    void initEnterprisePosition() {     // 480
+        quadrantX = fnr();
+        quadrantY = fnr();
+        sectorX = fnr();
+        sectorY = fnr();
+        IntStream.range(1, 9).forEach(i -> {
+            cardinalDirections[i][1] = 0;
+            cardinalDirections[i][2] = 0;
+        });
+        cardinalDirections[3][1] = -1;
+        cardinalDirections[2][1] = -1;
+        cardinalDirections[4][1] = -1;
+        cardinalDirections[4][2] = -1;
+        cardinalDirections[5][2] = -1;
+        cardinalDirections[6][2] = -1;
+        cardinalDirections[1][2] = 1;
+        cardinalDirections[2][2] = 1;
+        cardinalDirections[6][1] = 1;
+        cardinalDirections[7][1] = 1;
+        cardinalDirections[8][1] = 1;
+        cardinalDirections[8][2] = 1;
+        cardinalDirections[9][2] = 1;
+        IntStream.range(1, 8).forEach(i -> deviceStatus[i] = 0);
+    }
+
+    void setupWhatExistsInTheGalaxy() {     // 810
+        // KLINGONS, STARBASES, STARS
+        IntStream.range(1, 8).forEach(x -> {
+            IntStream.range(1, 8).forEach(y -> {
+                klingons = 0;
+                chartedGalaxy[x][y] = 0;
+                float random = random();
+                if (random > .98) {
+                    klingons = 3;
+                    klingonsInGalaxy = +3;
+                } else if (random > .95) {
+                    klingons = 2;
+                    klingonsInGalaxy = +2;
+                } else if (random > .80) {
+                    klingons = 1;
+                    klingonsInGalaxy = +1;
+                }
+                starbases = 0;
+                if (random() > .96) {
+                    starbases = 1;
+                    basesInGalaxy = +1;
+                }
+                galaxy[x][y] = klingons * 100 + starbases * 10 + fnr();
+            });
+        });
+        if (klingonsInGalaxy > missionDuration) missionDuration = klingonsInGalaxy + 1;
+        if (basesInGalaxy == 0) {
+            if (galaxy[quadrantX][quadrantY] < 200) {
+                galaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY] + 120;
+                klingonsInGalaxy = +1;
+            }
+            basesInGalaxy = 1;
+            galaxy[quadrantX][quadrantY] = +10;
+            quadrantX = fnr();
+            quadrantY = fnr();
+        }
+        remainingKlingons = klingonsInGalaxy;
+        println("YOUR ORDERS ARE AS FOLLOWS:\n" +
+                "     DESTROY THE " + klingonsInGalaxy + " KLINGON WARSHIP" + ((klingonsInGalaxy == 1) ? "" : "S") + " WHICH HAVE INVADED\n" +
+                "   THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS\n" +
+                "   ON STARDATE " + initialStardate + missionDuration + "  THIS GIVES YOU " + missionDuration + " DAYS.  THERE " + ((basesInGalaxy == 1) ? "IS" : "ARE") + "\n" +
+                "  " + basesInGalaxy + " STARBASE" + ((basesInGalaxy == 1) ? "" : "S") + " IN THE GALAXY FOR RESUPPLYING YOUR SHIP");
+    }
+
+    void enterNewQuadrant() {   // 1320
+        // ANY TIME NEW QUADRANT ENTERED
+        klingons = 0;
+        starbases = 0;
+        stars = 0;
+        repairCost = .5 * random();
+        chartedGalaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY];
+        if (!(quadrantX < 1 || quadrantX > 8 || quadrantY < 1 || quadrantY > 8)) {
+            final String quadrantName = getQuadrantName(false, quadrantX, quadrantY);
+            if (initialStardate == stardate) {
+                println("YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED\n" +
+                        "IN THE GALACTIC QUADRANT, '" + quadrantName + "'.");
+            } else {
+                println("NOW ENTERING " + quadrantName + " QUADRANT . . .");
+            }
+            println("");
+            klingons = (int) Math.round(galaxy[quadrantX][quadrantY] * .01);
+            starbases = (int) Math.round(galaxy[quadrantX][quadrantY] * .1) - 10 * klingons;
+            stars = galaxy[quadrantX][quadrantY] - 100 * klingons - 10 * starbases;
+            if (klingons != 0) {
+                println("COMBAT AREA      CONDITION RED");
+                if (shields <= 200) {
+                    println("   SHIELDS DANGEROUSLY LOW");
+                }
+            }
+            IntStream.range(1, 3).forEach(i -> {
+                klingonQuadrants[i][1] = 0;
+                klingonQuadrants[i][2] = 0;
+            });
+        }
+        IntStream.range(1, 3).forEach(i -> {
+            klingonQuadrants[i][3] = 0;
+        });
+        // POSITION ENTERPRISE IN QUADRANT
+        insertMarker(MARKER_ENTERPRISE, sectorX, sectorY);
+        // position Klingons
+        if (klingons >= 1) {
+            for (int i = 1; i <= klingons; i++) {
+                final int[] emptyCoordinate = findEmptyPlaceInQuadrant(quadrantMap);
+                insertMarker(MARKER_KLINGON, emptyCoordinate[0], emptyCoordinate[1]);
+                klingonQuadrants[i][1] = emptyCoordinate[0];
+                klingonQuadrants[i][2] = emptyCoordinate[1];
+                klingonQuadrants[i][3] = (int) Math.round(avgKlingonShieldEnergy * (0.5 + random()));
+            }
+        }
+        // position Bases
+        if (starbases >= 1) {
+            final int[] emptyCoordinate = findEmptyPlaceInQuadrant(quadrantMap);
+            starbaseX = emptyCoordinate[0];
+            starbaseY = emptyCoordinate[1];
+            insertMarker(MARKER_STARBASE, emptyCoordinate[0], emptyCoordinate[1]);
+        }
+        // position stars
+        for (int i = 1; i <= stars; i++) {
+            final int[] emptyCoordinate = findEmptyPlaceInQuadrant(quadrantMap);
+            insertMarker(MARKER_STAR, emptyCoordinate[0], emptyCoordinate[1]);
+        }
+        shortRangeSensorScan(); // 1980
+    }
+
+    void commandLoop() {
+        while (!this.restart) {
+            checkShipEnergy();    // 1990
+            String cmdStr = "";
+            while ("".equals(cmdStr)) cmdStr = inputStr("COMMAND");
+            boolean foundCommand = false;
+            for (int i = 1; i <= 9; i++) {
+                if (leftStr(cmdStr, 3).equals(midStr(COMMANDS, 3 * i - 2, 3))) {
+                    switch (i) {
+                        case COMMAND_NAV:
+                            navigation();
+                            foundCommand = true;
+                            break;
+                        case COMMAND_SRS:
+                            shortRangeSensorScan();
+                            foundCommand = true;
+                            break;
+                        case COMMAND_LRS:
+                            longRangeSensorScan();
+                            foundCommand = true;
+                            break;
+                        case COMMAND_PHA:
+                            firePhasers();
+                            foundCommand = true;
+                            break;
+                        case COMMAND_TOR:
+                            firePhotonTorpedo();
+                            foundCommand = true;
+                            break;
+                        case COMMAND_SHE:
+                            shieldControl();
+                            foundCommand = true;
+                            break;
+                        case COMMAND_DAM:
+                            damageControl();
+                            foundCommand = true;
+                            break;
+                        case COMMAND_COM:
+                            libraryComputer();
+                            foundCommand = true;
+                            break;
+                        case COMMAND_XXX:
+                            endGameFail(false);
+                            foundCommand = true;
+                            break;
+                        default:
+                            printCommandOptions();
+                            foundCommand = true;
+                    }
+                }
+            }
+            if (!foundCommand) printCommandOptions();
+        }
+    }
+
+    void checkShipEnergy() {
+        int totalEnergy = (shields + energy);
+        if (totalEnergy < 10 && (energy <= 10 || deviceStatus[DEVICE_SHIELD_CONTROL] != 0)) {
+            println("\n** FATAL ERROR **   YOU'VE JUST STRANDED YOUR SHIP IN ");
+            println("SPACE");
+            println("YOU HAVE INSUFFICIENT MANEUVERING ENERGY,");
+            println(" AND SHIELD CONTROL");
+            println("IS PRESENTLY INCAPABLE OF CROSS");
+            println("-CIRCUITING TO ENGINE ROOM!!");
+            endGameFail(false);
+        }
+    }
+
+    void printCommandOptions() {
+        println("ENTER ONE OF THE FOLLOWING:");
+        println("  NAV  (TO SET COURSE)");
+        println("  SRS  (FOR SHORT RANGE SENSOR SCAN)");
+        println("  LRS  (FOR LONG RANGE SENSOR SCAN)");
+        println("  PHA  (TO FIRE PHASERS)");
+        println("  TOR  (TO FIRE PHOTON TORPEDOES)");
+        println("  SHE  (TO RAISE OR LOWER SHIELDS)");
+        println("  DAM  (FOR DAMAGE CONTROL REPORTS)");
+        println("  COM  (TO CALL ON LIBRARY-COMPUTER)");
+        println("  XXX  (TO RESIGN YOUR COMMAND)\n");
+    }
+
+    void navigation() {  // 2290
+        float course = toInt(inputFloat("COURSE (0-9)"));
+        if (course == 9) course = 1;
+        if (course < 1 || course >= 9) {
+            println("   LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'");
+            return;
+        }
+        println("WARP FACTOR (0-" + ((deviceStatus[DEVICE_WARP_ENGINES] < 0) ? "0.2" : "8") + ")");
+        float warp = inputFloat("");
+        if (deviceStatus[DEVICE_WARP_ENGINES] < 0 && warp > .2) {
+            // 2470
+            println("WARP ENGINES ARE DAMAGED.  MAXIMUM SPEED = WARP 0.2");
+            return;
+        }
+        if (warp == 0) return;
+        if (warp > 0 && warp <= 8) {
+            // 2490
+            int n = toInt(warp * 8);
+            if (energy - n >= 0) {
+                klingonsMoveAndFire();
+                repairDamagedDevices(course, warp, n);
+                moveStarship(course, warp, n);
+            } else {
+                println("ENGINEERING REPORTS   'INSUFFICIENT ENERGY AVAILABLE");
+                println("                       FOR MANEUVERING AT WARP" + warp + "!'");
+                if (shields < n - energy || deviceStatus[DEVICE_SHIELD_CONTROL] < 0) return;
+                println("DEFLECTOR CONTROL ROOM ACKNOWLEDGES" + shields + "UNITS OF ENERGY");
+                println("                         PRESENTLY DEPLOYED TO SHIELDS.");
+                return;
+            }
+        } else {
+            println("   CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE");
+            println(" WARP " + warp + "!'");
+            return;
+        }
+    }
+
+    void klingonsMoveAndFire() { // 2590
+        // KLINGONS MOVE/FIRE ON MOVING STARSHIP . . .
+        for (int i = 1; i <= klingons; i++) {
+            if (klingonQuadrants[i][3] == 0) continue;
+            insertMarker(MARKER_EMPTY, klingonQuadrants[i][1], klingonQuadrants[i][2]);
+            final int[] newCoords = findEmptyPlaceInQuadrant(quadrantMap);
+            klingonQuadrants[i][1] = newCoords[0];
+            klingonQuadrants[i][2] = newCoords[1];
+            insertMarker(MARKER_KLINGON, klingonQuadrants[i][1], klingonQuadrants[i][2]);
+        }
+        klingonsShoot();
+    }
+
+    void repairDamagedDevices(final float course, final float warp, final int N) {
+        // repair damaged devices and print damage report
+        for (int i = 1; i <= 8; i++) {
+            if (deviceStatus[i] < 0) {
+                deviceStatus[i] += Math.min(warp, 1);
+                if ((deviceStatus[i] > -.1) && (deviceStatus[i] < 0)) {
+                    deviceStatus[i] = -.1;
+                    break;
+                } else if (deviceStatus[i] >= 0) {
+                    println("DAMAGE CONTROL REPORT:  ");
+                    println(tab(8) + printDeviceName(i) + " REPAIR COMPLETED.");
+                }
+            }
+        }
+        if (random() > .2) moveStarship(course, warp, N);  // 80% chance no damage nor repair
+        int randomDevice = fnr();    // random device
+        if (random() >= .6) {   // 40% chance of repair of random device
+            deviceStatus[randomDevice] = deviceStatus[randomDevice] + random() * 3 + 1;
+            println("DAMAGE CONTROL REPORT:  " + printDeviceName(randomDevice) + " STATE OF REPAIR IMPROVED\n");
+        } else {            // 60% chance of damage of random device
+            deviceStatus[randomDevice] = deviceStatus[randomDevice] - (random() * 5 + 1);   //
+            println("DAMAGE CONTROL REPORT:  " + printDeviceName(randomDevice) + " DAMAGED");
+        }
+    }
+
+    void moveStarship(final float course, final float warp, final int n) {    // 3070
+        insertMarker(MARKER_EMPTY, toInt(sectorX), toInt(sectorY));
+        int ic1 = toInt(course);
+        float x1 = cardinalDirections[ic1][1] + (cardinalDirections[ic1 + 1][1] - cardinalDirections[ic1][1]) * (course - ic1);
+        float x = sectorX;
+        float y = sectorY;
+        float x2 = cardinalDirections[ic1][2] + (cardinalDirections[ic1 + 1][2] - cardinalDirections[ic1][2]) * (course - ic1);
+        final int initialQuadrantX = quadrantX;
+        final int initialQuadrantY = quadrantY;
+        for (int i = 1; i <= n; i++) {
+            sectorX += x1;
+            sectorY += x2;
+            if (sectorX < 1 || sectorX >= 9 || sectorY < 1 || sectorY >= 9) {
+                // exceeded quadrant limits
+                x = 8 * quadrantX + x + n * x1;
+                y = 8 * quadrantY + y + n * x2;
+                quadrantX = toInt(x / 8);
+                quadrantY = toInt(y / 8);
+                sectorX = toInt(x - quadrantX * 8);
+                sectorY = toInt(y - quadrantY * 8);
+                if (sectorX == 0) {
+                    quadrantX = quadrantX - 1;
+                    sectorX = 8;
+                }
+                if (sectorY == 0) {
+                    quadrantY = quadrantY - 1;
+                    sectorY = 8;
+                }
+                boolean hitEdge = false;
+                if (quadrantX < 1) {
+                    hitEdge = true;
+                    quadrantX = 1;
+                    sectorX = 1;
+                }
+                if (quadrantX > 8) {
+                    hitEdge = true;
+                    quadrantX = 8;
+                    sectorX = 8;
+                }
+                if (quadrantY < 1) {
+                    hitEdge = true;
+                    quadrantY = 8;
+                    sectorY = 8;
+                }
+                if (quadrantY > 8) {
+                    hitEdge = true;
+                    quadrantY = 8;
+                    sectorY = 8;
+                }
+                if (hitEdge) {
+                    println("LT. UHURA REPORTS MESSAGE FROM STARFLEET COMMAND:");
+                    println("  'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER");
+                    println("  IS HEREBY *DENIED*.  SHUT DOWN YOUR ENGINES.'");
+                    println("CHIEF ENGINEER SCOTT REPORTS  'WARP ENGINES SHUT DOWN");
+                    println("  AT SECTOR " + sectorX + "," + sectorY + " OF QUADRANT " + quadrantX + "," + quadrantY + ".'");
+                    if (stardate > initialStardate + missionDuration) endGameFail(false);
+                }
+                if (8 * quadrantX + quadrantY == 8 * initialQuadrantX + initialQuadrantY) {
+                    break;
+                }
+                stardate += 1;
+                maneuverEnergySR(n);
+                enterNewQuadrant();
+                return;
+            } else {
+                int S8 = toInt(sectorX) * 24 + toInt(sectorY) * 3 - 26; // S8 = pos
+                if (!("  ".equals(midStr(quadrantMap, S8, 2)))) {
+                    sectorX = toInt(sectorX - x1);
+                    sectorY = toInt(sectorY - x2);
+                    println("WARP ENGINES SHUT DOWN AT ");
+                    println("SECTOR " + sectorX + "," + sectorY + " DUE TO BAD NAVIGATION");
+                    break;
+                }
+            }
+        }
+        sectorX = toInt(sectorX);
+        sectorY = toInt(sectorY);
+        insertMarker(MARKER_ENTERPRISE, toInt(sectorX), toInt(sectorY));
+        maneuverEnergySR(n);
+        double stardateDelta = 1;
+        if (warp < 1) stardateDelta = .1 * toInt(10 * warp);
+        stardate = stardate + stardateDelta;
+        if (stardate > initialStardate + missionDuration) endGameFail(false);
+        shortRangeSensorScan();
+    }
+
+    void maneuverEnergySR(final int N) {  // 3910
+        energy = energy - N - 10;
+        if (energy >= 0) return;
+        println("SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER.");
+        shields = shields + energy;
+        energy = 0;
+        if (shields <= 0) shields = 0;
+    }
+
+    void longRangeSensorScan() {    // 3390
+        // LONG RANGE SENSOR SCAN CODE
+        if (deviceStatus[DEVICE_LONG_RANGE_SENSORS] < 0) {
+            println("LONG RANGE SENSORS ARE INOPERABLE");
+            return;
+        }
+        println("LONG RANGE SCAN FOR QUADRANT " + quadrantX + "," + quadrantY);
+        final String rowStr = "-------------------";
+        println(rowStr);
+        final int n[] = new int[4];
+        for (int i = quadrantX - 1; i <= quadrantX + 1; i++) {
+            n[1] = -1;
+            n[2] = -2;
+            n[3] = -3;
+            for (int j = quadrantY - 1; j <= quadrantY + 1; j++) {
+                if (i > 0 && i < 9 && j > 0 && j < 9) {
+                    n[j - quadrantY + 2] = galaxy[i][j];
+                    chartedGalaxy[i][j] = galaxy[i][j];
+                }
+            }
+            for (int l = 1; l <= 3; l++) {
+                print(": ");
+                if (n[l] < 0) {
+                    print("*** ");
+                    continue;
+                }
+                print(": " + rightStr(Integer.toString(n[l] + 1000), 3) + " ");
+            }
+            println(": \n" + rowStr);
+        }
+    }
+
+    void firePhasers() {    // 4260
+        if (deviceStatus[DEVICE_PHASER_CONTROL] < 0) {
+            println("PHASERS INOPERATIVE");
+            return;
+        }
+        if (klingons <= 0) {
+            printNoEnemyShipsMessage();
+            return;
+        }
+        if (deviceStatus[DEVICE_LIBRARY_COMPUTER] < 0) println("COMPUTER FAILURE HAMPERS ACCURACY");
+        println("PHASERS LOCKED ON TARGET;  ");
+        int nrUnitsToFire;
+        while (true) {
+            println("ENERGY AVAILABLE = " + energy + " UNITS");
+            nrUnitsToFire = toInt(inputFloat("NUMBER OF UNITS TO FIRE"));
+            if (nrUnitsToFire <= 0) return;
+            if (energy - nrUnitsToFire >= 0) break;
+        }
+        energy = energy - nrUnitsToFire;
+        if (deviceStatus[DEVICE_SHIELD_CONTROL] < 0) nrUnitsToFire = toInt(nrUnitsToFire * random());
+        int h1 = toInt(nrUnitsToFire / klingons);
+        for (int i = 1; i <= 3; i++) {
+            if (klingonQuadrants[i][3] <= 0) break;
+            int hitPoints = toInt((h1 / fnd(0)) * (random() + 2));
+            if (hitPoints <= .15 * klingonQuadrants[i][3]) {
+                println("SENSORS SHOW NO DAMAGE TO ENEMY AT " + klingonQuadrants[i][1] + "," + klingonQuadrants[i][2]);
+                continue;
+            }
+            klingonQuadrants[i][3] = klingonQuadrants[i][3] - hitPoints;
+            println(hitPoints + " UNIT HIT ON KLINGON AT SECTOR " + klingonQuadrants[i][1] + "," + klingonQuadrants[i][2]);
+            if (klingonQuadrants[i][3] <= 0) {
+                println("*** KLINGON DESTROYED ***");
+                klingons -= 1;
+                klingonsInGalaxy -= 1;
+                insertMarker(MARKER_EMPTY, klingonQuadrants[i][1], klingonQuadrants[i][2]);
+                klingonQuadrants[i][3] = 0;
+                galaxy[quadrantX][quadrantY] -= 100;
+                chartedGalaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY];
+                if (klingonsInGalaxy <= 0) endGameSuccess();
+            } else {
+                println("   (SENSORS SHOW" + klingonQuadrants[i][3] + "UNITS REMAINING)");
+            }
+        }
+        klingonsShoot();
+    }
+
+    void printNoEnemyShipsMessage() {   // 4270
+        println("SCIENCE OFFICER SPOCK REPORTS  'SENSORS SHOW NO ENEMY SHIPS");
+        println("                                IN THIS QUADRANT'");
+    }
+
+    void firePhotonTorpedo() {  // 4700
+        // PHOTON TORPEDO CODE BEGINS HERE
+        if (torpedoes <= 0) {
+            println("ALL PHOTON TORPEDOES EXPENDED");
+            return;
+        }
+        if (deviceStatus[DEVICE_PHOTON_TUBES] < 0) {
+            println("PHOTON TUBES ARE NOT OPERATIONAL");
+        }
+        float c1 = inputFloat("PHOTON TORPEDO COURSE (1-9)");
+        if (c1 == 9) c1 = 1;
+        if (c1 < 1 && c1 >= 9) {
+            println("ENSIGN CHEKOV REPORTS,  'INCORRECT COURSE DATA, SIR!'");
+            return;
+        }
+        int ic1 = toInt(c1);
+        float x1 = cardinalDirections[ic1][1] + (cardinalDirections[ic1 + 1][1] - cardinalDirections[ic1][1]) * (c1 - ic1);
+        energy = energy - 2;
+        torpedoes = torpedoes - 1;
+        float x2 = cardinalDirections[ic1][2] + (cardinalDirections[ic1 + 1][2] - cardinalDirections[ic1][2]) * (c1 - ic1);
+        float x = sectorX;
+        float y = sectorY;
+        println("TORPEDO TRACK:");
+        while (true) {
+            x = x + x1;
+            y = y + x2;
+            int x3 = Math.round(x);
+            int y3 = Math.round(y);
+            if (x3 < 1 || x3 > 8 || y3 < 1 || y3 > 8) {
+                println("TORPEDO MISSED"); // 5490
+                klingonsShoot();
+                return;
+            }
+            println("               " + x3 + "," + y3);
+            if (compareMarker(quadrantMap, MARKER_EMPTY, toInt(x), toInt(y)))  {
+                continue;
+            } else if (compareMarker(quadrantMap, MARKER_KLINGON, toInt(x), toInt(y))) {
+                println("*** KLINGON DESTROYED ***");
+                klingons = klingons - 1;
+                klingonsInGalaxy = klingonsInGalaxy - 1;
+                if (klingonsInGalaxy <= 0) endGameSuccess();
+                for (int i = 1; i <= 3; i++) {
+                    if (x3 == klingonQuadrants[i][1] && y3 == klingonQuadrants[i][2]) break;
+                }
+                int i = 3;
+                klingonQuadrants[i][3] = 0;
+            } else if (compareMarker(quadrantMap, MARKER_STAR, toInt(x), toInt(y))) {
+                println("STAR AT " + x3 + "," + y3 + " ABSORBED TORPEDO ENERGY.");
+                klingonsShoot();
+                return;
+            } else if (compareMarker(quadrantMap, MARKER_STARBASE, toInt(x), toInt(y))) {
+                println("*** STARBASE DESTROYED ***");
+                starbases = starbases - 1;
+                basesInGalaxy = basesInGalaxy - 1;
+                if (basesInGalaxy == 0 && klingonsInGalaxy <= stardate - initialStardate - missionDuration) {
+                    println("THAT DOES IT, CAPTAIN!!  YOU ARE HEREBY RELIEVED OF COMMAND");
+                    println("AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!");
+                    endGameFail(false);
+                } else {
+                    println("STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER");
+                    println("COURT MARTIAL!");
+                    shipDocked = false;
+                }
+            }
+            insertMarker(MARKER_EMPTY, toInt(x), toInt(y));
+            galaxy[quadrantX][quadrantY] = klingons * 100 + starbases * 10 + stars;
+            chartedGalaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY];
+            klingonsShoot();
+        }
+    }
+
+    void shieldControl() {
+        if (deviceStatus[DEVICE_SHIELD_CONTROL] < 0) {
+            println("SHIELD CONTROL INOPERABLE");
+            return;
+        }
+        println("ENERGY AVAILABLE = " + (energy + shields));
+        int energyToShields = toInt(inputFloat("NUMBER OF UNITS TO SHIELDS"));
+        if (energyToShields < 0 || shields == energyToShields) {
+            println("");
+            return;
+        }
+        if (energyToShields > energy + energyToShields) {
+            println("SHIELD CONTROL REPORTS  'THIS IS NOT THE FEDERATION TREASURY.'");
+            println("");
+            return;
+        }
+        energy = energy + shields - energyToShields;
+        shields = energyToShields;
+        println("DEFLECTOR CONTROL ROOM REPORT:");
+        println("  'SHIELDS NOW AT " + toInt(shields) + " UNITS PER YOUR COMMAND.'");
+    }
+
+    void shortRangeSensorScan() { // 6430
+        // SHORT RANGE SENSOR SCAN & STARTUP SUBROUTINE
+        boolean docked = false;
+        String shipCondition; // ship condition (docked, red, yellow, green)
+        for (int i = sectorX - 1; i <= sectorX + 1; i++) {
+            for (int j = sectorY - 1; j <= sectorY + 1; j++) {
+                if ((toInt(i) >= 1) && (toInt(i) <= 8) && (toInt(j) >= 1) && (toInt(j) <= 8)) {
+                    if (compareMarker(quadrantMap, MARKER_STARBASE, i, j)) {
+                        docked = true;
+                    }
+                }
+            }
+        }
+        if (!docked) {
+            shipDocked = false;
+            if (klingons > 0) {
+                shipCondition = "*RED*";
+            } else {
+                shipCondition = "GREEN";
+                if (energy < initialEnergy * .1) {
+                    shipCondition = "YELLOW";
+                }
+            }
+        } else {
+            shipDocked = true;
+            shipCondition = "DOCKED";
+            energy = initialEnergy;
+            torpedoes = initialTorpedoes;
+            println("SHIELDS DROPPED FOR DOCKING PURPOSES");
+            shields = 0;
+        }
+        if (deviceStatus[DEVICE_SHORT_RANGE_SENSORS] < 0) { // are short range sensors out?
+            println("\n*** SHORT RANGE SENSORS ARE OUT ***\n");
+            return;
+        }
+        final String row = "---------------------------------";
+        println(row);
+        for (int i = 1; i <= 8; i++) {
+            String sectorMapRow = "";
+            for (int j = (i - 1) * 24 + 1; j <= (i - 1) * 24 + 22; j += 3) {
+                sectorMapRow += " " + midStr(quadrantMap, j, 3);
+            }
+            switch (i) {
+                case 1:
+                    println(sectorMapRow + "        STARDATE           " + toInt(stardate * 10) * .1);
+                    break;
+                case 2:
+                    println(sectorMapRow + "        CONDITION          " + shipCondition);
+                    break;
+                case 3:
+                    println(sectorMapRow + "        QUADRANT           " + quadrantX + "," + quadrantY);
+                    break;
+                case 4:
+                    println(sectorMapRow + "        SECTOR             " + sectorX + "," + sectorY);
+                    break;
+                case 5:
+                    println(sectorMapRow + "        PHOTON TORPEDOES   " + toInt(torpedoes));
+                    break;
+                case 6:
+                    println(sectorMapRow + "        TOTAL ENERGY       " + toInt((energy + shields)));
+                    break;
+                case 7:
+                    println(sectorMapRow + "        SHIELDS            " + toInt(shields));
+                    break;
+                case 8:
+                    println(sectorMapRow + "        KLINGONS REMAINING " + toInt(klingonsInGalaxy));
+            }
+            ;
+        }
+        println(row); // 7260
+    }
+
+    void libraryComputer() {    // 7290
+        // REM LIBRARY COMPUTER CODE
+        if (deviceStatus[DEVICE_LIBRARY_COMPUTER] < 0) {
+            println("COMPUTER DISABLED");
+            return;
+        }
+        while (true) {
+            final float commandInput = inputFloat("COMPUTER ACTIVE AND AWAITING COMMAND");
+            if (commandInput < 0) return;
+            println("");
+            int command = toInt(commandInput) + 1;
+            if (command >= COMPUTER_COMMAND_CUMULATIVE_GALACTIC_RECORD && command <= COMPUTER_COMMAND_GALAXY_MAP) {
+                switch (command) {
+                    case COMPUTER_COMMAND_CUMULATIVE_GALACTIC_RECORD:
+                        //GOTO 7540
+                        cumulativeGalacticRecord(true);
+                        return;
+                    case COMPUTER_COMMAND_STATUS_REPORT:
+                        //GOTO 7900
+                        statusReport();
+                        return;
+                    case COMPUTER_COMMAND_PHOTON_TORPEDO_DATA:
+                        //GOTO 8070
+                        photonTorpedoData();
+                        return;
+                    case COMPUTER_COMMAND_STARBASE_NAV_DATA:
+                        //GOTO 8500
+                        starbaseNavData();
+                        return;
+                    case COMPUTER_COMMAND_DIR_DIST_CALC:
+                        //GOTO 8150
+                        directionDistanceCalculator();
+                        return;
+                    case COMPUTER_COMMAND_GALAXY_MAP:
+                        //GOTO 7400
+                        cumulativeGalacticRecord(false);
+                        return;
+                }
+            } else {
+                // invalid command
+                println("FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:");
+                println("   0 = CUMULATIVE GALACTIC RECORD");
+                println("   1 = STATUS REPORT");
+                println("   2 = PHOTON TORPEDO DATA");
+                println("   3 = STARBASE NAV DATA");
+                println("   4 = DIRECTION/DISTANCE CALCULATOR");
+                println("   5 = GALAXY 'REGION NAME' MAP");
+                println("");
+            }
+        }
+    }
+
+    void cumulativeGalacticRecord(final boolean cumulativeReport) {   // 7540
+        if (cumulativeReport) {
+            println("");
+            println("        ");
+            println("COMPUTER RECORD OF GALAXY FOR QUADRANT " + quadrantX + "," + quadrantY);
+            println("");
+        } else {
+            println("                        THE GALAXY");
+        }
+        println("       1     2     3     4     5     6     7     8");
+        final String rowDivider = "     ----- ----- ----- ----- ----- ----- ----- -----";
+        println(rowDivider);
+        for (int i = 1; i <= 8; i++) {
+            print(i + "  ");
+            if (cumulativeReport) {
+                int y = 1;
+                String quadrantName = getQuadrantName(false, i, y);
+                int tabLen = toInt(15 - .5 * strlen(quadrantName));
+                println(tab(tabLen) + quadrantName);
+                y = 5;
+                quadrantName = getQuadrantName(false, i, y);
+                tabLen = toInt(39 - .5 * strlen(quadrantName));
+                println(tab(tabLen) + quadrantName);
+            } else {
+                for (int j = 1; j <= 8; j++) {
+                    print("   ");
+                    if (chartedGalaxy[i][j] == 0) {
+                        print("***");
+                    } else {
+                        print(rightStr(Integer.toString(chartedGalaxy[i][j] + 1000), 3));
+                    }
+                }
+            }
+            println("");
+            println(rowDivider);
+        }
+        println("");
+    }
+
+    void statusReport() {   // 7900
+        println("   STATUS REPORT:");
+        println("KLINGON" + ((klingonsInGalaxy > 1)? "S" : "")  + " LEFT: " + klingonsInGalaxy);
+        println("MISSION MUST BE COMPLETED IN " + .1 * toInt((initialStardate + missionDuration - stardate) * 10) + "STARDATES");
+        if (basesInGalaxy >= 1) {
+            println("THE FEDERATION IS MAINTAINING " + basesInGalaxy + " STARBASE" + ((basesInGalaxy > 1)? "S" : "") + " IN THE GALAXY");
+        } else {
+            println("YOUR STUPIDITY HAS LEFT YOU ON YOUR OWN IN");
+            println("  THE GALAXY -- YOU HAVE NO STARBASES LEFT!");
+        }
+        damageControl();
+    }
+
+    void photonTorpedoData() {  // 8070
+        // TORPEDO, BASE NAV, D/D CALCULATOR
+        if (klingons <= 0) {
+            printNoEnemyShipsMessage();
+            return;
+        }
+        println("FROM ENTERPRISE TO KLINGON BATTLE CRUISER" + ((klingons > 1)? "S" : ""));
+        for (int i = 1; i <= 3; i++) {
+            if (klingonQuadrants[i][3] > 0) {
+                printDirection(sectorX, sectorY, klingonQuadrants[i][1], klingonQuadrants[i][2]);
+            }
+        }
+    }
+
+    void directionDistanceCalculator() {    // 8150
+        println("DIRECTION/DISTANCE CALCULATOR:");
+        println("YOU ARE AT QUADRANT " + quadrantX + "," + quadrantY + " SECTOR " + sectorX + "," + sectorY);
+        print("PLEASE ENTER ");
+        int[] initialCoords = inputCoords("  INITIAL COORDINATES (X,Y)");
+        int[] finalCoords = inputCoords("  FINAL COORDINATES (X,Y)");
+        printDirection(initialCoords[0], initialCoords[1], finalCoords[0], finalCoords[1]);
+    }
+
+    void printDirection(int from_x, int from_y, int to_x, int to_y) { // 8220
+        to_y = to_y - from_y;  // delta 2
+        from_y = from_x - to_x;    // delta 1
+        if (to_y > 0) {
+            if (from_y < 0) {
+                from_x = 7;
+            } else {
+                from_x = 1;
+                int tempA = from_y;
+                from_y = to_y;
+                to_y = tempA;
+            }
+        } else {
+            if (from_y > 0) {
+                from_x = 3;
+            } else {
+                from_x = 5;
+                int tempA = from_y;
+                from_y = to_y;
+                to_y = tempA;
+            }
+        }
+
+        from_y = Math.abs(from_y);
+        to_y = Math.abs(to_y);
+
+        if (from_y > 0 || to_y > 0) {
+            if (from_y >= to_y) {
+                println("DIRECTION = " + (from_x + to_y / from_y));
+            } else {
+                println("DIRECTION = " + (from_x + 2 - to_y / from_y));
+            }
+        }
+        println("DISTANCE = " + round(Math.sqrt(to_y ^ 2 + from_y ^ 2), 6));
+    }
+
+    void starbaseNavData() {    // 8500
+        if (starbases != 0) {
+            println("FROM ENTERPRISE TO STARBASE:");
+            printDirection(sectorX, sectorY, starbaseX, starbaseY);
+        } else {
+            println("MR. SPOCK REPORTS,  'SENSORS SHOW NO STARBASES IN THIS");
+            println(" QUADRANT.'");
+        }
+    }
+
+    /**
+     * Finds random empty coordinates in a quadrant.
+     *
+     * @param quadrantString
+     * @return an array with a pair of coordinates x, y
+     */
+    int[] findEmptyPlaceInQuadrant(String quadrantString) {   // 8590
+        final int x = fnr();
+        final int y = fnr();
+        if (!compareMarker(quadrantString, MARKER_EMPTY, x, y)) {
+            return findEmptyPlaceInQuadrant(quadrantString);
+        }
+        return new int[]{x, y};
+    }
+
+
+    void insertMarker(final String marker, final int x, final int y) {   // 8670
+        final int pos = toInt(y) * 3 + toInt(x) * 24 + 1;
+        if (marker.length() != 3) {
+            System.err.println("ERROR");
+            System.exit(-1);
+        }
+        if (pos == 1) {
+            quadrantMap = marker + rightStr(quadrantMap, 189);
+        }
+        if (pos == 190) {
+            quadrantMap = leftStr(quadrantMap, 189) + marker;
+        }
+        quadrantMap = leftStr(quadrantMap, (pos - 1)) + marker + rightStr(quadrantMap, (190 - pos));
+    }
+
+    String printDeviceName(final int deviceNumber) {  // 8790
+        // PRINTS DEVICE NAME
+        switch (deviceNumber) {
+            case DEVICE_WARP_ENGINES:
+                return "WARP ENGINES";
+            case DEVICE_SHORT_RANGE_SENSORS:
+                return "SHORT RANGE SENSORS";
+            case DEVICE_LONG_RANGE_SENSORS:
+                return "LONG RANGE SENSORS";
+            case DEVICE_PHASER_CONTROL:
+                return "PHASER CONTROL";
+            case DEVICE_PHOTON_TUBES:
+                return "PHOTON TUBES";
+            case DEVICE_DAMAGE_CONTROL:
+                return "DAMAGE CONTROL";
+            case DEVICE_SHIELD_CONTROL:
+                return "SHIELD CONTROL";
+            case DEVICE_LIBRARY_COMPUTER:
+                return "LIBRARY-COMPUTER";
+        }
+        return "";
+    }
+
+    boolean compareMarker(final String quadrantString, final String marker, int x, int y) { // 8830
+        final int markerRegion = (y - 1) * 3 + (x - 1) * 24 + 1;
+        if (midStr(quadrantString, markerRegion, 3).equals(marker)) {
+            return true;
+        }
+        return false;
+    }
+
+    String getRegionName(final boolean regionNameOnly, final int y) {
+        if (!regionNameOnly) {
+            switch (y % 4) {
+                case 1:
+                    return " I";
+                case 2:
+                    return " II";
+                case 3:
+                    return " III";
+                case 4:
+                    return " IV";
+            }
+        }
+        return "";
+    }
+
+    String getQuadrantName(final boolean regionNameOnly, final int x, final int y) { // 9030
+        if (y <= 4) {
+            switch (x) {
+                case 1:
+                    return "ANTARES" + getRegionName(regionNameOnly, y);
+                case 2:
+                    return "RIGEL" + getRegionName(regionNameOnly, y);
+                case 3:
+                    return "PROCYON" + getRegionName(regionNameOnly, y);
+                case 4:
+                    return "VEGA" + getRegionName(regionNameOnly, y);
+                case 5:
+                    return "CANOPUS" + getRegionName(regionNameOnly, y);
+                case 6:
+                    return "ALTAIR" + getRegionName(regionNameOnly, y);
+                case 7:
+                    return "SAGITTARIUS" + getRegionName(regionNameOnly, y);
+                case 8:
+                    return "POLLUX" + getRegionName(regionNameOnly, y);
+            }
+        } else {
+            switch (x) {
+                case 1:
+                    return "SIRIUS" + getRegionName(regionNameOnly, y);
+                case 2:
+                    return "DENEB" + getRegionName(regionNameOnly, y);
+                case 3:
+                    return "CAPELLA" + getRegionName(regionNameOnly, y);
+                case 4:
+                    return "BETELGEUSE" + getRegionName(regionNameOnly, y);
+                case 5:
+                    return "ALDEBARAN" + getRegionName(regionNameOnly, y);
+                case 6:
+                    return "REGULUS" + getRegionName(regionNameOnly, y);
+                case 7:
+                    return "ARCTURUS" + getRegionName(regionNameOnly, y);
+                case 8:
+                    return "SPICA" + getRegionName(regionNameOnly, y);
+            }
+        }
+        return "UNKNOWN - ERROR";
+    }
+
+    void damageControl() {  // 5690
+        if (deviceStatus[DEVICE_DAMAGE_CONTROL] < 0) {
+            println("DAMAGE CONTROL REPORT NOT AVAILABLE");
+        } else {
+            println("\nDEVICE             STATE OF REPAIR");
+            for (int deviceNr = 1; deviceNr <= 8; deviceNr++) {
+                print(printDeviceName(deviceNr) + leftStr(QUADRANT_ROW, 25 - strlen(printDeviceName(deviceNr))) + " " + toInt(deviceStatus[deviceNr] * 100) * .01 + "\n");
+            }
+        }
+        if (!shipDocked) return;
+
+        double deltaToRepair = 0;
+        for (int i = 1; i <= 8; i++) {
+            if (deviceStatus[i] < 0) deltaToRepair += .1;
+        }
+        if (deltaToRepair > 0) {
+            deltaToRepair += repairCost;
+            if (deltaToRepair >= 1) deltaToRepair = .9;
+            println("TECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;");
+            println("ESTIMATED TIME TO REPAIR:'" + .01 * toInt(100 * deltaToRepair) + " STARDATES");
+            final String reply = inputStr("WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)");
+            if ("Y".equals(reply)) {
+                for (int deviceNr = 1; deviceNr <= 8; deviceNr++) {
+                    if (deviceStatus[deviceNr] < 0) deviceStatus[deviceNr] = 0;
+                }
+                stardate = stardate + deltaToRepair + .1;
+            }
+        }
+    }
+
+    void klingonsShoot() {   // 6000
+        if (klingons <= 0) return; // no klingons
+        if (shipDocked) {  // enterprise is docked
+            println("STARBASE SHIELDS PROTECT THE ENTERPRISE");
+            return;
+        }
+        for (int i = 1; i <= 3; i++) {
+            if (klingonQuadrants[i][3] <= 0) continue;
+            int hits = toInt((klingonQuadrants[i][3] / fnd(1)) * (2 + random())); // hit points
+            shields = shields - hits;
+            klingonQuadrants[i][3] = toInt(klingonQuadrants[i][3] / (3 + random()));      // FIXME: RND(0)
+            println(hits + " UNIT HIT ON ENTERPRISE FROM SECTOR " + klingonQuadrants[i][1] + "," + klingonQuadrants[i][2]);
+            if (shields <= 0) endGameFail(true);
+            println("      ");
+            if (hits < 20) continue;
+            if ((random() > .6) || (hits / shields <= .02)) continue;
+            int randomDevice = fnr();
+            deviceStatus[randomDevice] = deviceStatus[randomDevice] - hits / shields - .5 * random();
+            println("DAMAGE CONTROL REPORTS " + printDeviceName(randomDevice) + " DAMAGED BY THE HIT'");
+        }
+    }
+
+    void endGameFail(final boolean enterpriseDestroyed) {    // 6220
+        if (enterpriseDestroyed) {
+            println("\nTHE ENTERPRISE HAS BEEN DESTROYED.  THEN FEDERATION ");
+            println("WILL BE CONQUERED");
+        }
+        println("\nIT IS STARDATE " + stardate);
+        println("THERE WERE " + klingonsInGalaxy + " KLINGON BATTLE CRUISERS LEFT AT");
+        println("THE END OF YOUR MISSION.");
+        repeatGame();
+    }
+
+    void endGameSuccess() { // 6370
+        println("CONGRATULATION, CAPTAIN!  THE LAST KLINGON BATTLE CRUISER");
+        println("MENACING THE FEDERATION HAS BEEN DESTROYED.\n");
+        println("YOUR EFFICIENCY RATING IS " + (Math.sqrt(1000 * (remainingKlingons / (stardate - initialStardate)))));
+        repeatGame();
+    }
+
+    void repeatGame() {// 6290
+        println("\n");
+        if (basesInGalaxy != 0) {
+            println("THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER");
+            println("FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER,");
+            final String reply = inputStr("LET HIM STEP FORWARD AND ENTER 'AYE'");
+            if ("AYE".equals(reply)) {
+                this.restart = true;
+            } else {
+                System.exit(0);
+            }
+        }
+    }
+
+    static int toInt(final double num) {
+        int x = (int) Math.floor(num);
+        if (x < 0) x *= -1;
+        return x;
+    }
+
+    static void println(final String s) {
+        System.out.println(s);
+    }
+
+    static void print(final String s) {
+        System.out.print(s);
+    }
+
+    static String tab(final int n) {
+        return IntStream.range(1, n).mapToObj(num -> " ").collect(Collectors.joining());
+    }
+
+    static int strlen(final String s) {
+        return s.length();
+    }
+
+    static String inputStr(final String message) {
+        System.out.print(message + "? ");
+        final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+        try {
+            return reader.readLine();
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+            return "";
+        }
+    }
+
+    static int[] inputCoords(final String message) {
+        while (true) {
+            final String input = inputStr(message);
+            try {
+                final String[] splitInput = input.split(",");
+                if (splitInput.length == 2) {
+                    int x = Integer.parseInt(splitInput[0]);
+                    int y = Integer.parseInt(splitInput[0]);
+                    return new int[]{x, y};
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    static float inputFloat(final String message) {
+        while (true) {
+            System.out.print(message + "? ");
+            final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+            try {
+                final String input = reader.readLine();
+                if (input.length() > 0) {
+                    return Float.parseFloat(input);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    static String leftStr(final String input, final int len) {
+        if (input == null || input.length() < len) return input;
+        return input.substring(0, len);
+    }
+
+    static String midStr(final String input, final int start, final int len) {
+        if (input == null || input.length() < ((start - 1) + len)) return input;
+        return input.substring(start - 1, (start - 1) + len);
+    }
+
+    static String rightStr(final String input, final int len) {
+        if (input == null || input.length() < len) return "";
+        return input.substring(input.length() - len);
+    }
+
+    static float random() {
+        return random.nextFloat();
+    }
+
+    private static double round(double value, int places) {
+        if (places < 0) throw new IllegalArgumentException();
+        BigDecimal bd = new BigDecimal(Double.toString(value));
+        bd = bd.setScale(places, RoundingMode.HALF_UP);
+        return bd.doubleValue();
+    }
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/java/SuperStarTrekInstructions.java b/00_Alternate_Languages/84_Super_Star_Trek/java/SuperStarTrekInstructions.java
new file mode 100644
index 00000000..16f730da
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/java/SuperStarTrekInstructions.java
@@ -0,0 +1,162 @@
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+
+/**
+ * SUPER STARTREK INSTRUCTIONS
+ * MAR 5, 1978
+ * Just the instructions for SUPERSTARTREK
+ *
+ * Ported to Java in Jan-Feb 2022 by
+ * Taciano Dreckmann Perez (taciano.perez@gmail.com)
+ */
+public class SuperStarTrekInstructions {
+
+    public static void main(String[] args) {
+        printBanner();
+        final String reply = inputStr("DO YOU NEED INSTRUCTIONS (Y/N)? ");
+        if ("Y".equals(reply)) {
+            printInstructions();
+        }
+    }
+
+    static void printBanner() {
+        print(tab(10)+"*************************************");
+        print(tab(10)+"*                                   *");
+        print(tab(10)+"*                                   *");
+        print(tab(10)+"*      * * SUPER STAR TREK * *      *");
+        print(tab(10)+"*                                   *");
+        print(tab(10)+"*                                   *");
+        print(tab(10)+"*************************************");
+    }
+
+    static void printInstructions() {
+        print("      INSTRUCTIONS FOR 'SUPER STAR TREK'");
+        print("");
+        print("1. WHEN YOU SEE \\COMMAND ?\\ PRINTED, ENTER ONE OF THE LEGAL");
+        print("     COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).");
+        print("2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT");
+        print("     LIST OF THE LEGAL COMMANDS PRINTED OUT.");
+        print("3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE");
+        print("     'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.)  IF YOU");
+        print("     TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND");
+        print("     WILL BE ABORTED");
+        print("");
+        print("     THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,");
+        print("AND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.");
+        print("");
+        print("     YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE");
+        print("GALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP");
+        print("\\ENTERPRISE\\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF");
+        print("KLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF");
+        print("PLANETS.");
+        print("");
+        print("     YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN");
+        print("OF THE STARSHIP ENTERPRISE:");
+        print("");
+        print("\\NAV\\ COMMAND = WARP ENGINE CONTROL --");
+        print("     COURSE IS IN A CIRCULAR NUMERICAL      4  3  2");
+        print("     VECTOR ARRANGEMENT AS SHOWN             . . .");
+        print("     INTEGER AND REAL VALUES MAY BE           ...");
+        print("     USED.  (THUS COURSE 1.5 IS HALF-     5 ---*--- 1");
+        print("     WAY BETWEEN 1 AND 2                      ...");
+        print("                                             . . .");
+        print("     VALUES MAY APPROACH 9.0, WHICH         6  7  8");
+        print("     ITSELF IS EQUIVALENT TO 1.0");
+        print("                                            COURSE");
+        print("     ONE WARP FACTOR IS THE SIZE OF ");
+        print("     ONE QUADTANT.  THEREFORE, TO GET");
+        print("     FROM QUADRANT 6,5 TO 5,5, YOU WOULD");
+        print("     USE COURSE 3, WARP FACTOR 1.");
+        print("");
+        print("\\SRS\\ COMMAND = SHORT RANGE SENSOR SCAN");
+        print("     SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.");
+        print("");
+        print("     SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:");
+        print("        <*> = YOUR STARSHIP'S POSITION");
+        print("        +K+ = KLINGON BATTLE CRUISER");
+        print("        >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)");
+        print("         *  = STAR");
+        print("");
+        print("     A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.");
+        print("");
+        print("\\LRS\\ COMMAND = LONG RANGE SENSOR SCAN");
+        print("     SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE");
+        print("     OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)");
+        print("     THE SCAN IS CODED IN THE FORM \\###\\, WHERE TH UNITS DIGIT");
+        print("     IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF");
+        print("     STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF");
+        print("     KLINGONS.");
+        print("");
+        print("     EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.");
+        print("");
+        print("\\PHA\\ COMMAND = PHASER CONTROL.");
+        print("     ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY ");
+        print("     ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO");
+        print("     DEPLETE THEIR SHIELD POWER.  (REMEMBER, KLINGONS HAVE");
+        print("     PHASERS TOO!)");
+        print("");
+        print("\\TOR\\ COMMAND = PHOTON TORPEDO CONTROL");
+        print("     TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL");
+        print("     IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND");
+        print("     CANNOT FIRE BACK AT YOU.  IF YOU MISS, YOU ARE SUBJECT TO");
+        print("     HIS PHASER FIRE.  IN EITHER CASE, YOU ARE ALSO SUBJECT TO ");
+        print("     THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.");
+        print("");
+        print("     THE LIBRARY-COMPUTER (\\COM\\ COMMAND) HAS AN OPTION TO ");
+        print("     COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)");
+        print("");
+        print("\\SHE\\ COMMAND = SHIELD CONTROL");
+        print("     DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE");
+        print("     SHIELDS.  ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY.  NOTE");
+        print("     THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY");
+        print("");
+        print("\\DAM\\ COMMAND = DAMMAGE CONTROL REPORT");
+        print("     GIVES THE STATE OF REPAIR OF ALL DEVICES.  WHERE A NEGATIVE");
+        print("     'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY");
+        print("     DAMAGED.");
+        print("");
+        print("\\COM\\ COMMAND = LIBRARY-COMPUTER");
+        print("     THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:");
+        print("     OPTION 0 = CUMULATIVE GALACTIC RECORD");
+        print("        THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL");
+        print("        PREVIOUS SHORT AND LONG RANGE SENSOR SCANS");
+        print("     OPTION 1 = STATUS REPORT");
+        print("        THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,");
+        print("        AND STARBASES REMAINING IN THE GAME.");
+        print("     OPTION 2 = PHOTON TORPEDO DATA");
+        print("        WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE");
+        print("        TO ALL KLINGONS IN YOUR QUADRANT");
+        print("     OPTION 3 = STARBASE NAV DATA");
+        print("        THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY ");
+        print("        STARBASE WITHIN YOUR QUADRANT");
+        print("     OPTION 4 = DIRECTION/DISTANCE CALCULATOR");
+        print("        THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR");
+        print("        DIRECTION/DISTANCE CALCULATIONS");
+        print("     OPTION 5 = GALACTIC /REGION NAME/ MAP");
+        print("        THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR ");
+        print("        GALACTIC REGIONS REFERRED TO IN THE GAME.");
+    }
+
+    static void print(final String s) {
+        System.out.println(s);
+    }
+
+    static String tab(final int n) {
+        return IntStream.range(1, n).mapToObj(num -> " ").collect(Collectors.joining());
+    }
+
+    static String inputStr(final String message) {
+        System.out.print(message + "? ");
+        final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+        try {
+            return reader.readLine();
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+            return "";
+        }
+    }
+
+}
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/javascript/README.md b/00_Alternate_Languages/84_Super_Star_Trek/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/84_Super_Star_Trek/javascript/index.html b/00_Alternate_Languages/84_Super_Star_Trek/javascript/index.html
new file mode 100644
index 00000000..d2e31b8f
--- /dev/null
+++ b/00_Alternate_Languages/84_Super_Star_Trek/javascript/index.html
@@ -0,0 +1,234 @@
+
+  
+    Super Star Trek
+    
+    
+    
+  
+  
+    
+
+
+
+
+

Super Star Trek

+

+ Originally found in + David Ahl's BASIC Computer Games (1978) +

+

+ Converted to JavaScript + in February 2021 + by Les Orchard + <me@lmorchard.com> +

+ +
+      INSTRUCTIONS FOR 'SUPER STAR TREK'
+
+1. WHEN YOU SEE \COMMAND ?\ PRINTED, ENTER ONE OF THE LEGAL
+     COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).
+
+2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT
+     LIST OF THE LEGAL COMMANDS PRINTED OUT.
+
+3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE
+     'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.)  IF YOU
+     TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND
+     WILL BE ABORTED
+     THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,
+AND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.
+     YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE
+GALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP
+\ENTERPRISE\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF
+KLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF
+PLANETS.
+
+     YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN
+OF THE STARSHIP ENTERPRISE:
+
+\NAV\ COMMAND = WARP ENGINE CONTROL --
+     COURSE IS IN A CIRCULAR NUMERICAL      4  3  2
+     VECTOR ARRANGEMENT AS SHOWN             . . .
+     INTEGER AND REAL VALUES MAY BE           ...
+     USED.  (THUS COURSE 1.5 IS HALF-     5 ---*--- 1
+     WAY BETWEEN 1 AND 2                      ...
+                                             . . .
+     VALUES MAY APPROACH 9.0, WHICH         6  7  8
+     ITSELF IS EQUIVALENT TO 1.0"
+                                            COURSE
+     ONE WARP FACTOR IS THE SIZE OF
+     ONE QUADTANT.  THEREFORE, TO GET
+     FROM QUADRANT 6,5 TO 5,5, YOU WOULD
+     USE COURSE 3, WARP FACTOR 1.
+
+\SRS\ COMMAND = SHORT RANGE SENSOR SCAN
+     SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.
+     SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:
+        <*> = YOUR STARSHIP'S POSITION
+        +K+ = KLINGON BATTLE CRUISER
+        >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)
+         *  = STAR
+     A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.
+
+\LRS\ COMMAND = LONG RANGE SENSOR SCAN
+     SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE
+     OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)
+     THE SCAN IS CODED IN THE FORM \###\, WHERE TH UNITS DIGIT
+     IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF
+     STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF
+     KLINGONS.
+     EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.
+
+\PHA\ COMMAND = PHASER CONTROL.
+     ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY
+     ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO
+     DEPLETE THEIR SHIELD POWER.  (REMBER, KLINGONS HAVE
+     PHASERS TOO!)
+
+\TOR\ COMMAND = PHOTON TORPEDO CONTROL
+     TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL
+     IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND
+     CANNOT FIRE BACK AT YOU.  IF YOU MISS, YOU ARE SUBJECT TO
+     HIS PHASER FIRE.  IN EITHER CASE, YOU ARE ALSO SUBJECT TO
+     THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.
+     THE LIBRARY-COMPUTER (\COM\ COMMAND) HAS AN OPTION TO
+     COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)
+
+\SHE\ COMMAND = SHIELD CONTROL
+     DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE
+     SHIELDS.  ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY.  NOTE
+     THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY
+
+\DAM\ COMMAND = DAMMAGE CONTROL REPORT
+     GIVES THE STATE OF REPAIR OF ALL DEVICES.  WHERE A NEGATIVE
+     'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY
+     DAMAGED."
+
+\COM\ COMMAND = LIBRARY-COMPUTER
+     THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:
+     OPTION 0 = CUMULATIVE GALACTIC RECORD
+        THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL
+        PREVIOUS SHORT AND LONG RANGE SENSOR SCANS
+     OPTION 1 = STATUS REPORT
+        THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,
+        AND STARBASES REMAINING IN THE GAME.
+     OPTION 2 = PHOTON TORPEDO DATA
+        WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE
+        TO ALL KLINGONS IN YOUR QUADRANT
+     OPTION 3 = STARBASE NAV DATA
+        THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY
+        STARBASE WITHIN YOUR QUADRANT
+     OPTION 4 = DIRECTION/DISTANCE CALCULATOR
+        THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR
+        DIRECTION/DISTANCE CALCULATIONS
+     OPTION 5 = GALACTIC /REGION NAME/ MAP
+        THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR
+        GALACTIC REGIONS REFERRED TO IN THE GAME.
+    
+
+
+ + + + + + + diff --git a/59_Lunar_LEM_Rocket/pascal/README.md b/00_Alternate_Languages/84_Super_Star_Trek/pascal/README.md similarity index 100% rename from 59_Lunar_LEM_Rocket/pascal/README.md rename to 00_Alternate_Languages/84_Super_Star_Trek/pascal/README.md diff --git a/00_Alternate_Languages/84_Super_Star_Trek/perl/README.md b/00_Alternate_Languages/84_Super_Star_Trek/perl/README.md new file mode 100644 index 00000000..e69c8b81 --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/perl/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Perl](https://www.perl.org/) diff --git a/00_Alternate_Languages/84_Super_Star_Trek/python/README.md b/00_Alternate_Languages/84_Super_Star_Trek/python/README.md new file mode 100644 index 00000000..781945ec --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/python/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Python](https://www.python.org/about/) diff --git a/00_Alternate_Languages/84_Super_Star_Trek/python/superstartrek.py b/00_Alternate_Languages/84_Super_Star_Trek/python/superstartrek.py new file mode 100644 index 00000000..dcd879f2 --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/python/superstartrek.py @@ -0,0 +1,976 @@ +# **** **** STAR TREK **** **** +# **** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE, +# **** AS SEEN ON THE STAR TREK TV SHOW. +# **** ORIGINAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION +# **** PUBLISHED IN DEC'S "101 BASIC GAMES", BY DAVE AHL. +# **** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB +# **** LEEDOM - APRIL & DECEMBER 1974, +# **** WITH A LITTLE HELP FROM HIS FRIENDS . . . +# +# Python translation by Jack Boyce - February 2021 +# Output is identical to BASIC version except for a few +# fixes (as noted, search `bug`) and minor cleanup. + + +import random +from math import sqrt +from typing import Any, List + +# ------------------------------------------------------------------------- +# Utility functions +# ------------------------------------------------------------------------- + + +def fnr(): + # Generate a random integer from 0 to 7 inclusive. + return random.randint(0, 7) + + +def quadrant_name(row, col, region_only=False): + # Return quadrant name visible on scans, etc. + region1 = [ + "ANTARES", + "RIGEL", + "PROCYON", + "VEGA", + "CANOPUS", + "ALTAIR", + "SAGITTARIUS", + "POLLUX", + ] + region2 = [ + "SIRIUS", + "DENEB", + "CAPELLA", + "BETELGEUSE", + "ALDEBARAN", + "REGULUS", + "ARCTURUS", + "SPICA", + ] + modifier = ["I", "II", "III", "IV"] + + quadrant = region1[row] if col < 4 else region2[row] + + if not region_only: + quadrant += " " + modifier[col % 4] + + return quadrant + + +def insert_marker(row, col, marker): + # Insert a marker into a given position in the quadrant string `qs`. The + # contents of a quadrant (Enterprise, stars, etc.) are stored in `qs`. + global qs + + if len(marker) != 3: + print("ERROR") + exit() + + pos = round(col) * 3 + round(row) * 24 + qs = qs[0:pos] + marker + qs[(pos + 3) : 192] + + +def compare_marker(row, col, test_marker): + # Check whether the position in the current quadrant is occupied with a + # given marker. + pos = round(col) * 3 + round(row) * 24 + return qs[pos : (pos + 3)] == test_marker + + +def find_empty_place(): + # Find an empty location in the current quadrant. + while True: + row, col = fnr(), fnr() + if compare_marker(row, col, " "): + return row, col + + +# ------------------------------------------------------------------------- +# Functions for individual player commands +# ------------------------------------------------------------------------- + + +def navigation(): + # Take navigation input and move the Enterprise. + global d, s, e, k, qs, t, q1, q2, s1, s2 + + while True: + c1s = input("COURSE (1-9)? ") + if len(c1s) > 0: + c1 = float(c1s) + break + if c1 == 9: + c1 = 1 + if c1 < 1 or c1 >= 9: + print(" LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'") + return + + while True: + warps = input(f"WARP FACTOR (0-{'0.2' if d[0] < 0 else '8'})? ") + if len(warps) > 0: + warp = float(warps) + break + if d[0] < 0 and warp > 0.2: + print("WARP ENGINES ARE DAMAGED. MAXIMUM SPEED = WARP 0.2") + return + if warp == 0: + return + if warp < 0 or warp > 8: + print(f" CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE WARP {warp}!'") + return + + n = round(warp * 8) + if e < n: + print("ENGINEERING REPORTS 'INSUFFICIENT ENERGY AVAILABLE") + print(f" FOR MANEUVERING AT WARP {warp}!'") + if s >= n - e and d[6] >= 0: + print(f"DEFLECTOR CONTROL ROOM ACKNOWLEDGES {s} UNITS OF ENERGY") + print(" PRESENTLY DEPLOYED TO SHIELDS.") + return + + # klingons move and fire + for i in range(3): + if k[i][2] != 0: + insert_marker(k[i][0], k[i][1], " ") + k[i][0], k[i][1] = find_empty_place() + insert_marker(k[i][0], k[i][1], "+K+") + + klingons_fire() + + # repair damaged devices and print damage report + line = "" + for i in range(8): + if d[i] < 0: + d[i] += min(warp, 1) + if -0.1 < d[i] < 0: + d[i] = -0.1 + elif d[i] >= 0: + if len(line) == 0: + line = "DAMAGE CONTROL REPORT:" + line += " " + devices[i] + " REPAIR COMPLETED\n" + if len(line) > 0: + print(line) + if random.random() <= 0.2: + r1 = fnr() + if random.random() < 0.6: + d[r1] -= random.random() * 5 + 1 + print(f"DAMAGE CONTROL REPORT: {devices[r1]} DAMAGED\n") + else: + d[r1] += random.random() * 3 + 1 + print(f"DAMAGE CONTROL REPORT: {devices[r1]} STATE OF REPAIR IMPROVED\n") + + # begin moving starship + insert_marker(int(s1), int(s2), " ") + ic1 = int(c1) + x1 = c[ic1 - 1][0] + (c[ic1][0] - c[ic1 - 1][0]) * (c1 - ic1) + x2 = c[ic1 - 1][1] + (c[ic1][1] - c[ic1 - 1][1]) * (c1 - ic1) + q1_start, q2_start = q1, q2 + x, y = s1, s2 + + for _ in range(n): + s1 += x1 + s2 += x2 + + if s1 < 0 or s1 > 7 or s2 < 0 or s2 > 7: + # exceeded quadrant limits; calculate final position + x += 8 * q1 + n * x1 + y += 8 * q2 + n * x2 + q1, q2 = int(x / 8), int(y / 8) + s1, s2 = int(x - q1 * 8), int(y - q2 * 8) + if s1 < 0: + q1 -= 1 + s1 = 7 + if s2 < 0: + q2 -= 1 + s2 = 7 + + hit_edge = False + if q1 < 0: + hit_edge = True + q1 = s1 = 0 + if q1 > 7: + hit_edge = True + q1 = s1 = 7 + if q2 < 0: + hit_edge = True + q2 = s2 = 0 + if q2 > 7: + hit_edge = True + q2 = s2 = 7 + if hit_edge: + print("LT. UHURA REPORTS MESSAGE FROM STARFLEET COMMAND:") + print(" 'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER") + print(" IS HEREBY *DENIED*. SHUT DOWN YOUR ENGINES.'") + print("CHIEF ENGINEER SCOTT REPORTS 'WARP ENGINES SHUT DOWN") + print( + f" AT SECTOR {s1 + 1} , {s2 + 1} OF QUADRANT " + f"{q1 + 1} , {q2 + 1}.'" + ) + if t > t0 + t9: + end_game(won=False, quit=False) + return + + if q1 == q1_start and q2 == q2_start: + break + t += 1 + maneuver_energy(n) + new_quadrant() + return + else: + pos = int(s1) * 24 + int(s2) * 3 + if qs[pos : (pos + 2)] != " ": + s1, s2 = int(s1 - x1), int(s2 - x2) + print( + "WARP ENGINES SHUT DOWN AT SECTOR " + f"{s1 + 1} , {s2 + 1} DUE TO BAD NAVAGATION" + ) + break + else: + s1, s2 = int(s1), int(s2) + + insert_marker(int(s1), int(s2), "<*>") + maneuver_energy(n) + + t += 0.1 * int(10 * warp) if warp < 1 else 1 + if t > t0 + t9: + end_game(won=False, quit=False) + return + + short_range_scan() + + +def maneuver_energy(n): + # Deduct the energy for navigation from energy/shields. + global e, s + + e -= n + 10 + + if e <= 0: + print("SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER.") + s += e + e = 0 + s = max(0, s) + + +def short_range_scan(): + # Print a short range scan. + global docked, e, p, s + + docked = False + for i in (s1 - 1, s1, s1 + 1): + for j in (s2 - 1, s2, s2 + 1): + if 0 <= i <= 7 and 0 <= j <= 7: + if compare_marker(i, j, ">!<"): + docked = True + cs = "DOCKED" + e, p = e0, p0 + print("SHIELDS DROPPED FOR DOCKING PURPOSES") + s = 0 + break + else: + continue + break + else: + if k3 > 0: + cs = "*RED*" + elif e < e0 * 0.1: + cs = "YELLOW" + else: + cs = "GREEN" + + if d[1] < 0: + print("\n*** SHORT RANGE SENSORS ARE OUT ***\n") + return + + sep = "---------------------------------" + print(sep) + for i in range(8): + line = "" + for j in range(8): + pos = i * 24 + j * 3 + line = line + " " + qs[pos : (pos + 3)] + + if i == 0: + line += f" STARDATE {round(int(t * 10) * 0.1, 1)}" + elif i == 1: + line += f" CONDITION {cs}" + elif i == 2: + line += f" QUADRANT {q1 + 1} , {q2 + 1}" + elif i == 3: + line += f" SECTOR {s1 + 1} , {s2 + 1}" + elif i == 4: + line += f" PHOTON TORPEDOES {int(p)}" + elif i == 5: + line += f" TOTAL ENERGY {int(e + s)}" + elif i == 6: + line += f" SHIELDS {int(s)}" + else: + line += f" KLINGONS REMAINING {k9}" + + print(line) + print(sep) + + +def long_range_scan(): + # Print a long range scan. + global z, g + + if d[2] < 0: + print("LONG RANGE SENSORS ARE INOPERABLE") + return + + print(f"LONG RANGE SCAN FOR QUADRANT {q1 + 1} , {q2 + 1}") + print_scan_results(q1, q2, g, z) + + +def print_scan_results( + q1: int, q2: int, g: List[List[Any]], z: List[List[Any]] +) -> None: + sep = "-------------------" + print(sep) + for i in (q1 - 1, q1, q1 + 1): + n = [-1, -2, -3] + + for j in (q2 - 1, q2, q2 + 1): + if 0 <= i <= 7 and 0 <= j <= 7: + n[j - q2 + 1] = g[i][j] + z[i][j] = g[i][j] + + line = ": " + for line_index in range(3): + if n[line_index] < 0: + line += "*** : " + else: + line += str(n[line_index] + 1000).rjust(4, " ")[-3:] + " : " + print(line) + print(sep) + + +def phaser_control(): + # Take phaser control input and fire phasers. + global e, k, g, z, k3, k9 + + if d[3] < 0: + print("PHASERS INOPERATIVE") + return + + if k3 <= 0: + print("SCIENCE OFFICER SPOCK REPORTS 'SENSORS SHOW NO ENEMY SHIPS") + print(" IN THIS QUADRANT'") + return + + if d[7] < 0: + print("COMPUTER FAILURE HAMPERS ACCURACY") + + print(f"PHASERS LOCKED ON TARGET; ENERGY AVAILABLE = {e} UNITS") + x = 0 + while True: + while True: + units_to_fire = input("NUMBER OF UNITS TO FIRE? ") + if len(units_to_fire) > 0: + x = int(units_to_fire) + break + if x <= 0: + return + if e >= x: + break + print(f"ENERGY AVAILABLE = {e} UNITS") + + e -= x + if d[7] < 0: # bug in original, was d[6] + x *= random.random() + + h1 = int(x / k3) + for i in range(3): + if k[i][2] <= 0: + continue + + h = int((h1 / fnd(i)) * (random.random() + 2)) + if h <= 0.15 * k[i][2]: + print(f"SENSORS SHOW NO DAMAGE TO ENEMY AT {k[i][0] + 1} , {k[i][1] + 1}") + else: + k[i][2] -= h + print(f" {h} UNIT HIT ON KLINGON AT SECTOR {k[i][0] + 1} , {k[i][1] + 1}") + if k[i][2] <= 0: + print("*** KLINGON DESTROYED ***") + k3 -= 1 + k9 -= 1 + insert_marker(k[i][0], k[i][1], " ") + k[i][2] = 0 + g[q1][q2] -= 100 + z[q1][q2] = g[q1][q2] + if k9 <= 0: + end_game(won=True, quit=False) + return + else: + print(f" (SENSORS SHOW {round(k[i][2],6)} UNITS REMAINING)") + + klingons_fire() + + +def photon_torpedoes(): + # Take photon torpedo input and process firing of torpedoes. + global e, p, k3, k9, k, b3, b9, docked, g, z + + if p <= 0: + print("ALL PHOTON TORPEDOES EXPENDED") + return + if d[4] < 0: + print("PHOTON TUBES ARE NOT OPERATIONAL") + return + + while True: + torpedo_course = input("PHOTON TORPEDO COURSE (1-9)? ") + if len(torpedo_course) > 0: + c1 = float(torpedo_course) + break + if c1 == 9: + c1 = 1 + if c1 < 1 or c1 >= 9: + print("ENSIGN CHEKOV REPORTS, 'INCORRECT COURSE DATA, SIR!'") + return + + ic1 = int(c1) + x1 = c[ic1 - 1][0] + (c[ic1][0] - c[ic1 - 1][0]) * (c1 - ic1) + e -= 2 + p -= 1 + x2 = c[ic1 - 1][1] + (c[ic1][1] - c[ic1 - 1][1]) * (c1 - ic1) + x, y = s1, s2 + x3, y3 = x, y + print("TORPEDO TRACK:") + while True: + x += x1 + y += x2 + x3, y3 = round(x), round(y) + if x3 < 0 or x3 > 7 or y3 < 0 or y3 > 7: + print("TORPEDO MISSED") + klingons_fire() + return + print(f" {x3 + 1} , {y3 + 1}") + if not compare_marker(x3, y3, " "): + break + + if compare_marker(x3, y3, "+K+"): + print("*** KLINGON DESTROYED ***") + k3 -= 1 + k9 -= 1 + if k9 <= 0: + end_game(won=True, quit=False) + return + for i in range(3): + if x3 == k[i][0] and y3 == k[i][1]: + k[i][2] = 0 + elif compare_marker(x3, y3, " * "): + print(f"STAR AT {x3 + 1} , {y3 + 1} ABSORBED TORPEDO ENERGY.") + klingons_fire() + return + elif compare_marker(x3, y3, ">!<"): + print("*** STARBASE DESTROYED ***") + b3 -= 1 + b9 -= 1 + if b9 == 0 and k9 <= t - t0 - t9: + print("THAT DOES IT, CAPTAIN!! YOU ARE HEREBY RELIEVED OF COMMAND") + print("AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!") + end_game(won=False) + return + else: + print("STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER") + print("COURT MARTIAL!") + docked = False + + insert_marker(x3, y3, " ") + g[q1][q2] = k3 * 100 + b3 * 10 + s3 + z[q1][q2] = g[q1][q2] + klingons_fire() + + +def fnd(i): + # Find distance between Enterprise and i'th Klingon warship. + return sqrt((k[i][0] - s1) ** 2 + (k[i][1] - s2) ** 2) + + +def klingons_fire(): + # Process nearby Klingons firing on Enterprise. + global s, k, d + + if k3 <= 0: + return + if docked: + print("STARBASE SHIELDS PROTECT THE ENTERPRISE") + return + + for i in range(3): + if k[i][2] <= 0: + continue + + h = int((k[i][2] / fnd(i)) * (random.random() + 2)) + s -= h + k[i][2] /= random.random() + 3 + print(f" {h} UNIT HIT ON ENTERPRISE FROM SECTOR {k[i][0] + 1} , {k[i][1] + 1}") + if s <= 0: + end_game(won=False, quit=False, enterprise_killed=True) + return + print(f" ") + if h >= 20 and random.random() < 0.60 and h / s > 0.02: + r1 = fnr() + d[r1] -= h / s + 0.5 * random.random() + print(f"DAMAGE CONTROL REPORTS '{devices[r1]} DAMAGED BY THE HIT'") + + +def shield_control(): + # Raise or lower the shields. + global e, s + + if d[6] < 0: + print("SHIELD CONTROL INOPERABLE") + return + + while True: + energy_to_shield = input( + f"ENERGY AVAILABLE = {e + s} NUMBER OF UNITS TO SHIELDS? " + ) + if len(energy_to_shield) > 0: + x = int(energy_to_shield) + break + + if x < 0 or s == x: + print("") + return + + if x > e + s: + print( + "SHIELD CONTROL REPORTS 'THIS IS NOT THE FEDERATION " + "TREASURY.'\n" + "" + ) + return + + e += s - x + s = x + print("DEFLECTOR CONTROL ROOM REPORT:") + print(f" 'SHIELDS NOW AT {s} UNITS PER YOUR COMMAND.'") + + +def damage_control(): + # Print a damage control report. + global d, t + + if d[5] < 0: + print("DAMAGE CONTROL REPORT NOT AVAILABLE") + else: + print("\nDEVICE STATE OF REPAIR") + for r1 in range(8): + print(f"{devices[r1].ljust(26, ' ')}{int(d[r1] * 100) * 0.01:g}") + print() + + if not docked: + return + + d3 = sum(0.1 for i in range(8) if d[i] < 0) + if d3 == 0: + return + + d3 += d4 + if d3 >= 1: + d3 = 0.9 + print("\nTECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;") + print(f"ESTIMATED TIME TO REPAIR: {round(0.01 * int(100 * d3), 2)} STARDATES") + if input("WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)? ").upper().strip() != "Y": + return + + for i in range(8): + if d[i] < 0: + d[i] = 0 + t += d3 + 0.1 + + +def computer(): + # Perform the various functions of the library computer. + global d, z, k9, t0, t9, t, b9, s1, s2, b4, b5 + + if d[7] < 0: + print("COMPUTER DISABLED") + return + + while True: + command = input("COMPUTER ACTIVE AND AWAITING COMMAND? ") + if len(command) == 0: + com = 6 + else: + com = int(command) + if com < 0: + return + + print() + + if com == 0 or com == 5: + if com == 5: + print(" THE GALAXY") + else: + print( + "\n COMPUTER RECORD OF GALAXY FOR " + f"QUADRANT {q1 + 1} , {q2 + 1}\n" + ) + + print(" 1 2 3 4 5 6 7 8") + sep = " ----- ----- ----- ----- ----- ----- ----- -----" + print(sep) + + for i in range(8): + line = " " + str(i + 1) + " " + + if com == 5: + g2s = quadrant_name(i, 0, True) + line += (" " * int(12 - 0.5 * len(g2s))) + g2s + g2s = quadrant_name(i, 4, True) + line += (" " * int(39 - 0.5 * len(g2s) - len(line))) + g2s + else: + for j in range(8): + line += " " + if z[i][j] == 0: + line += "***" + else: + line += str(z[i][j] + 1000)[-3:] + + print(line) + print(sep) + + print() + return + elif com == 1: + print(" STATUS REPORT:") + print(f"KLINGON{'S' if k9 > 1 else ''} LEFT: {k9}") + print( + "MISSION MUST BE COMPLETED IN " + f"{round(0.1 * int((t0+t9-t) * 10), 1)} STARDATES" + ) + + if b9 == 0: + print("YOUR STUPIDITY HAS LEFT YOU ON YOUR OWN IN") + print(" THE GALAXY -- YOU HAVE NO STARBASES LEFT!") + else: + print( + f"THE FEDERATION IS MAINTAINING {b9} " + f"STARBASE{'S' if b9 > 1 else ''} IN THE GALAXY" + ) + + damage_control() + return + elif com == 2: + if k3 <= 0: + print( + "SCIENCE OFFICER SPOCK REPORTS 'SENSORS SHOW NO ENEMY " + "SHIPS\n" + " IN THIS QUADRANT'" + ) + return + + print(f"FROM ENTERPRISE TO KLINGON BATTLE CRUISER{'S' if k3 > 1 else ''}") + + for i in range(3): + if k[i][2] > 0: + print_direction(s1, s2, k[i][0], k[i][1]) + return + elif com == 3: + if b3 == 0: + print( + "MR. SPOCK REPORTS, 'SENSORS SHOW NO STARBASES IN THIS " + "QUADRANT.'" + ) + return + + print("FROM ENTERPRISE TO STARBASE:") + print_direction(s1, s2, b4, b5) + return + elif com == 4: + print("DIRECTION/DISTANCE CALCULATOR:") + print(f"YOU ARE AT QUADRANT {q1+1} , {q2+1} SECTOR {s1+1} , {s2+1}") + print("PLEASE ENTER") + while True: + coordinates = input(" INITIAL COORDINATES (X,Y)? ").split(",") + if len(coordinates) == 2: + from1, from2 = int(coordinates[0]) - 1, int(coordinates[1]) - 1 + if 0 <= from1 <= 7 and 0 <= from2 <= 7: + break + while True: + coordinates = input(" FINAL COORDINATES (X,Y)? ").split(",") + if len(coordinates) == 2: + to1, to2 = int(coordinates[0]) - 1, int(coordinates[1]) - 1 + if 0 <= to1 <= 7 and 0 <= to2 <= 7: + break + print_direction(from1, from2, to1, to2) + return + else: + print( + "FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:\n" + " 0 = CUMULATIVE GALACTIC RECORD\n" + " 1 = STATUS REPORT\n" + " 2 = PHOTON TORPEDO DATA\n" + " 3 = STARBASE NAV DATA\n" + " 4 = DIRECTION/DISTANCE CALCULATOR\n" + " 5 = GALAXY 'REGION NAME' MAP\n" + ) + + +def print_direction(from1, from2, to1, to2): + # Print direction and distance between two locations in the grid. + delta1 = -(to1 - from1) # flip so positive is up (heading = 3) + delta2 = to2 - from2 + + if delta2 > 0: + if delta1 < 0: + base = 7 + else: + base = 1 + delta1, delta2 = delta2, delta1 + else: + if delta1 > 0: + base = 3 + else: + base = 5 + delta1, delta2 = delta2, delta1 + + delta1, delta2 = abs(delta1), abs(delta2) + + if delta1 > 0 or delta2 > 0: # bug in original; no check for divide by 0 + if delta1 >= delta2: + print(f"DIRECTION = {round(base + delta2 / delta1, 6)}") + else: + print(f"DIRECTION = {round(base + 2 - delta1 / delta2, 6)}") + + print(f"DISTANCE = {round(sqrt(delta1 ** 2 + delta2 ** 2), 6)}") + + +# ------------------------------------------------------------------------- +# Game transitions +# ------------------------------------------------------------------------- + + +def startup(): + # Initialize the game variables and map, and print startup messages. + global g, z, d, t, t0, t9, docked, e, e0, p, p0, s, k9, b9, s9, c + global devices, q1, q2, s1, s2, k7 + + print( + "\n\n\n\n\n\n\n\n\n\n\n" + " ,------*------,\n" + " ,------------- '--- ------'\n" + " '-------- --' / /\n" + " ,---' '-------/ /--,\n" + " '----------------'\n\n" + " THE USS ENTERPRISE --- NCC-1701\n" + "\n\n\n\n" + ) + + # set up global game variables + g = [[0] * 8 for _ in range(8)] # galaxy map + z = [[0] * 8 for _ in range(8)] # charted galaxy map + d = [0] * 8 # damage stats for devices + t = t0 = 100 * random.randint(20, 39) # stardate (current, initial) + t9 = random.randint(25, 34) # mission duration (stardates) + docked = False # true when docked at starbase + e = e0 = 3000 # energy (current, initial) + p = p0 = 10 # torpedoes (current, initial) + s = 0 # shields + k9, b9 = 0, 0 # total Klingons, bases in galaxy + # ^ bug in original, was b9 = 2 + s9 = 200 # avg. Klingon shield strength + + c = [ + [0, 1], + [-1, 1], + [-1, 0], + [-1, -1], + [0, -1], + [1, -1], + [1, 0], + [1, 1], + [0, 1], + ] # vectors in cardinal directions + + devices = [ + "WARP ENGINES", + "SHORT RANGE SENSORS", + "LONG RANGE SENSORS", + "PHASER CONTROL", + "PHOTON TUBES", + "DAMAGE CONTROL", + "SHIELD CONTROL", + "LIBRARY-COMPUTER", + ] + + # initialize Enterprise's position + q1, q2 = fnr(), fnr() # Enterprise's quadrant + s1, s2 = fnr(), fnr() # ...and sector + + # initialize contents of galaxy + for i in range(8): + for j in range(8): + k3 = 0 + r1 = random.random() + + if r1 > 0.98: + k3 = 3 + elif r1 > 0.95: + k3 = 2 + elif r1 > 0.80: + k3 = 1 + k9 += k3 + + b3 = 0 + if random.random() > 0.96: + b3 = 1 + b9 += 1 + g[i][j] = k3 * 100 + b3 * 10 + fnr() + 1 + + if k9 > t9: + t9 = k9 + 1 + + if b9 == 0: # original has buggy extra code here + b9 = 1 + g[q1][q2] += 10 + q1, q2 = fnr(), fnr() + + k7 = k9 # Klingons at start of game + + print( + "YOUR ORDERS ARE AS FOLLOWS:\n" + f" DESTROY THE {k9} KLINGON WARSHIPS WHICH HAVE INVADED\n" + " THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS\n" + f" ON STARDATE {t0+t9}. THIS GIVES YOU {t9} DAYS. THERE " + f"{'IS' if b9 == 1 else 'ARE'}\n" + f" {b9} STARBASE{'' if b9 == 1 else 'S'} IN THE GALAXY FOR " + "RESUPPLYING YOUR SHIP.\n" + ) + + +def new_quadrant(): + # Enter a new quadrant: populate map and print a short range scan. + global z, k3, b3, s3, d4, k, qs, b4, b5 + + k3 = b3 = s3 = 0 # Klingons, bases, stars in quad. + d4 = 0.5 * random.random() # extra delay in repairs at base + z[q1][q2] = g[q1][q2] + + if 0 <= q1 <= 7 and 0 <= q2 <= 7: + quad = quadrant_name(q1, q2, False) + if t == t0: + print("\nYOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED") + print(f"IN THE GALACTIC QUADRANT, '{quad}'.\n") + else: + print(f"\nNOW ENTERING {quad} QUADRANT . . .\n") + + k3 = g[q1][q2] // 100 + b3 = g[q1][q2] // 10 - 10 * k3 + s3 = g[q1][q2] - 100 * k3 - 10 * b3 + + if k3 != 0: + print("COMBAT AREA CONDITION RED") + if s <= 200: + print(" SHIELDS DANGEROUSLY LOW") + + k = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] # Klingons in current quadrant + qs = " " * 192 # quadrant string + + # build quadrant string + insert_marker(s1, s2, "<*>") + for i in range(k3): + r1, r2 = find_empty_place() + insert_marker(r1, r2, "+K+") + k[i] = [r1, r2, s9 * (0.5 + random.random())] + if b3 > 0: + b4, b5 = find_empty_place() # position of starbase (sector) + insert_marker(b4, b5, ">!<") + for i in range(s3): + r1, r2 = find_empty_place() + insert_marker(r1, r2, " * ") + + short_range_scan() + + +def end_game(won=False, quit=True, enterprise_killed=False): + # Handle end-of-game situations. + global restart + + if won: + print("CONGRATULATIONS, CAPTAIN! THE LAST KLINGON BATTLE CRUISER") + print("MENACING THE FEDERATION HAS BEEN DESTROYED.\n") + print(f"YOUR EFFICIENCY RATING IS {round(1000 * (k7 / (t - t0))**2, 4)}\n\n") + else: + if not quit: + if enterprise_killed: + print( + "\nTHE ENTERPRISE HAS BEEN DESTROYED. THE FEDERATION " + "WILL BE CONQUERED." + ) + print(f"IT IS STARDATE {round(t, 1)}") + + print(f"THERE WERE {k9} KLINGON BATTLE CRUISERS LEFT AT") + print("THE END OF YOUR MISSION.\n\n") + + if b9 == 0: + exit() + + print("THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER") + print("FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER,") + if input("LET HIM STEP FORWARD AND ENTER 'AYE'? ").upper().strip() != "AYE": + exit() + restart = True + + +# ------------------------------------------------------------------------- +# Entry point and main game loop +# ------------------------------------------------------------------------- + + +def main(): + global restart + + f = { + "NAV": navigation, + "SRS": short_range_scan, + "LRS": long_range_scan, + "PHA": phaser_control, + "TOR": photon_torpedoes, + "SHE": shield_control, + "DAM": damage_control, + "COM": computer, + "XXX": end_game, + } + + while True: + startup() + new_quadrant() + restart = False + + while not restart: + if s + e <= 10 or (e <= 10 and d[6] != 0): + print( + "\n** FATAL ERROR ** YOU'VE JUST STRANDED YOUR SHIP " + "IN SPACE.\nYOU HAVE INSUFFICIENT MANEUVERING ENERGY, " + "AND SHIELD CONTROL\nIS PRESENTLY INCAPABLE OF CROSS-" + "CIRCUITING TO ENGINE ROOM!!" + ) + + command = input("COMMAND? ").upper().strip() + + if command in f: + f[command]() + else: + print( + "ENTER ONE OF THE FOLLOWING:\n" + " NAV (TO SET COURSE)\n" + " SRS (FOR SHORT RANGE SENSOR SCAN)\n" + " LRS (FOR LONG RANGE SENSOR SCAN)\n" + " PHA (TO FIRE PHASERS)\n" + " TOR (TO FIRE PHOTON TORPEDOES)\n" + " SHE (TO RAISE OR LOWER SHIELDS)\n" + " DAM (FOR DAMAGE CONTROL REPORTS)\n" + " COM (TO CALL ON LIBRARY-COMPUTER)\n" + " XXX (TO RESIGN YOUR COMMAND)\n" + ) + + +if __name__ == "__main__": + main() diff --git a/00_Alternate_Languages/84_Super_Star_Trek/python/superstartrekins.py b/00_Alternate_Languages/84_Super_Star_Trek/python/superstartrekins.py new file mode 100644 index 00000000..63736e4c --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/python/superstartrekins.py @@ -0,0 +1,150 @@ +""" +SUPER STARTREK INSTRUCTIONS +MAR 5, 1978 + +Just the instructions for SUPERSTARTREK + +Ported by Dave LeCompte +""" + + +def get_yes_no(prompt): + response = input(prompt).upper() + return response[0] != "N" + + +def print_header(): + for i in range(12): + print() + t10 = " " * 10 + print(t10 + "*************************************") + print(t10 + "* *") + print(t10 + "* *") + print(t10 + "* * * SUPER STAR TREK * * *") + print(t10 + "* *") + print(t10 + "* *") + print(t10 + "*************************************") + for i in range(8): + print() + + +def print_instructions(): + # Back in the 70s, at this point, the user would be prompted to + # turn on their (printing) TTY to capture the output to hard copy. + + print(" INSTRUCTIONS FOR 'SUPER STAR TREK'") + print() + print("1. WHEN YOU SEE \\COMMAND ?\\ PRINTED, ENTER ONE OF THE LEGAL") + print(" COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX).") + print("2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT") + print(" LIST OF THE LEGAL COMMANDS PRINTED OUT.") + print("3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE") + print(" 'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.) IF YOU") + print(" TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND") + print(" WILL BE ABORTED") + print() + print(" THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,") + print("AND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID.") + print() + print(" YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE") + print("GALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP") + print("\\ENTERPRISE\\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF") + print("KLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF") + print("PLANETS.") + print() + print(" YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN") + print("OF THE STARSHIP ENTERPRISE:") + print() + print("\\NAV\\ COMMAND = WARP ENGINE CONTROL --") + print(" COURSE IS IN A CIRCULAR NUMERICAL 4 3 2") + print(" VECTOR ARRANGEMENT AS SHOWN . . .") + print(" INTEGER AND REAL VALUES MAY BE ...") + print(" USED. (THUS COURSE 1.5 IS HALF- 5 ---*--- 1") + print(" WAY BETWEEN 1 AND 2 ...") + print(" . . .") + print(" VALUES MAY APPROACH 9.0, WHICH 6 7 8") + print(" ITSELF IS EQUIVALENT TO 1.0") + print(" COURSE") + print(" ONE WARP FACTOR IS THE SIZE OF ") + print(" ONE QUADTANT. THEREFORE, TO GET") + print(" FROM QUADRANT 6,5 TO 5,5, YOU WOULD") + print(" USE COURSE 3, WARP FACTOR 1.") + print() + print("\\SRS\\ COMMAND = SHORT RANGE SENSOR SCAN") + print(" SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT.") + print() + print(" SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:") + print(" <*> = YOUR STARSHIP'S POSITION") + print(" +K+ = KLINGON BATTLE CRUISER") + print(" >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)") + print(" * = STAR") + print() + print(" A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED.") + print() + print("\\LRS\\ COMMAND = LONG RANGE SENSOR SCAN") + print(" SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE") + print(" OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)") + print(" THE SCAN IS CODED IN THE FORM \\###\\, WHERE TH UNITS DIGIT") + print(" IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF") + print(" STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF") + print(" KLINGONS.") + print() + print(" EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS.") + print() + print("\\PHA\\ COMMAND = PHASER CONTROL.") + print(" ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY ") + print(" ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO") + print(" DEPLETE THEIR SHIELD POWER. (REMEMBER, KLINGONS HAVE") + print(" PHASERS TOO!)") + print() + print("\\TOR\\ COMMAND = PHOTON TORPEDO CONTROL") + print(" TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL") + print(" IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND") + print(" CANNOT FIRE BACK AT YOU. IF YOU MISS, YOU ARE SUBJECT TO") + print(" HIS PHASER FIRE. IN EITHER CASE, YOU ARE ALSO SUBJECT TO ") + print(" THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT.") + print() + print(" THE LIBRARY-COMPUTER (\\COM\\ COMMAND) HAS AN OPTION TO ") + print(" COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)") + print() + print("\\SHE\\ COMMAND = SHIELD CONTROL") + print(" DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE") + print(" SHIELDS. ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY. NOTE") + print(" THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY") + print() + print("\\DAM\\ COMMAND = DAMMAGE CONTROL REPORT") + print(" GIVES THE STATE OF REPAIR OF ALL DEVICES. WHERE A NEGATIVE") + print(" 'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY") + print(" DAMAGED.") + print() + print("\\COM\\ COMMAND = LIBRARY-COMPUTER") + print(" THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:") + print(" OPTION 0 = CUMULATIVE GALACTIC RECORD") + print(" THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL") + print(" PREVIOUS SHORT AND LONG RANGE SENSOR SCANS") + print(" OPTION 1 = STATUS REPORT") + print(" THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,") + print(" AND STARBASES REMAINING IN THE GAME.") + print(" OPTION 2 = PHOTON TORPEDO DATA") + print(" WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE") + print(" TO ALL KLINGONS IN YOUR QUADRANT") + print(" OPTION 3 = STARBASE NAV DATA") + print(" THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY ") + print(" STARBASE WITHIN YOUR QUADRANT") + print(" OPTION 4 = DIRECTION/DISTANCE CALCULATOR") + print(" THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR") + print(" DIRECTION/DISTANCE CALCULATIONS") + print(" OPTION 5 = GALACTIC /REGION NAME/ MAP") + print(" THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR ") + print(" GALACTIC REGIONS REFERRED TO IN THE GAME.") + + +def main(): + print_header() + if not get_yes_no("DO YOU NEED INSTRUCTIONS (Y/N)? "): + return + print_instructions() + + +if __name__ == "__main__": + main() diff --git a/00_Alternate_Languages/84_Super_Star_Trek/ruby/README.md b/00_Alternate_Languages/84_Super_Star_Trek/ruby/README.md new file mode 100644 index 00000000..fb32811e --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/ruby/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Ruby](https://www.ruby-lang.org/en/) diff --git a/00_Alternate_Languages/84_Super_Star_Trek/superstartrek.bas b/00_Alternate_Languages/84_Super_Star_Trek/superstartrek.bas new file mode 100644 index 00000000..efd74cb0 --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/superstartrek.bas @@ -0,0 +1,425 @@ +10 REM SUPER STARTREK - MAY 16,1978 - REQUIRES 24K MEMORY +30 REM +40 REM **** **** STAR TREK **** **** +50 REM **** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE, +60 REM **** AS SEEN ON THE STAR TREK TV SHOW. +70 REM **** ORIGIONAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION +80 REM **** PUBLISHED IN DEC'S "101 BASIC GAMES", BY DAVE AHL. +90 REM **** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB +100 REM *** LEEDOM - APRIL & DECEMBER 1974, +110 REM *** WITH A LITTLE HELP FROM HIS FRIENDS . . . +120 REM *** COMMENTS, EPITHETS, AND SUGGESTIONS SOLICITED -- +130 REM *** SEND TO: R. C. LEEDOM +140 REM *** WESTINGHOUSE DEFENSE & ELECTRONICS SYSTEMS CNTR. +150 REM *** BOX 746, M.S. 338 +160 REM *** BALTIMORE, MD 21203 +170 REM *** +180 REM *** CONVERTED TO MICROSOFT 8 K BASIC 3/16/78 BY JOHN GORDERS +190 REM *** LINE NUMBERS FROM VERSION STREK7 OF 1/12/75 PRESERVED AS +200 REM *** MUCH AS POSSIBLE WHILE USING MULTIPLE STATEMENTS PER LINE +205 REM *** SOME LINES ARE LONGER THAN 72 CHARACTERS; THIS WAS DONE +210 REM *** BY USING "?" INSTEAD OF "PRINT" WHEN ENTERING LINES +215 REM *** +220 PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT +221 PRINT " ,------*------," +222 PRINT " ,------------- '--- ------'" +223 PRINT " '-------- --' / /" +224 PRINT " ,---' '-------/ /--," +225 PRINT " '----------------'":PRINT +226 PRINT " THE USS ENTERPRISE --- NCC-1701" +227 PRINT:PRINT:PRINT:PRINT:PRINT +260 REM CLEAR 600 +270 Z$=" " +330 DIM G(8,8),C(9,2),K(3,3),N(3),Z(8,8),D(8) +370 T=INT(RND(1)*20+20)*100:T0=T:T9=25+INT(RND(1)*10):D0=0:E=3000:E0=E +440 P=10:P0=P:S9=200:S=0:B9=2:K9=0:X$="":X0$=" IS " +470 DEF FND(D)=SQR((K(I,1)-S1)^2+(K(I,2)-S2)^2) +475 DEF FNR(R)=INT(RND(R)*7.98+1.01) +480 REM INITIALIZE ENTERPRIZE'S POSITION +490 Q1=FNR(1):Q2=FNR(1):S1=FNR(1):S2=FNR(1) +530 FOR I=1 TO 9:C(I,1)=0:C(I,2)=0:NEXT I +540 C(3,1)=-1:C(2,1)=-1:C(4,1)=-1:C(4,2)=-1:C(5,2)=-1:C(6,2)=-1 +600 C(1,2)=1:C(2,2)=1:C(6,1)=1:C(7,1)=1:C(8,1)=1:C(8,2)=1:C(9,2)=1 +670 FOR I=1 TO 8:D(I)=0:NEXT I +710 A1$="NAVSRSLRSPHATORSHEDAMCOMXXX" +810 REM SETUP WHAT EXHISTS IN GALAXY . . . +815 REM K3= # KLINGONS B3= # STARBASES S3 = # STARS +820 FOR I=1 TO 8:FOR J=1 TO 8:K3=0:Z(I,J)=0:R1=RND(1) +850 IF R1>.98 THEN K3=3:K9=K9+3:GOTO 980 +860 IF R1>.95 THEN K3=2:K9=K9+2:GOTO 980 +870 IF R1>.80 THEN K3=1:K9=K9+1 +980 B3=0:IF RND(1)>.96 THEN B3=1:B9=B9+1 +1040 G(I,J)=K3*100+B3*10+FNR(1):NEXT J:NEXT I:IF K9>T9 THEN T9=K9+1 +1100 IF B9<>0 THEN 1200 +1150 IF G(Q1,Q2)<200 THEN G(Q1,Q2)=G(Q1,Q2)+120:K9=K9+1 +1160 B9=1:G(Q1,Q2)=G(Q1,Q2)+10:Q1=FNR(1):Q2=FNR(1) +1200 K7=K9:IF B9<>1 THEN X$="S":X0$=" ARE " +1230 PRINT "YOUR ORDERS ARE AS FOLLOWS:" +1240 PRINT " DESTROY THE";K9;"KLINGON WARSHIPS WHICH HAVE INVADED" +1252 PRINT " THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS" +1260 PRINT " ON STARDATE";T0+T9;" THIS GIVES YOU";T9;"DAYS. THERE";X0$ +1272 PRINT " ";B9;"STARBASE";X$;" IN THE GALAXY FOR RESUPPLYING YOUR SHIP" +1280 PRINT:REM PRINT "HIT ANY KEY EXCEPT RETURN WHEN READY TO ACCEPT COMMAND" +1300 I=RND(1):REM IF INP(1)=13 THEN 1300 +1310 REM HERE ANY TIME NEW QUADRANT ENTERED +1320 Z4=Q1:Z5=Q2:K3=0:B3=0:S3=0:G5=0:D4=.5*RND(1):Z(Q1,Q2)=G(Q1,Q2) +1390 IF Q1<1 OR Q1>8 OR Q2<1 OR Q2>8 THEN 1600 +1430 GOSUB 9030:PRINT:IF T0<>T THEN 1490 +1460 PRINT "YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED" +1470 PRINT "IN THE GALACTIC QUADRANT, '";G2$;"'.":GOTO 1500 +1490 PRINT "NOW ENTERING ";G2$;" QUADRANT . . ." +1500 PRINT:K3=INT(G(Q1,Q2)*.01):B3=INT(G(Q1,Q2)*.1)-10*K3 +1540 S3=G(Q1,Q2)-100*K3-10*B3:IF K3=0 THEN 1590 +1560 PRINT "COMBAT AREA CONDITION RED":IF S>200 THEN 1590 +1580 PRINT " SHIELDS DANGEROUSLY LOW" +1590 FOR I=1 TO 3:K(I,1)=0:K(I,2)=0:NEXT I +1600 FOR I=1 TO 3:K(I,3)=0:NEXT I:Q$=Z$+Z$+Z$+Z$+Z$+Z$+Z$+LEFT$(Z$,17) +1660 REM POSITION ENTERPRISE IN QUADRANT, THEN PLACE "K3" KLINGONS, & +1670 REM "B3" STARBASES, & "S3" STARS ELSEWHERE. +1680 A$="<*>":Z1=S1:Z2=S2:GOSUB 8670:IF K3<1 THEN 1820 +1720 FOR I=1 TO K3:GOSUB 8590:A$="+K+":Z1=R1:Z2=R2 +1780 GOSUB 8670:K(I,1)=R1:K(I,2)=R2:K(I,3)=S9*(0.5+RND(1)):NEXT I +1820 IF B3<1 THEN 1910 +1880 GOSUB 8590:A$=">!<":Z1=R1:B4=R1:Z2=R2:B5=R2:GOSUB 8670 +1910 FOR I=1 TO S3:GOSUB 8590:A$=" * ":Z1=R1:Z2=R2:GOSUB 8670:NEXT I +1980 GOSUB 6430 +1990 IF S+E>10 THEN IF E>10 OR D(7)=0 THEN 2060 +2020 PRINT:PRINT "** FATAL ERROR ** YOU'VE JUST STRANDED YOUR SHIP IN " +2030 PRINT "SPACE":PRINT "YOU HAVE INSUFFICIENT MANEUVERING ENERGY,"; +2040 PRINT " AND SHIELD CONTROL":PRINT "IS PRESENTLY INCAPABLE OF CROSS"; +2050 PRINT "-CIRCUITING TO ENGINE ROOM!!":GOTO 6220 +2060 INPUT"COMMAND";A$ +2080 FOR I=1 TO 9:IF LEFT$(A$,3)<>MID$(A1$,3*I-2,3) THEN 2160 +2140 ON I GOTO 2300,1980,4000,4260,4700,5530,5690,7290,6270 +2160 NEXT I:PRINT "ENTER ONE OF THE FOLLOWING:" +2180 PRINT " NAV (TO SET COURSE)" +2190 PRINT " SRS (FOR SHORT RANGE SENSOR SCAN)" +2200 PRINT " LRS (FOR LONG RANGE SENSOR SCAN)" +2210 PRINT " PHA (TO FIRE PHASERS)" +2220 PRINT " TOR (TO FIRE PHOTON TORPEDOES)" +2230 PRINT " SHE (TO RAISE OR LOWER SHIELDS)" +2240 PRINT " DAM (FOR DAMAGE CONTROL REPORTS)" +2250 PRINT " COM (TO CALL ON LIBRARY-COMPUTER)" +2260 PRINT " XXX (TO RESIGN YOUR COMMAND)":PRINT:GOTO 1990 +2290 REM COURSE CONTROL BEGINS HERE +2300 INPUT"COURSE (0-9)";C1:IF C1=9 THEN C1=1 +2310 IF C1>=1 AND C1<9 THEN 2350 +2330 PRINT " LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'":GOTO 1990 +2350 X$="8":IF D(1)<0 THEN X$="0.2" +2360 PRINT "WARP FACTOR (0-";X$;")";:INPUT W1:IF D(1)<0 AND W1>.2 THEN 2470 +2380 IF W1>0 AND W1<=8 THEN 2490 +2390 IF W1=0 THEN 1990 +2420 PRINT " CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE"; +2430 PRINT " WARP ";W1;"!'":GOTO 1990 +2470 PRINT "WARP ENGINES ARE DAMAGED. MAXIUM SPEED = WARP 0.2":GOTO 1990 +2490 N=INT(W1*8+.5):IF E-N>=0 THEN 2590 +2500 PRINT "ENGINEERING REPORTS 'INSUFFICIENT ENERGY AVAILABLE" +2510 PRINT " FOR MANEUVERING AT WARP";W1;"!'" +2530 IF S=1 THEN D6=1 +2770 FOR I=1 TO 8:IF D(I)>=0 THEN 2880 +2790 D(I)=D(I)+D6:IF D(I)>-.1 AND D(I)<0 THEN D(I)=-.1:GOTO 2880 +2800 IF D(I)<0 THEN 2880 +2810 IF D1<>1 THEN D1=1:PRINT "DAMAGE CONTROL REPORT: "; +2840 PRINT TAB(8);:R1=I:GOSUB 8790:PRINT G2$;" REPAIR COMPLETED." +2880 NEXT I:IF RND(1)>.2 THEN 3070 +2910 R1=FNR(1):IF RND(1)>=.6 THEN 3000 +2930 D(R1)=D(R1)-(RND(1)*5+1):PRINT "DAMAGE CONTROL REPORT: "; +2960 GOSUB 8790:PRINT G2$;" DAMAGED":PRINT:GOTO 3070 +3000 D(R1)=D(R1)+RND(1)*3+1:PRINT "DAMAGE CONTROL REPORT: "; +3030 GOSUB 8790:PRINT G2$;" STATE OF REPAIR IMPROVED":PRINT +3060 REM BEGIN MOVING STARSHIP +3070 A$=" ":Z1=INT(S1):Z2=INT(S2):GOSUB 8670 +3110 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1)):X=S1:Y=S2 +3140 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1)):Q4=Q1:Q5=Q2 +3170 FOR I=1 TO N:S1=S1+X1:S2=S2+X2:IF S1<1 OR S1>=9 OR S2<1 OR S2>=9 THEN 3500 +3240 S8=INT(S1)*24+INT(S2)*3-26:IF MID$(Q$,S8,2)=" " THEN 3360 +3320 S1=INT(S1-X1):S2=INT(S2-X2):PRINT "WARP ENGINES SHUT DOWN AT "; +3350 PRINT "SECTOR";S1;",";S2;"DUE TO BAD NAVAGATION":GOTO 3370 +3360 NEXT I:S1=INT(S1):S2=INT(S2) +3370 A$="<*>":Z1=INT(S1):Z2=INT(S2):GOSUB 8670:GOSUB 3910:T8=1 +3430 IF W1<1 THEN T8=.1*INT(10*W1) +3450 T=T+T8:IF T>T0+T9 THEN 6220 +3470 REM SEE IF DOCKED, THEN GET COMMAND +3480 GOTO 1980 +3490 REM EXCEEDED QUADRANT LIMITS +3500 X=8*Q1+X+N*X1:Y=8*Q2+Y+N*X2:Q1=INT(X/8):Q2=INT(Y/8):S1=INT(X-Q1*8) +3550 S2=INT(Y-Q2*8):IF S1=0 THEN Q1=Q1-1:S1=8 +3590 IF S2=0 THEN Q2=Q2-1:S2=8 +3620 X5=0:IF Q1<1 THEN X5=1:Q1=1:S1=1 +3670 IF Q1>8 THEN X5=1:Q1=8:S1=8 +3710 IF Q2<1 THEN X5=1:Q2=1:S2=1 +3750 IF Q2>8 THEN X5=1:Q2=8:S2=8 +3790 IF X5=0 THEN 3860 +3800 PRINT "LT. UHURA REPORTS MESSAGE FROM STARFLEET COMMAND:" +3810 PRINT " 'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER" +3820 PRINT " IS HEREBY *DENIED*. SHUT DOWN YOUR ENGINES.'" +3830 PRINT "CHIEF ENGINEER SCOTT REPORTS 'WARP ENGINES SHUT DOWN" +3840 PRINT " AT SECTOR";S1;",";S2;"OF QUADRANT";Q1;",";Q2;".'" +3850 IF T>T0+T9 THEN 6220 +3860 IF 8*Q1+Q2=8*Q4+Q5 THEN 3370 +3870 T=T+1:GOSUB 3910:GOTO 1320 +3900 REM MANEUVER ENERGY S/R ** +3910 E=E-N-10:IF E>=0 THEN RETURN +3930 PRINT "SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER." +3940 S=S+E:E=0:IF S<=0 THEN S=0 +3980 RETURN +3990 REM LONG RANGE SENSOR SCAN CODE +4000 IF D(3)<0 THEN PRINT "LONG RANGE SENSORS ARE INOPERABLE":GOTO 1990 +4030 PRINT "LONG RANGE SCAN FOR QUADRANT";Q1;",";Q2 +4040 O1$="-------------------":PRINT O1$ +4060 FOR I=Q1-1TOQ1+1:N(1)=-1:N(2)=-2:N(3)=-3:FOR J=Q2-1TOQ2+1 +4120 IF I>0 AND I<9 AND J>0 AND J<9 THEN N(J-Q2+2)=G(I,J):Z(I,J)=G(I,J) +4180 NEXT J:FOR L=1 TO 3:PRINT ": ";:IF N(L)<0 THEN PRINT "*** ";:GOTO 4230 +4210 PRINT RIGHT$(STR$(N(L)+1000),3);" "; +4230 NEXT L:PRINT ":":PRINT O1$:NEXT I:GOTO 1990 +4250 REM PHASER CONTROL CODE BEGINS HERE +4260 IF D(4)<0 THEN PRINT "PHASERS INOPERATIVE":GOTO 1990 +4265 IF K3>0 THEN 4330 +4270 PRINT "SCIENCE OFFICER SPOCK REPORTS 'SENSORS SHOW NO ENEMY SHIPS" +4280 PRINT " IN THIS QUADRANT'":GOTO 1990 +4330 IF D(8)<0 THEN PRINT "COMPUTER FAILURE HAMPERS ACCURACY" +4350 PRINT "PHASERS LOCKED ON TARGET; "; +4360 PRINT "ENERGY AVAILABLE =";E;"UNITS" +4370 INPUT"NUMBER OF UNITS TO FIRE";X:IF X<=0 THEN 1990 +4400 IF E-X<0 THEN 4360 +4410 E=E-X:IF D(7)<0 THEN X=X*RND(1) +4450 H1=INT(X/K3):FOR I=1TO3:IF K(I,3)<=0 THEN 4670 +4480 H=INT((H1/FND(0))*(RND(1)+2)):IF H>.15*K(I,3) THEN 4530 +4500 PRINT "SENSORS SHOW NO DAMAGE TO ENEMY AT ";K(I,1);",";K(I,2):GOTO 4670 +4530 K(I,3)=K(I,3)-H:PRINT H;"UNIT HIT ON KLINGON AT SECTOR";K(I,1);","; +4550 PRINT K(I,2):IF K(I,3)<=0 THEN PRINT "*** KLINGON DESTROYED ***":GOTO 4580 +4560 PRINT " (SENSORS SHOW";K(I,3);"UNITS REMAINING)":GOTO 4670 +4580 K3=K3-1:K9=K9-1:Z1=K(I,1):Z2=K(I,2):A$=" ":GOSUB 8670 +4650 K(I,3)=0:G(Q1,Q2)=G(Q1,Q2)-100:Z(Q1,Q2)=G(Q1,Q2):IF K9<=0 THEN 6370 +4670 NEXT I:GOSUB 6000:GOTO 1990 +4690 REM PHOTON TORPEDO CODE BEGINS HERE +4700 IF P<=0 THEN PRINT "ALL PHOTON TORPEDOES EXPENDED":GOTO 1990 +4730 IF D(5)<0 THEN PRINT "PHOTON TUBES ARE NOT OPERATIONAL":GOTO 1990 +4760 INPUT"PHOTON TORPEDO COURSE (1-9)";C1:IF C1=9 THEN C1=1 +4780 IF C1>=1ANDC1<9 THEN 4850 +4790 PRINT "ENSIGN CHEKOV REPORTS, 'INCORRECT COURSE DATA, SIR!'" +4800 GOTO 1990 +4850 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1)):E=E-2:P=P-1 +4860 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1)):X=S1:Y=S2 +4910 PRINT "TORPEDO TRACK:" +4920 X=X+X1:Y=Y+X2:X3=INT(X+.5):Y3=INT(Y+.5) +4960 IF X3<1 OR X3>8 OR Y3<1 OR Y3>8 THEN 5490 +5000 PRINT " ";X3;",";Y3:A$=" ":Z1=X:Z2=Y:GOSUB 8830 +5050 IF Z3<>0 THEN 4920 +5060 A$="+K+":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 5210 +5110 PRINT "*** KLINGON DESTROYED ***":K3=K3-1:K9=K9-1:IF K9<=0 THEN 6370 +5150 FOR I=1TO3:IF X3=K(I,1) AND Y3=K(I,2) THEN 5190 +5180 NEXT I:I=3 +5190 K(I,3)=0:GOTO 5430 +5210 A$=" * ":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 5280 +5260 PRINT "STAR AT";X3;",";Y3;"ABSORBED TORPEDO ENERGY.":GOSUB 6000:GOTO 1990 +5280 A$=">!<":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 4760 +5330 PRINT "*** STARBASE DESTROYED ***":B3=B3-1:B9=B9-1 +5360 IF B9>0 OR K9>T-T0-T9 THEN 5400 +5370 PRINT "THAT DOES IT, CAPTAIN!! YOU ARE HEREBY RELIEVED OF COMMAND" +5380 PRINT "AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!" +5390 GOTO 6270 +5400 PRINT "STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER" +5410 PRINT "COURT MARTIAL!":D0=0 +5430 Z1=X:Z2=Y:A$=" ":GOSUB 8670 +5470 G(Q1,Q2)=K3*100+B3*10+S3:Z(Q1,Q2)=G(Q1,Q2):GOSUB 6000:GOTO 1990 +5490 PRINT "TORPEDO MISSED":GOSUB 6000:GOTO 1990 +5520 REM SHIELD CONTROL +5530 IF D(7)<0 THEN PRINT "SHIELD CONTROL INOPERABLE":GOTO 1990 +5560 PRINT "ENERGY AVAILABLE =";E+S;:INPUT"NUMBER OF UNITS TO SHIELDS";X +5580 IF X<0 OR S=X THEN PRINT "":GOTO 1990 +5590 IF X<=E+S THEN 5630 +5600 PRINT "SHIELD CONTROL REPORTS 'THIS IS NOT THE FEDERATION TREASURY.'" +5610 PRINT "":GOTO 1990 +5630 E=E+S-X:S=X:PRINT "DEFLECTOR CONTROL ROOM REPORT:" +5660 PRINT " 'SHIELDS NOW AT";INT(S);"UNITS PER YOUR COMMAND.'":GOTO 1990 +5680 REM DAMAGE CONTROL +5690 IF D(6)>=0 THEN 5910 +5700 PRINT "DAMAGE CONTROL REPORT NOT AVAILABLE":IF D0=0 THEN 1990 +5720 D3=0:FOR I=1TO8:IF D(I)<0 THEN D3=D3+.1 +5760 NEXT I:IF D3=0 THEN 1990 +5780 PRINT:D3=D3+D4:IF D3>=1 THEN D3=.9 +5810 PRINT "TECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;" +5820 PRINT "ESTIMATED TIME TO REPAIR:";.01*INT(100*D3);"STARDATES" +5840 INPUT "WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)";A$ +5860 IF A$<>"Y" THEN 1990 +5870 FOR I=1TO8:IF D(I)<0 THEN D(I)=0 +5890 NEXT I:T=T+D3+.1 +5910 PRINT:PRINT "DEVICE STATE OF REPAIR":FOR R1=1TO8 +5920 GOSUB 8790:PRINT G2$;LEFT$(Z$,25-LEN(G2$));INT(D(R1)*100)*.01 +5950 NEXT R1:PRINT:IF D0<>0 THEN 5720 +5980 GOTO 1990 +5990 REM KLINGONS SHOOTING +6000 IF K3<=0 THEN RETURN +6010 IF D0<>0 THEN PRINT "STARBASE SHIELDS PROTECT THE ENTERPRISE":RETURN +6040 FOR I=1TO3:IF K(I,3)<=0 THEN 6200 +6060 H=INT((K(I,3)/FND(1))*(2+RND(1))):S=S-H:K(I,3)=K(I,3)/(3+RND(0)) +6080 PRINT H;"UNIT HIT ON ENTERPRISE FROM SECTOR";K(I,1);",";K(I,2) +6090 IF S<=0 THEN 6240 +6100 PRINT " ":IF H<20 THEN 6200 +6120 IF RND(1)>.6 OR H/S<=.02 THEN 6200 +6140 R1=FNR(1):D(R1)=D(R1)-H/S-.5*RND(1):GOSUB 8790 +6170 PRINT "DAMAGE CONTROL REPORTS ";G2$;" DAMAGED BY THE HIT'" +6200 NEXT I:RETURN +6210 REM END OF GAME +6220 PRINT "IT IS STARDATE";T:GOTO 6270 +6240 PRINT:PRINT "THE ENTERPRISE HAS BEEN DESTROYED. THEN FEDERATION "; +6250 PRINT "WILL BE CONQUERED":GOTO 6220 +6270 PRINT "THERE WERE";K9;"KLINGON BATTLE CRUISERS LEFT AT" +6280 PRINT "THE END OF YOUR MISSION." +6290 PRINT:PRINT:IF B9=0 THEN 6360 +6310 PRINT "THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER" +6320 PRINT "FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER," +6330 INPUT"LET HIM STEP FORWARD AND ENTER 'AYE'";A$:IF A$="AYE" THEN 10 +6360 END +6370 PRINT "CONGRULATION, CAPTAIN! THEN LAST KLINGON BATTLE CRUISER" +6380 PRINT "MENACING THE FDERATION HAS BEEN DESTROYED.":PRINT +6400 PRINT "YOUR EFFICIENCY RATING IS";1000*(K7/(T-T0))^2:GOTO 6290 +6420 REM SHORT RANGE SENSOR SCAN & STARTUP SUBROUTINE +6430 FOR I=S1-1TOS1+1:FOR J=S2-1 TO S2+1 +6450 IF INT(I+.5)<1 OR INT(I+.5)>8 OR INT(J+.5)<1 OR INT(J+.5)>8 THEN 6540 +6490 A$=">!<":Z1=I:Z2=J:GOSUB 8830:IF Z3=1 THEN 6580 +6540 NEXT J:NEXT I:D0=0:GOTO 6650 +6580 D0=1:C$="DOCKED":E=E0:P=P0 +6620 PRINT "SHIELDS DROPPED FOR DOCKING PURPOSES":S=0:GOTO 6720 +6650 IF K3>0 THEN C$="*RED*":GOTO 6720 +6660 C$="GREEN":IF E=0 THEN 6770 +6730 PRINT:PRINT "*** SHORT RANGE SENSORS ARE OUT ***":PRINT:RETURN +6770 O1$="---------------------------------":PRINT O1$:FOR I=1 TO 8 +6820 FOR J=(I-1)*24+1 TO (I-1)*24+22STEP3:PRINT " ";MID$(Q$,J,3);:NEXT J +6830 ON I GOTO 6850,6900,6960,7020,7070,7120,7180,7240 +6850 PRINT " STARDATE ";INT(T*10)*.1:GOTO 7260 +6900 PRINT " CONDITION ";C$:GOTO 7260 +6960 PRINT " QUADRANT ";Q1;",";Q2:GOTO 7260 +7020 PRINT " SECTOR ";S1;",";S2:GOTO 7260 +7070 PRINT " PHOTON TORPEDOES ";INT(P):GOTO 7260 +7120 PRINT " TOTAL ENERGY ";INT(E+S):GOTO 7260 +7180 PRINT " SHIELDS ";INT(S):GOTO 7260 +7240 PRINT " KLINGONS REMAINING";INT(K9) +7260 NEXT I:PRINT O1$:RETURN +7280 REM LIBRARY COMPUTER CODE +7290 IF D(8)<0 THEN PRINT "COMPUTER DISABLED":GOTO 1990 +7320 INPUT"COMPUTER ACTIVE AND AWAITING COMMAND";A:IF A<0 THEN 1990 +7350 PRINT:H8=1:ON A+1 GOTO 7540,7900,8070,8500,8150,7400 +7360 PRINT "FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:" +7370 PRINT " 0 = CUMULATIVE GALACTIC RECORD" +7372 PRINT " 1 = STATUS REPORT" +7374 PRINT " 2 = PHOTON TORPEDO DATA" +7376 PRINT " 3 = STARBASE NAV DATA" +7378 PRINT " 4 = DIRECTION/DISTANCE CALCULATOR" +7380 PRINT " 5 = GALAXY 'REGION NAME' MAP":PRINT:GOTO 7320 +7390 REM SETUP TO CHANGE CUM GAL RECORD TO GALAXY MAP +7400 H8=0:G5=1:PRINT " THE GALAXY":GOTO 7550 +7530 REM CUM GALACTIC RECORD +7540 REM INPUT"DO YOU WANT A HARDCOPY? IS THE TTY ON (Y/N)";A$ +7542 REM IF A$="Y" THEN POKE1229,2:POKE1237,3:NULL1 +7543 PRINT:PRINT " "; +7544 PRINT "COMPUTER RECORD OF GALAXY FOR QUADRANT";Q1;",";Q2 +7546 PRINT +7550 PRINT " 1 2 3 4 5 6 7 8" +7560 O1$=" ----- ----- ----- ----- ----- ----- ----- -----" +7570 PRINT O1$:FOR I=1 TO 8:PRINT I;:IF H8=0 THEN 7740 +7630 FOR J=1 TO 8:PRINT " ";:IF Z(I,J)=0 THEN PRINT "***";:GOTO 7720 +7700 PRINT RIGHT$(STR$(Z(I,J)+1000),3); +7720 NEXT J:GOTO 7850 +7740 Z4=I:Z5=1:GOSUB 9030:J0=INT(15-.5*LEN(G2$)):PRINT TAB(J0);G2$; +7800 Z5=5:GOSUB 9030:J0=INT(39-.5*LEN(G2$)):PRINT TAB(J0);G2$; +7850 PRINT:PRINT O1$:NEXT I:PRINT:GOTO 1990 +7890 REM STATUS REPORT +7900 PRINT " STATUS REPORT:":X$="":IF K9>1 THEN X$="S" +7940 PRINT "KLINGON";X$;" LEFT: ";K9 +7960 PRINT "MISSION MUST BE COMPLETED IN";.1*INT((T0+T9-T)*10);"STARDATES" +7970 X$="S":IF B9<2 THEN X$="":IF B9<1 THEN 8010 +7980 PRINT "THE FEDERATION IS MAINTAINING";B9;"STARBASE";X$;" IN THE GALAXY" +7990 GOTO 5690 +8010 PRINT "YOUR STUPIDITY HAS LEFT YOU ON YOUR ON IN" +8020 PRINT " THE GALAXY -- YOU HAVE NO STARBASES LEFT!":GOTO 5690 +8060 REM TORPEDO, BASE NAV, D/D CALCULATOR +8070 IF K3<=0 THEN 4270 +8080 X$="":IF K3>1 THEN X$="S" +8090 PRINT "FROM ENTERPRISE TO KLINGON BATTLE CRUSER";X$ +8100 H8=0:FOR I=1 TO 3:IF K(I,3)<=0 THEN 8480 +8110 W1=K(I,1):X=K(I,2) +8120 C1=S1:A=S2:GOTO 8220 +8150 PRINT "DIRECTION/DISTANCE CALCULATOR:" +8160 PRINT "YOU ARE AT QUADRANT ";Q1;",";Q2;" SECTOR ";S1;",";S2 +8170 PRINT "PLEASE ENTER":INPUT" INITIAL COORDINATES (X,Y)";C1,A +8200 INPUT" FINAL COORDINATES (X,Y)";W1,X +8220 X=X-A:A=C1-W1:IF X<0 THEN 8350 +8250 IF A<0 THEN 8410 +8260 IF X>0 THEN 8280 +8270 IF A=0 THEN C1=5:GOTO 8290 +8280 C1=1 +8290 IF ABS(A)<=ABS(X) THEN 8330 +8310 PRINT "DIRECTION =";C1+(((ABS(A)-ABS(X))+ABS(A))/ABS(A)):GOTO 8460 +8330 PRINT "DIRECTION =";C1+(ABS(A)/ABS(X)):GOTO 8460 +8350 IF A>0 THEN C1=3:GOTO 8420 +8360 IF X<>0 THEN C1=5:GOTO 8290 +8410 C1=7 +8420 IF ABS(A)>=ABS(X) THEN 8450 +8430 PRINT "DIRECTION =";C1+(((ABS(X)-ABS(A))+ABS(X))/ABS(X)):GOTO 8460 +8450 PRINT "DIRECTION =";C1+(ABS(X)/ABS(A)) +8460 PRINT "DISTANCE =";SQR(X^2+A^2):IF H8=1 THEN 1990 +8480 NEXT I:GOTO 1990 +8500 IF B3<>0 THEN PRINT "FROM ENTERPRISE TO STARBASE:":W1=B4:X=B5:GOTO 8120 +8510 PRINT "MR. SPOCK REPORTS, 'SENSORS SHOW NO STARBASES IN THIS"; +8520 PRINT " QUADRANT.'":GOTO 1990 +8580 REM FIND EMPTY PLACE IN QUADRANT (FOR THINGS) +8590 R1=FNR(1):R2=FNR(1):A$=" ":Z1=R1:Z2=R2:GOSUB 8830:IF Z3=0 THEN 8590 +8600 RETURN +8660 REM INSERT IN STRING ARRAY FOR QUADRANT +8670 S8=INT(Z2-.5)*3+INT(Z1-.5)*24+1 +8675 IF LEN(A$)<>3 THEN PRINT "ERROR":STOP +8680 IF S8=1 THEN Q$=A$+RIGHT$(Q$,189):RETURN +8690 IF S8=190 THEN Q$=LEFT$(Q$,189)+A$:RETURN +8700 Q$=LEFT$(Q$,S8-1)+A$+RIGHT$(Q$,190-S8):RETURN +8780 REM PRINTS DEVICE NAME +8790 ON R1 GOTO 8792,8794,8796,8798,8800,8802,8804,8806 +8792 G2$="WARP ENGINES":RETURN +8794 G2$="SHORT RANGE SENSORS":RETURN +8796 G2$="LONG RANGE SENSORS":RETURN +8798 G2$="PHASER CONTROL":RETURN +8800 G2$="PHOTON TUBES":RETURN +8802 G2$="DAMAGE CONTROL":RETURN +8804 G2$="SHIELD CONTROL":RETURN +8806 G2$="LIBRARY-COMPUTER":RETURN +8820 REM STRING COMPARISON IN QUADRANT ARRAY +8830 Z1=INT(Z1+.5):Z2=INT(Z2+.5):S8=(Z2-1)*3+(Z1-1)*24+1:Z3=0 +8890 IF MID$(Q$,S8,3)<>A$ THEN RETURN +8900 Z3=1:RETURN +9010 REM QUADRANT NAME IN G2$ FROM Z4,Z5 (=Q1,Q2) +9020 REM CALL WITH G5=1 TO GET REGION NAME ONLY +9030 IF Z5<=4 THEN ON Z4 GOTO 9040,9050,9060,9070,9080,9090,9100,9110 +9035 GOTO 9120 +9040 G2$="ANTARES":GOTO 9210 +9050 G2$="RIGEL":GOTO 9210 +9060 G2$="PROCYON":GOTO 9210 +9070 G2$="VEGA":GOTO 9210 +9080 G2$="CANOPUS":GOTO 9210 +9090 G2$="ALTAIR":GOTO 9210 +9100 G2$="SAGITTARIUS":GOTO 9210 +9110 G2$="POLLUX":GOTO 9210 +9120 ON Z4 GOTO 9130,9140,9150,9160,9170,9180,9190,9200 +9130 G2$="SIRIUS":GOTO 9210 +9140 G2$="DENEB":GOTO 9210 +9150 G2$="CAPELLA":GOTO 9210 +9160 G2$="BETELGEUSE":GOTO 9210 +9170 G2$="ALDEBARAN":GOTO 9210 +9180 G2$="REGULUS":GOTO 9210 +9190 G2$="ARCTURUS":GOTO 9210 +9200 G2$="SPICA" +9210 IF G5<>1 THEN ON Z5 GOTO 9230,9240,9250,9260,9230,9240,9250,9260 +9220 RETURN +9230 G2$=G2$+" I":RETURN +9240 G2$=G2$+" II":RETURN +9250 G2$=G2$+" III":RETURN +9260 G2$=G2$+" IV":RETURN diff --git a/00_Alternate_Languages/84_Super_Star_Trek/superstartrekins.bas b/00_Alternate_Languages/84_Super_Star_Trek/superstartrekins.bas new file mode 100644 index 00000000..b3aa1daa --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/superstartrekins.bas @@ -0,0 +1,127 @@ +10 REM INSTRUCTIONS FOR "SUPER STARTREK" MAR 5, 1978 +20 FOR I=1 TO 12:PRINT:NEXT I +21 PRINT TAB(10);"*************************************" +22 PRINT TAB(10);"* *" +23 PRINT TAB(10);"* *" +30 PRINT TAB(10);"* * * SUPER STAR TREK * * *" +31 PRINT TAB(10);"* *" +32 PRINT TAB(10);"* *" +35 PRINT TAB(10);"*************************************" +36 FOR I=1 TO 8:PRINT:NEXT I +40 INPUT "DO YOU NEED INSTRUCTIONS (Y/N)";K$:IF K$="N" THEN 2000 +44 PRINT +45 REM PRINT "TURN THE TTY ON-LINE AND HIT ANY KEY EXCEPT RETURN" +46 REM IF INP(1)=13 THEN 46 +50 REM POKE 1229,2:POKE 1237,3:NULL 1 +90 PRINT" INSTRUCTIONS FOR 'SUPER STAR TREK'" +100 PRINT +110 PRINT"1. WHEN YOU SEE \COMMAND ?\ PRINTED, ENTER ONE OF THE LEGAL" +120 PRINT" COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX)." +130 PRINT"2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT" +140 PRINT" LIST OF THE LEGAL COMMANDS PRINTED OUT." +150 PRINT"3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE" +160 PRINT" 'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.) IF YOU" +170 PRINT" TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND" +180 PRINT" WILL BE ABORTED" +190 PRINT +270 PRINT" THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID," +280 PRINT"AND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID." +290 PRINT +300 PRINT" YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE" +310 PRINT"GALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP" +320 PRINT"\ENTERPRISE\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF" +330 PRINT"KLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF" +340 PRINT"PLANETS." +360 PRINT +370 PRINT" YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN" +380 PRINT"OF THE STARSHIP ENTERPRISE:" +385 PRINT +390 PRINT"\NAV\ COMMAND = WARP ENGINE CONTROL --" +400 PRINT" COURSE IS IN A CIRCULAR NUMERICAL 4 3 2" +410 PRINT" VECTOR ARRANGEMENT AS SHOWN . . ." +420 PRINT" INTEGER AND REAL VALUES MAY BE ..." +430 PRINT" USED. (THUS COURSE 1.5 IS HALF- 5 ---*--- 1" +440 PRINT" WAY BETWEEN 1 AND 2 ..." +450 PRINT" . . ." +460 PRINT" VALUES MAY APPROACH 9.0, WHICH 6 7 8" +470 PRINT" ITSELF IS EQUIVALENT TO 1.0" +480 PRINT" COURSE" +490 PRINT" ONE WARP FACTOR IS THE SIZE OF " +500 PRINT" ONE QUADTANT. THEREFORE, TO GET" +510 PRINT" FROM QUADRANT 6,5 TO 5,5, YOU WOULD" +520 PRINT" USE COURSE 3, WARP FACTOR 1." +530 PRINT +540 PRINT"\SRS\ COMMAND = SHORT RANGE SENSOR SCAN" +550 PRINT" SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT." +555 PRINT +560 PRINT" SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:" +570 PRINT" <*> = YOUR STARSHIP'S POSITION" +580 PRINT" +K+ = KLINGON BATTLE CRUISER" +590 PRINT" >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)" +600 PRINT" * = STAR" +605 PRINT +610 PRINT" A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED." +620 PRINT +640 PRINT"\LRS\ COMMAND = LONG RANGE SENSOR SCAN" +650 PRINT" SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE" +660 PRINT" OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)" +670 PRINT" THE SCAN IS CODED IN THE FORM \###\, WHERE TH UNITS DIGIT" +680 PRINT" IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF" +690 PRINT" STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF" +700 PRINT" KLINGONS." +705 PRINT +706 PRINT" EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS." +710 PRINT +720 PRINT"\PHA\ COMMAND = PHASER CONTROL." +730 PRINT" ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY " +740 PRINT" ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO" +750 PRINT" DEPLETE THEIR SHIELD POWER. (REMEMBER, KLINGONS HAVE" +760 PRINT" PHASERS TOO!)" +770 PRINT +780 PRINT"\TOR\ COMMAND = PHOTON TORPEDO CONTROL" +790 PRINT" TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL" +800 PRINT" IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND" +810 PRINT" CANNOT FIRE BACK AT YOU. IF YOU MISS, YOU ARE SUBJECT TO" +820 PRINT" HIS PHASER FIRE. IN EITHER CASE, YOU ARE ALSO SUBJECT TO " +825 PRINT" THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT." +830 PRINT +835 PRINT" THE LIBRARY-COMPUTER (\COM\ COMMAND) HAS AN OPTION TO " +840 PRINT" COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)" +850 PRINT +860 PRINT"\SHE\ COMMAND = SHIELD CONTROL" +870 PRINT" DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE" +880 PRINT" SHIELDS. ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY. NOTE" +890 PRINT" THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY" +900 PRINT +910 PRINT"\DAM\ COMMAND = DAMMAGE CONTROL REPORT" +920 PRINT" GIVES THE STATE OF REPAIR OF ALL DEVICES. WHERE A NEGATIVE" +930 PRINT" 'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY" +940 PRINT" DAMAGED." +950 PRINT +960 PRINT"\COM\ COMMAND = LIBRARY-COMPUTER" +970 PRINT" THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:" +980 PRINT" OPTION 0 = CUMULATIVE GALACTIC RECORD" +990 PRINT" THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL" +1000 PRINT" PREVIOUS SHORT AND LONG RANGE SENSOR SCANS" +1010 PRINT" OPTION 1 = STATUS REPORT" +1020 PRINT" THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES," +1030 PRINT" AND STARBASES REMAINING IN THE GAME." +1040 PRINT" OPTION 2 = PHOTON TORPEDO DATA" +1050 PRINT" WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE" +1060 PRINT" TO ALL KLINGONS IN YOUR QUADRANT" +1070 PRINT" OPTION 3 = STARBASE NAV DATA" +1080 PRINT" THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY " +1090 PRINT" STARBASE WITHIN YOUR QUADRANT" +1100 PRINT" OPTION 4 = DIRECTION/DISTANCE CALCULATOR" +1110 PRINT" THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR" +1120 PRINT" DIRECTION/DISTANCE CALCULATIONS" +1130 PRINT" OPTION 5 = GALACTIC /REGION NAME/ MAP" +1140 PRINT" THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR " +1150 PRINT" GALACTIC REGIONS REFERRED TO IN THE GAME." +1990 REM POKE 1229,0:POKE 1237,1:NULL 0 +2000 REM PRINT:PRINT:PRINT +2010 REM PRINT "TURN CASSETTE PLAYER ON AND HIT ANY KEY EXCEPT RETURN" +2020 REM IF INP(1)=13 THEN 2020 +2030 REM PRINT +2040 REM PRINT "TURN CASSETTE PLAYER OFF AND " +2050 REM PRINT "TYPE 'RUN' WHEN COMPUTER PRINTS 'OK'" diff --git a/00_Alternate_Languages/84_Super_Star_Trek/vbnet/README.md b/00_Alternate_Languages/84_Super_Star_Trek/vbnet/README.md new file mode 100644 index 00000000..98b702c7 --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/vbnet/README.md @@ -0,0 +1,3 @@ +Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET) diff --git a/00_Alternate_Languages/84_Super_Star_Trek/vbnet/SuperStarTrek.sln b/00_Alternate_Languages/84_Super_Star_Trek/vbnet/SuperStarTrek.sln new file mode 100644 index 00000000..82633753 --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/vbnet/SuperStarTrek.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "SuperStarTrek", "SuperStarTrek.vbproj", "{92825C31-5966-4E6A-9CB0-5AEEE3D6A2A4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {92825C31-5966-4E6A-9CB0-5AEEE3D6A2A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {92825C31-5966-4E6A-9CB0-5AEEE3D6A2A4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {92825C31-5966-4E6A-9CB0-5AEEE3D6A2A4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {92825C31-5966-4E6A-9CB0-5AEEE3D6A2A4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/00_Alternate_Languages/84_Super_Star_Trek/vbnet/SuperStarTrek.vbproj b/00_Alternate_Languages/84_Super_Star_Trek/vbnet/SuperStarTrek.vbproj new file mode 100644 index 00000000..1a4afed5 --- /dev/null +++ b/00_Alternate_Languages/84_Super_Star_Trek/vbnet/SuperStarTrek.vbproj @@ -0,0 +1,8 @@ + + + Exe + SuperStarTrek + net6.0 + 16.9 + + diff --git a/00_Alternate_Languages/85_Synonym/README.md b/00_Alternate_Languages/85_Synonym/README.md new file mode 100644 index 00000000..50a7a8b4 --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/README.md @@ -0,0 +1,9 @@ +Please refer to the `readme.md` in the parent folder. + +Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria: + +1. Popular (by TIOBE index) +2. Memory safe +3. Generally considered a 'scripting' language + +We welcome additional ports, but these additional ports are for educational purposes only. \ No newline at end of file diff --git a/00_Alternate_Languages/85_Synonym/csharp/README.md b/00_Alternate_Languages/85_Synonym/csharp/README.md new file mode 100644 index 00000000..4daabb5c --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/csharp/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/) diff --git a/00_Alternate_Languages/85_Synonym/csharp/Synonym.cs b/00_Alternate_Languages/85_Synonym/csharp/Synonym.cs new file mode 100644 index 00000000..1a90fd72 --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/csharp/Synonym.cs @@ -0,0 +1,149 @@ +using System.Text; + +namespace Synonym +{ + class Synonym + { + Random rand = new Random(); + + // Initialize list of corrent responses + private string[] Affirmations = { "Right", "Correct", "Fine", "Good!", "Check" }; + + // Initialize list of words and their synonyms + private string[][] Words = + { + new string[] {"first", "start", "beginning", "onset", "initial"}, + new string[] {"similar", "alike", "same", "like", "resembling"}, + new string[] {"model", "pattern", "prototype", "standard", "criterion"}, + new string[] {"small", "insignificant", "little", "tiny", "minute"}, + new string[] {"stop", "halt", "stay", "arrest", "check", "standstill"}, + new string[] {"house", "dwelling", "residence", "domicile", "lodging", "habitation"}, + new string[] {"pit", "hole", "hollow", "well", "gulf", "chasm", "abyss"}, + new string[] {"push", "shove", "thrust", "prod", "poke", "butt", "press"}, + new string[] {"red", "rouge", "scarlet", "crimson", "flame", "ruby"}, + new string[] {"pain", "suffering", "hurt", "misery", "distress", "ache", "discomfort"} + }; + + private void DisplayIntro() + { + Console.WriteLine(""); + Console.WriteLine("SYNONYM".PadLeft(23)); + Console.WriteLine("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + Console.WriteLine(""); + Console.WriteLine("A synonym of a word means another word in the English"); + Console.WriteLine("language which has the same or very nearly the same meaning."); + Console.WriteLine("I choose a word -- you type a synonym."); + Console.WriteLine("If you can't think of a synonym, type the word 'help'"); + Console.WriteLine("and I will tell you a synonym."); + Console.WriteLine(""); + } + + private void DisplayOutro() + { + Console.WriteLine("Synonym drill completed."); + } + + private void RandomizeTheList() + { + // Randomize the list of Words to pick from + int[] Order = new int[Words.Length]; + foreach (int i in Order) + { + Order[i] = rand.Next(); + } + Array.Sort(Order, Words); + } + + private string GetAnAffirmation() + { + return Affirmations[rand.Next(Affirmations.Length)]; + } + + private bool CheckTheResponse(string WordName, int WordIndex, string LineInput, string[] WordList) + { + if (LineInput.Equals("help")) + { + // Choose a random correct synonym response that doesn't equal the current word given + int HelpIndex = rand.Next(WordList.Length); + while (HelpIndex == WordIndex) + { + HelpIndex = rand.Next(0, WordList.Length); + } + Console.WriteLine("**** A synonym of {0} is {1}.", WordName, WordList[HelpIndex]); + + return false; + } + else + { + // Check to see if the response is one of the listed synonyms and not the current word prompt + if (WordList.Contains(LineInput) && LineInput != WordName) + { + // Randomly display one of the five correct answer exclamations + Console.WriteLine(GetAnAffirmation()); + + return true; + } + else + { + // Incorrect response. Try again. + Console.WriteLine(" Try again.".PadLeft(5)); + + return false; + } + } + } + + private string PromptForSynonym(string WordName) + { + Console.Write(" What is a synonym of {0}? ", WordName); + string LineInput = Console.ReadLine().Trim().ToLower(); + + return LineInput; + } + + private void AskForSynonyms() + { + Random rand = new Random(); + + // Loop through the now randomized list of Words and display a random word from each to prompt for a synonym + foreach (string[] WordList in Words) + { + int WordIndex = rand.Next(WordList.Length); // random word position in the current list of words + string WordName = WordList[WordIndex]; // what is that actual word + bool Success = false; + + while (!Success) + { + // Ask for the synonym of the current word + string LineInput = PromptForSynonym(WordName); + + // Check the response + Success = CheckTheResponse(WordName, WordIndex, LineInput, WordList); + + // Add extra line space for formatting + Console.WriteLine(""); + } + } + } + + public void PlayTheGame() + { + RandomizeTheList(); + + DisplayIntro(); + + AskForSynonyms(); + + DisplayOutro(); + } + } + class Program + { + static void Main(string[] args) + { + + new Synonym().PlayTheGame(); + + } + } +} diff --git a/00_Alternate_Languages/85_Synonym/csharp/Synonym.csproj b/00_Alternate_Languages/85_Synonym/csharp/Synonym.csproj new file mode 100644 index 00000000..1fd332a6 --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/csharp/Synonym.csproj @@ -0,0 +1,10 @@ + + + Exe + net6.0 + 10 + enable + enable + Synonym.Program + + diff --git a/00_Alternate_Languages/85_Synonym/csharp/Synonym.sln b/00_Alternate_Languages/85_Synonym/csharp/Synonym.sln new file mode 100644 index 00000000..69614aff --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/csharp/Synonym.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Synonym", "Synonym.csproj", "{9CCC22AC-EDF3-4137-8EF7-EBB2F8677CE4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9CCC22AC-EDF3-4137-8EF7-EBB2F8677CE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9CCC22AC-EDF3-4137-8EF7-EBB2F8677CE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9CCC22AC-EDF3-4137-8EF7-EBB2F8677CE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9CCC22AC-EDF3-4137-8EF7-EBB2F8677CE4}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/00_Alternate_Languages/85_Synonym/java/README.md b/00_Alternate_Languages/85_Synonym/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/85_Synonym/java/src/Synonym.java b/00_Alternate_Languages/85_Synonym/java/src/Synonym.java new file mode 100644 index 00000000..2804bb49 --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/java/src/Synonym.java @@ -0,0 +1,137 @@ +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Scanner; + +/** + * Game of Synonym + *

+ * Based on the Basic game of Synonym here + * https://github.com/coding-horror/basic-computer-games/blob/main/85%20Synonym/synonym.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. + */ +public class Synonym { + + public static final String[] RANDOM_ANSWERS = {"RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK"}; + + // Used for keyboard input + private final Scanner kbScanner; + + // List of words and synonyms + private final ArrayList synonyms; + + private enum GAME_STATE { + INIT, + PLAY, + GAME_OVER + } + + // Current game state + private GAME_STATE gameState; + + private int currentQuestion; + + public Synonym() { + + kbScanner = new Scanner(System.in); + synonyms = new ArrayList<>(); + + gameState = GAME_STATE.INIT; + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + case INIT: + intro(); + currentQuestion = 0; + + // Load data + synonyms.add(new SynonymList("FIRST", new String[]{"START", "BEGINNING", "ONSET", "INITIAL"})); + synonyms.add(new SynonymList("SIMILAR", new String[]{"SAME", "LIKE", "RESEMBLING"})); + synonyms.add(new SynonymList("MODEL", new String[]{"PATTERN", "PROTOTYPE", "STANDARD", "CRITERION"})); + synonyms.add(new SynonymList("SMALL", new String[]{"INSIGNIFICANT", "LITTLE", "TINY", "MINUTE"})); + synonyms.add(new SynonymList("STOP", new String[]{"HALT", "STAY", "ARREST", "CHECK", "STANDSTILL"})); + synonyms.add(new SynonymList("HOUSE", new String[]{"DWELLING", "RESIDENCE", "DOMICILE", "LODGING", "HABITATION"})); + synonyms.add(new SynonymList("PIT", new String[]{"HOLE", "HOLLOW", "WELL", "GULF", "CHASM", "ABYSS"})); + synonyms.add(new SynonymList("PUSH", new String[]{"SHOVE", "THRUST", "PROD", "POKE", "BUTT", "PRESS"})); + synonyms.add(new SynonymList("RED", new String[]{"ROUGE", "SCARLET", "CRIMSON", "FLAME", "RUBY"})); + synonyms.add(new SynonymList("PAIN", new String[]{"SUFFERING", "HURT", "MISERY", "DISTRESS", "ACHE", "DISCOMFORT"})); + + gameState = GAME_STATE.PLAY; + break; + + case PLAY: + + // Get the word and synonyms to ask a question about + SynonymList synonym = synonyms.get(currentQuestion); + String getAnswer = displayTextAndGetInput(" WHAT IS A SYNONYM OF " + synonym.getWord() + " ? "); + + // HELP is used to give a random synonym for the current word + if (getAnswer.equals("HELP")) { + int randomSynonym = (int) (Math.random() * synonym.size()); + System.out.println("**** A SYNONYM OF " + synonym.getWord() + " IS " + synonym.getSynonyms()[randomSynonym] + "."); + } else { + // Check if the entered word is in the synonym list + if (synonym.exists(getAnswer)) { + // If it is, give a random "correct" response + System.out.println(RANDOM_ANSWERS[(int) (Math.random() * RANDOM_ANSWERS.length)]); + currentQuestion++; + // Have we reached the final word/synonyms on file? + if (currentQuestion == synonyms.size()) { + // We have so end game. + System.out.println("SYNONYM DRILL COMPLETED."); + gameState = GAME_STATE.GAME_OVER; + } + } else { + // Word does not exist in the synonym list + System.out.println("TRY AGAIN."); + } + } + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + private void intro() { + System.out.println(simulateTabs(33) + "SYNONYM"); + System.out.println(simulateTabs(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH"); + System.out.println("LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME"); + System.out.println(" MEANING."); + System.out.println("I CHOOSE A WORD -- YOU TYPE A SYNONYM."); + System.out.println("IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'"); + System.out.println("AND I WILL TELL YOU A SYNONYM."); + System.out.println(); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * Converts input to uppercase. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next().toUpperCase(); + } + + /** + * Simulate the old basic tab(xx) command which indented text by xx spaces. + * + * @param spaces number of spaces required + * @return String with number of spaces + */ + private String simulateTabs(int spaces) { + char[] spacesTemp = new char[spaces]; + Arrays.fill(spacesTemp, ' '); + return new String(spacesTemp); + } +} diff --git a/00_Alternate_Languages/85_Synonym/java/src/SynonymGame.java b/00_Alternate_Languages/85_Synonym/java/src/SynonymGame.java new file mode 100644 index 00000000..8ad52f4b --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/java/src/SynonymGame.java @@ -0,0 +1,6 @@ +public class SynonymGame { + public static void main(String[] args) { + Synonym synonym = new Synonym(); + synonym.play(); + } +} diff --git a/00_Alternate_Languages/85_Synonym/java/src/SynonymList.java b/00_Alternate_Languages/85_Synonym/java/src/SynonymList.java new file mode 100644 index 00000000..d692d48a --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/java/src/SynonymList.java @@ -0,0 +1,46 @@ +import java.util.ArrayList; +import java.util.Arrays; + +/** + * Stores a word and a list of synonyms for that word + */ +public class SynonymList { + + private final String word; + + private final ArrayList synonyms; + + public SynonymList(String word, String[] synonyms) { + this.word = word; + this.synonyms = new ArrayList<>(Arrays.asList(synonyms)); + } + + /** + * Check if the word passed to this method exists in the list of synonyms + * N.B. Case insensitive + * + * @param word word to search for + * @return true if found, otherwise false + */ + public boolean exists(String word) { + return synonyms.stream().anyMatch(str -> str.equalsIgnoreCase(word)); + } + + public String getWord() { + return word; + } + + public int size() { + return synonyms.size(); + } + + /** + * Returns all synonyms for this word in string array format + * + * @return + */ + public String[] getSynonyms() { + // Parameter to toArray method determines type of the resultant array + return synonyms.toArray(new String[0]); + } +} diff --git a/00_Alternate_Languages/85_Synonym/javascript/README.md b/00_Alternate_Languages/85_Synonym/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/85_Synonym/javascript/synonym.html b/00_Alternate_Languages/85_Synonym/javascript/synonym.html new file mode 100644 index 00000000..ec24a89a --- /dev/null +++ b/00_Alternate_Languages/85_Synonym/javascript/synonym.html @@ -0,0 +1,9 @@ + + +SYNONYM + + +


+
+
+
diff --git a/00_Alternate_Languages/85_Synonym/javascript/synonym.js b/00_Alternate_Languages/85_Synonym/javascript/synonym.js
new file mode 100644
index 00000000..e48bf77f
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/javascript/synonym.js
@@ -0,0 +1,124 @@
+// SYNONYM
+//
+// 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 ra = [, "RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK"];
+var la = [];
+var tried = [];
+
+var synonym = [[5,"FIRST","START","BEGINNING","ONSET","INITIAL"],
+               [5,"SIMILAR","ALIKE","SAME","LIKE","RESEMBLING"],
+               [5,"MODEL","PATTERN","PROTOTYPE","STANDARD","CRITERION"],
+               [5,"SMALL","INSIGNIFICANT","LITTLE","TINY","MINUTE"],
+               [6,"STOP","HALT","STAY","ARREST","CHECK","STANDSTILL"],
+               [6,"HOUSE","DWELLING","RESIDENCE","DOMICILE","LODGING","HABITATION"],
+               [7,"PIT","HOLE","HOLLOW","WELL","GULF","CHASM","ABYSS"],
+               [7,"PUSH","SHOVE","THRUST","PROD","POKE","BUTT","PRESS"],
+               [6,"RED","ROUGE","SCARLET","CRIMSON","FLAME","RUBY"],
+               [7,"PAIN","SUFFERING","HURT","MISERY","DISTRESS","ACHE","DISCOMFORT"]
+               ];
+
+// Main program
+async function main()
+{
+    print(tab(33) + "SYNONYM\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    for (c = 0; c <= synonym.length; c++)
+        tried[c] = false;
+    print("A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH\n");
+    print("LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME");
+    print(" MEANING.\n");
+    print("I CHOOSE A WORD -- YOU TYPE A SYNONYM.\n");
+    print("IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'\n");
+    print("AND I WILL TELL YOU A SYNONYM.\n");
+    print("\n");
+    c = 0;
+    while (c < synonym.length) {
+        c++;
+        do {
+            n1 = Math.floor(Math.random() * synonym.length + 1);
+        } while (tried[n1]) ;
+        tried[n1] = true;
+        n2 = synonym[n1][0];    // Length of synonym list
+        // This array keeps a list of words not shown
+        for (j = 1; j <= n2; j++)
+            la[j] = j;
+        la[0] = n2;
+        g = 1;  // Always show first word
+        print("\n");
+        la[g] = la[la[0]];  // Replace first word with last word
+        la[0] = n2 - 1; // Reduce size of list by one.
+        print("\n");
+        while (1) {
+            print("     WHAT IS A SYNONYM OF " + synonym[n1][g]);
+            str = await input();
+            if (str == "HELP") {
+                g1 = Math.floor(Math.random() * la[0] + 1);
+                print("**** A SYNONYM OF " + synonym[n1][g] + " IS " + synonym[n1][la[g1]] + ".\n");
+                print("\n");
+                la[g1] = la[la[0]];
+                la[0]--;
+                continue;
+            }
+            for (k = 1; k <= n2; k++) {
+                if (g == k)
+                    continue;
+                if (str == synonym[n1][k])
+                    break;
+            }
+            if (k > n2) {
+                print("     TRY AGAIN.\n");
+            } else {
+                print(synonym[n1][Math.floor(Math.random() * 5 + 1)] + "\n");
+                break;
+            }
+        }
+    }
+    print("\n");
+    print("SYNONYM DRILL COMPLETED.\n");
+}
+
+main();
diff --git a/00_Alternate_Languages/85_Synonym/kotlin/README.md b/00_Alternate_Languages/85_Synonym/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/00_Alternate_Languages/85_Synonym/kotlin/Synonym.kt b/00_Alternate_Languages/85_Synonym/kotlin/Synonym.kt
new file mode 100644
index 00000000..e85b142a
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/kotlin/Synonym.kt
@@ -0,0 +1,73 @@
+/**
+ * Game of Synonym
+ *
+ *
+ * Based on the Basic game of Synonym here
+ * https://github.com/coding-horror/basic-computer-games/blob/main/85%20Synonym/synonym.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.
+ */
+
+fun main() {
+    println(introText)
+    synonyms.forEach {
+        it.testUser()
+    }
+    println("SYNONYM DRILL COMPLETED.")
+}
+// We could put this inside of SynonymList, but this keeps the core implementation
+// right here at the top
+private fun SynonymList.testUser() {
+    do {
+        val answer = ask("     WHAT IS A SYNONYM OF $word ? ")
+        when {
+            answer == "HELP" ->
+                println("""**** A SYNONYM OF $word IS ${synonyms.random()}.""")
+            synonyms.contains(answer) ->
+                println(AFFIRMATIONS.random())
+            else ->
+                println("TRY AGAIN.")
+        }
+    } while (!synonyms.contains(answer))
+}
+
+val introText = """
+${tab(33)}SYNONYM
+${tab(15)}CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH
+LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME
+ MEANING.
+I CHOOSE A WORD -- YOU TYPE A SYNONYM.
+IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'
+AND I WILL TELL YOU A SYNONYM.
+
+    """
+
+// prints a question and reads a string (and converts to uppercase)
+private fun ask(text: String): String {
+    print(text)
+    return readln().uppercase()
+}
+
+// Just like TAB in BASIC
+private fun tab(spaces: Int): String = " ".repeat(spaces)
+
+val AFFIRMATIONS = arrayOf("RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK")
+
+// List of words and synonyms
+private val synonyms = listOf(
+    SynonymList("FIRST", listOf("START", "BEGINNING", "ONSET", "INITIAL")),
+    SynonymList("SIMILAR", listOf("SAME", "LIKE", "RESEMBLING")),
+    SynonymList("MODEL", listOf("PATTERN", "PROTOTYPE", "STANDARD", "CRITERION")),
+    SynonymList("SMALL", listOf("INSIGNIFICANT", "LITTLE", "TINY", "MINUTE")),
+    SynonymList("STOP", listOf("HALT", "STAY", "ARREST", "CHECK", "STANDSTILL")),
+    SynonymList("HOUSE", listOf("DWELLING", "RESIDENCE", "DOMICILE", "LODGING", "HABITATION")),
+    SynonymList("PIT", listOf("HOLE", "HOLLOW", "WELL", "GULF", "CHASM", "ABYSS")),
+    SynonymList("PUSH", listOf("SHOVE", "THRUST", "PROD", "POKE", "BUTT", "PRESS")),
+    SynonymList("RED", listOf("ROUGE", "SCARLET", "CRIMSON", "FLAME", "RUBY")),
+    SynonymList("PAIN", listOf("SUFFERING", "HURT", "MISERY", "DISTRESS", "ACHE", "DISCOMFORT"))
+)
+
+class SynonymList(val word: String, val synonyms: List)
diff --git a/60_Mastermind/pascal/README.md b/00_Alternate_Languages/85_Synonym/pascal/README.md
similarity index 100%
rename from 60_Mastermind/pascal/README.md
rename to 00_Alternate_Languages/85_Synonym/pascal/README.md
diff --git a/00_Alternate_Languages/85_Synonym/perl/README.md b/00_Alternate_Languages/85_Synonym/perl/README.md
new file mode 100644
index 00000000..977a834a
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/perl/README.md
@@ -0,0 +1,7 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
+
+I used List::Util to do all the heavy work to show that perl can handle all the various
+array functions.  It would be interesting to see a version that handled all of this
+manually as there ended up being very little code left in this program.
diff --git a/00_Alternate_Languages/85_Synonym/perl/synonym.pl b/00_Alternate_Languages/85_Synonym/perl/synonym.pl
new file mode 100644
index 00000000..7b9ef90c
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/perl/synonym.pl
@@ -0,0 +1,57 @@
+#!/usr/bin/perl
+
+use v5.32; # for sample from List::Util, also includes 'use strict'
+use warnings; # always a good idea
+
+use List::Util qw/ any sample shuffle /; # Rather than write our own utilities, use the built in ones
+
+my @correct = qw/ Right Correct Fine Good! Check /;
+
+# lowercase all words here
+my @synonyms = (
+  [ qw/ first start beginning onset initial / ],
+  [ qw/ similar alike same like resembling / ],
+  [ qw/ model pattern prototype standard criterion /],
+  [ qw/ small insignificant little tiny minute /],
+  [ qw/ stop halt stay arrest check standstill /],
+  [ qw/ house dwelling residense domicile lodging habitation /],
+  [ qw/ pit hole hollow well gulf chasm abyss /],
+  [ qw/ push shove thrust prod poke butt press /],
+  [ qw/ red rouge scarlet crimson flame ruby /],
+  [ qw/ pain suffering hurt misery distress ache discomfort /],
+);
+
+print <<__END_OF_INTRO;
+                                 Synonym
+                Creative Computing  Morristown, New Jersey
+
+
+
+A synonym of a word means another word in the English
+language which has the same or very nearly the same meaning
+I choose a word -- you type a synonym.
+If you can't think of a synonym, type the word 'HELP'
+and I will tell you a synonym.
+
+__END_OF_INTRO
+
+foreach my $drill ( shuffle @synonyms ) {
+  my $word = $drill->[0];
+  my @answers = $drill->@[1 .. $drill->$#*];
+  print "     What is a synonym of $word? ";
+  my $response = <>;
+  chomp $response;
+  $response = lc $response;
+
+  if ( $response eq 'help' ) {
+    say "**** A synonym of $word is ", sample(1, @answers);
+    redo;
+  } elsif ( not any { $response eq $_ } @answers ) {
+    say '     Try again.';
+    redo;
+  } else {
+    say sample 1, @correct;
+  }
+}
+
+say "\nSynonym drill completed.";
diff --git a/00_Alternate_Languages/85_Synonym/python/README.md b/00_Alternate_Languages/85_Synonym/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/85_Synonym/python/synonym.py b/00_Alternate_Languages/85_Synonym/python/synonym.py
new file mode 100644
index 00000000..046758d6
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/python/synonym.py
@@ -0,0 +1,99 @@
+"""
+SYNONYM
+
+Vocabulary quiz
+
+Ported by Dave LeCompte
+"""
+
+import random
+
+PAGE_WIDTH = 64
+
+
+def print_centered(msg):
+    spaces = " " * ((PAGE_WIDTH - len(msg)) // 2)
+    print(spaces + msg)
+
+
+def print_header(title):
+    print_centered(title)
+    print_centered("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+
+def print_instructions():
+    print("A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH")
+    print("LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME MEANING.")
+    print("I CHOOSE A WORD -- YOU TYPE A SYNONYM.")
+    print("IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'")
+    print("AND I WILL TELL YOU A SYNONYM.")
+    print()
+
+
+right_words = ["RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK"]
+
+synonym_words = [
+    ["FIRST", "START", "BEGINNING", "ONSET", "INITIAL"],
+    ["SIMILAR", "ALIKE", "SAME", "LIKE", "RESEMBLING"],
+    ["MODEL", "PATTERN", "PROTOTYPE", "STANDARD", "CRITERION"],
+    ["SMALL", "INSIGNIFICANT", "LITTLE", "TINY", "MINUTE"],
+    ["STOP", "HALT", "STAY", "ARREST", "CHECK", "STANDSTILL"],
+    ["HOUSE", "DWELLING", "RESIDENCE", "DOMICILE", "LODGING", "HABITATION"],
+    ["PIT", "HOLE", "HOLLOW", "WELL", "GULF", "CHASM", "ABYSS"],
+    ["PUSH", "SHOVE", "THRUST", "PROD", "POKE", "BUTT", "PRESS"],
+    ["RED", "ROUGE", "SCARLET", "CRIMSON", "FLAME", "RUBY"],
+    ["PAIN", "SUFFERING", "HURT", "MISERY", "DISTRESS", "ACHE", "DISCOMFORT"],
+]
+
+
+def print_right():
+    print(random.choice(right_words))
+
+
+def ask_question(question_number):
+    words = synonym_words[question_number]
+    clues = words[:]
+    base_word = clues.pop(0)
+
+    while True:
+        question = f"     WHAT IS A SYNONYM OF {base_word}? "
+        response = input(question).upper()
+
+        if response == "HELP":
+            clue = random.choice(clues)
+            print(f"**** A SYNONYM OF {base_word} IS {clue}.")
+            print()
+
+            # remove the clue from available clues
+            clues.remove(clue)
+            continue
+
+        if (response != base_word) and (response in words):
+            print_right()
+            return
+
+
+def finish():
+    print()
+    print("SYNONYM DRILL COMPLETED.")
+
+
+def main():
+    print_header("SYNONYM")
+    print_instructions()
+
+    num_questions = len(synonym_words)
+    word_indices = list(range(num_questions))
+    random.shuffle(word_indices)
+
+    for word_number in word_indices:
+        ask_question(word_number)
+
+    finish()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/85_Synonym/ruby/README.md b/00_Alternate_Languages/85_Synonym/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/85_Synonym/ruby/synonim.rb b/00_Alternate_Languages/85_Synonym/ruby/synonim.rb
new file mode 100644
index 00000000..d155af5b
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/ruby/synonim.rb
@@ -0,0 +1,94 @@
+########################################################
+#
+# Synonym
+#
+# From Basic Computer Games (1978)
+#
+# A synonym of a word is another word (in the English language) which has the same,
+# or very nearly the same, meaning. This program tests your knowledge of synonyms
+# of a few common words.
+#
+# The computer chooses a word and asks you for a synonym. The computer then tells
+# you whether you’re right or wrong. If you can’t think of a synonym, type “HELP”
+# which causes a synonym to be printed.
+# You may put in words of your choice in the data statements.
+# The number following DATA in Statement 500 is the total number of data statements.
+# In each data statement, the first number is the number of words in that statement.
+#
+# Can you think of a way to make this into a more general kind of CAI program for any subject?
+# Walt Koetke of Lexington High School, Massachusetts created this program.
+#
+#
+########################################################
+
+puts <<~INSTRUCTIONS
+                                 SYNONYM
+                 CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+
+A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH
+LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME MEANING.
+I CHOOSE A WORD -- YOU TYPE A SYNONYM.
+IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'
+AND I WILL TELL YOU A SYNONYM.
+
+
+INSTRUCTIONS
+
+right_words = ["RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK"]
+
+synonym_words = [
+    ["FIRST", "START", "BEGINNING", "ONSET", "INITIAL"],
+    ["SIMILAR", "ALIKE", "SAME", "LIKE", "RESEMBLING"],
+    ["MODEL", "PATTERN", "PROTOTYPE", "STANDARD", "CRITERION"],
+    ["SMALL", "INSIGNIFICANT", "LITTLE", "TINY", "MINUTE"],
+    ["STOP", "HALT", "STAY", "ARREST", "CHECK", "STANDSTILL"],
+    ["HOUSE", "DWELLING", "RESIDENCE", "DOMICILE", "LODGING", "HABITATION"],
+    ["PIT", "HOLE", "HOLLOW", "WELL", "GULF", "CHASM", "ABYSS"],
+    ["PUSH", "SHOVE", "THRUST", "PROD", "POKE", "BUTT", "PRESS"],
+    ["RED", "ROUGE", "SCARLET", "CRIMSON", "FLAME", "RUBY"],
+    ["PAIN", "SUFFERING", "HURT", "MISERY", "DISTRESS", "ACHE", "DISCOMFORT"],
+]
+
+synonym_words.shuffle.each {|words_ar|
+
+}
+
+
+synonym_words.each {|words_ar|
+    answer = false
+    keyword = words_ar.shift
+
+    while not answer and words_ar.length != 0
+        puts "     WHAT IS A SYNONYM OF #{keyword}? "
+        inp = gets.chomp.upcase
+
+        if inp  == "HELP"
+            clue = words_ar.sample
+            puts "**** A SYNONYM OF #{keyword} IS #{clue}."
+            words_ar.delete(clue)
+        elsif words_ar.include? inp
+            puts right_words.sample
+            answer = true
+        else
+            puts "TRY AGAIN."
+        end
+
+    end
+
+}
+
+puts "SYNONYM DRILL COMPLETED"
+
+
+######################################################################
+#
+# Porting notes
+#
+#  There is a bug in the original program where if you keep asking for
+# synoyms of a given word it ends up running out of synonyms
+# in the array and the program crashes.
+#  The bug has been fixed in this version and now when
+# it runs out of words it continues with the next
+# array.
+#
+######################################################################
diff --git a/00_Alternate_Languages/85_Synonym/synonym.bas b/00_Alternate_Languages/85_Synonym/synonym.bas
new file mode 100644
index 00000000..868657d9
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/synonym.bas
@@ -0,0 +1,53 @@
+2 PRINT TAB(33);"SYNONYM"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT: PRINT: PRINT
+10 DIM R$(5),W$(10),L(30),R(30)
+20 R$(1)="RIGHT": R$(2)="CORRECT": R$(3)="FINE": R$(4)="GOOD!"
+30 R$(5)="CHECK"
+70 C=0
+90 PRINT "A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH"
+100 PRINT "LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME";
+110 PRINT " MEANING."
+130 PRINT "I CHOOSE A WORD -- YOU TYPE A SYNONYM."
+140 PRINT "IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'"
+145 PRINT "AND I WILL TELL YOU A SYNONYM.": PRINT
+150 RESTORE: C=C+1: READ N
+160 IF C>N THEN 420
+170 N1=INT(RND(1)*N+1)
+174 IF R(N1)=1 THEN 170
+176 R(N1)=1
+180 FOR I=1 TO N1
+190 READ N2
+200 FOR J=1 TO N2
+210 READ W$(J)
+220 NEXT J
+230 NEXT I
+232 FOR J=1 TO N2: L(J)=J: NEXT J
+235 L(0)=N2: G=1: PRINT
+237 L(G)=L(L(0)): L(0)=N2-1: PRINT
+240 PRINT "     WHAT IS A SYNONYM OF ";W$(G);: INPUT A$
+250 IF A$="HELP" THEN 340
+260 FOR K=1 TO N2
+270 IF G=K THEN 290
+280 IF A$=W$(K) THEN 320
+290 NEXT K
+300 PRINT "     TRY AGAIN.": GOTO 240
+320 PRINT R$(INT(RND(1)*5+1)): GOTO 150
+340 G1=INT(RND(1)*L(0)+1)
+360 PRINT "**** A SYNONYM OF ";W$(G);" IS ";W$(L(G1));".": PRINT
+370 L(G1)=L(L(0)): L(0)=L(0)-1: GOTO 240
+420 PRINT: PRINT "SYNONYM DRILL COMPLETED.": GOTO 999
+500 DATA 10
+510 DATA 5,"FIRST","START","BEGINNING","ONSET","INITIAL"
+520 DATA 5,"SIMILAR","ALIKE","SAME","LIKE","RESEMBLING"
+530 DATA 5,"MODEL","PATTERN","PROTOTYPE","STANDARD","CRITERION"
+540 DATA 5,"SMALL","INSIGNIFICANT","LITTLE","TINY","MINUTE"
+550 DATA 6,"STOP","HALT","STAY","ARREST","CHECK","STANDSTILL"
+560 DATA 6,"HOUSE","DWELLING","RESIDENCE","DOMICILE","LODGING"
+565 DATA "HABITATION"
+570 DATA 7,"PIT","HOLE","HOLLOW","WELL","GULF","CHASM","ABYSS"
+580 DATA 7,"PUSH","SHOVE","THRUST","PROD","POKE","BUTT","PRESS"
+590 DATA 6,"RED","ROUGE","SCARLET","CRIMSON","FLAME","RUBY"
+600 DATA 7,"PAIN","SUFFERING","HURT","MISERY","DISTRESS","ACHE"
+605 DATA "DISCOMFORT"
+999 END
diff --git a/00_Alternate_Languages/85_Synonym/vbnet/README.md b/00_Alternate_Languages/85_Synonym/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/85_Synonym/vbnet/Synonym.sln b/00_Alternate_Languages/85_Synonym/vbnet/Synonym.sln
new file mode 100644
index 00000000..8b55f812
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/vbnet/Synonym.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Synonym", "Synonym.vbproj", "{E6BEB53F-F6A3-4AA9-8EB9-68D8238DFAA6}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{E6BEB53F-F6A3-4AA9-8EB9-68D8238DFAA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E6BEB53F-F6A3-4AA9-8EB9-68D8238DFAA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E6BEB53F-F6A3-4AA9-8EB9-68D8238DFAA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E6BEB53F-F6A3-4AA9-8EB9-68D8238DFAA6}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/85_Synonym/vbnet/Synonym.vbproj b/00_Alternate_Languages/85_Synonym/vbnet/Synonym.vbproj
new file mode 100644
index 00000000..8c920a56
--- /dev/null
+++ b/00_Alternate_Languages/85_Synonym/vbnet/Synonym.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Synonym
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/86_Target/README.md b/00_Alternate_Languages/86_Target/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/86_Target/csharp/Angle.cs b/00_Alternate_Languages/86_Target/csharp/Angle.cs
new file mode 100644
index 00000000..a14dd782
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/Angle.cs
@@ -0,0 +1,18 @@
+namespace Target
+{
+    internal class Angle
+    {
+        // Use same precision for constants as original code
+        private const float PI = 3.14159f;
+        private const float DegreesPerRadian = 57.296f;
+
+        private readonly float _radians;
+
+        private Angle(float radians) => _radians = radians;
+
+        public static Angle InDegrees(float degrees) => new (degrees / DegreesPerRadian);
+        public static Angle InRotations(float rotations) => new (2 * PI * rotations);
+
+        public static implicit operator float(Angle angle) => angle._radians;
+    }
+}
diff --git a/00_Alternate_Languages/86_Target/csharp/Explosion.cs b/00_Alternate_Languages/86_Target/csharp/Explosion.cs
new file mode 100644
index 00000000..89a94a93
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/Explosion.cs
@@ -0,0 +1,22 @@
+namespace Target
+{
+    internal class Explosion
+    {
+        private readonly Point _position;
+
+        public Explosion(Point position, Offset targetOffset)
+        {
+            _position = position;
+            FromTarget = targetOffset;
+            DistanceToTarget = targetOffset.Distance;
+        }
+
+        public Point Position => _position;
+        public Offset FromTarget { get; }
+        public float DistanceToTarget { get; }
+        public string GetBearing() => _position.GetBearing();
+
+        public bool IsHit => DistanceToTarget <= 20;
+        public bool IsTooClose => _position.Distance < 20;
+    }
+}
diff --git a/00_Alternate_Languages/86_Target/csharp/FiringRange.cs b/00_Alternate_Languages/86_Target/csharp/FiringRange.cs
new file mode 100644
index 00000000..b8a6399c
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/FiringRange.cs
@@ -0,0 +1,24 @@
+using Games.Common.Randomness;
+
+namespace Target
+{
+    internal class FiringRange
+    {
+        private readonly IRandom _random;
+        private Point _targetPosition;
+
+        public FiringRange(IRandom random)
+        {
+            _random = random;
+        }
+
+        public Point NextTarget() =>  _targetPosition = _random.NextPosition();
+
+        public Explosion Fire(Angle angleFromX, Angle angleFromZ, float distance)
+        {
+            var explosionPosition = new Point(angleFromX, angleFromZ, distance);
+            var targetOffset = explosionPosition - _targetPosition;
+            return new (explosionPosition, targetOffset);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/86_Target/csharp/Game.cs b/00_Alternate_Languages/86_Target/csharp/Game.cs
new file mode 100644
index 00000000..4bb4f9b2
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/Game.cs
@@ -0,0 +1,92 @@
+using System;
+using Games.Common.IO;
+
+namespace Target
+{
+    internal class Game
+    {
+        private readonly IReadWrite _io;
+        private readonly FiringRange _firingRange;
+        private int _shotCount;
+
+        public Game(IReadWrite io, FiringRange firingRange)
+        {
+            _io = io;
+            _firingRange = firingRange;
+        }
+
+        public void Play()
+        {
+            _shotCount = 0;
+            var target = _firingRange.NextTarget();
+            _io.WriteLine(target.GetBearing());
+            _io.WriteLine($"Target sighted: approximate coordinates:  {target}");
+
+            while (true)
+            {
+                _io.WriteLine($"     Estimated distance: {target.EstimateDistance()}");
+                _io.WriteLine();
+
+                var explosion = Shoot();
+
+                if (explosion.IsTooClose)
+                {
+                    _io.WriteLine("You blew yourself up!!");
+                    return;
+                }
+
+                _io.WriteLine(explosion.GetBearing());
+
+                if (explosion.IsHit)
+                {
+                    ReportHit(explosion.DistanceToTarget);
+                    return;
+                }
+
+                ReportMiss(explosion);
+            }
+        }
+
+        private Explosion Shoot()
+        {
+            var (xDeviation, zDeviation, distance) = _io.Read3Numbers(
+                "Input angle deviation from X, angle deviation from Z, distance");
+            _shotCount++;
+            _io.WriteLine();
+
+            return _firingRange.Fire(Angle.InDegrees(xDeviation), Angle.InDegrees(zDeviation), distance);
+        }
+
+        private void ReportHit(float distance)
+        {
+            _io.WriteLine();
+            _io.WriteLine($" * * * HIT * * *   Target is non-functional");
+            _io.WriteLine();
+            _io.WriteLine($"Distance of explosion from target was {distance} kilometers.");
+            _io.WriteLine();
+            _io.WriteLine($"Mission accomplished in {_shotCount} shots.");
+        }
+
+        private void ReportMiss(Explosion explosion)
+        {
+            ReportMiss(explosion.FromTarget);
+            _io.WriteLine($"Approx position of explosion:  {explosion.Position}");
+            _io.WriteLine($"     Distance from target = {explosion.DistanceToTarget}");
+            _io.WriteLine();
+            _io.WriteLine();
+            _io.WriteLine();
+        }
+
+        private void ReportMiss(Offset targetOffset)
+        {
+            ReportMiss(targetOffset.DeltaX, "in front of", "behind");
+            ReportMiss(targetOffset.DeltaY, "to left of", "to right of");
+            ReportMiss(targetOffset.DeltaZ, "above", "below");
+        }
+
+        private void ReportMiss(float delta, string positiveText, string negativeText) =>
+            _io.WriteLine(delta >= 0 ? GetOffsetText(positiveText, delta) : GetOffsetText(negativeText, -delta));
+
+        private static string GetOffsetText(string text, float distance) => $"Shot {text} target {distance} kilometers.";
+    }
+}
diff --git a/00_Alternate_Languages/86_Target/csharp/Offset.cs b/00_Alternate_Languages/86_Target/csharp/Offset.cs
new file mode 100644
index 00000000..2bd8710c
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/Offset.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Target
+{
+    internal class Offset
+    {
+        public Offset(float deltaX, float deltaY, float deltaZ)
+        {
+            DeltaX = deltaX;
+            DeltaY = deltaY;
+            DeltaZ = deltaZ;
+
+            Distance = (float)Math.Sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ + deltaZ);
+        }
+
+        public float DeltaX { get; }
+        public float DeltaY { get; }
+        public float DeltaZ { get; }
+        public float Distance { get; }
+    }
+}
diff --git a/00_Alternate_Languages/86_Target/csharp/Point.cs b/00_Alternate_Languages/86_Target/csharp/Point.cs
new file mode 100644
index 00000000..f004b1c4
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/Point.cs
@@ -0,0 +1,47 @@
+using System;
+
+namespace Target
+{
+    internal class Point
+    {
+        private readonly float _angleFromX;
+        private readonly float _angleFromZ;
+
+        private readonly float _x;
+        private readonly float _y;
+        private readonly float _z;
+
+        private int _estimateCount;
+
+        public Point(Angle angleFromX, Angle angleFromZ, float distance)
+        {
+            _angleFromX = angleFromX;
+            _angleFromZ = angleFromZ;
+            Distance = distance;
+
+            _x = distance * (float)Math.Sin(_angleFromZ) * (float)Math.Cos(_angleFromX);
+            _y = distance * (float)Math.Sin(_angleFromZ) * (float)Math.Sin(_angleFromX);
+            _z = distance * (float)Math.Cos(_angleFromZ);
+        }
+
+        public float Distance { get; }
+
+        public float EstimateDistance() =>
+            ++_estimateCount switch
+            {
+                1 => EstimateDistance(20),
+                2 => EstimateDistance(10),
+                3 => EstimateDistance(5),
+                4 => EstimateDistance(1),
+                _ => Distance
+            };
+
+        public float EstimateDistance(int precision) => (float)Math.Floor(Distance / precision) * precision;
+
+        public string GetBearing() => $"Radians from X axis = {_angleFromX}   from Z axis = {_angleFromZ}";
+
+        public override string ToString() => $"X= {_x}   Y = {_y}   Z= {_z}";
+
+        public static Offset operator -(Point p1, Point p2) => new (p1._x - p2._x, p1._y - p2._y, p1._z - p2._z);
+    }
+}
diff --git a/00_Alternate_Languages/86_Target/csharp/Program.cs b/00_Alternate_Languages/86_Target/csharp/Program.cs
new file mode 100644
index 00000000..cafa559a
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/Program.cs
@@ -0,0 +1,43 @@
+using System;
+using System.Reflection;
+using Games.Common.IO;
+using Games.Common.Randomness;
+
+namespace Target
+{
+    class Program
+    {
+        static void Main()
+        {
+            var io = new ConsoleIO();
+            var game = new Game(io, new FiringRange(new RandomNumberGenerator()));
+
+            Play(game, io, () => true);
+        }
+
+        public static void Play(Game game, TextIO io, Func playAgain)
+        {
+            DisplayTitleAndInstructions(io);
+
+            while (playAgain())
+            {
+                game.Play();
+
+                io.WriteLine();
+                io.WriteLine();
+                io.WriteLine();
+                io.WriteLine();
+                io.WriteLine();
+                io.WriteLine("Next target...");
+                io.WriteLine();
+            }
+        }
+
+        private static void DisplayTitleAndInstructions(TextIO io)
+        {
+            using var stream = Assembly.GetExecutingAssembly()
+                .GetManifestResourceStream("Target.Strings.TitleAndInstructions.txt");
+            io.Write(stream);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/86_Target/csharp/README.md b/00_Alternate_Languages/86_Target/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/86_Target/csharp/RandomExtensions.cs b/00_Alternate_Languages/86_Target/csharp/RandomExtensions.cs
new file mode 100644
index 00000000..a76b0279
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/RandomExtensions.cs
@@ -0,0 +1,12 @@
+using Games.Common.Randomness;
+
+namespace Target
+{
+    internal static class RandomExtensions
+    {
+        public static Point NextPosition(this IRandom rnd) => new (
+            Angle.InRotations(rnd.NextFloat()),
+            Angle.InRotations(rnd.NextFloat()),
+            100000 * rnd.NextFloat() + rnd.NextFloat());
+    }
+}
diff --git a/00_Alternate_Languages/86_Target/csharp/Strings/TitleAndInstructions.txt b/00_Alternate_Languages/86_Target/csharp/Strings/TitleAndInstructions.txt
new file mode 100644
index 00000000..f883ac7a
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/Strings/TitleAndInstructions.txt
@@ -0,0 +1,16 @@
+                                 Target
+               Creative Computing  Morristown, New Jersey
+
+
+
+You are the weapons officer on the Starship Enterprise
+and this is a test to see how accurate a shot you
+are in a three-dimensional range.  You will be told
+the radian offset for the X and Z axes, the location
+of the target in three dimensional rectangular coordinates,
+the approximate number of degrees from the X and Z
+axes, and the approximate distance to the target.
+You will then proceed to shoot at the target until it is
+destroyed!
+
+Good luck!!
diff --git a/00_Alternate_Languages/86_Target/csharp/Target.csproj b/00_Alternate_Languages/86_Target/csharp/Target.csproj
new file mode 100644
index 00000000..ea8ff526
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/Target.csproj
@@ -0,0 +1,16 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+  
+    
+  
+
+  
+    
+  
+
+
diff --git a/00_Alternate_Languages/86_Target/csharp/Target.sln b/00_Alternate_Languages/86_Target/csharp/Target.sln
new file mode 100644
index 00000000..9aa2c86d
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/csharp/Target.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Target", "Target.csproj", "{DF03CFDB-2857-4416-A07A-80D84874F46E}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{DF03CFDB-2857-4416-A07A-80D84874F46E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DF03CFDB-2857-4416-A07A-80D84874F46E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DF03CFDB-2857-4416-A07A-80D84874F46E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DF03CFDB-2857-4416-A07A-80D84874F46E}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {B49DF932-4DF9-44C3-B63F-FD9443B4DDD2}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/86_Target/java/README.md b/00_Alternate_Languages/86_Target/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/86_Target/java/Target.java b/00_Alternate_Languages/86_Target/java/Target.java
new file mode 100644
index 00000000..4a60005d
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/java/Target.java
@@ -0,0 +1,144 @@
+import java.util.Scanner;
+
+/**
+ * TARGET
+ * 

+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm) + */ +public class Target { + + private static final double RADIAN = 180 / Math.PI; + + public static void main(String[] args) { + Scanner scan = new Scanner(System.in); + + printIntro(); + + //continue till the user aborts + while (true) { + int numberShots = 0; + + final double xAxisInRadians = Math.random() * 2 * Math.PI; + final double yAxisInRadians = Math.random() * 2 * Math.PI; + System.out.printf("RADIANS FROM X AXIS = %.7f FROM Z AXIS = %.7f\n", xAxisInRadians, yAxisInRadians); + + final double p1 = 100000 * Math.random() + Math.random(); + final double x = Math.sin(yAxisInRadians) * Math.cos(xAxisInRadians) * p1; + final double y = Math.sin(yAxisInRadians) * Math.sin(xAxisInRadians) * p1; + final double z = Math.cos(yAxisInRadians) * p1; + System.out.printf("TARGET SIGHTED: APPROXIMATE COORDINATES: X=%.3f Y=%.3f Z=%.3f\n", x, y, z); + boolean targetOrSelfDestroyed = false; + while (!targetOrSelfDestroyed) { + numberShots++; + int estimatedDistance = 0; + switch (numberShots) { + case 1: + estimatedDistance = (int) (p1 * .05) * 20; + break; + case 2: + estimatedDistance = (int) (p1 * .1) * 10; + break; + case 3: + estimatedDistance = (int) (p1 * .5) * 2; + break; + case 4: + case 5: + estimatedDistance = (int) (p1); + break; + } + + System.out.printf(" ESTIMATED DISTANCE: %s\n\n", estimatedDistance); + + final TargetAttempt targetAttempt = readInput(scan); + if (targetAttempt.distance < 20) { + System.out.println("YOU BLEW YOURSELF UP!!"); + targetOrSelfDestroyed = true; + } else { + final double a1 = targetAttempt.xDeviation / RADIAN; + final double b1 = targetAttempt.zDeviation / RADIAN; + System.out.printf("RADIANS FROM X AXIS = %.7f FROM Z AXIS = %.7f\n", a1, b1); + + final double x1 = targetAttempt.distance * Math.sin(b1) * Math.cos(a1); + final double y1 = targetAttempt.distance * Math.sin(b1) * Math.sin(a1); + final double z1 = targetAttempt.distance * Math.cos(b1); + + double distance = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y) + (z1 - z) * (z1 - z)); + if (distance > 20) { + double X2 = x1 - x; + double Y2 = y1 - y; + double Z2 = z1 - z; + if (X2 < 0) { + System.out.printf("SHOT BEHIND TARGET %.7f KILOMETERS.\n", -X2); + } else { + System.out.printf("SHOT IN FRONT OF TARGET %.7f KILOMETERS.\n", X2); + } + if (Y2 < 0) { + System.out.printf("SHOT TO RIGHT OF TARGET %.7f KILOMETERS.\n", -Y2); + } else { + System.out.printf("SHOT TO LEFT OF TARGET %.7f KILOMETERS.\n", Y2); + } + if (Z2 < 0) { + System.out.printf("SHOT BELOW TARGET %.7f KILOMETERS.\n", -Z2); + } else { + System.out.printf("SHOT ABOVE TARGET %.7f KILOMETERS.\n", Z2); + } + System.out.printf("APPROX POSITION OF EXPLOSION: X=%.7f Y=%.7f Z=%.7f\n", x1, y1, z1); + System.out.printf(" DISTANCE FROM TARGET =%.7f\n\n\n\n", distance); + } else { + System.out.println(" * * * HIT * * * TARGET IS NON-FUNCTIONAL"); + System.out.printf("DISTANCE OF EXPLOSION FROM TARGET WAS %.5f KILOMETERS.\n", distance); + System.out.printf("MISSION ACCOMPLISHED IN %s SHOTS.\n", numberShots); + targetOrSelfDestroyed = true; + } + } + } + System.out.println("\n\n\n\n\nNEXT TARGET...\n"); + } + } + + private static TargetAttempt readInput(Scanner scan) { + System.out.println("INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE "); + boolean validInput = false; + TargetAttempt targetAttempt = new TargetAttempt(); + while (!validInput) { + String input = scan.nextLine(); + final String[] split = input.split(","); + try { + targetAttempt.xDeviation = Float.parseFloat(split[0]); + targetAttempt.zDeviation = Float.parseFloat(split[1]); + targetAttempt.distance = Float.parseFloat(split[2]); + validInput = true; + } catch (NumberFormatException nfe) { + System.out.println("!NUMBER EXPECTED - RETRY INPUT LINE\n? "); + } + + } + return targetAttempt; + } + + private static void printIntro() { + System.out.println(" TARGET"); + System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + System.out.println("YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE"); + System.out.println("AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU"); + System.out.println("ARE IN A THREE-DIMENSIONAL RANGE. YOU WILL BE TOLD"); + System.out.println("THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION"); + System.out.println("OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,"); + System.out.println("THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z"); + System.out.println("AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET."); + System.out.println("YOU WILL THEN PROCEED TO SHOOT AT THE TARGET UNTIL IT IS"); + System.out.println("DESTROYED!"); + System.out.println("\nGOOD LUCK!!\n\n"); + } + + /** + * Represents the user input + */ + private static class TargetAttempt { + + double xDeviation; + double zDeviation; + double distance; + } +} diff --git a/00_Alternate_Languages/86_Target/javascript/README.md b/00_Alternate_Languages/86_Target/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/86_Target/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/86_Target/javascript/target.html b/00_Alternate_Languages/86_Target/javascript/target.html new file mode 100644 index 00000000..97bba5ea --- /dev/null +++ b/00_Alternate_Languages/86_Target/javascript/target.html @@ -0,0 +1,9 @@ + + +TARGET + + +


+
+
+
diff --git a/00_Alternate_Languages/86_Target/javascript/target.js b/00_Alternate_Languages/86_Target/javascript/target.js
new file mode 100644
index 00000000..f32fc6b9
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/javascript/target.js
@@ -0,0 +1,157 @@
+// TARGET
+//
+// 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(33) + "TARGET\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    r = 0;  // 1 in original
+    r1 = 57.296;
+    p = Math.PI;
+    print("YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE\n");
+    print("AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU\n");
+    print("ARE IN A THREE-DIMENSIONAL RANGE.  YOU WILL BE TOLD\n");
+    print("THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION\n");
+    print("OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,\n");
+    print("THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z\n");
+    print("AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET.\n");
+    print("YOU WILL THEN PROCEEED TO SHOOT AT THE TARGET UNTIL IT IS\n");
+    print("DESTROYED!\n");
+    print("\n");
+    print("GOOD LUCK!!\n");
+    print("\n");
+    print("\n");
+    while (1) {
+        a = Math.random() * 2 * p;
+        b = Math.random() * 2 * p;
+        q = Math.floor(a * r1);
+        w = Math.floor(b * r1);
+        print("RADIANS FROM X AXIS = " + a + "   FROM Z AXIS = " + b + "\n");
+        p1 = 100000 * Math.random() + Math.random();
+        x = Math.sin(b) * Math.cos(a) * p1;
+        y = Math.sin(b) * Math.sin(a) * p1;
+        z = Math.cos(b) * p1;
+        print("TARGET SIGHTED: APPROXIMATE COORDINATES:  X=" + x + "  Y=" + y + "  Z=" + z + "\n");
+        while (1) {
+            r++;
+            switch (r) {
+                case 1:
+                    p3 = Math.floor(p1 * 0.05) * 20;
+                    break;
+                case 2:
+                    p3 = Math.floor(p1 * 0.1) * 10;
+                    break;
+                case 3:
+                    p3 = Math.floor(p1 * 0.5) * 2;
+                    break;
+                case 4:
+                    p3 = Math.floor(p1);
+                    break;
+                case 5:
+                    p3 = p1;
+                    break;
+            }
+            print("     ESTIMATED DISTANCE: " + p3 + "\n");
+            print("\n");
+            print("INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE");
+            str = await input();
+            a1 = parseInt(str);
+            b1 = parseInt(str.substr(str.indexOf(",") + 1));
+            p2 = parseInt(str.substr(str.lastIndexOf(",") + 1));
+            print("\n");
+            if (p2 < 20) {
+                print("YOU BLEW YOURSELF UP!!\n");
+                break;
+            }
+            a1 /= r1;
+            b1 /= r1;
+            print("RADIANS FROM X AXIS = " + a1 + "  ");
+            print("FROM Z AXIS = " + b1 + "\n");
+            x1 = p2 * Math.sin(b1) * Math.cos(a1);
+            y1 = p2 * Math.sin(b1) * Math.sin(a1);
+            z1 = p2 * Math.cos(b1);
+            d = Math.sqrt((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y) + (z1 - z) * (z1 - z));
+            if (d <= 20) {
+                print("\n");
+                print(" * * * HIT * * *   TARGET IS NON-FUNCTIONAL\n");
+                print("\n");
+                print("DISTANCE OF EXPLOSION FROM TARGET WAS " + d + " KILOMETERS.");
+                print("\n");
+                print("MISSION ACCOMPLISHED IN " + r + " SHOTS.\n");
+                r = 0;
+                for (i = 1; i <= 5; i++)
+                    print("\n");
+                print("NEXT TARGET...\n");
+                print("\n");
+                break;
+            }
+            x2 = x1 - x;
+            y2 = y1 - y;
+            z2 = z1 - z;
+            if (x2 >= 0)
+                print("SHOT IN FRONT OF TARGET " + x2 + " KILOMETERS.\n");
+            else
+                print("SHOT BEHIND TARGET " + -x2 + " KILOMETERS.\n");
+            if (y2 >= 0)
+                print("SHOT TO LEFT OF TARGET " + y2 + " KILOMETERS.\n");
+            else
+                print("SHOT TO RIGHT OF TARGET " + -y2 + " KILOMETERS.\n");
+            if (z2 >= 0)
+                print("SHOT ABOVE TARGET " + z2 + " KILOMETERS.\n");
+            else
+                print("SHOT BELOW TARGET " + -z2 + " KILOMETERS.\n");
+            print("APPROX POSITION OF EXPLOSION:  X=" + x1 + "   Y=" + y1 + "   Z=" + z1 + "\n");
+            print("     DISTANCE FROM TARGET = " + d + "\n");
+            print("\n");
+            print("\n");
+            print("\n");
+        }
+    }
+}
+
+main();
diff --git a/62_Mugwump/pascal/README.md b/00_Alternate_Languages/86_Target/pascal/README.md
similarity index 100%
rename from 62_Mugwump/pascal/README.md
rename to 00_Alternate_Languages/86_Target/pascal/README.md
diff --git a/00_Alternate_Languages/86_Target/perl/README.md b/00_Alternate_Languages/86_Target/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/86_Target/python/README.md b/00_Alternate_Languages/86_Target/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/86_Target/python/target.py b/00_Alternate_Languages/86_Target/python/target.py
new file mode 100644
index 00000000..055891b0
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/python/target.py
@@ -0,0 +1,171 @@
+"""
+TARGET
+
+Weapon targeting simulation / 3d trigonometry practice
+
+Ported by Dave LeCompte
+"""
+
+import math
+import random
+
+PAGE_WIDTH = 64
+
+
+def print_centered(msg):
+    spaces = " " * ((PAGE_WIDTH - len(msg)) // 2)
+    print(spaces + msg)
+
+
+def print_header(title):
+    print_centered(title)
+    print_centered("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+
+
+def print_instructions():
+    print("YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE")
+    print("AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU")
+    print("ARE IN A THREE-DIMENSIONAL RANGE.  YOU WILL BE TOLD")
+    print("THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION")
+    print("OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,")
+    print("THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z")
+    print("AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET.")
+    print("YOU WILL THEN PROCEEED TO SHOOT AT THE TARGET UNTIL IT IS")
+    print("DESTROYED!")
+    print()
+    print("GOOD LUCK!!")
+    print()
+    print()
+
+
+def prompt():
+    while True:
+        response = input("INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE? ")
+        if not ("," in response):
+            continue
+
+        terms = response.split(",")
+        if len(terms) != 3:
+            continue
+
+        return [float(t) for t in terms]
+
+
+def next_target():
+    for i in range(5):
+        print()
+    print("NEXT TARGET...")
+    print()
+
+
+def describe_miss(x, y, z, x1, y1, z1, d):
+    x2 = x1 - x
+    y2 = y1 - y
+    z2 = z1 - z
+
+    if x2 < 0:
+        print(f"SHOT BEHIND TARGET {-x2:.2f} KILOMETERS.")
+    else:
+        print(f"SHOT IN FRONT OF TARGET {x2:.2f} KILOMETERS.")
+
+    if y2 < 0:
+        print(f"SHOT TO RIGHT OF TARGET {-y2:.2f} KILOMETERS.")
+    else:
+        print(f"SHOT TO LEFT OF TARGET {y2:.2f} KILOMETERS.")
+
+    if z2 < 0:
+        print(f"SHOT BELOW TARGET {-z2:.2f} KILOMETERS.")
+    else:
+        print(f"SHOT ABOVE TARGET {z2:.2f} KILOMETERS.")
+
+    print(f"APPROX POSITION OF EXPLOSION:  X={x1:.4f}   Y={y1:.4f}   Z={z1:.4f}")
+    print(f"     DISTANCE FROM TARGET = {d:.2f}")
+    print()
+    print()
+    print()
+
+
+def do_shot_loop(p1, x, y, z):
+    shot_count = 0
+    while True:
+        shot_count += 1
+        if shot_count == 1:
+            p3 = int(p1 * 0.05) * 20
+        elif shot_count == 2:
+            p3 = int(p1 * 0.1) * 10
+        elif shot_count == 3:
+            p3 = int(p1 * 0.5) * 2
+        elif shot_count == 4:
+            p3 = int(p1)
+        else:
+            p3 = p1
+
+        if p3 == int(p3):
+            print(f"     ESTIMATED DISTANCE: {p3}")
+        else:
+            print(f"     ESTIMATED DISTANCE: {p3:.2f}")
+        print()
+        a1, b1, p2 = prompt()
+
+        if p2 < 20:
+            print("YOU BLEW YOURSELF UP!!")
+            return
+
+        a1 = math.radians(a1)
+        b1 = math.radians(b1)
+        show_radians(a1, b1)
+
+        x1 = p2 * math.sin(b1) * math.cos(a1)
+        y1 = p2 * math.sin(b1) * math.sin(a1)
+        z1 = p2 * math.cos(b1)
+
+        distance = math.sqrt((x1 - x) ** 2 + (y1 - y) ** 2 + (z1 - z) ** 2)
+
+        if distance <= 20:
+            print()
+            print(" * * * HIT * * *   TARGET IS NON FUNCTIONAL")
+            print()
+            print(f"DISTANCE OF EXPLOSION FROM TARGET WAS {distance:.4f} KILOMETERS")
+            print()
+            print(f"MISSION ACCOMPLISHED IN {shot_count} SHOTS.")
+
+            return
+        else:
+            describe_miss(x, y, z, x1, y1, z1, distance)
+
+
+def show_radians(a, b):
+    print(f"RADIANS FROM X AXIS = {a:.4f}   FROM Z AXIS = {b:.4f}")
+
+
+def play_game():
+    while True:
+        a = random.uniform(0, 2 * math.pi)  # random angle
+        b = random.uniform(0, 2 * math.pi)  # random angle
+
+        show_radians(a, b)
+
+        p1 = random.uniform(0, 100000) + random.uniform(0, 1)
+        x = math.sin(b) * math.cos(a) * p1
+        y = math.sin(b) * math.sin(a) * p1
+        z = math.cos(b) * p1
+        print(
+            f"TARGET SIGHTED: APPROXIMATE COORDINATES:  X={x:.1f}  Y={y:.1f}  Z={z:.1f}"
+        )
+
+        do_shot_loop(p1, x, y, z)
+        next_target()
+
+
+def main():
+    print_header("TARGET")
+    print_instructions()
+
+    play_game()
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/86_Target/ruby/README.md b/00_Alternate_Languages/86_Target/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/86_Target/target.bas b/00_Alternate_Languages/86_Target/target.bas
new file mode 100644
index 00000000..7e99d3bb
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/target.bas
@@ -0,0 +1,51 @@
+10 PRINT TAB(33);"TARGET"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT: PRINT: PRINT
+100 R=1: R1=57.296: P=3.14159
+110 PRINT "YOU ARE THE WEAPONS OFFICER ON THE STARSHIP ENTERPRISE"
+120 PRINT "AND THIS IS A TEST TO SEE HOW ACCURATE A SHOT YOU"
+130 PRINT "ARE IN A THREE-DIMENSIONAL RANGE.  YOU WILL BE TOLD"
+140 PRINT "THE RADIAN OFFSET FOR THE X AND Z AXES, THE LOCATION"
+150 PRINT "OF THE TARGET IN THREE DIMENSIONAL RECTANGULAR COORDINATES,"
+160 PRINT "THE APPROXIMATE NUMBER OF DEGREES FROM THE X AND Z"
+170 PRINT "AXES, AND THE APPROXIMATE DISTANCE TO THE TARGET."
+180 PRINT "YOU WILL THEN PROCEEED TO SHOOT AT THE TARGET UNTIL IT IS"
+190 PRINT "DESTROYED!": PRINT: PRINT "GOOD LUCK!!":PRINT: PRINT
+220 A=RND(1)*2*P: B=RND(1)*2*P: Q=INT(A*R1): W=INT(B*R1)
+260 PRINT "RADIANS FROM X AXIS =";A;"   FROM Z AXIS =";B
+280 P1=100000*RND(1)+RND(1): X=SIN(B)*COS(A)*P1: Y=SIN(B)*SIN(A)*P1
+290 Z=COS(B)*P1
+340 PRINT "TARGET SIGHTED: APPROXIMATE COORDINATES:  X=";X;"  Y=";Y;"  Z=";Z
+345 R=R+1: IF R>5 THEN 390
+350 ON R GOTO 355,360,365,370,375
+355 P3=INT(P1*.05)*20: GOTO 390
+360 P3=INT(P1*.1)*10: GOTO 390
+365 P3=INT(P1*.5)*2: GOTO 390
+370 P3=INT(P1): GOTO 390
+375 P3=P1
+390 PRINT "     ESTIMATED DISTANCE:";P3
+400 PRINT:PRINT "INPUT ANGLE DEVIATION FROM X, DEVIATION FROM Z, DISTANCE";
+405 INPUT A1,B1,P2
+410 PRINT: IF P2<20 THEN PRINT "YOU BLEW YOURSELF UP!!": GOTO 580
+420 A1=A1/R1: B1=B1/R1: PRINT "RADIANS FROM X AXIS =";A1;"  ";
+425 PRINT "FROM Z AXIS =";B1
+480 X1=P2*SIN(B1)*COS(A1): Y1=P2*SIN(B1)*SIN(A1): Z1=P2*COS(B1)
+510 D=((X1-X)^2+(Y1-Y)^2+(Z1-Z)^2)^(1/2)
+520 IF D>20 THEN 670
+530 PRINT: PRINT " * * * HIT * * *   TARGET IS NON-FUNCTIONAL": PRINT
+550 PRINT "DISTANCE OF EXPLOSION FROM TARGET WAS";D;"KILOMETERS."
+570 PRINT: PRINT "MISSION ACCOMPLISHED IN ";R;" SHOTS."
+580 R=0: FOR I=1 TO 5: PRINT: NEXT I: PRINT "NEXT TARGET...": PRINT
+590 GOTO 220
+670 X2=X1-X: Y2=Y1-Y: Z2=Z1-Z: IF X2<0 THEN 730
+710 PRINT "SHOT IN FRONT OF TARGET";X2;"KILOMETERS.": GOTO 740
+730 PRINT "SHOT BEHIND TARGET";-X2;"KILOMETERS."
+740 IF Y2<0 THEN 770
+750 PRINT "SHOT TO LEFT OF TARGET";Y2;"KILOMETERS.": GOTO 780
+770 PRINT "SHOT TO RIGHT OF TARGET";-Y2;"KILOMETERS."
+780 IF Z2<0 THEN 810
+790 PRINT "SHOT ABOVE TARGET";Z2;"KILOMETERS.": GOTO 820
+810 PRINT "SHOT BELOW TARGET";-Z2;"KILOMETERS."
+820 PRINT "APPROX POSITION OF EXPLOSION:  X=";X1;"   Y=";Y1;"   Z=";Z1
+830 PRINT "     DISTANCE FROM TARGET =";D: PRINT: PRINT: PRINT: GOTO 345
+999 END
diff --git a/00_Alternate_Languages/86_Target/vbnet/README.md b/00_Alternate_Languages/86_Target/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/86_Target/vbnet/Target.sln b/00_Alternate_Languages/86_Target/vbnet/Target.sln
new file mode 100644
index 00000000..3b1edd8c
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/vbnet/Target.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Target", "Target.vbproj", "{48A62242-16CC-4BFC-B7DB-C2DAE3C13B5A}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{48A62242-16CC-4BFC-B7DB-C2DAE3C13B5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{48A62242-16CC-4BFC-B7DB-C2DAE3C13B5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{48A62242-16CC-4BFC-B7DB-C2DAE3C13B5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{48A62242-16CC-4BFC-B7DB-C2DAE3C13B5A}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/86_Target/vbnet/Target.vbproj b/00_Alternate_Languages/86_Target/vbnet/Target.vbproj
new file mode 100644
index 00000000..21a19379
--- /dev/null
+++ b/00_Alternate_Languages/86_Target/vbnet/Target.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Target
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/87_3-D_Plot/3dplot.bas b/00_Alternate_Languages/87_3-D_Plot/3dplot.bas
new file mode 100644
index 00000000..4ee0f8a5
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/3dplot.bas
@@ -0,0 +1,17 @@
+1 PRINT TAB(32);"3D PLOT"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+5 DEF FNA(Z)=30*EXP(-Z*Z/100)
+100 PRINT
+110 FOR X=-30 TO 30 STEP 1.5
+120 L=0
+130 Y1=5*INT(SQR(900-X*X)/5)
+140 FOR Y=Y1 TO -Y1 STEP -5
+150 Z=INT(25+FNA(SQR(X*X+Y*Y))-.7*Y)
+160 IF Z<=L THEN 190
+170 L=Z
+180 PRINT TAB(Z);"*";
+190 NEXT Y
+200 PRINT
+210 NEXT X
+300 END
diff --git a/00_Alternate_Languages/87_3-D_Plot/README.md b/00_Alternate_Languages/87_3-D_Plot/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/87_3-D_Plot/csharp/Function.cs b/00_Alternate_Languages/87_3-D_Plot/csharp/Function.cs
new file mode 100644
index 00000000..3a459d4e
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/csharp/Function.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+
+namespace Plot
+{
+    internal static class Function
+    {
+        internal static IEnumerable> GetRows()
+        {
+            for (var x = -30f; x <= 30f; x += 1.5f)
+            {
+                yield return GetValues(x);
+            }
+        }
+
+        private static IEnumerable GetValues(float x)
+        {
+            var zPrevious = 0;
+            var yLimit = 5 * (int)(Math.Sqrt(900 - x * x) / 5);
+
+            for (var y = yLimit; y >= -yLimit; y -= 5)
+            {
+                var z = GetValue(x, y);
+
+                if (z > zPrevious)
+                {
+                    zPrevious = z;
+                    yield return z;
+                }
+            }
+        }
+
+        private static int GetValue(float x, float y)
+        {
+            var r = (float)Math.Sqrt(x * x + y * y);
+            return (int)(25 + 30 * Math.Exp(-r * r / 100) - 0.7f * y);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/87_3-D_Plot/csharp/Plot.csproj b/00_Alternate_Languages/87_3-D_Plot/csharp/Plot.csproj
new file mode 100644
index 00000000..20827042
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/csharp/Plot.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+
diff --git a/00_Alternate_Languages/87_3-D_Plot/csharp/Plot.sln b/00_Alternate_Languages/87_3-D_Plot/csharp/Plot.sln
new file mode 100644
index 00000000..b296ace9
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/csharp/Plot.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Plot", "Plot.csproj", "{8000A3CF-612D-4FB7-B53D-885BB6E5492B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{8000A3CF-612D-4FB7-B53D-885BB6E5492B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8000A3CF-612D-4FB7-B53D-885BB6E5492B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8000A3CF-612D-4FB7-B53D-885BB6E5492B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8000A3CF-612D-4FB7-B53D-885BB6E5492B}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {5DE8E572-67C9-4DE3-B851-447B78FE983A}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/87_3-D_Plot/csharp/Program.cs b/00_Alternate_Languages/87_3-D_Plot/csharp/Program.cs
new file mode 100644
index 00000000..132c41ef
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/csharp/Program.cs
@@ -0,0 +1,38 @@
+using System;
+
+namespace Plot
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            PrintTitle();
+
+            foreach (var row in Function.GetRows())
+            {
+                foreach (var z in row)
+                {
+                    Plot(z);
+                }
+                Console.WriteLine();
+            }
+        }
+
+        private static void PrintTitle()
+        {
+            Console.WriteLine("                                3D Plot");
+            Console.WriteLine("               Creative Computing  Morristown, New Jersey");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+        }
+
+        private static void Plot(int z)
+        {
+            var x = Console.GetCursorPosition().Top;
+            Console.SetCursorPosition(z, x);
+            Console.Write("*");
+        }
+    }
+}
diff --git a/00_Alternate_Languages/87_3-D_Plot/csharp/README.md b/00_Alternate_Languages/87_3-D_Plot/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/87_3-D_Plot/d/.gitignore b/00_Alternate_Languages/87_3-D_Plot/d/.gitignore
new file mode 100644
index 00000000..d969f6b2
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/d/.gitignore
@@ -0,0 +1,2 @@
+*.exe
+*.obj
diff --git a/00_Alternate_Languages/87_3-D_Plot/d/README.md b/00_Alternate_Languages/87_3-D_Plot/d/README.md
new file mode 100644
index 00000000..8a01faf3
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/d/README.md
@@ -0,0 +1,182 @@
+Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).
+
+## Running the code
+
+Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:
+```shell
+dmd -dip1000 -run threedeeplot.d
+```
+
+[Other compilers](https://dlang.org/download.html) also exist.
+
+## On rounding floating point values to integer values
+
+The D equivalent of Basic `INT` is [`floor`](https://dlang.org/phobos/std_math_rounding.html#.floor),
+which rounds towards negative infinity. If you change occurrences of `floor` to
+[`lrint`](https://dlang.org/phobos/std_math_rounding.html#.lrint), you'll see that the plots show a bit more detail,
+as is done in the bonus below.
+
+## Bonus: Self-writing programs
+
+With a small modification to the source, the program can be extended to **plot a random function**, and **print its formula**.
+
+```shell
+rdmd -dip1000 threedeeplot_random.d
+```
+(`rdmd` caches the executable, which results in speedy execution when the source does not change.)
+
+### Example output
+```
+                                    3D Plot
+              (After Creative Computing  Morristown, New Jersey)
+
+
+                           f(z) = 30 * sin(z / 10.0)
+
+                             *
+                      *      *    * *
+                *         *      *    * *
+                    *         *      *    * *
+            *           *        *       *   *  *
+               *           *         *      *   *  *
+                  *           *         *     *    * **
+       *             *           *        *      *   *  *
+         *              *           *       *     *   *  **
+            *              *          *       *    *   *  * *
+              *              *          *      *   *   *  *  *
+                *              *          *     *  *  *   *   **
+                  *              *         *    * *  *   *    * *
+   *                *             *        *    ** *    *     * *
+    *                *             *        *  **     *      *   *
+     *                 *            *       * *     *       *    *
+      *                 *            *      * *   *         *    *
+       *                *             *     ** *           *     **
+        *                *            *     **            *      **
+        *                *            *     *            *       **
+        *                *            *     *            *       **
+        *                *            *     *            *       **
+        *                *            *     **            *      **
+       *                *             *     ** *           *     **
+      *                 *            *      * *   *         *    *
+     *                 *            *       * *     *       *    *
+    *                *             *        *  **     *      *   *
+   *                *             *        *    ** *    *     * *
+                  *              *         *    * *  *   *    * *
+                *              *          *     *  *  *   *   **
+              *              *          *      *   *   *  *  *
+            *              *          *       *    *   *  * *
+         *              *           *       *     *   *  **
+       *             *           *        *      *   *  *
+                  *           *         *     *    * **
+               *           *         *      *   *  *
+            *           *        *       *   *  *
+                    *         *      *    * *
+                *         *      *    * *
+                      *      *    * *
+                             *
+```
+
+### Breakdown of differences
+
+Have a look at the relevant differences between `threedeeplot.d` and `threedeeplot_random.d`.
+This is the original function with the single expression that is evaluated for the plot:
+```d
+    static float fna(float z)
+    {
+        return 30.0 * exp(-z * z / 100.0);
+    }
+```
+Here `static` means that the nested function does not need acces to its enclosing scope.
+
+Now, by inserting the following:
+```d
+    enum functions = ["30.0 * exp(-z * z / 100.0)",
+                      "sqrt(900.01 - z * z) * .9 - 2",
+                      "30 * (cos(z / 16.0) + .5)",
+                      "30 - 30 * sin(z / 18.0)",
+                      "30 * exp(-cos(z / 16.0)) - 30",
+                      "30 * sin(z / 10.0)"];
+
+    size_t index = uniform(0, functions.length);
+    writeln(center("f(z) = " ~ functions[index], width), "\n");
+```
+and changing the implementation of `fna` to
+```d
+    float fna(float z)
+    {
+        final switch (index)
+        {
+            static foreach (i, f; functions)
+                case i:
+                    mixin("return " ~ f ~ ";");
+        }
+    }
+```
+we unlock some very special abilities of D. Let's break it down:
+
+```d
+    enum functions = ["30.0 * exp(-z * z / 100.0)", /*...*/];
+```
+This defines an array of strings, each containing a mathematical expression. Due to the `enum` keyword, this is an
+array that really only exists at compile-time.
+
+```d
+    size_t index = uniform(0, functions.length);
+```
+This defines a random index into the array. `functions.length` is evaluated at compile-time, due to D's compile-time
+function evaluation (CTFE).
+
+```d
+    writeln(center("f(z) = " ~ functions[index], width), "\n");
+```
+Unmistakenly, this prints the formula centered on a line. What happens behind the scenes is that `functions` (which
+only existed at compile-time before now) is pasted in, so that an instance of that array actually exists at run-time
+at this spot, and is instantly indexed.
+
+```d
+    float fna(float z)
+    {
+        final switch (index)
+        {
+            // ...
+        }
+    }
+```
+`static` has been dropped from the nested function because we want to evaluate `index` inside it. The function contains
+an ordinary `switch`, with `final` providing some extra robustness. It disallows a `default` case and produces an error
+when the switch doesn't handle all cases. The `switch` body is where the magic happens and consists of these three
+lines:
+```d
+            static foreach (i, f; functions)
+                case i:
+                    mixin("return " ~ f ~ ";");
+```
+The `static foreach` iterates over `functions` at compile-time, producing one `case` for every element in `functions`.
+`mixin` takes a string, which is constructed at compile-time, and pastes it right into the source.
+
+In effect, the implementation of `float fna(float z)` unrolls itself into
+```d
+    float fna(float z)
+    {
+        final switch (index)
+        {
+            case 0:
+                return 30.0 * exp(-z * z / 100.0);
+            case 1:
+                return sqrt(900.01 - z * z) * .9 - 2;
+            case 2:
+                return 30 * (cos(z / 16.0) + .5);
+            case 3:
+                return 30 - 30 * sin(z / 18.0);
+            case 4:
+                return 30 * exp(-cos(z / 16.0)) - 30;
+            case 5:
+                return 30 * sin(z / 10.0)";
+        }
+    }
+```
+
+So if you feel like adding another function, all you need to do is append it to the `functions` array, and the rest of
+the program *rewrites itself...*
diff --git a/00_Alternate_Languages/87_3-D_Plot/d/threedeeplot.d b/00_Alternate_Languages/87_3-D_Plot/d/threedeeplot.d
new file mode 100644
index 00000000..a3660321
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/d/threedeeplot.d
@@ -0,0 +1,35 @@
+@safe: // Make @safe the default for this file, enforcing memory-safety.
+import std.stdio, std.string, std.math, std.range, std.conv, std.algorithm;
+
+void main()
+{
+    enum width = 80;
+    writeln(center("3D Plot", width));
+    writeln(center("(After Creative Computing  Morristown, New Jersey)\n\n\n", width));
+
+    static float fna(float z)
+    {
+        return 30.0 * exp(-z * z / 100.0);
+    }
+
+    char[] row;
+
+    for (float x = -30.0; x <= 30.0; x += 1.5)
+    {
+        size_t max_z = 0L;
+        auto y1 = 5 * floor((sqrt(900 - x * x)) / 5.0);
+        for (float y = y1; y >= -y1; y -= 5)
+        {
+            auto z = to!size_t(max(0, floor(25 + fna(sqrt(x * x + y * y)) - .7 * y)));
+            if (z > max_z) // Visible
+            {
+                max_z = z;
+                if (z + 1 > row.length) // row needs to grow
+                    row ~= ' '.repeat(z + 1 - row.length).array;
+                row[z] = '*';
+            }
+        }
+        writeln(row);
+        row = null;
+    }
+}
diff --git a/00_Alternate_Languages/87_3-D_Plot/d/threedeeplot_random.d b/00_Alternate_Languages/87_3-D_Plot/d/threedeeplot_random.d
new file mode 100644
index 00000000..3db1a2cd
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/d/threedeeplot_random.d
@@ -0,0 +1,50 @@
+@safe: // Make @safe the default for this file, enforcing memory-safety.
+import std.stdio, std.string, std.math, std.range, std.conv, std.random, std.algorithm;
+
+void main()
+{
+    enum width = 80;
+    writeln(center("3D Plot", width));
+    writeln(center("(After Creative Computing  Morristown, New Jersey)\n\n", width));
+
+    enum functions = ["30.0 * exp(-z * z / 100.0)",
+                      "sqrt(900.01 - z * z) * .9 - 2",
+                      "30 * (cos(z / 16.0) + .5)",
+                      "30 - 30 * sin(z / 18.0)",
+                      "30 * exp(-cos(z / 16.0)) - 30",
+                      "30 * sin(z / 10.0)"];
+
+    size_t index = uniform(0, functions.length);
+    writeln(center("f(z) = " ~ functions[index], width), "\n");
+
+    float fna(float z)
+    {
+        final switch (index)
+        {
+            static foreach (i, f; functions)
+                case i:
+                    mixin("return " ~ f ~ ";");
+        }
+    }
+
+    char[] row;
+
+    for (float x = -30.0; x <= 30.0; x += 1.5)
+    {
+        size_t max_z = 0L;
+        auto y1 = 5 * lrint((sqrt(900 - x * x)) / 5.0);
+        for (float y = y1; y >= -y1; y -= 5)
+        {
+            auto z = to!size_t(max(0, lrint(25 + fna(sqrt(x * x + y * y)) - .7 * y)));
+            if (z > max_z) // Visible
+            {
+                max_z = z;
+                if (z + 1 > row.length) // row needs to grow
+                    row ~= ' '.repeat(z + 1 - row.length).array;
+                row[z] = '*';
+            }
+        }
+        writeln(row);
+        row = null;
+    }
+}
diff --git a/00_Alternate_Languages/87_3-D_Plot/java/Plot3D.java b/00_Alternate_Languages/87_3-D_Plot/java/Plot3D.java
new file mode 100644
index 00000000..ee9b0234
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/java/Plot3D.java
@@ -0,0 +1,97 @@
+import java.lang.Math;
+
+/**
+ * Game of 3-D Plot
+ * 

+ * Based on the BASIC game of 3-D Plot here + * https://github.com/coding-horror/basic-computer-games/blob/main/87%203-D%20Plot/3dplot.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. + */ + +// Java class names cannot begin with a letter, so class name 3dplot cannot be used +public class Plot3D { + + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + + private void showIntro() { + + System.out.println(" ".repeat(31) + "3D PLOT"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n\n"); + + } // End of method showIntro + + + private void startGame() { + + float row = 0; + int column = 0; + int limit = 0; + int plotVal = 0; + int root = 0; + + String lineContent = ""; + + // Begin loop through all rows + for (row = -30; row <= 30; row += 1.5) { + + limit = 0; + + root = 5 * (int) Math.floor((Math.sqrt(900 - row * row) / 5)); + + // Begin loop through all columns + for (column = root; column >= -root; column += -5) { + + plotVal = 25 + (int) Math.floor(func(Math.sqrt(row * row + column * column)) - 0.7 * column); + + if (plotVal > limit) { + + limit = plotVal; + + // Add whitespace + while (lineContent.length() < (plotVal-1)) { + lineContent += " "; + } + + lineContent += "*"; + + } + + } // End loop through all columns + + System.out.println(lineContent); + + lineContent = ""; + + } // End loop through all rows + + } // End of method startGame + + + // Function to be plotted + public double func(double inputVal) { + + return (30 * Math.exp(-inputVal * inputVal / 100)); + + } + + + public static void main(String[] args) { + + Plot3D plot = new Plot3D(); + plot.play(); + + } // End of method main + +} // End of class Plot3D diff --git a/00_Alternate_Languages/87_3-D_Plot/java/README.md b/00_Alternate_Languages/87_3-D_Plot/java/README.md new file mode 100644 index 00000000..51edd8d4 --- /dev/null +++ b/00_Alternate_Languages/87_3-D_Plot/java/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [Oracle Java](https://openjdk.java.net/) diff --git a/00_Alternate_Languages/87_3-D_Plot/javascript/3dplot.html b/00_Alternate_Languages/87_3-D_Plot/javascript/3dplot.html new file mode 100644 index 00000000..003096bf --- /dev/null +++ b/00_Alternate_Languages/87_3-D_Plot/javascript/3dplot.html @@ -0,0 +1,9 @@ + + +3D PLOT + + +


+
+
+
diff --git a/00_Alternate_Languages/87_3-D_Plot/javascript/3dplot.js b/00_Alternate_Languages/87_3-D_Plot/javascript/3dplot.js
new file mode 100644
index 00000000..aac5b5e1
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/javascript/3dplot.js
@@ -0,0 +1,40 @@
+// 3D PLOT
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+function print(str)
+{
+	document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function tab(space)
+{
+	var str = "";
+	while (space-- > 0)
+		str += " ";
+	return str;
+}
+
+function equation(input)
+{
+	return 30 * Math.exp(-input * input / 100);
+}
+
+print(tab(32) + "3D PLOT\n");
+print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+
+for (x = -30; x <= 30; x += 1.5) {
+	l = 0;
+	y1 = 5 * Math.floor(Math.sqrt(900 - x * x) / 5);
+	str = "";
+	for (y = y1; y >= -y1; y -= 5) {
+		z = Math.floor(25 + equation(Math.sqrt(x * x + y * y)) - .7 * y);
+		if (z > l) {
+			l = z;
+			while (str.length < z)
+				str += " ";
+			str += "*";
+		}
+	}
+	print(str + "\n");
+}
diff --git a/00_Alternate_Languages/87_3-D_Plot/javascript/README.md b/00_Alternate_Languages/87_3-D_Plot/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/63_Name/pascal/README.md b/00_Alternate_Languages/87_3-D_Plot/pascal/README.md
similarity index 100%
rename from 63_Name/pascal/README.md
rename to 00_Alternate_Languages/87_3-D_Plot/pascal/README.md
diff --git a/00_Alternate_Languages/87_3-D_Plot/perl/3dplot.pl b/00_Alternate_Languages/87_3-D_Plot/perl/3dplot.pl
new file mode 100644
index 00000000..a7cfb1c6
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/perl/3dplot.pl
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+print ' 'x32 ."3D PLOT\n";
+print ' 'x15 ."CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+
+sub FNA {
+	my ($Z)= @_;
+	return 30*exp(-$Z*$Z/100);
+	}
+
+print "\n";
+
+for (my $X=-30; $X<=30; $X+=1.5) {
+	my $L=0;
+	my $Line=" "x80; #Empty buffer string;
+	my $Y1=5*int(sqrt(900-$X*$X)/5);
+	for (my $Y=$Y1; $Y>=-$Y1; $Y-=5) {
+		my $Z=int(25+&FNA(sqrt($X*$X+$Y*$Y))-.7*$Y);
+		if ($Z<=$L) { next; }
+		$L= $Z;
+		substr $Line, $Z, 1, "*"; #Plot on the line by sustitution.
+		}
+	print "$Line\n"; #Now print the line.
+	}
diff --git a/00_Alternate_Languages/87_3-D_Plot/perl/README.md b/00_Alternate_Languages/87_3-D_Plot/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/87_3-D_Plot/python/3dplot.py b/00_Alternate_Languages/87_3-D_Plot/python/3dplot.py
new file mode 100644
index 00000000..c53e9508
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/python/3dplot.py
@@ -0,0 +1,28 @@
+#!/usr/bin/env python3
+
+# 3D PLOT
+#
+# Converted from BASIC to Python by Trevor Hobson
+
+from math import exp, floor, sqrt
+
+
+def equation(x: float) -> float:
+    return 30 * exp(-x * x / 100)
+
+
+print(" " * 32 + "3D PLOT")
+print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\n")
+
+for x in range(-300, 315, 15):
+    x1 = x / 10
+    max_column = 0
+    y1 = 5 * floor(sqrt(900 - x1 * x1) / 5)
+    y_plot = [" "] * 80
+
+    for y in range(y1, -(y1 + 5), -5):
+        column = floor(25 + equation(sqrt(x1 * x1 + y * y)) - 0.7 * y)
+        if column > max_column:
+            max_column = column
+            y_plot[column] = "*"
+    print("".join(y_plot))
diff --git a/00_Alternate_Languages/87_3-D_Plot/python/README.md b/00_Alternate_Languages/87_3-D_Plot/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/87_3-D_Plot/ruby/3dplot.rb b/00_Alternate_Languages/87_3-D_Plot/ruby/3dplot.rb
new file mode 100644
index 00000000..ca673e9c
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/ruby/3dplot.rb
@@ -0,0 +1,28 @@
+def intro
+  puts "                                3D PLOT
+               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n\n\n"
+end
+
+def fna(z) = 30 * Math.exp(-z * z / 100)
+
+def render
+  (-30..30).step(1.5).each do |x|
+    l = 0
+    y1 = 5 * (Math.sqrt(900 - x * x) / 5).to_i
+    y_plot = " " * 80
+    (y1..-y1).step(-5).each do |y|
+      z = (25 + fna(Math.sqrt(x * x + y * y)) - 0.7 * y).to_i
+      next if z <= l
+      l = z
+      y_plot[z] = '*'
+    end
+    puts y_plot
+  end
+end
+
+def main
+  intro
+  render
+end
+
+main
diff --git a/00_Alternate_Languages/87_3-D_Plot/ruby/README.md b/00_Alternate_Languages/87_3-D_Plot/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/87_3-D_Plot/vbnet/Plot.sln b/00_Alternate_Languages/87_3-D_Plot/vbnet/Plot.sln
new file mode 100644
index 00000000..a0dcbfcb
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/vbnet/Plot.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Plot", "Plot.vbproj", "{534355CC-A2C1-4138-9EB5-09D658DD4504}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{534355CC-A2C1-4138-9EB5-09D658DD4504}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{534355CC-A2C1-4138-9EB5-09D658DD4504}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{534355CC-A2C1-4138-9EB5-09D658DD4504}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{534355CC-A2C1-4138-9EB5-09D658DD4504}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {CAD09CCC-4522-438E-A8C6-514A866D90DE}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/87_3-D_Plot/vbnet/Plot.vbproj b/00_Alternate_Languages/87_3-D_Plot/vbnet/Plot.vbproj
new file mode 100644
index 00000000..be687f57
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/vbnet/Plot.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Plot
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/87_3-D_Plot/vbnet/README.md b/00_Alternate_Languages/87_3-D_Plot/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/87_3-D_Plot/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/Program.cs b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/Program.cs
new file mode 100644
index 00000000..42a2e60a
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/Program.cs
@@ -0,0 +1,10 @@
+namespace ThreeDTicTacToe
+{
+    class Program
+    {
+        static void Main()
+        {
+            new Qubic().Run();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/Qubic.cs b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/Qubic.cs
new file mode 100644
index 00000000..6557ca9f
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/Qubic.cs
@@ -0,0 +1,1192 @@
+using System.Text;
+
+namespace ThreeDTicTacToe
+{
+    /// 
+    /// Qubic is a 3D Tic-Tac-Toe game played on a 4x4x4 cube. This code allows
+    ///  a player to compete against a deterministic AI that is surprisingly
+    ///  difficult to beat.
+    /// 
+    internal class Qubic
+    {
+        // The Y variable in the original BASIC.
+        private static readonly int[] CornersAndCenters = QubicData.CornersAndCenters;
+        // The M variable in the original BASIC.
+        private static readonly int[,] RowsByPlane = QubicData.RowsByPlane;
+
+        // Board spaces are filled in with numeric values. A space could be:
+        //
+        //  - EMPTY: no one has moved here yet.
+        //  - PLAYER: the player moved here.
+        //  - MACHINE: the machine moved here.
+        //  - POTENTIAL: the machine, in the middle of its move,
+        //      might fill a space with a potential move marker, which
+        //      prioritizes the space once it finally chooses where to move.
+        //
+        // The numeric values allow the program to determine what moves have
+        //  been made in a row by summing the values in a row. In theory, the
+        //  individual values could be any positive numbers that satisfy the
+        //  following:
+        //
+        //  - EMPTY = 0
+        //  - POTENTIAL * 4 < PLAYER
+        //  - PLAYER * 4 < MACHINE
+        private const double PLAYER = 1.0;
+        private const double MACHINE = 5.0;
+        private const double POTENTIAL = 0.125;
+        private const double EMPTY = 0.0;
+
+        // The X variable in the original BASIC. This is the Qubic board,
+        //  flattened into a 1D array.
+        private readonly double[] Board = new double[64];
+
+        // The L variable in the original BASIC. There are 76 unique winning rows
+        //  in the board, so each gets an entry in RowSums. A row sum can be used
+        //  to check what moves have been made to that row in the board.
+        //
+        // Example: if RowSums[i] == PLAYER * 4, the player won with row i!
+        private readonly double[] RowSums = new double[76];
+
+        public Qubic() { }
+
+        /// 
+        /// Run the Qubic game.
+        ///
+        /// Show the title, prompt for instructions, then begin the game loop.
+        /// 
+        public void Run()
+        {
+            Title();
+            Instructions();
+            Loop();
+        }
+
+        /***********************************************************************
+        /* Terminal Text/Prompts
+        /**********************************************************************/
+        #region TerminalText
+
+        /// 
+        /// Display title and attribution.
+        ///
+        /// Original BASIC: 50-120
+        /// 
+        private static void Title()
+        {
+            Console.WriteLine(
+                "\n" +
+                "                                 QUBIC\n\n" +
+                "               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n"
+            );
+        }
+
+        /// 
+        /// Prompt user for game instructions.
+        ///
+        /// Original BASIC: 210-313
+        /// 
+        private static void Instructions()
+        {
+            Console.Write("DO YOU WANT INSTRUCTIONS? ");
+            var yes = ReadYesNo();
+
+            if (yes)
+            {
+                Console.WriteLine(
+                    "\n" +
+                    "THE GAME IS TIC-TAC-TOE IN A 4 X 4 X 4 CUBE.\n" +
+                    "EACH MOVE IS INDICATED BY A 3 DIGIT NUMBER, WITH EACH\n" +
+                    "DIGIT BETWEEN 1 AND 4 INCLUSIVE.  THE DIGITS INDICATE THE\n" +
+                    "LEVEL, ROW, AND COLUMN, RESPECTIVELY, OF THE OCCUPIED\n" +
+                    "PLACE.\n" +
+                    "\n" +
+                    "TO PRINT THE PLAYING BOARD, TYPE 0 (ZERO) AS YOUR MOVE.\n" +
+                    "THE PROGRAM WILL PRINT THE BOARD WITH YOUR MOVES INDI-\n" +
+                    "CATED WITH A (Y), THE MACHINE'S MOVES WITH AN (M), AND\n" +
+                    "UNUSED SQUARES WITH A ( ).  OUTPUT IS ON PAPER.\n" +
+                    "\n" +
+                    "TO STOP THE PROGRAM RUN, TYPE 1 AS YOUR MOVE.\n\n"
+                );
+            }
+        }
+
+        /// 
+        /// Prompt player for whether they would like to move first, or allow
+        ///  the machine to make the first move.
+        ///
+        /// Original BASIC: 440-490
+        /// 
+        /// true if the player wants to move first
+        private static bool PlayerMovePreference()
+        {
+            Console.Write("DO YOU WANT TO MOVE FIRST? ");
+            var result = ReadYesNo();
+            Console.WriteLine();
+            return result;
+        }
+
+        /// 
+        /// Run the Qubic program loop.
+        /// 
+        private void Loop()
+        {
+            // The "retry" loop; ends if player quits or chooses not to retry
+            // after game ends.
+            while (true)
+            {
+                ClearBoard();
+                var playerNext = PlayerMovePreference();
+
+                // The "game" loop; ends if player quits, player/machine wins,
+                // or game ends in draw.
+                while (true)
+                {
+                    if (playerNext)
+                    {
+                        // Player makes a move.
+                        var playerAction = PlayerMove();
+                        if (playerAction == PlayerAction.Move)
+                        {
+                            playerNext = !playerNext;
+                        }
+                        else
+                        {
+                            return;
+                        }
+                    }
+                    else
+                    {
+                        // Check for wins, if any.
+                        RefreshRowSums();
+                        if (CheckPlayerWin() || CheckMachineWin())
+                        {
+                            break;
+                        }
+
+                        // Machine makes a move.
+                        var machineAction = MachineMove();
+                        if (machineAction == MachineAction.Move)
+                        {
+                            playerNext = !playerNext;
+                        }
+                        else if (machineAction == MachineAction.End)
+                        {
+                            break;
+                        }
+                        else
+                        {
+                            throw new Exception("unreachable; machine should always move or end game in game loop");
+                        }
+                    }
+                }
+
+                var retry = RetryPrompt();
+
+                if (!retry)
+                {
+                    return;
+                }
+            }
+        }
+
+        /// 
+        /// Prompt the user to try another game.
+        ///
+        /// Original BASIC: 1490-1560
+        /// 
+        /// true if the user wants to play again
+        private static bool RetryPrompt()
+        {
+            Console.Write("DO YOU WANT TO TRY ANOTHER GAME? ");
+            return ReadYesNo();
+        }
+
+        /// 
+        /// Read a yes/no from the terminal. This method accepts anything that
+        ///  starts with N/n as no and Y/y as yes.
+        /// 
+        /// true if the player answered yes
+        private static bool ReadYesNo()
+        {
+            while (true)
+            {
+                var response = Console.ReadLine() ?? " ";
+                if (response.ToLower().StartsWith("y"))
+                {
+                    return true;
+                }
+                else if (response.ToLower().StartsWith("n"))
+                {
+                    return false;
+                }
+                else
+                {
+                    Console.Write("INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'. ");
+                }
+            }
+        }
+
+        #endregion
+
+        /***********************************************************************
+        /* Player Move
+        /**********************************************************************/
+        #region PlayerMove
+
+        /// 
+        /// Possible actions player has taken after ending their move. This
+        ///  replaces the `GOTO` logic that allowed the player to jump out of
+        ///  the game loop and quit.
+        /// 
+        private enum PlayerAction
+        {
+            /// 
+            /// The player ends the game prematurely.
+            /// 
+            Quit,
+            /// 
+            /// The player makes a move on the board.
+            /// 
+            Move,
+        }
+
+        /// 
+        /// Make the player's move based on their input.
+        ///
+        /// Original BASIC: 500-620
+        /// 
+        /// Whether the player moved or quit the program.
+        private PlayerAction PlayerMove()
+        {
+            // Loop until a valid move is inputted.
+            while (true)
+            {
+                var move = ReadMove();
+                if (move == 1)
+                {
+                    return PlayerAction.Quit;
+                }
+                else if (move == 0)
+                {
+                    ShowBoard();
+                }
+                else
+                {
+                    ClearPotentialMoves();
+                    if (TryCoordToIndex(move, out int moveIndex))
+                    {
+                        if (Board[moveIndex] == EMPTY)
+                        {
+                            Board[moveIndex] = PLAYER;
+                            return PlayerAction.Move;
+                        }
+                        else
+                        {
+                            Console.WriteLine("THAT SQUARE IS USED, TRY AGAIN.");
+                        }
+                    }
+                    else
+                    {
+                        Console.WriteLine("INCORRECT MOVE, TRY AGAIN.");
+                    }
+                }
+            }
+        }
+
+        /// 
+        /// Read a player move from the terminal. Move can be any integer.
+        ///
+        /// Original BASIC: 510-520
+        /// 
+        /// the move inputted
+        private static int ReadMove()
+        {
+            Console.Write("YOUR MOVE? ");
+            return ReadInteger();
+        }
+
+        /// 
+        /// Read an integer from the terminal.
+        ///
+        /// Original BASIC: 520
+        ///
+        /// Unlike the basic, this code will not accept any string that starts
+        ///  with a number; only full number strings are allowed.
+        /// 
+        /// the integer inputted
+        private static int ReadInteger()
+        {
+            while (true)
+            {
+                var response = Console.ReadLine() ?? " ";
+
+                if (int.TryParse(response, out var move))
+                {
+                    return move;
+
+                }
+                else
+                {
+                    Console.Write("!NUMBER EXPECTED - RETRY INPUT LINE--? ");
+                }
+            }
+        }
+
+        /// 
+        /// Display the board to the player. Spaces taken by the player are
+        ///  marked with "Y", while machine spaces are marked with "M".
+        ///
+        /// Original BASIC: 2550-2740
+        /// 
+        private void ShowBoard()
+        {
+            var s = new StringBuilder(new string('\n', 9));
+
+            for (int i = 1; i <= 4; i++)
+            {
+                for (int j = 1; j <= 4; j++)
+                {
+                    s.Append(' ', 3 * (j + 1));
+                    for (int k = 1; k <= 4; k++)
+                    {
+                        int q = (16 * i) + (4 * j) + k - 21;
+                        s.Append(Board[q] switch
+                        {
+                            EMPTY or POTENTIAL => "( )      ",
+                            PLAYER => "(Y)      ",
+                            MACHINE => "(M)      ",
+                            _ => throw new Exception($"invalid space value {Board[q]}"),
+                        });
+                    }
+                    s.Append("\n\n");
+                }
+                s.Append("\n\n");
+            }
+
+            Console.WriteLine(s.ToString());
+        }
+
+        #endregion
+
+        /***********************************************************************
+        /* Machine Move
+        /**********************************************************************/
+        #region MachineMove
+
+        /// 
+        /// Check all rows for a player win.
+        ///
+        /// A row indicates a player win if its sum = PLAYER * 4.
+        ///
+        /// Original BASIC: 720-780
+        /// 
+        /// whether the player won in any row
+        private bool CheckPlayerWin()
+        {
+            for (int row = 0; row < 76; row++)
+            {
+                if (RowSums[row] == (PLAYER * 4))
+                {
+                    // Found player win!
+                    Console.WriteLine("YOU WIN AS FOLLOWS");
+                    DisplayRow(row);
+                    return true;
+                }
+            }
+
+            // No player win found.
+            return false;
+        }
+
+        /// 
+        /// Check all rows for a row that the machine could move to to win
+        ///  immediately.
+        ///
+        /// A row indicates a player could win immediately if it has three
+        ///  machine moves already; that is, sum = MACHINE * 3.
+        ///
+        /// Original Basic: 790-920
+        /// 
+        /// 
+        private bool CheckMachineWin()
+        {
+            for (int row = 0; row < 76; row++)
+            {
+                if (RowSums[row] == (MACHINE * 3))
+                {
+                    // Found a winning row!
+                    for (int space = 0; space < 4; space++)
+                    {
+                        int move = RowsByPlane[row, space];
+                        if (Board[move] == EMPTY)
+                        {
+                            // Found empty space in winning row; move there.
+                            Board[move] = MACHINE;
+                            Console.WriteLine($"MACHINE MOVES TO {IndexToCoord(move)} , AND WINS AS FOLLOWS");
+                            DisplayRow(row);
+                            return true;
+                        }
+                    }
+                }
+            }
+
+            // No winning row available.
+            return false;
+        }
+
+        /// 
+        /// Display the coordinates of a winning row.
+        /// 
+        /// index into RowsByPlane data
+        private void DisplayRow(int row)
+        {
+            for (int space = 0; space < 4; space++)
+            {
+                Console.Write($" {IndexToCoord(RowsByPlane[row, space])} ");
+            }
+            Console.WriteLine();
+        }
+
+        /// 
+        /// Possible actions machine can take in a move. This helps replace the
+        ///  complex GOTO logic from the original BASIC, which allowed the
+        ///  program to jump from the machine's action to the end of the game.
+        /// 
+        private enum MachineAction
+        {
+            /// 
+            /// Machine did not take any action.
+            /// 
+            None,
+            /// 
+            /// Machine made a move.
+            /// 
+            Move,
+            /// 
+            /// Machine either won, conceded, or found a draw.
+            /// 
+            End,
+        }
+
+        /// 
+        /// Machine decides where to move on the board, and ends the game if
+        ///  appropriate.
+        ///
+        /// The machine's AI tries to take the following actions (in order):
+        ///
+        ///  1. If the player has a row that will get them the win on their
+        ///     next turn, block that row.
+        ///  2. If the machine can trap the player (create two different rows
+        ///     with three machine moves each that cannot be blocked by only a
+        ///     single player move, create such a trap.
+        ///  3. If the player can create a similar trap for the machine on
+        ///     their next move, block the space where that trap would be
+        ///     created.
+        ///  4. Find a plane in the board that is well-populated by player
+        ///     moves, and take a space in the first such plane.
+        ///  5. Find the first open corner or center and move there.
+        ///  6. Find the first open space and move there.
+        ///
+        /// If none of these actions are possible, then the board is entirely
+        ///  full, and the game results in a draw.
+        ///
+        /// Original BASIC: start at 930
+        /// 
+        /// the action the machine took
+        private MachineAction MachineMove()
+        {
+            // The actions the machine attempts to take, in order.
+            var actions = new Func[]
+            {
+                BlockPlayer,
+                MakePlayerTrap,
+                BlockMachineTrap,
+                MoveByPlane,
+                MoveCornerOrCenter,
+                MoveAnyOpenSpace,
+            };
+
+            foreach (var action in actions)
+            {
+                // Try each action, moving to the next if nothing happens.
+                var actionResult = action();
+                if (actionResult != MachineAction.None)
+                {
+                    // Not in original BASIC: check for draw after each machine
+                    // move.
+                    if (CheckDraw())
+                    {
+                        return DrawGame();
+                    }
+                    return actionResult;
+                }
+            }
+
+            // If we got here, all spaces are taken. Draw the game.
+            return DrawGame();
+        }
+
+        /// 
+        /// Block a row with three spaces already taken by the player.
+        ///
+        /// Original BASIC: 930-1010
+        /// 
+        /// 
+        /// Move if the machine blocked,
+        /// None otherwise
+        /// 
+        private MachineAction BlockPlayer()
+        {
+            for (int row = 0; row < 76; row++)
+            {
+                if (RowSums[row] == (PLAYER * 3))
+                {
+                    // Found a row to block on!
+                    for (int space = 0; space < 4; space++)
+                    {
+                        if (Board[RowsByPlane[row, space]] == EMPTY)
+                        {
+                            // Take the remaining empty space.
+                            Board[RowsByPlane[row, space]] = MACHINE;
+                            Console.WriteLine($"NICE TRY. MACHINE MOVES TO {IndexToCoord(RowsByPlane[row, space])}");
+                            return MachineAction.Move;
+                        }
+                    }
+                }
+            }
+
+            // Didn't find a row to block on.
+            return MachineAction.None;
+        }
+
+        /// 
+        /// Create a trap for the player if possible. A trap can be created if
+        ///  moving to a space on the board results in two different rows having
+        ///  three MACHINE spaces, with the remaining space not shared between
+        ///  the two rows. The player can only block one of these traps, so the
+        ///  machine will win.
+        ///
+        /// If a player trap is not possible, but a row is found that is
+        ///  particularly advantageous for the machine to move to, the machine
+        ///  will try and move to a plane edge in that row.
+        ///
+        /// Original BASIC: 1300-1480
+        ///
+        /// Lines 1440/50 of the BASIC call 2360 (MovePlaneEdge). Because it
+        ///  goes to this code only after it has found an open space marked as
+        ///  potential, it cannot reach line 2440 of that code, as that is only
+        ///  reached if an open space failed to be found in the row on which
+        ///  that code was called.
+        /// 
+        /// 
+        /// Move if a trap was created,
+        /// End if the machine conceded,
+        /// None otherwise
+        /// 
+        private MachineAction MakePlayerTrap()
+        {
+            for (int row = 0; row < 76; row++)
+            {
+                // Refresh row sum, since new POTENTIALs might have changed it.
+                var rowSum = RefreshRowSum(row);
+
+                // Machine has moved in this row twice, and player has not moved
+                // in this row.
+                if (rowSum >= (MACHINE * 2) && rowSum < (MACHINE * 2) + 1)
+                {
+                    // Machine has no potential moves yet in this row.
+                    if (rowSum == (MACHINE * 2))
+                    {
+                        for (int space = 0; space < 4; space++)
+                        {
+                            // Empty space can potentially be used to create a
+                            // trap.
+                            if (Board[RowsByPlane[row, space]] == EMPTY)
+                            {
+                                Board[RowsByPlane[row, space]] = POTENTIAL;
+                            }
+                        }
+                    }
+                    // Machine has already found a potential move in this row,
+                    // so a trap can be created with another row.
+                    else
+                    {
+                        return MakeOrBlockTrap(row);
+                    }
+                }
+            }
+
+            // No player traps can be made.
+            RefreshRowSums();
+
+            for (int row = 0; row < 76; row++)
+            {
+                // A row may be particularly advantageous for the machine to
+                // move to at this point; this is the case if a row is entirely
+                // filled with POTENTIAL or has one MACHINE and others
+                // POTENTIAL. Such rows may help set up trapping opportunities.
+                if (RowSums[row] == (POTENTIAL * 4) || RowSums[row] == MACHINE + (POTENTIAL * 3))
+                {
+                    // Try moving to a plane edge in an advantageous row.
+                    return MovePlaneEdge(row, POTENTIAL);
+                }
+            }
+
+            // No spaces found that are particularly advantageous to machine.
+            ClearPotentialMoves();
+            return MachineAction.None;
+        }
+
+        /// 
+        /// Block a trap that the player could create for the machine on their
+        ///  next turn.
+        ///
+        /// If there are no player traps to block, but a row is found that is
+        ///  particularly advantageous for the player to move to, the machine
+        ///  will try and move to a plane edge in that row.
+        ///
+        /// Original BASIC: 1030-1190
+        ///
+        /// Lines 1160/1170 of the BASIC call 2360 (MovePlaneEdge). As with
+        ///  MakePlayerTrap, because it goes to this code only after it has
+        ///  found an open space marked as potential, it cannot reach line 2440
+        ///  of that code, as that is only reached if an open space failed to be
+        ///  found in the row on which that code was called.
+        /// 
+        /// 
+        /// Move if a trap was created,
+        /// End if the machine conceded,
+        /// None otherwise
+        /// 
+        private MachineAction BlockMachineTrap()
+        {
+            for (int i = 0; i < 76; i++)
+            {
+                // Refresh row sum, since new POTENTIALs might have changed it.
+                var rowSum = RefreshRowSum(i);
+
+                // Player has moved in this row twice, and machine has not moved
+                // in this row.
+                if (rowSum >= (PLAYER * 2) && rowSum < (PLAYER * 2) + 1)
+                {
+                    // Machine has no potential moves yet in this row.
+                    if (rowSum == (PLAYER * 2))
+                    {
+                        for (int j = 0; j < 4; j++)
+                        {
+                            if (Board[RowsByPlane[i, j]] == EMPTY)
+                            {
+                                Board[RowsByPlane[i, j]] = POTENTIAL;
+                            }
+                        }
+                    }
+                    // Machine has already found a potential move in this row,
+                    // so a trap can be created with another row by the player.
+                    // Move to block.
+                    else
+                    {
+                        return MakeOrBlockTrap(i);
+                    }
+                }
+            }
+
+            // No player traps to block found.
+            RefreshRowSums();
+
+            for (int row = 0; row < 76; row++)
+            {
+                // A row may be particularly advantageous for the player to move
+                // to at this point, indicated by a row containing all POTENTIAL
+                // moves or one PLAYER and rest POTENTIAL. Such rows may aid in
+                // in the later creation of traps.
+                if (RowSums[row] == (POTENTIAL * 4) || RowSums[row] == PLAYER + (POTENTIAL * 3))
+                {
+                    // Try moving to a plane edge in an advantageous row.
+                    return MovePlaneEdge(row, POTENTIAL);
+                }
+            }
+
+            // No spaces found that are particularly advantageous to the player.
+            return MachineAction.None;
+        }
+
+        /// 
+        /// Either make a trap for the player or block a trap the player could
+        ///  create on their next turn.
+        ///
+        /// Unclear how this method could possibly end with a concession; it
+        ///  seems it can only be called if the row contains a potential move.
+        ///
+        /// Original BASIC: 2230-2350
+        /// 
+        /// the row containing the space to move to
+        /// 
+        /// Move if the machine moved,
+        /// End if the machine conceded
+        /// 
+        private MachineAction MakeOrBlockTrap(int row)
+        {
+            for (int space = 0; space < 4; space++)
+            {
+                if (Board[RowsByPlane[row, space]] == POTENTIAL)
+                {
+                    Board[RowsByPlane[row, space]] = MACHINE;
+
+                    // Row sum indicates we're blocking a player trap.
+                    if (RowSums[row] < MACHINE)
+                    {
+                        Console.Write("YOU FOX.  JUST IN THE NICK OF TIME, ");
+                    }
+                    // Row sum indicates we're completing a machine trap.
+                    else
+                    {
+                        Console.Write("LET'S SEE YOU GET OUT OF THIS:  ");
+                    }
+
+                    Console.WriteLine($"MACHINE MOVES TO {IndexToCoord(RowsByPlane[row, space])}");
+
+                    return MachineAction.Move;
+                }
+            }
+
+            // Unclear how this can be reached.
+            Console.WriteLine("MACHINE CONCEDES THIS GAME.");
+            return MachineAction.End;
+        }
+
+        /// 
+        /// Find a satisfactory plane on the board and move to one if that
+        ///  plane's plane edges.
+        ///
+        /// A plane on the board is satisfactory if it meets the following
+        ///  conditions:
+        ///     1. Player has made exactly 4 moves on the plane.
+        ///     2. Machine has made either 0 or one moves on the plane.
+        ///  Such a plane is one that the player could likely use to form traps.
+        ///
+        /// Original BASIC: 1830-2020
+        ///
+        /// Line 1990 of the original basic calls 2370 (MovePlaneEdge). Only on
+        ///  this call to MovePlaneEdge can line 2440 of that method be reached,
+        ///  which surves to help this method iterate through the rows of a
+        ///  plane.
+        /// 
+        /// 
+        /// Move if a move in a plane was found,
+        /// None otherwise
+        /// 
+        private MachineAction MoveByPlane()
+        {
+            // For each plane in the cube...
+            for (int plane = 1; plane <= 18; plane++)
+            {
+                double planeSum = PlaneSum(plane);
+
+                // Check that plane sum satisfies condition.
+                const double P4 = PLAYER * 4;
+                const double P4_M1 = (PLAYER * 4) + MACHINE;
+                if (
+                    (planeSum >= P4 && planeSum < P4 + 1) ||
+                    (planeSum >= P4_M1 && planeSum < P4_M1 + 1)
+                )
+                {
+                    // Try to move to plane edges in each row of plane
+                    // First, check for plane edges marked as POTENTIAL.
+                    for (int row = (4 * plane) - 4; row < (4 * plane); row++)
+                    {
+                        var moveResult = MovePlaneEdge(row, POTENTIAL);
+                        if (moveResult != MachineAction.None)
+                        {
+                            return moveResult;
+                        }
+                    }
+
+                    // If no POTENTIAL plane edge found, look for an EMPTY one.
+                    for (int row = (4 * plane) - 4; row < (4 * plane); row++)
+                    {
+                        var moveResult = MovePlaneEdge(row, EMPTY);
+                        if (moveResult != MachineAction.None)
+                        {
+                            return moveResult;
+                        }
+                    }
+                }
+            }
+
+            // No satisfactory planes with open plane edges found.
+            ClearPotentialMoves();
+            return MachineAction.None;
+        }
+
+        /// 
+        /// Given a row, move to the first space in that row that:
+        ///  1. is a plane edge, and
+        ///  2. has the given value in Board
+        ///
+        /// Plane edges are any spaces on a plane with one face exposed. The AI
+        ///  prefers to move to these spaces before others, presumably
+        ///  because they are powerful moves: a plane edge is contained on 3-4
+        ///  winning rows of the cube.
+        ///
+        /// Original BASIC: 2360-2490
+        ///
+        /// In the original BASIC, this code is pointed to from three different
+        ///  locations by GOTOs:
+        ///  - 1440/50, or MakePlayerTrap;
+        ///  - 1160/70, or BlockMachineTrap; and
+        ///  - 1990, or MoveByPlane.
+        /// At line 2440, this code jumps back to line 2000, which is in
+        ///  MoveByPlane. This makes it appear as though calling MakePlayerTrap
+        ///  or BlockPlayerTrap in the BASIC could jump into the middle of the
+        ///  MoveByPlane method; were this to happen, not all of MoveByPlane's
+        ///  variables would be defined! However, the program logic prevents
+        ///  this from ever occurring; see each method's description for why
+        ///  this is the case.
+        /// 
+        /// the row to try to move to
+        /// 
+        /// what value the space to move to should have in Board
+        /// 
+        /// 
+        /// Move if a plane edge piece in the row with the given spaceValue was
+        /// found,
+        /// None otherwise
+        /// 
+        private MachineAction MovePlaneEdge(int row, double spaceValue)
+        {
+            // Given a row, we want to find the plane edge pieces in that row.
+            // We know that each row is part of a plane, and that the first
+            // and last rows of the plane are on the plane edge, while the
+            // other two rows are in the middle. If we know whether a row is an
+            // edge or middle, we can determine which spaces in that row are
+            // plane edges.
+            //
+            // Below is a birds-eye view of a plane in the cube, with rows
+            // oriented horizontally:
+            //
+            //   row 0: ( ) (1) (2) ( )
+            //   row 1: (0) ( ) ( ) (3)
+            //   row 2: (0) ( ) ( ) (3)
+            //   row 3: ( ) (1) (2) ( )
+            //
+            // The plane edge pieces have their row indices marked. The pattern
+            // above shows that:
+            //
+            //  if row == 0 | 3, plane edge spaces = [1, 2]
+            //  if row == 1 | 2, plane edge spaces = [0, 3]
+
+            // The below condition replaces the following BASIC code (2370):
+            //
+            //  I-(INT(I/4)*4)>1
+            //
+            // which in C# would be:
+            //
+            //
+            // int a = i - (i / 4) * 4 <= 1)
+            //     ? 1
+            //     : 2;
+            //
+            // In the above, i is the one-indexed row in RowsByPlane.
+            //
+            // This condition selects a different a value based on whether the
+            // given row is on the edge or middle of its plane.
+            int a = (row % 4) switch
+            {
+                0 or 3 => 1,  // row is on edge of plane
+                1 or 2 => 2,  // row is in middle of plane
+                _ => throw new Exception($"unreachable ({row % 4})"),
+            };
+
+            // Iterate through plane edge pieces of the row.
+            //
+            //  if a = 1 (row is edge), iterate through [0, 3]
+            //  if a = 2 (row is middle), iterate through [1, 2]
+            for (int space = a - 1; space <= 4 - a; space += 5 - (2 * a))
+            {
+                if (Board[RowsByPlane[row, space]] == spaceValue)
+                {
+                    // Found a plane edge to take!
+                    Board[RowsByPlane[row, space]] = MACHINE;
+                    Console.WriteLine($"MACHINE TAKES {IndexToCoord(RowsByPlane[row, space])}");
+                    return MachineAction.Move;
+                }
+            }
+
+            // No valid corner edge to take.
+            return MachineAction.None;
+        }
+
+        /// 
+        /// Find the first open corner or center in the board and move there.
+        ///
+        /// Original BASIC: 1200-1290
+        ///
+        /// This is the only place where the Z variable from the BASIC code is
+        ///  used; here it is implied in the for loop.
+        /// 
+        /// 
+        /// Move if an open corner/center was found and moved to,
+        /// None otherwise
+        /// 
+        private MachineAction MoveCornerOrCenter()
+        {
+            foreach (int space in CornersAndCenters)
+            {
+                if (Board[space] == EMPTY)
+                {
+                    Board[space] = MACHINE;
+                    Console.WriteLine($"MACHINE MOVES TO {IndexToCoord(space)}");
+                    return MachineAction.Move;
+                }
+            }
+
+            return MachineAction.None;
+        }
+
+        /// 
+        /// Find the first open space in the board and move there.
+        ///
+        /// Original BASIC: 1720-1800
+        /// 
+        /// 
+        /// Move if an open space was found and moved to,
+        /// None otherwise
+        /// 
+        private MachineAction MoveAnyOpenSpace()
+        {
+            for (int row = 0; row < 64; row++)
+            {
+                if (Board[row] == EMPTY)
+                {
+                    Board[row] = MACHINE;
+                    Console.WriteLine($"MACHINE LIKES {IndexToCoord(row)}");
+                    return MachineAction.Move;
+                }
+            }
+            return MachineAction.None;
+        }
+
+        /// 
+        /// Draw the game in the event that there are no open spaces.
+        ///
+        /// Original BASIC: 1810-1820
+        /// 
+        /// End
+        private MachineAction DrawGame()
+        {
+            Console.WriteLine("THIS GAME IS A DRAW.");
+            return MachineAction.End;
+        }
+
+        #endregion
+
+        /***********************************************************************
+        /* Helpers
+        /**********************************************************************/
+        #region Helpers
+
+        /// 
+        /// Attempt to transform a cube coordinate to an index into Board.
+        ///
+        /// A valid cube coordinate is a three-digit number, where each digit
+        ///  of the number X satisfies 1 <= X <= 4.
+        ///
+        /// Examples:
+        ///  111 -> 0
+        ///  444 -> 63
+        ///  232 -> 35
+        ///
+        /// If the coord provided is not valid, the transformation fails.
+        ///
+        /// The conversion from coordinate to index is essentially a conversion
+        ///  between base 4 and base 10.
+        ///
+        /// Original BASIC: 525-580
+        ///
+        /// This method fixes a bug in the original BASIC (525-526), which only
+        ///  checked whether the given coord satisfied 111 <= coord <= 444. This
+        ///  allows invalid coordinates such as 199 and 437, whose individual
+        ///  digits are out of range.
+        /// 
+        /// cube coordinate (e.g. "111", "342")
+        /// trasnformation output
+        /// 
+        /// true if the transformation was successful, false otherwise
+        /// 
+        private static bool TryCoordToIndex(int coord, out int index)
+        {
+            // parse individual digits, subtract 1 to get base 4 number
+            var hundreds = (coord / 100) - 1;
+            var tens = ((coord % 100) / 10) - 1;
+            var ones = (coord % 10) - 1;
+
+            // bounds check for each digit
+            foreach (int digit in new int[] { hundreds, tens, ones })
+            {
+                if (digit < 0 || digit > 3)
+                {
+                    index = -1;
+                    return false;
+                }
+            }
+
+            // conversion from base 4 to base 10
+            index = (16 * hundreds) + (4 * tens) + ones;
+            return true;
+        }
+
+        /// 
+        /// Transform a Board index into a valid cube coordinate.
+        ///
+        /// Examples:
+        ///  0 -> 111
+        ///  63 -> 444
+        ///  35 -> 232
+        ///
+        /// The conversion from index to coordinate is essentially a conversion
+        ///  between base 10 and base 4.
+        ///
+        /// Original BASIC: 1570-1610
+        /// 
+        /// Board index
+        /// the corresponding cube coordinate
+        private static int IndexToCoord(int index)
+        {
+            // check that index is valid
+            if (index < 0 || index > 63)
+            {
+                // runtime exception; all uses of this method are with
+                // indices provided by the program, so this should never fail
+                throw new Exception($"index {index} is out of range");
+            }
+
+            // convert to base 4, add 1 to get cube coordinate
+            var hundreds = (index / 16) + 1;
+            var tens = ((index % 16) / 4) + 1;
+            var ones = (index % 4) + 1;
+
+            // concatenate digits
+            int coord = (hundreds * 100) + (tens * 10) + ones;
+            return coord;
+        }
+
+        /// 
+        /// Refresh the values in RowSums to account for any changes.
+        ///
+        /// Original BASIC: 1640-1710
+        /// 
+        private void RefreshRowSums()
+        {
+            for (var row = 0; row < 76; row++)
+            {
+                RefreshRowSum(row);
+            }
+        }
+
+        /// 
+        /// Refresh a row in RowSums to reflect changes.
+        /// 
+        /// row in RowSums to refresh
+        /// row sum after refresh
+        private double RefreshRowSum(int row)
+        {
+            double rowSum = 0;
+            for (int space = 0; space < 4; space++)
+            {
+                rowSum += Board[RowsByPlane[row, space]];
+            }
+            RowSums[row] = rowSum;
+            return rowSum;
+        }
+
+        /// 
+        /// Calculate the sum of spaces in one of the 18 cube planes in RowSums.
+        ///
+        /// Original BASIC: 1840-1890
+        /// 
+        /// the desired plane
+        /// sum of spaces in plane
+        private double PlaneSum(int plane)
+        {
+            double planeSum = 0;
+            for (int row = (4 * (plane - 1)); row < (4 * plane); row++)
+            {
+                for (int space = 0; space < 4; space++)
+                {
+                    planeSum += Board[RowsByPlane[row, space]];
+                }
+            }
+            return planeSum;
+        }
+
+        /// 
+        /// Check whether the board is in a draw state, that is all spaces are
+        ///  full and neither the player nor the machine has won.
+        ///
+        /// The original BASIC contains a bug that if the player moves first, a
+        ///  draw will go undetected. An example series of player inputs
+        ///  resulting in such a draw (assuming player goes first):
+        ///
+        ///  114, 414, 144, 444, 122, 221, 112, 121,
+        ///  424, 332, 324, 421, 231, 232, 244, 311,
+        ///  333, 423, 331, 134, 241, 243, 143, 413,
+        ///  142, 212, 314, 341, 432, 412, 431, 442
+        /// 
+        /// whether the game is a draw
+        private bool CheckDraw()
+        {
+            for (var i = 0; i < 64; i++)
+            {
+                if (Board[i] != PLAYER && Board[i] != MACHINE)
+                {
+                    return false;
+                }
+            }
+
+            RefreshRowSums();
+
+            for (int row = 0; row < 76; row++)
+            {
+                var rowSum = RowSums[row];
+                if (rowSum == PLAYER * 4 || rowSum == MACHINE * 4)
+                {
+                    return false;
+                }
+            }
+
+
+            return true;
+        }
+
+        /// 
+        /// Reset POTENTIAL spaces in Board to EMPTY.
+        ///
+        /// Original BASIC: 2500-2540
+        /// 
+        private void ClearPotentialMoves()
+        {
+            for (var i = 0; i < 64; i++)
+            {
+                if (Board[i] == POTENTIAL)
+                {
+                    Board[i] = EMPTY;
+                }
+            }
+        }
+
+        /// 
+        /// Reset all spaces in Board to EMPTY.
+        ///
+        /// Original BASIC: 400-420
+        /// 
+        private void ClearBoard()
+        {
+            for (var i = 0; i < 64; i++)
+            {
+                Board[i] = EMPTY;
+            }
+        }
+
+        #endregion
+    }
+}
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/QubicData.cs b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/QubicData.cs
new file mode 100644
index 00000000..823d0f2e
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/QubicData.cs
@@ -0,0 +1,559 @@
+namespace ThreeDTicTacToe
+{
+    /// 
+    /// Data in this class was originally given by the following DATA section in
+    /// the BASIC program:
+    ///
+    /// 2030 DATA 1,49,52,4,13,61,64,16,22,39,23,38,26,42,27,43
+    /// 2040 DATA 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
+    /// 2050 DATA 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38
+    /// 2060 DATA 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56
+    /// 2070 DATA 57,58,59,60,61,62,63,64
+    /// 2080 DATA 1,17,33,49,5,21,37,53,9,25,41,57,13,29,45,61
+    /// 2090 DATA 2,18,34,50,6,22,38,54,10,26,42,58,14,30,46,62
+    /// 2100 DATA 3,19,35,51,7,23,39,55,11,27,43,59,15,31,47,63
+    /// 2110 DATA 4,20,36,52,8,24,40,56,12,28,44,60,16,32,48,64
+    /// 2120 DATA 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61
+    /// 2130 DATA 2,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62
+    /// 2140 DATA 3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63
+    /// 2150 DATA 4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64
+    /// 2160 DATA 1,6,11,16,17,22,27,32,33,38,43,48,49,54,59,64
+    /// 2170 DATA 13,10,7,4,29,26,23,20,45,42,39,36,61,58,55,52
+    /// 2180 DATA 1,21,41,61,2,22,42,62,3,23,43,63,4,24,44,64
+    /// 2190 DATA 49,37,25,13,50,38,26,14,51,39,27,15,52,40,28,16
+    /// 2200 DATA 1,18,35,52,5,22,39,56,9,26,43,60,13,30,47,64
+    /// 2210 DATA 49,34,19,4,53,38,23,8,57,42,27,12,61,46,31,16
+    /// 2220 DATA 1,22,43,64,16,27,38,49,4,23,42,61,13,26,39,52
+    ///
+    /// In short, each number is an index into the board. The data in this class
+    /// is zero-indexed, as opposed to the original data which was one-indexed.
+    /// 
+    internal static class QubicData
+    {
+        /// 
+        /// The corners and centers of the Qubic board. They correspond to the
+        ///  following coordinates:
+        ///
+        /// [
+        ///     111, 411, 414, 114, 141, 441, 444, 144,
+        ///     222, 323, 223, 322, 232, 332, 233, 333
+        /// ]
+        /// 
+        public static readonly int[] CornersAndCenters = new int[16]
+        {
+           //     (X)      ( )      ( )      (X)
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 (X)      ( )      ( )      (X)
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      (X)      (X)      ( )
+           //             ( )      (X)      (X)      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      (X)      (X)      ( )
+           //             ( )      (X)      (X)      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     (X)      ( )      ( )      (X)
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 (X)      ( )      ( )      (X)
+
+            0,48,51,3,12,60,63,15,21,38,22,37,25,41,26,42
+        };
+
+        /// 
+        /// A list of all "winning" rows in the Qubic board; that is, sets of
+        ///  four spaces that, if filled entirely by the player (or machine),
+        ///  would result in a win.
+        ///
+        /// Each group of four rows in the list corresponds to a plane in the
+        ///  cube, and each plane is organized so that the first and last rows
+        ///  are on the plane's edges, while the second and third rows are in
+        ///  the middle of the plane. The only exception is the last group of
+        ///  rows, which contains the corners and centers rather than a plane.
+        ///
+        /// The order of the rows in this list is key to how the Qubic AI
+        ///  decides its next move.
+        /// 
+        public static readonly int[,] RowsByPlane = new int[76, 4]
+        {
+           //     (1)      (1)      (1)      (1)
+           //         (2)      (2)      (2)      (2)
+           //             (3)      (3)      (3)      (3)
+           //                 (4)      (4)      (4)      (4)
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           { 0, 1, 2, 3,  },
+           { 4, 5, 6, 7,  },
+           { 8, 9, 10,11, },
+           { 12,13,14,15, },
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     (1)      (1)      (1)      (1)
+           //         (2)      (2)      (2)      (2)
+           //             (3)      (3)      (3)      (3)
+           //                 (4)      (4)      (4)      (4)
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           { 16,17,18,19, },
+           { 20,21,22,23, },
+           { 24,25,26,27, },
+           { 28,29,30,31, },
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     (1)      (1)      (1)      (1)
+           //         (2)      (2)      (2)      (2)
+           //             (3)      (3)      (3)      (3)
+           //                 (4)      (4)      (4)      (4)
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           { 32,33,34,35, },
+           { 36,37,38,39, },
+           { 40,41,42,43, },
+           { 44,45,46,47, },
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     (1)      (1)      (1)      (1)
+           //         (2)      (2)      (2)      (2)
+           //             (3)      (3)      (3)      (3)
+           //                 (4)      (4)      (4)      (4)
+
+           { 48,49,50,51, },
+           { 52,53,54,55, },
+           { 56,57,58,59, },
+           { 60,61,62,63, },
+
+           //     (1)      ( )      ( )      ( )
+           //         (2)      ( )      ( )      ( )
+           //             (3)      ( )      ( )      ( )
+           //                 (4)      ( )      ( )      ( )
+
+           //     (1)      ( )      ( )      ( )
+           //         (2)      ( )      ( )      ( )
+           //             (3)      ( )      ( )      ( )
+           //                 (4)      ( )      ( )      ( )
+
+           //     (1)      ( )      ( )      ( )
+           //         (2)      ( )      ( )      ( )
+           //             (3)      ( )      ( )      ( )
+           //                 (4)      ( )      ( )      ( )
+
+           //     (1)      ( )      ( )      ( )
+           //         (2)      ( )      ( )      ( )
+           //             (3)      ( )      ( )      ( )
+           //                 (4)      ( )      ( )      ( )
+
+           { 0, 16,32,48, },
+           { 4, 20,36,52, },
+           { 8, 24,40,56, },
+           { 12,28,44,60, },
+
+           //     ( )      (1)      ( )      ( )
+           //         ( )      (2)      ( )      ( )
+           //             ( )      (3)      ( )      ( )
+           //                 ( )      (4)      ( )      ( )
+
+           //     ( )      (1)      ( )      ( )
+           //         ( )      (2)      ( )      ( )
+           //             ( )      (3)      ( )      ( )
+           //                 ( )      (4)      ( )      ( )
+
+           //     ( )      (1)      ( )      ( )
+           //         ( )      (2)      ( )      ( )
+           //             ( )      (3)      ( )      ( )
+           //                 ( )      (4)      ( )      ( )
+
+           //     ( )      (1)      ( )      ( )
+           //         ( )      (2)      ( )      ( )
+           //             ( )      (3)      ( )      ( )
+           //                 ( )      (4)      ( )      ( )
+
+           { 1, 17,33,49, },
+           { 5, 21,37,53, },
+           { 9, 25,41,57, },
+           { 13,29,45,61, },
+
+           //     ( )      ( )      (1)      ( )
+           //         ( )      ( )      (2)      ( )
+           //             ( )      ( )      (3)      ( )
+           //                 ( )      ( )      (4)      ( )
+
+           //     ( )      ( )      (1)      ( )
+           //         ( )      ( )      (2)      ( )
+           //             ( )      ( )      (3)      ( )
+           //                 ( )      ( )      (4)      ( )
+
+           //     ( )      ( )      (1)      ( )
+           //         ( )      ( )      (2)      ( )
+           //             ( )      ( )      (3)      ( )
+           //                 ( )      ( )      (4)      ( )
+
+           //     ( )      ( )      (1)      ( )
+           //         ( )      ( )      (2)      ( )
+           //             ( )      ( )      (3)      ( )
+           //                 ( )      ( )      (4)      ( )
+
+           { 2, 18,34,50, },
+           { 6, 22,38,54, },
+           { 10,26,42,58, },
+           { 14,30,46,62, },
+
+           //     ( )      ( )      ( )      (1)
+           //         ( )      ( )      ( )      (2)
+           //             ( )      ( )      ( )      (3)
+           //                 ( )      ( )      ( )      (4)
+
+           //     ( )      ( )      ( )      (1)
+           //         ( )      ( )      ( )      (2)
+           //             ( )      ( )      ( )      (3)
+           //                 ( )      ( )      ( )      (4)
+
+           //     ( )      ( )      ( )      (1)
+           //         ( )      ( )      ( )      (2)
+           //             ( )      ( )      ( )      (3)
+           //                 ( )      ( )      ( )      (4)
+
+           //     ( )      ( )      ( )      (1)
+           //         ( )      ( )      ( )      (2)
+           //             ( )      ( )      ( )      (3)
+           //                 ( )      ( )      ( )      (4)
+
+           { 3, 19,35,51, },
+           { 7, 23,39,55, },
+           { 11,27,43,59, },
+           { 15,31,47,63, },
+
+           //     (1)      ( )      ( )      ( )
+           //         (1)      ( )      ( )      ( )
+           //             (1)      ( )      ( )      ( )
+           //                 (1)      ( )      ( )      ( )
+
+           //     (2)      ( )      ( )      ( )
+           //         (2)      ( )      ( )      ( )
+           //             (2)      ( )      ( )      ( )
+           //                 (2)      ( )      ( )      ( )
+
+           //     (3)      ( )      ( )      ( )
+           //         (3)      ( )      ( )      ( )
+           //             (3)      ( )      ( )      ( )
+           //                 (3)      ( )      ( )      ( )
+
+           //     (4)      ( )      ( )      ( )
+           //         (4)      ( )      ( )      ( )
+           //             (4)      ( )      ( )      ( )
+           //                 (4)      ( )      ( )      ( )
+
+           { 0, 4, 8, 12, },
+           { 16,20,24,28, },
+           { 32,36,40,44, },
+           { 48,52,56,60, },
+
+           //     ( )      (1)      ( )      ( )
+           //         ( )      (1)      ( )      ( )
+           //             ( )      (1)      ( )      ( )
+           //                 ( )      (1)      ( )      ( )
+
+           //     ( )      (2)      ( )      ( )
+           //         ( )      (2)      ( )      ( )
+           //             ( )      (2)      ( )      ( )
+           //                 ( )      (2)      ( )      ( )
+
+           //     ( )      (3)      ( )      ( )
+           //         ( )      (3)      ( )      ( )
+           //             ( )      (3)      ( )      ( )
+           //                 ( )      (3)      ( )      ( )
+
+           //     ( )      (4)      ( )      ( )
+           //         ( )      (4)      ( )      ( )
+           //             ( )      (4)      ( )      ( )
+           //                 ( )      (4)      ( )      ( )
+
+           { 1, 5, 9, 13, },
+           { 17,21,25,29, },
+           { 33,37,41,45, },
+           { 49,53,57,61, },
+
+           //     ( )      ( )      (1)      ( )
+           //         ( )      ( )      (1)      ( )
+           //             ( )      ( )      (1)      ( )
+           //                 ( )      ( )      (1)      ( )
+
+           //     ( )      ( )      (2)      ( )
+           //         ( )      ( )      (2)      ( )
+           //             ( )      ( )      (2)      ( )
+           //                 ( )      ( )      (2)      ( )
+
+           //     ( )      ( )      (3)      ( )
+           //         ( )      ( )      (3)      ( )
+           //             ( )      ( )      (3)      ( )
+           //                 ( )      ( )      (3)      ( )
+
+           //     ( )      ( )      (4)      ( )
+           //         ( )      ( )      (4)      ( )
+           //             ( )      ( )      (4)      ( )
+           //                 ( )      ( )      (4)      ( )
+
+           { 2, 6, 10,14, },
+           { 18,22,26,30, },
+           { 34,38,42,46, },
+           { 50,54,58,62, },
+
+           //     ( )      ( )      ( )      (1)
+           //         ( )      ( )      ( )      (1)
+           //             ( )      ( )      ( )      (1)
+           //                 ( )      ( )      ( )      (1)
+
+           //     ( )      ( )      ( )      (2)
+           //         ( )      ( )      ( )      (2)
+           //             ( )      ( )      ( )      (2)
+           //                 ( )      ( )      ( )      (2)
+
+           //     ( )      ( )      ( )      (3)
+           //         ( )      ( )      ( )      (3)
+           //             ( )      ( )      ( )      (3)
+           //                 ( )      ( )      ( )      (3)
+
+           //     ( )      ( )      ( )      (4)
+           //         ( )      ( )      ( )      (4)
+           //             ( )      ( )      ( )      (4)
+           //                 ( )      ( )      ( )      (4)
+
+           { 3, 7, 11,15, },
+           { 19,23,27,31, },
+           { 35,39,43,47, },
+           { 51,55,59,63, },
+
+           //     (1)      ( )      ( )      ( )
+           //         ( )      (1)      ( )      ( )
+           //             ( )      ( )      (1)      ( )
+           //                 ( )      ( )      ( )      (1)
+
+           //     (2)      ( )      ( )      ( )
+           //         ( )      (2)      ( )      ( )
+           //             ( )      ( )      (2)      ( )
+           //                 ( )      ( )      ( )      (2)
+
+           //     (3)      ( )      ( )      ( )
+           //         ( )      (3)      ( )      ( )
+           //             ( )      ( )      (3)      ( )
+           //                 ( )      ( )      ( )      (3)
+
+           //     (4)      ( )      ( )      ( )
+           //         ( )      (4)      ( )      ( )
+           //             ( )      ( )      (4)      ( )
+           //                 ( )      ( )      ( )      (4)
+
+           { 0, 5, 10,15, },
+           { 16,21,26,31, },
+           { 32,37,42,47, },
+           { 48,53,58,63, },
+
+           //     ( )      ( )      ( )      (1)
+           //         ( )      ( )      (1)      ( )
+           //             ( )      (1)      ( )      ( )
+           //                 (1)      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      (2)
+           //         ( )      ( )      (2)      ( )
+           //             ( )      (2)      ( )      ( )
+           //                 (2)      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      (3)
+           //         ( )      ( )      (3)      ( )
+           //             ( )      (3)      ( )      ( )
+           //                 (3)      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      (4)
+           //         ( )      ( )      (4)      ( )
+           //             ( )      (4)      ( )      ( )
+           //                 (4)      ( )      ( )      ( )
+
+           { 12,9, 6, 3,  },
+           { 28,25,22,19, },
+           { 44,41,38,35, },
+           { 60,57,54,51, },
+
+           //     (1)      (2)      (3)      (4)
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         (1)      (2)      (3)      (4)
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             (1)      (2)      (3)      (4)
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 (1)      (2)      (3)      (4)
+
+           { 0, 20,40,60, },
+           { 1, 21,41,61, },
+           { 2, 22,42,62, },
+           { 3, 23,43,63, },
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 (1)      (2)      (3)      (4)
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      ( )      ( )      ( )
+           //             (1)      (2)      (3)      (4)
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         (1)      (2)      (3)      (4)
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     (1)      (2)      (3)      (4)
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           { 48,36,24,12, },
+           { 49,37,25,13, },
+           { 50,38,26,14, },
+           { 51,39,27,15, },
+
+           //     (1)      ( )      ( )      ( )
+           //         (2)      ( )      ( )      ( )
+           //             (3)      ( )      ( )      ( )
+           //                 (4)      ( )      ( )      ( )
+
+           //     ( )      (1)      ( )      ( )
+           //         ( )      (2)      ( )      ( )
+           //             ( )      (3)      ( )      ( )
+           //                 ( )      (4)      ( )      ( )
+
+           //     ( )      ( )      (1)      ( )
+           //         ( )      ( )      (2)      ( )
+           //             ( )      ( )      (3)      ( )
+           //                 ( )      ( )      (4)      ( )
+
+           //     ( )      ( )      ( )      (1)
+           //         ( )      ( )      ( )      (2)
+           //             ( )      ( )      ( )      (3)
+           //                 ( )      ( )      ( )      (4)
+
+           { 0, 17,34,51, },
+           { 4, 21,38,55, },
+           { 8, 25,42,59, },
+           { 12,29,46,63, },
+
+           //     ( )      ( )      ( )      (1)
+           //         ( )      ( )      ( )      (2)
+           //             ( )      ( )      ( )      (3)
+           //                 ( )      ( )      ( )      (4)
+
+           //     ( )      ( )      (1)      ( )
+           //         ( )      ( )      (2)      ( )
+           //             ( )      ( )      (3)      ( )
+           //                 ( )      ( )      (4)      ( )
+
+           //     ( )      (1)      ( )      ( )
+           //         ( )      (2)      ( )      ( )
+           //             ( )      (3)      ( )      ( )
+           //                 ( )      (4)      ( )      ( )
+
+           //     (1)      ( )      ( )      ( )
+           //         (2)      ( )      ( )      ( )
+           //             (3)      ( )      ( )      ( )
+           //                 (4)      ( )      ( )      ( )
+
+           { 48,33,18,3,  },
+           { 52,37,22,7,  },
+           { 56,41,26,11, },
+           { 60,45,30,15, },
+
+           //     (1)      ( )      ( )      (3)
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 (4)      ( )      ( )      (2)
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      (1)      (3)      ( )
+           //             ( )      (4)      (2)      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     ( )      ( )      ( )      ( )
+           //         ( )      (2)      (4)      ( )
+           //             ( )      (3)      (1)      ( )
+           //                 ( )      ( )      ( )      ( )
+
+           //     (2)      ( )      ( )      (4)
+           //         ( )      ( )      ( )      ( )
+           //             ( )      ( )      ( )      ( )
+           //                 (3)      ( )      ( )      (1)
+
+           { 0, 21,42,63, },
+           { 15,26,37,48, },
+           { 3, 22,41,60, },
+           { 12,25,38,51, },
+        };
+    }
+}
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/ThreeDTicTacToe.csproj b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/ThreeDTicTacToe.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/ThreeDTicTacToe.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/ThreeDTicTacToe.sln b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/ThreeDTicTacToe.sln
new file mode 100644
index 00000000..0dcb9034
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/csharp/ThreeDTicTacToe.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ThreeDTicTacToe", "ThreeDTicTacToe.csproj", "{6001B6FB-DF8A-4D59-8E22-BA126C8DA274}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6001B6FB-DF8A-4D59-8E22-BA126C8DA274}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6001B6FB-DF8A-4D59-8E22-BA126C8DA274}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6001B6FB-DF8A-4D59-8E22-BA126C8DA274}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6001B6FB-DF8A-4D59-8E22-BA126C8DA274}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/java/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/javascript/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/javascript/qubit.html b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/javascript/qubit.html
new file mode 100644
index 00000000..813015bb
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/javascript/qubit.html
@@ -0,0 +1,9 @@
+
+
+QUBIT
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/javascript/qubit.js b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/javascript/qubit.js
new file mode 100644
index 00000000..0057619f
--- /dev/null
+++ b/00_Alternate_Languages/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();
diff --git a/64_Nicomachus/pascal/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/pascal/README.md
similarity index 100%
rename from 64_Nicomachus/pascal/README.md
rename to 00_Alternate_Languages/88_3-D_Tic-Tac-Toe/pascal/README.md
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/perl/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/python/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/python/qubit.py b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/python/qubit.py
new file mode 100644
index 00000000..da5a6c59
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/python/qubit.py
@@ -0,0 +1,414 @@
+#!/usr/bin/python3
+
+# Ported from the BASIC source for 3D Tic Tac Toe
+# in BASIC Computer Games, by David H. Ahl
+# The code originated from Dartmouth College
+
+from enum import Enum
+
+
+class Move(Enum):
+    """Game status and types of machine move"""
+
+    HUMAN_WIN = 0
+    MACHINE_WIN = 1
+    DRAW = 2
+    MOVES = 3
+    LIKES = 4
+    TAKES = 5
+    GET_OUT = 6
+    YOU_FOX = 7
+    NICE_TRY = 8
+    CONCEDES = 9
+
+
+class Player(Enum):
+    EMPTY = 0
+    HUMAN = 1
+    MACHINE = 2
+
+
+class TicTacToe3D:
+    """The game logic for 3D Tic Tac Toe and the machine opponent"""
+
+    def __init__(self):
+
+        # 4x4x4 board keeps track of which player occupies each place
+        # and used by machine to work out its strategy
+        self.board = [0] * 64
+
+        # starting move
+        self.corners = [0, 48, 51, 3, 12, 60, 63, 15, 21, 38, 22, 37, 25, 41, 26, 42]
+
+        # lines to check for end game
+        self.lines = [
+            [0, 1, 2, 3],
+            [4, 5, 6, 7],
+            [8, 9, 10, 11],
+            [12, 13, 14, 15],
+            [16, 17, 18, 19],
+            [20, 21, 22, 23],
+            [24, 25, 26, 27],
+            [28, 29, 30, 31],
+            [32, 33, 34, 35],
+            [36, 37, 38, 39],
+            [40, 41, 42, 43],
+            [44, 45, 46, 47],
+            [48, 49, 50, 51],
+            [52, 53, 54, 55],
+            [56, 57, 58, 59],
+            [60, 61, 62, 63],
+            [0, 16, 32, 48],
+            [4, 20, 36, 52],
+            [8, 24, 40, 56],
+            [12, 28, 44, 60],
+            [1, 17, 33, 49],
+            [5, 21, 37, 53],
+            [9, 25, 41, 57],
+            [13, 29, 45, 61],
+            [2, 18, 34, 50],
+            [6, 22, 38, 54],
+            [10, 26, 42, 58],
+            [14, 30, 46, 62],
+            [3, 19, 35, 51],
+            [7, 23, 39, 55],
+            [11, 27, 43, 59],
+            [15, 31, 47, 63],
+            [0, 4, 8, 12],
+            [16, 20, 24, 28],
+            [32, 36, 40, 44],
+            [48, 52, 56, 60],
+            [1, 5, 9, 13],
+            [17, 21, 25, 29],
+            [33, 37, 41, 45],
+            [49, 53, 57, 61],
+            [2, 6, 10, 14],
+            [18, 22, 26, 30],
+            [34, 38, 42, 46],
+            [50, 54, 58, 62],
+            [3, 7, 11, 15],
+            [19, 23, 27, 31],
+            [35, 39, 43, 47],
+            [51, 55, 59, 63],
+            [0, 5, 10, 15],
+            [16, 21, 26, 31],
+            [32, 37, 42, 47],
+            [48, 53, 58, 63],
+            [12, 9, 6, 3],
+            [28, 25, 22, 19],
+            [44, 41, 38, 35],
+            [60, 57, 54, 51],
+            [0, 20, 40, 60],
+            [1, 21, 41, 61],
+            [2, 22, 42, 62],
+            [3, 23, 43, 63],
+            [48, 36, 24, 12],
+            [49, 37, 25, 13],
+            [50, 38, 26, 14],
+            [51, 39, 27, 15],
+            [0, 17, 34, 51],
+            [4, 21, 38, 55],
+            [8, 25, 42, 59],
+            [12, 29, 46, 63],
+            [48, 33, 18, 3],
+            [52, 37, 22, 7],
+            [56, 41, 26, 11],
+            [60, 45, 30, 15],
+            [0, 21, 42, 63],
+            [15, 26, 37, 48],
+            [3, 22, 41, 60],
+            [12, 25, 38, 51],
+        ]
+
+    def get(self, x, y, z):
+        m = self.board[4 * (4 * z + y) + x]
+        if m == 40:
+            return Player.MACHINE
+        elif m == 8:
+            return Player.HUMAN
+        else:
+            return Player.EMPTY
+
+    def move3D(self, x, y, z, player):
+        m = 4 * (4 * z + y) + x
+        return self.move(m, player)
+
+    def move(self, m, player):
+        if self.board[m] > 1:
+            return False
+
+        if player == Player.MACHINE:
+            self.board[m] = 40
+        else:
+            self.board[m] = 8
+        return True
+
+    def get3DPosition(self, m):
+        x = m % 4
+        y = (m // 4) % 4
+        z = m // 16
+        return x, y, z
+
+    def evaluateLines(self):
+        self.lineValues = [0] * 76
+        for j in range(76):
+            value = 0
+            for k in range(4):
+                value += self.board[self.lines[j][k]]
+            self.lineValues[j] = value
+
+    def strategyMarkLine(self, i):
+        for j in range(4):
+            m = self.lines[i][j]
+            if self.board[m] == 0:
+                self.board[m] = 1
+
+    def clearStrategyMarks(self):
+        for i in range(64):
+            if self.board[i] == 1:
+                self.board[i] = 0
+
+    def markAndMove(self, vlow, vhigh, vmove):
+        """
+        mark lines that can potentially win the game for the human
+        or the machine and choose best place to play
+        """
+        for i in range(76):
+            value = 0
+            for j in range(4):
+                value += self.board[self.lines[i][j]]
+            self.lineValues[i] = value
+            if vlow <= value < vhigh:
+                if value > vlow:
+                    return self.moveTriple(i)
+                self.strategyMarkLine(i)
+        self.evaluateLines()
+
+        for i in range(76):
+            value = self.lineValues[i]
+            if value == 4 or value == vmove:
+                return self.moveDiagonals(i, 1)
+        return None
+
+    def machineMove(self):
+        """machine works out what move to play"""
+        self.clearStrategyMarks()
+
+        self.evaluateLines()
+        for value, event in [
+            (32, self.humanWin),
+            (120, self.machineWin),
+            (24, self.blockHumanWin),
+        ]:
+            for i in range(76):
+                if self.lineValues[i] == value:
+                    return event(i)
+
+        m = self.markAndMove(80, 88, 43)
+        if m is not None:
+            return m
+
+        self.clearStrategyMarks()
+
+        m = self.markAndMove(16, 24, 11)
+        if m is not None:
+            return m
+
+        for k in range(18):
+            value = 0
+            for i in range(4 * k, 4 * k + 4):
+                for j in range(4):
+                    value += self.board[self.lines[i][j]]
+            if (32 <= value < 40) or (72 <= value < 80):
+                for s in [1, 0]:
+                    for i in range(4 * k, 4 * k + 4):
+                        m = self.moveDiagonals(i, s)
+                        if m is not None:
+                            return m
+
+        self.clearStrategyMarks()
+
+        for y in self.corners:
+            if self.board[y] == 0:
+                return (Move.MOVES, y)
+
+        for i in range(64):
+            if self.board[i] == 0:
+                return (Move.LIKES, i)
+
+        return (Move.DRAW, -1)
+
+    def humanWin(self, i):
+        return (Move.HUMAN_WIN, -1, i)
+
+    def machineWin(self, i):
+        for j in range(4):
+            m = self.lines[i][j]
+            if self.board[m] == 0:
+                return (Move.MACHINE_WIN, m, i)
+        return None
+
+    def blockHumanWin(self, i):
+        for j in range(4):
+            m = self.lines[i][j]
+            if self.board[m] == 0:
+                return (Move.NICE_TRY, m)
+        return None
+
+    def moveTriple(self, i):
+        """make two lines-of-3 or prevent human from doing this"""
+        for j in range(4):
+            m = self.lines[i][j]
+            if self.board[m] == 1:
+                if self.lineValues[i] < 40:
+                    return (Move.YOU_FOX, m)
+                else:
+                    return (Move.GET_OUT, m)
+        return (Move.CONCEDES, -1)
+
+    # choose move in corners or center boxes of square 4x4
+    def moveDiagonals(self, i, s):
+        if 0 < (i % 4) < 3:
+            jrange = [1, 2]
+        else:
+            jrange = [0, 3]
+        for j in jrange:
+            m = self.lines[i][j]
+            if self.board[m] == s:
+                return (Move.TAKES, m)
+        return None
+
+
+class Qubit:
+    def moveCode(self, board, m):
+        x, y, z = board.get3DPosition(m)
+        return f"{z + 1:d}{y + 1:d}{x + 1:d}"
+
+    def showWin(self, board, i):
+        for m in board.lines[i]:
+            print(self.moveCode(board, m))
+
+    def showBoard(self, board):
+        c = " YM"
+        for z in range(4):
+            for y in range(4):
+                print("   " * y, end="")
+                for x in range(4):
+                    p = board.get(x, y, z)
+                    print(f"({c[p.value]})      ", end="")
+                print("\n")
+            print("\n")
+
+    def humanMove(self, board):
+        print("")
+        c = "1234"
+        while True:
+            h = input("Your move?\n")
+            if h == "1":
+                return False
+            if h == "0":
+                self.showBoard(board)
+                continue
+            if (len(h) == 3) and (h[0] in c) and (h[1] in c) and (h[2] in c):
+                x = c.find(h[2])
+                y = c.find(h[1])
+                z = c.find(h[0])
+                if board.move3D(x, y, z, Player.HUMAN):
+                    break
+
+                print("That square is used. Try again.")
+            else:
+                print("Incorrect move. Retype it--")
+
+        return True
+
+    def play(self):
+        print("Qubic\n")
+        print("Create Computing Morristown, New Jersey\n\n\n")
+        while True:
+            c = input("Do you want instructions?\n")
+            if len(c) >= 1 and (c[0] in "ynYN"):
+                break
+            print("Incorrect answer. Please type 'yes' or 'no.")
+
+        c = c.lower()
+        if c[0] == "y":
+            print("The game is Tic-Tac-Toe in a 4 x 4 x 4 cube.")
+            print("Each move is indicated by a 3 digit number, with each")
+            print("digit between 1 and 4 inclusive.  The digits indicate the")
+            print("level, row, and column, respectively, of the occupied")
+            print("place.\n")
+
+            print("To print the playing board, type 0 (zero) as your move.")
+            print("The program will print the board with your moves indicated")
+            print("with a (Y), the machine's moves with an (M), and")
+            print("unused squares with a ( ).\n")
+
+            print("To stop the program run, type 1 as your move.\n\n")
+
+        play_again = True
+        while play_again:
+            board = TicTacToe3D()
+
+            while True:
+                s = input("Do you want to move first?\n")
+                if len(s) >= 1 and (s[0] in "ynYN"):
+                    break
+                print("Incorrect answer. Please type 'yes' or 'no'.")
+
+            skipHuman = s[0] in "nN"
+
+            move_text = [
+                "Machine moves to",
+                "Machine likes",
+                "Machine takes",
+                "Let's see you get out of this:  Machine moves to",
+                "You fox.  Just in the nick of time, machine moves to",
+                "Nice try. Machine moves to",
+            ]
+
+            while True:
+                if not skipHuman:
+                    if not self.humanMove(board):
+                        break
+                skipHuman = False
+
+                m = board.machineMove()
+                if m[0] == Move.HUMAN_WIN:
+                    print("You win as follows,")
+                    self.showWin(board, m[2])
+                    break
+                elif m[0] == Move.MACHINE_WIN:
+                    print(
+                        "Machine moves to {}, and wins as follows".format(
+                            self.moveCode(board, m[1])
+                        )
+                    )
+                    self.showWin(board, m[2])
+                    break
+                elif m[0] == Move.DRAW:
+                    print("The game is a draw.")
+                    break
+                elif m[0] == Move.CONCEDES:
+                    print("Machine concedes this game.")
+                    break
+                else:
+                    print(move_text[m[0].value - Move.MOVES.value])
+                    print(self.moveCode(board, m[1]))
+                    board.move(m[1], Player.MACHINE)
+
+                self.showBoard(board)
+
+            print(" ")
+            while True:
+                x = input("Do you want to try another game\n")
+                if len(x) >= 1 and x[0] in "ynYN":
+                    break
+                print("Incorrect answer. Please Type 'yes' or 'no'.")
+
+            play_again = x[0] in "yY"
+
+
+if __name__ == "__main__":
+    game = Qubit()
+    game.play()
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/qubit.bas b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/qubit.bas
new file mode 100644
index 00000000..473e955a
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/qubit.bas
@@ -0,0 +1,281 @@
+50 PRINT CHR$(26):REM WIDTH 80
+100 PRINT TAB(33);"QUBIC":PRINT
+110 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+120 PRINT:PRINT:PRINT
+210 PRINT "DO YOU WANT INSTRUCTIONS";
+220 INPUT C$
+230 IF LEFT$(C$,1)="N" THEN 315
+240 IF LEFT$(C$,1)="Y" THEN 265
+250 PRINT "INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'";
+260 GOTO 220
+265 PRINT
+270 PRINT "THE GAME IS TIC-TAC-TOE IN A 4 X 4 X 4 CUBE."
+280 PRINT "EACH MOVE IS INDICATED BY A 3 DIGIT NUMBER, WITH EACH"
+290 PRINT "DIGIT BETWEEN 1 AND 4 INCLUSIVE.  THE DIGITS INDICATE THE"
+300 PRINT "LEVEL, ROW, AND COLUMN, RESPECTIVELY, OF THE OCCUPIED"
+305 PRINT "PLACE.  "
+306 PRINT
+307 PRINT "TO PRINT THE PLAYING BOARD, TYPE 0 (ZERO) AS YOUR MOVE."
+308 PRINT "THE PROGRAM WILL PRINT THE BOARD WITH YOUR MOVES INDI-"
+309 PRINT "CATED WITH A (Y), THE MACHINE'S MOVES WITH AN (M), AND"
+310 PRINT "UNUSED SQUARES WITH A ( ).  OUTPUT IS ON PAPER."
+311 PRINT
+312 PRINT "TO STOP THE PROGRAM RUN, TYPE 1 AS YOUR MOVE."
+313 PRINT:PRINT
+315 DIM X(64),L(76),M(76,4),Y(16)
+320 FOR I = 1 TO 16
+330 READ Y(I)
+340 NEXT I
+350 FOR I=1 TO 76
+360 FOR J = 1 TO 4
+370 READ M(I,J)
+380 NEXT J
+390 NEXT I
+400 FOR I = 1 TO 64
+410 LET X (I) =0
+420 NEXT I
+430 LET Z=1
+440 PRINT "DO YOU WANT TO MOVE FIRST";
+450 INPUT S$
+460 IF LEFT$(S$,1)="N" THEN 630
+470 IF LEFT$(S$,1)="Y" THEN 500
+480 PRINT "INCORRECT ANSWER.  PLEASE TYPE 'YES' OR 'NO'.";
+490 GOTO 450
+500 PRINT " "
+510 PRINT "YOUR MOVE";
+520 INPUT J1
+521 IF J1=1 THEN 2770
+522 IF J1<>0 THEN 525
+523 GOSUB 2550
+524 GOTO 500
+525 IF J1<111 THEN 2750
+526 IF J1>444 THEN 2750
+530 GOSUB 2500
+540 LET K1=INT(J1/100)
+550 LET J2=(J1-K1*100)
+560 LET K2=INT(J2/10)
+570 LET K3= J1 - K1*100 -K2*10
+580 LET M=16*K1+4*K2+K3-20
+590 IF X(M)=0 THEN 620
+600 PRINT "THAT SQUARE IS USED, TRY AGAIN."
+610 GOTO 500
+620 LET X(M)=1
+630 GOSUB 1640
+640 J=1
+650 I=1
+660 IF J=1 THEN 720
+670 IF J=2 THEN 790
+680 IF J=3 THEN 930
+690 I=I+1: IF I<=76 THEN 660
+700 J=J+1: IF J<=3 THEN 650
+710 GOTO 1300
+720 IF L(I)<>4 THEN 690
+730 PRINT "YOU WIN AS FOLLOWS";
+740 FOR J=1 TO 4
+750 LET M=M(I,J)
+760 GOSUB 1570
+770 NEXT J
+780 GOTO 1490
+790 IF L(I)<>15 THEN 690
+800 FOR J=1 TO 4
+810 LET M=M(I,J)
+820 IF X(M)<>0 THEN 860
+830 LET X(M)=5
+840 PRINT "MACHINE MOVES TO";
+850 GOSUB 1570
+860 NEXT J
+870 PRINT ", AND WINS AS FOLLOWS"
+880 FOR J=1 TO 4
+890 LET M=M(I,J)
+900 GOSUB 1570
+910 NEXT J
+920 GOTO 1490
+930 IF L(I)<>3 THEN 690
+940 PRINT "NICE TRY. MACHINE MOVES TO";
+950 FOR J=1 TO 4
+960 LET M=M(I,J)
+970 IF X(M)<>0 THEN 1010
+980 LET X(M)=5
+990 GOSUB 1570
+1000 GOTO 500
+1010 NEXT J
+1020 GOTO 1300
+1030 I=1
+1040 LET L(I)=X(M(I,1))+X(M(I,2))+X(M(I,3))+X(M(I,4))
+1050 LET L = L(I)
+1060 IF L <2 THEN 1130
+1070 IF L>=3 THEN 1130
+1080 IF L>2 THEN 2230
+1090 FOR J = 1 TO 4
+1100 IF X(M(I,J))<>0 THEN 1120
+1110 LET X(M(I,J))=1/8
+1120 NEXT J
+1130 I=I+1: IF I<=76 THEN 1040
+1140 GOSUB 1640
+1150 I=1
+1160 IF L(I)=1/2 THEN 2360
+1170 IF L(I)=1+3/8 THEN 2360
+1180 I=I+1: IF I<=76 THEN 1160
+1190 GOTO 1830
+1200 LET Z = 1
+1210 IF X(Y(Z))=0 THEN 1250
+1220 LET Z=Z+1
+1230 IF Z<>17 THEN 1210
+1240 GOTO 1720
+1250 LET M=Y(Z)
+1260 LET X(M)=5
+1270 PRINT "MACHINE MOVES TO";
+1280 GOSUB 1570
+1290 GOTO 500
+1300 LET X=X
+1310 I=1
+1320 LET L(I)=X(M(I,1))+X(M(I,2))+X(M(I,3))+X(M(I,4))
+1330 LET L=L(I)
+1340 IF L<10 THEN 1410
+1350 IF L>=11 THEN 1410
+1360 IF L>10 THEN 2230
+1370 FOR J=1 TO 4
+1380 IF X(M(I,J))<>0 THEN 1400
+1390 LET X(M(I,J))=1/8
+1400 NEXT J
+1410 I=I+1: IF I<=76 THEN 1320
+1420 GOSUB 1640
+1430 I=1
+1440 IF L(I)=.5 THEN 2360
+1450 IF L(I)=5+3/8 THEN 2360
+1460 I=I+1: IF I<=76 THEN 1440
+1470 GOSUB 2500
+1480 GOTO 1030
+1490 PRINT " "
+1500 PRINT "DO YOU WANT TO TRY ANOTHER GAME";
+1510 INPUT X$
+1520 IF LEFT$(X$,1)="Y" THEN 400
+1530 IF LEFT$(X$,1)="N" THEN 1560
+1540 PRINT "INCORRECT ANSWER. PLEASE TYPE 'YES' OR 'NO'";
+1550 GOTO 1510
+1560 END
+1570 LET K1=INT((M-1)/16)+1
+1580 LET J2=M-16*(K1-1)
+1590 LET K2=INT((J2-1)/4)+1
+1600 LET K3=M-(K1-1)*16-(K2-1)*4
+1610 LET M=K1*100+K2*10+K3
+1620 PRINT M;
+1630 RETURN
+1640 FOR S=1 TO 76
+1650 LET J1 = M(S,1)
+1660 LET J2=M(S,2)
+1670 LET J3=M(S,3)
+1680 LET J4=M(S,4)
+1690 LET L(S)=X(J1)+X(J2)+X(J3)+X(J4)
+1700 NEXT S
+1710 RETURN
+1720 FOR I=1 TO 64
+1730 IF X(I)<>0 THEN 1800
+1740 LET X(I)=5
+1750 LET M=I
+1760 PRINT "MACHINE LIKES";
+1770 GOSUB 1570
+1780 PRINT " "
+1790 GOTO 500
+1800 NEXT I
+1810 PRINT "THE GAME IS A DRAW."
+1820 GOTO 1490
+1830 FOR K=1 TO 18
+1840 LET P=0
+1850 FOR I=4*K-3 TO 4*K
+1860 FOR J=1 TO 4
+1870 LET P=P+X(M(I,J))
+1880 NEXT J
+1890 NEXT I
+1900 IF P<4 THEN 1940
+1910 IF P<5 THEN 1970
+1920 IF P<9 THEN 1940
+1930 IF P<10 THEN 1970
+1940 NEXT K
+1950 GOSUB 2500
+1960 GOTO 1200
+1970 LET S=1/8
+1980 FOR I=4*K-3 TO 4*K
+1990 GOTO 2370
+2000 NEXT I
+2010 LET S=0
+2020 GOTO 1980
+2030 DATA 1,49,52,4,13,61,64,16,22,39,23,38,26,42,27,43
+2040 DATA 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20
+2050 DATA 21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38
+2060 DATA 39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56
+2070 DATA 57,58,59,60,61,62,63,64
+2080 DATA 1,17,33,49,5,21,37,53,9,25,41,57,13,29,45,61
+2090 DATA 2,18,34,50,6,22,38,54,10,26,42,58,14,30,46,62
+2100 DATA 3,19,35,51,7,23,39,55,11,27,43,59,15,31,47,63
+2110 DATA 4,20,36,52,8,24,40,56,12,28,44,60,16,32,48,64
+2120 DATA 1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61
+2130 DATA 2,6,10,14,18,22,26,30,34,38,42,46,50,54,58,62
+2140 DATA 3,7,11,15,19,23,27,31,35,39,43,47,51,55,59,63
+2150 DATA 4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64
+2160 DATA 1,6,11,16,17,22,27,32,33,38,43,48,49,54,59,64
+2170 DATA 13,10,7,4,29,26,23,20,45,42,39,36,61,58,55,52
+2180 DATA 1,21,41,61,2,22,42,62,3,23,43,63,4,24,44,64
+2190 DATA 49,37,25,13,50,38,26,14,51,39,27,15,52,40,28,16
+2200 DATA 1,18,35,52,5,22,39,56,9,26,43,60,13,30,47,64
+2210 DATA 49,34,19,4,53,38,23,8,57,42,27,12,61,46,31,16
+2220 DATA 1,22,43,64,16,27,38,49,4,23,42,61,13,26,39,52
+2230 FOR J=1 TO 4
+2240 IF X(M(I,J))<>1/8 THEN 2330
+2250 LET X(M(I,J))=5
+2260 IF L(I)<5 THEN 2290
+2270 PRINT "LET'S SEE YOU GET OUT OF THIS:  MACHINE MOVES TO";
+2280 GOTO 2300
+2290 PRINT "YOU FOX.  JUST IN THE NICK OF TIME, MACHINE MOVES TO";
+2300 LET M=M(I,J)
+2310 GOSUB 1570
+2320 GOTO 500
+2330 NEXT J
+2340 PRINT "MACHINE CONCEDES THIS GAME."
+2350 GOTO 1490
+2360 LET S=1/8
+2370 IF I-INT(I/4)*4>1 THEN 2400
+2380 LET A=1
+2390 GOTO 2410
+2400 LET A=2
+2410 FOR J=A TO 5-A STEP 5-2*A
+2420 IF X(M(I,J))=S THEN 2450
+2430 NEXT J
+2440 GOTO 2000
+2450 LET X(M(I,J))=5
+2460 LET M=M(I,J)
+2470 PRINT "MACHINE TAKES";
+2480 GOSUB 1570
+2490 GOTO 500
+2500 FOR I=1 TO 64
+2510 IF X(I)<>1/8 THEN 2530
+2520 LET X(I)=0
+2530 NEXT I
+2540 RETURN
+2550 FOR XX=1 TO 9:PRINT:NEXT:FOR I=1 TO 4
+2560 FOR J=1 TO 4
+2562 FOR I1=1 TO J
+2564 PRINT"   ";
+2566 NEXT I1
+2570 FOR K=1 TO 4
+2600 LET Q=16*I+4*J+K-20
+2610 IF X(Q)<>O THEN 2630
+2620 PRINT"( )      ";
+2630 IF X(Q)<>5 THEN 2650
+2640 PRINT"(M)      ";
+2650 IF X(Q)<>1 THEN 2660
+2655 PRINT"(Y)      ";
+2660 IF X(Q)<>1/8 THEN 2670
+2665 PRINT"( )      ";
+2670 NEXT K
+2680 PRINT
+2690 PRINT
+2700 NEXT J
+2710 PRINT
+2720 PRINT
+2730 NEXT I
+2735 REM PRINT CHR$(12)
+2740 RETURN
+2750 PRINT"INCORRECT MOVE, RETYPE IT--";
+2760 GOTO 520
+2770 END
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/ruby/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/vbnet/README.md b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/vbnet/ThreeDTicTacToe.sln b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/vbnet/ThreeDTicTacToe.sln
new file mode 100644
index 00000000..6479b013
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/vbnet/ThreeDTicTacToe.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "ThreeDTicTacToe", "ThreeDTicTacToe.vbproj", "{AD17E9E0-4795-4533-A215-09DD99F7D696}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{AD17E9E0-4795-4533-A215-09DD99F7D696}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AD17E9E0-4795-4533-A215-09DD99F7D696}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AD17E9E0-4795-4533-A215-09DD99F7D696}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AD17E9E0-4795-4533-A215-09DD99F7D696}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/vbnet/ThreeDTicTacToe.vbproj b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/vbnet/ThreeDTicTacToe.vbproj
new file mode 100644
index 00000000..d1cd4c2b
--- /dev/null
+++ b/00_Alternate_Languages/88_3-D_Tic-Tac-Toe/vbnet/ThreeDTicTacToe.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    ThreeDTicTacToe
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/89_Tic-Tac-Toe/README.md b/00_Alternate_Languages/89_Tic-Tac-Toe/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/89_Tic-Tac-Toe/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/65_Nim/pascal/README.md b/00_Alternate_Languages/89_Tic-Tac-Toe/go/README.md
similarity index 100%
rename from 65_Nim/pascal/README.md
rename to 00_Alternate_Languages/89_Tic-Tac-Toe/go/README.md
diff --git a/89_Tic-Tac-Toe/go/src/tictactoe1.go b/00_Alternate_Languages/89_Tic-Tac-Toe/go/src/tictactoe1.go
similarity index 100%
rename from 89_Tic-Tac-Toe/go/src/tictactoe1.go
rename to 00_Alternate_Languages/89_Tic-Tac-Toe/go/src/tictactoe1.go
diff --git a/66_Number/pascal/README.md b/00_Alternate_Languages/89_Tic-Tac-Toe/pascal/README.md
similarity index 100%
rename from 66_Number/pascal/README.md
rename to 00_Alternate_Languages/89_Tic-Tac-Toe/pascal/README.md
diff --git a/89_Tic-Tac-Toe/pascal/tictactoe1.pas b/00_Alternate_Languages/89_Tic-Tac-Toe/pascal/tictactoe1.pas
similarity index 100%
rename from 89_Tic-Tac-Toe/pascal/tictactoe1.pas
rename to 00_Alternate_Languages/89_Tic-Tac-Toe/pascal/tictactoe1.pas
diff --git a/00_Alternate_Languages/89_Tic-Tac-Toe/tictactoe1.bas b/00_Alternate_Languages/89_Tic-Tac-Toe/tictactoe1.bas
new file mode 100644
index 00000000..57eace47
--- /dev/null
+++ b/00_Alternate_Languages/89_Tic-Tac-Toe/tictactoe1.bas
@@ -0,0 +1,69 @@
+10 PRINT TAB(30);"TIC TAC TOE"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+50 REM
+100 REM   THIS PROGRAM PLAYS TIC TAC TOE
+110 REM   THE MACHINE GOES FIRST
+120 PRINT "THE GAME BOARD IS NUMBERED:": PRINT
+130 PRINT "1  2  3": PRINT "8  9  4": PRINT "7  6  5"
+140 PRINT
+150 REM
+160 REM
+170 REM
+180 DEF FNM(X)=X-8*INT((X-1)/8)
+190 REM
+200 REM  MAIN PROGRAM
+210 PRINT
+220 PRINT
+230 A=9
+240 M=A
+250 GOSUB 650
+260 P=M
+270 B=FNM(P+1)
+280 M=B
+290 GOSUB 650
+300 Q=M
+310 IF Q=FNM(B+4) THEN 360
+320 C=FNM(B+4)
+330 M=C
+340 GOSUB 700
+350 GOTO 730
+360 C=FNM(B+2)
+370 M=C
+380 GOSUB 650
+390 R=M
+400 IF R=FNM(C+4) THEN 450
+410 D=FNM(C+4)
+420 M=D
+430 GOSUB 700
+440 GOTO 730
+450 IF P/2<>INT(P/2) THEN 500
+460 D=FNM(C+7)
+470 M=D
+480 GOSUB 700
+490 GOTO 730
+500 D=FNM(C+3)
+510 M=D
+520 GOSUB 650
+530 S=M
+540 IF S=FNM(D+4) THEN 590
+550 E=FNM(D+4)
+560 M=E
+570 GOSUB 700
+580 REM
+590 E=FNM(D+6)
+600 M=E
+610 GOSUB 700
+620 PRINT "THE GAME IS A DRAW."
+630 GOTO 210
+640 REM
+650 GOSUB 700
+660 PRINT "YOUR MOVE";
+670 INPUT M
+680 RETURN
+700 PRINT "COMPUTER MOVES";M
+710 RETURN
+720 REM
+730 PRINT "AND WINS ********"
+740 GOTO 210
+750 END
diff --git a/00_Alternate_Languages/89_Tic-Tac-Toe/tictactoe2.bas b/00_Alternate_Languages/89_Tic-Tac-Toe/tictactoe2.bas
new file mode 100644
index 00000000..ef6fee8e
--- /dev/null
+++ b/00_Alternate_Languages/89_Tic-Tac-Toe/tictactoe2.bas
@@ -0,0 +1,114 @@
+2 PRINT TAB(30);"TIC-TAC-TOE"
+4 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+6 PRINT:PRINT:PRINT
+8 PRINT "THE BOARD IS NUMBERED:"
+10 PRINT " 1  2  3"
+12 PRINT " 4  5  6"
+14 PRINT " 7  8  9"
+16 PRINT:PRINT:PRINT
+20 DIM S(9)
+50 INPUT"DO YOU WANT 'X' OR 'O'";C$
+55 IF C$="X"THEN 475
+60 P$="O":Q$="X"
+100 G=-1:H=1:IF S(5)<>0 THEN 103
+102 S(5)=-1:GOTO 195
+103 IF S(5)<>1 THEN 106
+104 IF S(1)<>0 THEN 110
+105 S(1)=-1:GOTO 195
+106 IF S(2)=1 AND S(1)=0 THEN 181
+107 IF S(4)=1 AND S(1)=0 THEN 181
+108 IF S(6)=1 AND S(9)=0 THEN 189
+109 IF S(8)=1 AND S(9)=0 THEN 189
+110 IF G=1 THEN 112
+111 GOTO 118
+112 J=3*INT((M-1)/3)+1
+113 IF 3*INT((M-1)/3)+1=M THEN K=1
+114 IF 3*INT((M-1)/3)+2=M THEN K=2
+115 IF 3*INT((M-1)/3)+3=M THEN K=3
+116 GOTO 120
+118 FOR J=1 TO 7 STEP 3:FOR K=1 TO 3
+120 IF S(J)<>G THEN 130
+122 IF S(J+2)<>G THEN 135
+126 IF S(J+1)<>0 THEN 150
+128 S(J+1)=-1:GOTO 195
+130 IF S(J)=H THEN 150
+131 IF S(J+2)<>G THEN 150
+132 IF S(J+1)<>G THEN 150
+133 S(J)=-1:GOTO 195
+135 IF S(J+2)<>0 THEN 150
+136 IF S(J+1)<>G THEN 150
+138 S(J+2)=-1:GOTO 195
+150 IF S(K)<>G THEN 160
+152 IF S(K+6)<>G THEN 165
+156 IF S(K+3)<>0 THEN 170
+158 S(K+3)=-1:GOTO 195
+160 IF S(K)=H THEN 170
+161 IF S(K+6)<>G THEN 170
+162 IF S(K+3)<>G THEN 170
+163 S(K)=-1:GOTO 195
+165 IF S(K+6)<>0 THEN 170
+166 IF S(K+3)<>G THEN 170
+168 S(K+6)=-1:GOTO 195
+170 GOTO 450
+171 IF S(3)=G AND S(7)=0 THEN 187
+172 IF S(9)=G AND S(1)=0 THEN 181
+173 IF S(7)=G AND S(3)=0 THEN 183
+174 IF S(9)=0 AND S(1)=G THEN 189
+175 IF G=-1 THEN G=1:H=-1:GOTO 110
+176 IF S(9)=1 AND S(3)=0 THEN 182
+177 FOR I=2 TO 9:IF S(I)<>0 THEN 179
+178 S(I)=-1:GOTO 195
+179 NEXT I
+181 S(1)=-1:GOTO 195
+182 IF S(1)=1 THEN 177
+183 S(3)=-1:GOTO 195
+187 S(7)=-1:GOTO 195
+189 S(9)=-1
+195 PRINT:PRINT"THE COMPUTER MOVES TO..."
+202 GOSUB 1000
+205 GOTO 500
+450 IF G=1 THEN 465
+455 IF J=7 AND K=3 THEN 465
+460 NEXT K,J
+465 IF S(5)=G THEN 171
+467 GOTO 175
+475 P$="X":Q$="O"
+500 PRINT:INPUT"WHERE DO YOU MOVE";M
+502 IF M=0 THEN PRINT"THANKS FOR THE GAME.":GOTO 2000
+503 IF M>9 THEN 506
+505 IF S(M)=0 THEN 510
+506 PRINT"THAT SQUARE IS OCCUPIED.":PRINT:PRINT:GOTO 500
+510 G=1:S(M)=1
+520 GOSUB 1000
+530 GOTO 100
+1000 PRINT:FOR I=1 TO 9:PRINT" ";:IF S(I)<>-1 THEN 1014
+1012 PRINT Q$" ";:GOTO 1020
+1014 IF S(I)<>0 THEN 1018
+1016 PRINT"  ";:GOTO 1020
+1018 PRINT P$" ";
+1020 IF I<>3 AND I<>6 THEN 1050
+1030 PRINT:PRINT"---+---+---"
+1040 GOTO 1080
+1050 IF I=9 THEN 1080
+1060 PRINT"!";
+1080 NEXT I:PRINT:PRINT:PRINT
+1095 FOR I=1 TO 7 STEP 3
+1100 IF S(I)<>S(I+1)THEN 1115
+1105 IF S(I)<>S(I+2)THEN 1115
+1110 IF S(I)=-1 THEN 1350
+1112 IF S(I)=1 THEN 1200
+1115 NEXT I:FOR I=1 TO 3:IF S(I)<>S(I+3)THEN 1150
+1130 IF S(I)<>S(I+6)THEN 1150
+1135 IF S(I)=-1 THEN 1350
+1137 IF S(I)=1 THEN 1200
+1150 NEXT I:FOR I=1 TO 9:IF S(I)=0 THEN 1155
+1152 NEXT I:GOTO 1400
+1155 IF S(5)<>G THEN 1170
+1160 IF S(1)=G AND S(9)=G THEN 1180
+1165 IF S(3)=G AND S(7)=G THEN 1180
+1170 RETURN
+1180 IF G=-1 THEN 1350
+1200 PRINT"YOU BEAT ME!! GOOD GAME.":GOTO 2000
+1350 PRINT"I WIN, TURKEY!!!":GOTO 2000
+1400 PRINT"IT'S A DRAW. THANK YOU."
+2000 END
diff --git a/00_Alternate_Languages/90_Tower/README.md b/00_Alternate_Languages/90_Tower/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/90_Tower/csharp/Game.cs b/00_Alternate_Languages/90_Tower/csharp/Game.cs
new file mode 100644
index 00000000..7e0c7d0b
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Game.cs
@@ -0,0 +1,78 @@
+using System;
+using Tower.Models;
+using Tower.Resources;
+using Tower.UI;
+
+namespace Tower
+{
+    internal class Game
+    {
+        private readonly Towers _towers;
+        private readonly TowerDisplay _display;
+        private readonly int _optimalMoveCount;
+        private int _moveCount;
+
+        public Game(int diskCount)
+        {
+            _towers = new Towers(diskCount);
+            _display = new TowerDisplay(_towers);
+            _optimalMoveCount = (1 << diskCount) - 1;
+        }
+
+        public bool Play()
+        {
+            Console.Write(Strings.Instructions);
+
+            Console.Write(_display);
+
+            while (true)
+            {
+                if (!Input.TryReadNumber(Prompt.Disk, out int disk)) { return false; }
+
+                if (!_towers.TryFindDisk(disk, out var from, out var message))
+                {
+                    Console.WriteLine(message);
+                    continue;
+                }
+
+                if (!Input.TryReadNumber(Prompt.Needle, out var to)) { return false; }
+
+                if (!_towers.TryMoveDisk(from, to))
+                {
+                    Console.Write(Strings.IllegalMove);
+                    continue;
+                }
+
+                Console.Write(_display);
+
+                var result = CheckProgress();
+                if (result.HasValue) { return result.Value; }
+            }
+        }
+
+        private bool? CheckProgress()
+        {
+            _moveCount++;
+
+            if (_moveCount == 128)
+            {
+                Console.Write(Strings.TooManyMoves);
+                return false;
+            }
+
+            if (_towers.Finished)
+            {
+                if (_moveCount == _optimalMoveCount)
+                {
+                    Console.Write(Strings.Congratulations);
+                }
+
+                Console.WriteLine(Strings.TaskFinished, _moveCount);
+
+                return true;
+            }
+
+            return default;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/90_Tower/csharp/Models/Needle.cs b/00_Alternate_Languages/90_Tower/csharp/Models/Needle.cs
new file mode 100644
index 00000000..8ea67aa4
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Models/Needle.cs
@@ -0,0 +1,33 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Tower.Models
+{
+    internal class Needle : IEnumerable
+    {
+        private readonly Stack _disks = new Stack();
+
+        public bool IsEmpty => _disks.Count == 0;
+
+        public int Top => _disks.TryPeek(out var disk) ? disk : default;
+
+        public bool TryPut(int disk)
+        {
+            if (_disks.Count == 0 || disk < _disks.Peek())
+            {
+                _disks.Push(disk);
+                return true;
+            }
+
+            return false;
+        }
+
+        public bool TryGetTopDisk(out int disk) => _disks.TryPop(out disk);
+
+        public IEnumerator GetEnumerator() =>
+            Enumerable.Repeat(0, 7 - _disks.Count).Concat(_disks).GetEnumerator();
+
+        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+    }
+}
diff --git a/00_Alternate_Languages/90_Tower/csharp/Models/Towers.cs b/00_Alternate_Languages/90_Tower/csharp/Models/Towers.cs
new file mode 100644
index 00000000..0625a5b7
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Models/Towers.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using Tower.Resources;
+
+namespace Tower.Models
+{
+    internal class Towers : IEnumerable<(int, int, int)>
+    {
+        private static int[] _availableDisks = new[] { 15, 13, 11, 9, 7, 5, 3 };
+
+        private readonly Needle[] _needles = new[] { new Needle(), new Needle(), new Needle() };
+        private readonly int _smallestDisk;
+
+        public Towers(int diskCount)
+        {
+            foreach (int disk in _availableDisks.Take(diskCount))
+            {
+                this[1].TryPut(disk);
+                _smallestDisk = disk;
+            }
+        }
+
+        private Needle this[int i] => _needles[i-1];
+
+        public bool Finished => this[1].IsEmpty && this[2].IsEmpty;
+
+        public bool TryFindDisk(int disk, out int needle, out string message)
+        {
+            needle = default;
+            message = default;
+
+            if (disk < _smallestDisk)
+            {
+                message = Strings.DiskNotInPlay;
+                return false;
+            }
+
+            for (needle = 1; needle <= 3; needle++)
+            {
+                if (this[needle].Top == disk) { return true; }
+            }
+
+            message = Strings.DiskUnavailable;
+            return false;
+        }
+
+        public bool TryMoveDisk(int from, int to)
+        {
+            if (!this[from].TryGetTopDisk(out var disk))
+            {
+                throw new InvalidOperationException($"Needle {from} is empty");
+            }
+
+            if (this[to].TryPut(disk)) { return true; }
+
+            this[from].TryPut(disk);
+            return false;
+        }
+
+        public IEnumerator<(int, int, int)> GetEnumerator() => new TowersEnumerator(_needles);
+
+        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+
+        private class TowersEnumerator : IEnumerator<(int, int, int)>
+        {
+            private readonly List> _enumerators;
+
+            public TowersEnumerator(Needle[] needles)
+            {
+                _enumerators = needles.Select(n => n.GetEnumerator()).ToList();
+            }
+
+            public (int, int, int) Current =>
+                (_enumerators[0].Current, _enumerators[1].Current, _enumerators[2].Current);
+
+            object IEnumerator.Current => Current;
+
+            public void Dispose() => _enumerators.ForEach(e => e.Dispose());
+
+            public bool MoveNext() => _enumerators.All(e => e.MoveNext());
+
+            public void Reset() => _enumerators.ForEach(e => e.Reset());
+        }
+    }
+}
diff --git a/00_Alternate_Languages/90_Tower/csharp/Program.cs b/00_Alternate_Languages/90_Tower/csharp/Program.cs
new file mode 100644
index 00000000..6bc9f107
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Program.cs
@@ -0,0 +1,27 @@
+using System;
+using Tower.Resources;
+using Tower.UI;
+
+namespace Tower
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            Console.Write(Strings.Title);
+
+            do
+            {
+                Console.Write(Strings.Intro);
+
+                if (!Input.TryReadNumber(Prompt.DiskCount, out var diskCount)) { return; }
+
+                var game = new Game(diskCount);
+
+                if (!game.Play()) { return; }
+            } while (Input.ReadYesNo(Strings.PlayAgainPrompt, Strings.YesNoPrompt));
+
+            Console.Write(Strings.Thanks);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/90_Tower/csharp/README.md b/00_Alternate_Languages/90_Tower/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/Congratulations.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/Congratulations.txt
new file mode 100644
index 00000000..fb078fba
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/Congratulations.txt
@@ -0,0 +1,2 @@
+
+Congratulations!!
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/DiskCountPrompt.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskCountPrompt.txt
new file mode 100644
index 00000000..454960fc
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskCountPrompt.txt
@@ -0,0 +1 @@
+How many disks do you want to move (7 is max)
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/DiskCountQuit.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskCountQuit.txt
new file mode 100644
index 00000000..b33b3c51
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskCountQuit.txt
@@ -0,0 +1,2 @@
+All right, wise guy, if you can't play the game right, I'll
+just take my puzzle and go home.  So long.
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/DiskCountRetry.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskCountRetry.txt
new file mode 100644
index 00000000..4857ffa4
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskCountRetry.txt
@@ -0,0 +1 @@
+Sorry, but i can't do that job for you.
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/DiskNotInPlay.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskNotInPlay.txt
new file mode 100644
index 00000000..817e8455
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskNotInPlay.txt
@@ -0,0 +1 @@
+That disk is not in play.  Make another choice.
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/DiskPrompt.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskPrompt.txt
new file mode 100644
index 00000000..91f2583c
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskPrompt.txt
@@ -0,0 +1 @@
+Which disk would you like to move
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/DiskQuit.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskQuit.txt
new file mode 100644
index 00000000..240fe7d2
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskQuit.txt
@@ -0,0 +1 @@
+Stop wasting my time.  Go bother someone else.
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/DiskRetry.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskRetry.txt
new file mode 100644
index 00000000..5927a86d
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskRetry.txt
@@ -0,0 +1 @@
+Illegal entry... You may only type 3, 5, 7, 9, 11, 13, or 15.
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/DiskUnavailable.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskUnavailable.txt
new file mode 100644
index 00000000..1ce62e02
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/DiskUnavailable.txt
@@ -0,0 +1 @@
+That disk is below another one.  Make another choice.
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/IllegalMove.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/IllegalMove.txt
new file mode 100644
index 00000000..ccb425e7
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/IllegalMove.txt
@@ -0,0 +1,3 @@
+You can't place a larger disk on top of a smaller one,
+it might crush it!
+Now then,
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/Instructions.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/Instructions.txt
new file mode 100644
index 00000000..93c71b8d
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/Instructions.txt
@@ -0,0 +1,10 @@
+In this program, we shall refer to disks by numerical code.
+3 will represent the smallest disk, 5 the next size,
+7 the next, and so on, up to 15.  If you do the puzzle with
+2 disks, their code names would be 13 and 15.  With 3 disks
+the code names would be 11, 13 and 15, etc.  The needles
+are numbered from left to right, 1 to 3.  We will
+startup with the disks on needle 1, and attempt to move them
+to needle 3.
+
+Good luck!
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/Intro.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/Intro.txt
new file mode 100644
index 00000000..160d8176
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/Intro.txt
@@ -0,0 +1,6 @@
+
+Towers of Hanoi puzzle.
+
+You must transfer the disks from the left to the right
+tower, one at a time, never putting a larger dish on a
+smaller disk.
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/NeedlePrompt.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/NeedlePrompt.txt
new file mode 100644
index 00000000..9d70b47b
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/NeedlePrompt.txt
@@ -0,0 +1 @@
+Place disk on which needle
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/NeedleQuit.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/NeedleQuit.txt
new file mode 100644
index 00000000..942298e4
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/NeedleQuit.txt
@@ -0,0 +1,2 @@
+I tried to warn you, but you wouldn't listen,
+Bye bye, big shot.
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/NeedleRetry.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/NeedleRetry.txt
new file mode 100644
index 00000000..2c4a2286
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/NeedleRetry.txt
@@ -0,0 +1,2 @@
+I'll assume you hit the wrong key this time.  But watch it,
+I only allow one mistake
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/PlayAgainPrompt.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/PlayAgainPrompt.txt
new file mode 100644
index 00000000..793486dd
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/PlayAgainPrompt.txt
@@ -0,0 +1,2 @@
+
+Try again (Yes or No)
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/Strings.cs b/00_Alternate_Languages/90_Tower/csharp/Resources/Strings.cs
new file mode 100644
index 00000000..0cd8f6e1
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/Strings.cs
@@ -0,0 +1,40 @@
+using System.IO;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace Tower.Resources
+{
+    internal static class Strings
+    {
+        internal static string Congratulations => GetResource();
+        internal static string DiskCountPrompt => GetResource();
+        internal static string DiskCountQuit => GetResource();
+        internal static string DiskCountRetry => GetResource();
+        internal static string DiskNotInPlay => GetResource();
+        internal static string DiskPrompt => GetResource();
+        internal static string DiskQuit => GetResource();
+        internal static string DiskRetry => GetResource();
+        internal static string DiskUnavailable => GetResource();
+        internal static string IllegalMove => GetResource();
+        internal static string Instructions => GetResource();
+        internal static string Intro => GetResource();
+        internal static string NeedlePrompt => GetResource();
+        internal static string NeedleQuit => GetResource();
+        internal static string NeedleRetry => GetResource();
+        internal static string PlayAgainPrompt => GetResource();
+        internal static string TaskFinished => GetResource();
+        internal static string Thanks => GetResource();
+        internal static string Title => GetResource();
+        internal static string TooManyMoves => GetResource();
+        internal static string YesNoPrompt => GetResource();
+
+        private static string GetResource([CallerMemberName] string name = "")
+        {
+            var streamName = $"Tower.Resources.{name}.txt";
+            using var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(streamName);
+            using var reader = new StreamReader(stream);
+
+            return reader.ReadToEnd();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/TaskFinished.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/TaskFinished.txt
new file mode 100644
index 00000000..454bc1f4
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/TaskFinished.txt
@@ -0,0 +1,2 @@
+
+You have performed the task in {0} moves.
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/Thanks.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/Thanks.txt
new file mode 100644
index 00000000..435d89c7
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/Thanks.txt
@@ -0,0 +1,2 @@
+
+Thanks for the game!
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/Title.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/Title.txt
new file mode 100644
index 00000000..af05e12e
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/Title.txt
@@ -0,0 +1,2 @@
+                                 Towers
+               Creative Computing  Morristown, New Jersey
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/TooManyMoves.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/TooManyMoves.txt
new file mode 100644
index 00000000..5c190ec3
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/TooManyMoves.txt
@@ -0,0 +1,2 @@
+Sorry, but I have orders to stop if you make more than
+128 moves.
diff --git a/00_Alternate_Languages/90_Tower/csharp/Resources/YesNoPrompt.txt b/00_Alternate_Languages/90_Tower/csharp/Resources/YesNoPrompt.txt
new file mode 100644
index 00000000..c4539f5a
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Resources/YesNoPrompt.txt
@@ -0,0 +1,2 @@
+
+'Yes' or 'No' please
diff --git a/00_Alternate_Languages/90_Tower/csharp/Tower.csproj b/00_Alternate_Languages/90_Tower/csharp/Tower.csproj
new file mode 100644
index 00000000..c0de0594
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Tower.csproj
@@ -0,0 +1,12 @@
+
+
+  
+    Exe
+    net5.0
+  
+
+  
+    
+  
+
+
diff --git a/00_Alternate_Languages/90_Tower/csharp/Tower.sln b/00_Alternate_Languages/90_Tower/csharp/Tower.sln
new file mode 100644
index 00000000..6f87b0b9
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/Tower.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tower", "Tower.csproj", "{EEED33AD-3DE2-49AA-8AF1-2174C510E128}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{EEED33AD-3DE2-49AA-8AF1-2174C510E128}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EEED33AD-3DE2-49AA-8AF1-2174C510E128}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EEED33AD-3DE2-49AA-8AF1-2174C510E128}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EEED33AD-3DE2-49AA-8AF1-2174C510E128}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {BDCB8278-62ED-46E3-92C2-FF572E0E3ED3}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/90_Tower/csharp/UI/Input.cs b/00_Alternate_Languages/90_Tower/csharp/UI/Input.cs
new file mode 100644
index 00000000..d1eca384
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/UI/Input.cs
@@ -0,0 +1,85 @@
+using System;
+using System.Collections.Generic;
+
+namespace Tower.UI
+{
+    // Provides input methods which emulate the BASIC interpreter's keyboard input routines
+    internal static class Input
+    {
+        private static void Prompt(string text = "") => Console.Write($"{text}? ");
+
+        internal static bool ReadYesNo(string prompt, string retryPrompt)
+        {
+            var response = ReadString(prompt);
+
+            while (true)
+            {
+                if (response.Equals("No", StringComparison.InvariantCultureIgnoreCase)) { return false; }
+                if (response.Equals("Yes", StringComparison.InvariantCultureIgnoreCase)) { return true; }
+                response = ReadString(retryPrompt);
+            }
+        }
+
+        internal static bool TryReadNumber(Prompt prompt, out int number)
+        {
+            var message = prompt.Message;
+
+            for (int retryCount = 0; retryCount <= prompt.RetriesAllowed; retryCount++)
+            {
+                if (retryCount > 0) { Console.WriteLine(prompt.RetryMessage); }
+
+                if (prompt.TryValidateResponse(ReadNumber(message), out number)) { return true; }
+
+                if (!prompt.RepeatPrompt) { message = ""; }
+            }
+
+            Console.WriteLine(prompt.QuitMessage);
+
+            number = 0;
+            return false;
+        }
+
+        private static float ReadNumber(string prompt)
+        {
+            Prompt(prompt);
+
+            while (true)
+            {
+                var inputValues = ReadStrings();
+
+                if (TryParseNumber(inputValues[0], out var number))
+                {
+                    if (inputValues.Length > 1)
+                    {
+                        Console.WriteLine("!Extra input ingored");
+                    }
+
+                    return number;
+                }
+            }
+        }
+
+        private static string ReadString(string prompt)
+        {
+            Prompt(prompt);
+
+            var inputValues = ReadStrings();
+            if (inputValues.Length > 1)
+            {
+                Console.WriteLine("!Extra input ingored");
+            }
+            return inputValues[0];
+        }
+
+        private static string[] ReadStrings() => Console.ReadLine().Split(',', StringSplitOptions.TrimEntries);
+
+        private static bool TryParseNumber(string text, out float number)
+        {
+            if (float.TryParse(text, out number)) { return true; }
+
+            Console.WriteLine("!Number expected - retry input line");
+            number = default;
+            return false;
+        }
+    }
+}
diff --git a/00_Alternate_Languages/90_Tower/csharp/UI/Prompt.cs b/00_Alternate_Languages/90_Tower/csharp/UI/Prompt.cs
new file mode 100644
index 00000000..34477bb7
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/UI/Prompt.cs
@@ -0,0 +1,41 @@
+using System.Collections.Generic;
+using System.Linq;
+using static Tower.Resources.Strings;
+
+namespace Tower.UI
+{
+    internal class Prompt
+    {
+        public static Prompt DiskCount =
+            new(DiskCountPrompt, DiskCountRetry, DiskCountQuit, 1, 2, 3, 4, 5, 6, 7) { RetriesAllowed = 2 };
+
+        public static Prompt Disk =
+            new(DiskPrompt, DiskRetry, DiskQuit, 3, 5, 7, 9, 11, 13, 15) { RepeatPrompt = false };
+
+        public static Prompt Needle = new(NeedlePrompt, NeedleRetry, NeedleQuit, 1, 2, 3);
+
+        private readonly HashSet _validValues;
+
+        private Prompt(string prompt, string retryMessage, string quitMessage, params int[] validValues)
+        {
+            Message = prompt;
+            RetryMessage = retryMessage;
+            QuitMessage = quitMessage;
+            _validValues = validValues.ToHashSet();
+            RetriesAllowed = 1;
+            RepeatPrompt = true;
+        }
+
+        public string Message { get; }
+        public string RetryMessage { get; }
+        public string QuitMessage { get; }
+        public int RetriesAllowed { get; private set; }
+        public bool RepeatPrompt { get; private set; }
+
+        public bool TryValidateResponse(float number, out int integer)
+        {
+            integer = (int)number;
+            return integer == number && _validValues.Contains(integer);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/90_Tower/csharp/UI/TowerDisplay.cs b/00_Alternate_Languages/90_Tower/csharp/UI/TowerDisplay.cs
new file mode 100644
index 00000000..d6917fd9
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/csharp/UI/TowerDisplay.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Text;
+using Tower.Models;
+
+namespace Tower.UI
+{
+    internal class TowerDisplay
+    {
+        private readonly Towers _towers;
+
+        public TowerDisplay(Towers towers)
+        {
+            _towers = towers;
+        }
+
+        public override string ToString()
+        {
+            var builder = new StringBuilder();
+
+            foreach (var row in _towers)
+            {
+                AppendTower(row.Item1);
+                AppendTower(row.Item2);
+                AppendTower(row.Item3);
+                builder.AppendLine();
+            }
+
+            return builder.ToString();
+
+            void AppendTower(int size)
+            {
+                var padding = 10 - size / 2;
+                builder.Append(' ', padding).Append('*', Math.Max(1, size)).Append(' ', padding);
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/90_Tower/java/README.md b/00_Alternate_Languages/90_Tower/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/90_Tower/java/Tower.java b/00_Alternate_Languages/90_Tower/java/Tower.java
new file mode 100644
index 00000000..a1705c8b
--- /dev/null
+++ b/00_Alternate_Languages/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 diff --git a/00_Alternate_Languages/90_Tower/javascript/README.md b/00_Alternate_Languages/90_Tower/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/90_Tower/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/90_Tower/javascript/tower.html b/00_Alternate_Languages/90_Tower/javascript/tower.html new file mode 100644 index 00000000..84318f33 --- /dev/null +++ b/00_Alternate_Languages/90_Tower/javascript/tower.html @@ -0,0 +1,9 @@ + + +TOWER + + +


+
+
+
diff --git a/00_Alternate_Languages/90_Tower/javascript/tower.js b/00_Alternate_Languages/90_Tower/javascript/tower.js
new file mode 100644
index 00000000..18f1f8fd
--- /dev/null
+++ b/00_Alternate_Languages/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();
diff --git a/67_One_Check/pascal/README.md b/00_Alternate_Languages/90_Tower/pascal/README.md
similarity index 100%
rename from 67_One_Check/pascal/README.md
rename to 00_Alternate_Languages/90_Tower/pascal/README.md
diff --git a/00_Alternate_Languages/90_Tower/perl/README.md b/00_Alternate_Languages/90_Tower/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/90_Tower/perl/tower.pl b/00_Alternate_Languages/90_Tower/perl/tower.pl
new file mode 100644
index 00000000..f9258eea
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/perl/tower.pl
@@ -0,0 +1,381 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'state' and 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use Term::ReadLine;     # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+# Manifest constant representing the maximum number of disks. We can
+# change this within limits. It needs to be at least 3 or the
+# explanatory text will contain negative numbers. There is no known
+# upper limit, though if it is more than 10 the output lines can be more
+# than 80 columns, and if it is more than 49 the disk numbers will be
+# more than two digits, which will cause output lines not to align
+# properly.
+use constant MAX_DISKS  => 7;
+
+print <<'EOD';
+                                 TOWERS
+               Creative Computing  Morristown, New Jersey
+
+
+EOD
+
+while ( 1 ) {   # Iterate until something makes us stop.
+
+    print <<'EOD';
+Towers of Hanoi Puzzle.
+
+You must transfer the disks from the left to the right
+Tower, one at a time, never putting a larger disk on a
+smaller disk.
+
+EOD
+
+    # Get the desired number of disks to work with.
+    my $size = get_input(
+
+        # Manifest constants do not interpolate into strings. This can
+        # be worked around using the @{[ ... ]} construction, which
+        # interpolates any expression.
+        "How many disks do you want to move (@{[ MAX_DISKS ]} is max)? ",
+
+        sub {
+
+            # Accept any response which is an integer greater than zero
+            # and less than or equal to the maximum number of disks.
+            # NOTE that 'and' performs the same operation as &&, but
+            # binds much more loosely.
+            return m/ \A [0-9]+ \z /smx &&
+                $ARG > 0 &&
+                $ARG <= MAX_DISKS;
+        },
+
+        3,
+        "Sorry, but I can't do that job for you.\n",    # Warning
+        <<'EOD',
+All right, wise guy, if you can't play the game right, I'll
+just take my puzzle and go home.  So long.
+EOD
+    );
+
+    # Expressions can be interpolated using @{[ ... ]}
+    print <<"EOD";
+In this program, we shall refer to disks by numerical code.
+3 will represent the smallest disk, 5 the next size,
+7 the next, and so on, up to @{[ MAX_DISKS * 2 + 1 ]}.  If you do the puzzle with
+2 disks, their code names would be @{[ MAX_DISKS * 2 - 1 ]} and @{[ MAX_DISKS * 2 + 1 ]}.  With 3 disks
+the code names would be @{[ MAX_DISKS * 2 - 3 ]}, @{[ MAX_DISKS * 2 - 1 ]} and @{[ MAX_DISKS * 2 + 1 ]}, etc.  The needles
+are numbered from left to right, 1 to 3.  We will
+start with the disks on needle 1, and attempt to move them
+to needle 3.
+
+
+Good luck!
+
+EOD
+
+    # Compute the legal disk numbers for this puzzle. The expression
+    # reads right to left thus:
+    #   * The .. operator generates the integers between and including
+    #     its end points, that is, from MAX_DISKS + 1 - $size to
+    #     MAX_DISKS, inclusive.
+    #   * map { .. } calls the block once for each of its arguments.
+    #     The value of the argument appears in the topic variable $ARG,
+    #     and the result of the block is returned.
+    #   * The list generated by the map {} is assigned to array
+    #     @legal_disks.
+    my @legal_disks = map { $ARG * 2 + 1 }
+        MAX_DISKS + 1 - $size ..  MAX_DISKS;
+
+    # Generate the board. This is an array of needles, indexed from
+    # zero. Each needle is represented by a reference to an array
+    # containing the disks on that needle, bottom to top.
+    my @board = (
+        [ reverse @legal_disks ],
+        [],
+        []
+    );
+
+    display( \@board ); # Display the initial board.
+
+    my $moves = 0;  # Move counter.
+
+    while ( 1 ) {   # Iterate until something makes us stop.
+        my $disk = get_input(
+            'Which disk would you like to move? ',
+            sub {
+                # Accept any odd integer in the required range.
+                # NOTE that 'and' performs the same operation as &&, but
+                # binds much more loosely.
+                return m/ \A [0-9]+ \z /smx &&
+                    $ARG % 2 &&
+                    $ARG >= ( MAX_DISKS + 1 - $size ) * 2 + 1 &&
+                    $ARG <= MAX_DISKS * 2 + 1;
+            },
+            3,
+            do {    # Compound statement and scope for 'local'
+
+                # We want to interpolate @legal_disks into our warning.
+                # Interpolation of an array places $LIST_SEPARATOR
+                # between the elements of the array. The default is ' ',
+                # but we want ', '. We use 'local' to restrict the
+                # change to the current block and code called by it.
+                # Failure to localize the change can cause Spooky Action
+                # at a Distance.
+                local $LIST_SEPARATOR = ', ';
+
+                "Illegal entry... You may only type @legal_disks\n";
+            },
+            "Stop wasting my time.  Go bother someone else.\n",
+        );
+
+        # Return the number (from zero) of the needle which has the
+        # desired disk on top. If the desired disk is not found, we got
+        # undef back. In this case we redo the innermost loop.
+        redo unless defined( my $from = find_disk( $disk, \@board ) );
+
+        # Find out where the chosen disk goes.
+        # NOTE that unlike the BASIC implementation, we require the
+        # needle to be moved.
+        my $to = get_input(
+            'Place disk on which needle? ',
+            sub {
+                # Accept integers 1 through 3, but not the current
+                # location of the disk
+                return m/ \A [0-9]+ \z /smx &&
+                    $ARG > 0 &&
+                    $ARG <= 3 &&
+                    $ARG != $from + 1;
+            },
+            2,
+            <<'EOD',
+I'll assume you hit the wrong key this time.  But watch it,
+I only allow one mistake.
+EOD
+            <<'EOD',
+I tried to warn you, but you wouldn't listen.
+Bye bye, big shot.
+EOD
+        ) - 1;
+
+        # Check for placing a larger disk on a smaller one. The check is
+        # that the destination needle has something on it (an empty
+        # array is false in Boolean context) and that the destination
+        # needle's top disk ([-1] selects the last element of an array)
+        # is smaller than the source needle's disk.
+        if ( @{ $board[$to] } && $board[$to][-1] < $board[$from][-1] ) {
+            warn <<'EOD';
+You can't place a larger disk on top of a smaller one,
+It might crush it!
+EOD
+            redo;
+        }
+
+        # Remove the selected disk from its needle, and place it on the
+        # destination needle.
+        push @{ $board[$to] }, pop @{ $board[$from] };
+
+        $moves++;   # Count another move.
+
+        display( \@board ); # Display the current board.
+
+        # If all the disks are on the last needle, we are done.
+        if ( @{ $board[2] } == $size ) {
+
+            # Print a success message
+            print <<"EOD";
+Congratulations!
+
+You have performed the task in $moves moves.
+
+EOD
+            last;   # Exit the innermost loop.
+
+        # If the maximum allowed moves have been exceeded
+        } elsif ( $moves >= 2 ** MAX_DISKS ) {
+
+            # Warn
+            warn <<"EOD";
+Sorry, but I have orders to stop if you make more than
+$moves moves.
+EOD
+
+            last;   # Exit the innermost loop.
+        }
+    }
+
+    say '';
+    get_input(
+        'Try again? [y/N]: ',
+        sub {
+            exit if $ARG eq '' || m/ \A n /smxi;
+            return m/ \A y /smxi;
+        },
+        ~0, # The 1's complement of 0 = largest possible integer
+        "Please respond 'y' or 'n'\n",
+    );
+}
+
+# Display the board, which is passed in as a reference.
+sub display {
+    my ( $board ) = @_;
+    say '';
+
+    # Use a manifest constant for an empty needle. This is global
+    # despite its appearing to be nested in the subroutine. Perl uses
+    # 'x' as its string replication operator. The initial 4 blanks
+    # accommodate the disk number and spacing between needles.
+    use constant EMPTY_NEEDLE   => ' ' x 4 . ' ' x MAX_DISKS . '|' .
+        ' ' x MAX_DISKS;
+
+    # Iterate over the rows to be printed.
+    foreach my $inx ( reverse 0 .. MAX_DISKS ) {
+
+        my $line;   # Line buffer.
+
+        # Iterate over needles.
+        foreach my $col ( 0 .. 2 ) {
+
+            # If this position on the needle is occupied
+            if ( my $disk_num = $board->[$col][$inx] ) {
+
+                # Compute the width of a half disk
+                my $half_width = ( $disk_num - 1 ) / 2;
+
+                # Compute the graphic for the half disk. Perl uses 'x'
+                # as its string replication operator.
+                my $half_disk = '*' x $half_width;
+
+                # Append the disk to the line. The inner sprintf() does
+                # most of the work; the outer simply pads the graphic to
+                # the required total width.
+                $line .= sprintf( '%*s', -( MAX_DISKS * 2 + 5 ),
+                    sprintf( '%*d %s|%s', MAX_DISKS + 3 - $half_width,
+                        $disk_num, $half_disk, $half_disk ) );
+
+            # Else this position is not occupied
+            } else {
+
+                # So just append the empty needle.
+                $line .= EMPTY_NEEDLE;
+            }
+        }
+
+        # Remove white space at the end of the line
+        $line =~ s/ \s+ \z //smx;
+
+        # Display the line
+        say $line;
+    }
+    {   # Display the needle numbers
+        my $line;
+        foreach my $col ( 0 .. 2 ) {
+            $line .= sprintf '%*d%*s', MAX_DISKS + 5, $col + 1,
+            MAX_DISKS, ' ';
+        }
+        $line =~ s/ \s+ \z //smx;
+        say $line;
+    }
+
+    say ''; # Empty line
+
+    return;
+}
+
+# Find the named disk. The arguments are the disk number (which is
+# assumed valid) and a reference to the board. If the disk is found on
+# the top of a needle, the needle's index (from zero) is returned.
+# Otherwise a warning is issued and undef is returned.
+sub find_disk {
+    my ( $disk, $board ) = @_;
+    foreach my $inx ( 0 .. 2 ) {
+        @{ $board->[$inx] }                 # If the needle is occupied
+            and $disk == $board->[$inx][-1] # and we want its topmost
+            and return $inx;                # return needle index
+    }
+
+    # Since we assume the disk number is valid but we did not find it,
+    # it must not be the topmost disk.
+    warn "That disk is below another one.  Make another choice.\n";
+
+    return undef;
+}
+
+# Input subroutine. The arguments are:
+# * The prompt.
+# * Validation code. This recieves the input in the topic variable $ARG,
+#   and returns a true value if the validation passed, and a false value
+#   if it failed.
+# * The maximum number of tries before dying.
+# * The warning message for a validation failure, with trailing "\n".
+# * The error message when the number of tries is exceeded, with
+#   trailing "\n".
+# The return is the valid input. We exit if end-of-file is reached,
+sub get_input {
+    my ( $prompt, $validate, $tries, $warning, $error ) = @_;
+
+    # Instantiate the readline object. A state variable is only
+    # initialized once.
+    state $term = Term::ReadLine->new( 'tower' );
+
+    while ( 1 ) {   # Iterate until something makes us stop.
+
+        # The input gets read into the localized topic variable. If it
+        # is undefined, it signals end-of-file, so we exit.
+        exit unless defined( local $ARG = $term->readline( $prompt ) );
+
+        # Call the validation code. If it returns a true value, we
+        # return our input.
+        return $ARG if $validate->();
+
+        # Die if we are out of retries. In Perl, 0 is false and all
+        # other integers are true.
+        die $error unless --$tries;
+
+        # Warn.
+        warn $warning;
+    }
+}
+
+__END__
+
+=head1 TITLE
+
+tower.pl - Play the game 'tower' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ tower.pl
+
+=head1 DETAILS
+
+This Perl script is a port of C, which is the 90th entry in Basic
+Computer Games.
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :
diff --git a/00_Alternate_Languages/90_Tower/python/README.md b/00_Alternate_Languages/90_Tower/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/90_Tower/python/tower.py b/00_Alternate_Languages/90_Tower/python/tower.py
new file mode 100644
index 00000000..5935af38
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/python/tower.py
@@ -0,0 +1,171 @@
+import sys
+
+
+class Disk:
+    def __init__(self, size):
+        self.__size = size
+
+    def size(self):
+        return self.__size
+
+    def print(self):
+        print("[ %s ]" % self.size())
+
+
+class Tower:
+    def __init__(self):
+        self.__disks = []
+
+    def empty(self):
+        return len(self.__disks) == 0
+
+    def top(self):
+        if self.empty():
+            return None
+        else:
+            return self.__disks[-1]
+
+    def add(self, disk):
+        if not self.empty():
+            t = self.top()
+            if disk.size() > t.size():
+                raise Exception(
+                    "YOU CAN'T PLACE A LARGER DISK ON TOP OF A SMALLER ONE, IT MIGHT CRUSH IT!"
+                )
+        self.__disks.append(disk)
+
+    def pop(self):
+        if self.empty():
+            raise Exception("empty pop")
+        return self.__disks.pop()
+
+    def print(self):
+        r = "Needle: [%s]" % (", ".join([str(x.size()) for x in self.__disks]))
+        print(r)
+
+
+print(
+    """
+IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE.
+3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,
+7 THE NEXT, AND SO ON, UP TO 15.  IF YOU DO THE PUZZLE WITH
+2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15.  WITH 3 DISKS
+THE CODE NAMES WOULD BE 11, 13 AND 15, ETC.  THE NEEDLES
+ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3.  WE WILL
+START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM
+TO NEEDLE 3.
+
+GOOD LUCK!
+
+"""
+)
+
+
+class Game:
+    def __init__(self):
+        # use fewer sizes to make debugging easier
+        # self.__sizes = [3, 5, 7]  # ,9,11,13,15]
+        self.__sizes = [3, 5, 7, 9, 11, 13, 15]
+
+        self.__sizes.sort()
+
+        self.__towers = []
+        self.__moves = 0
+        self.__towers = [Tower(), Tower(), Tower()]
+        self.__sizes.reverse()
+        for size in self.__sizes:
+            disk = Disk(size)
+            self.__towers[0].add(disk)
+
+    def winner(self):
+        return self.__towers[0].empty() and self.__towers[1].empty()
+
+    def print(self):
+        for t in self.__towers:
+            t.print()
+
+    def moves(self):
+        return self.__moves
+
+    def which_disk(self):
+        w = int(input("WHICH DISK WOULD YOU LIKE TO MOVE\n"))
+        if w in self.__sizes:
+            return w
+        else:
+            raise Exception()
+
+    def pick_disk(self):
+        which = None
+        while which is None:
+            try:
+                which = self.which_disk()
+            except Exception:
+                print("ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15.\n")
+
+        valids = [t for t in self.__towers if t.top() and t.top().size() == which]
+        assert len(valids) in (0, 1)
+        if not valids:
+            print("THAT DISK IS BELOW ANOTHER ONE.  MAKE ANOTHER CHOICE.\n")
+            return None
+        else:
+            assert valids[0].top().size() == which
+            return valids[0]
+
+    def which_tower(self):
+        try:
+            needle = int(input("PLACE DISK ON WHICH NEEDLE\n"))
+            tower = self.__towers[needle - 1]
+        except Exception:
+            print(
+                "I'LL ASSUME YOU HIT THE WRONG KEY THIS TIME.  BUT WATCH IT,\nI ONLY ALLOW ONE MISTAKE.\n"
+            )
+            return None
+        else:
+            return tower
+
+    def take_turn(self):
+        from_tower = None
+        while from_tower is None:
+            from_tower = self.pick_disk()
+
+        to_tower = self.which_tower()
+        if not to_tower:
+            to_tower = self.which_tower()
+
+        if not to_tower:
+            print("I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN.\nBYE BYE, BIG SHOT.\n")
+            sys.exit(0)
+
+        disk = from_tower.pop()
+        try:
+            to_tower.add(disk)
+            self.__moves += 1
+        except Exception as err:
+            print(err)
+            from_tower.add(disk)
+
+
+game = Game()
+while True:
+    game.print()
+
+    game.take_turn()
+
+    if game.winner():
+        print(
+            "CONGRATULATIONS!!\nYOU HAVE PERFORMED THE TASK IN %s MOVES.\n"
+            % game.moves()
+        )
+        while True:
+            yesno = input("TRY AGAIN (YES OR NO)\n")
+            if yesno.upper() == "YES":
+                game = Game()
+                break
+            elif yesno.upper() == "NO":
+                print("THANKS FOR THE GAME!\n")
+                sys.exit(0)
+            else:
+                print("'YES' OR 'NO' PLEASE\n")
+    elif game.moves() > 128:
+        print("SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN 128 MOVES.")
+        sys.exit(0)
diff --git a/00_Alternate_Languages/90_Tower/python/tower_test.py b/00_Alternate_Languages/90_Tower/python/tower_test.py
new file mode 100644
index 00000000..b3e0e2f0
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/python/tower_test.py
@@ -0,0 +1,52 @@
+import unittest
+
+import tower
+
+
+class MyTestCase(unittest.TestCase):
+    def test_something(self):
+        t = tower.Tower()
+        self.assertTrue(t.empty())
+
+        d = tower.Disk(3)
+        t.add(d)
+        self.assertFalse(t.empty())
+
+        d5 = tower.Disk(5)
+        self.assertRaises(Exception, t.add, d5)
+        self.assertFalse(t.empty())
+
+    def test_oksize(self):
+        t = tower.Tower()
+        self.assertTrue(t.empty())
+
+        d5 = tower.Disk(5)
+        t.add(d5)
+        self.assertFalse(t.empty())
+
+        d3 = tower.Disk(3)
+        t.add(d3)
+        self.assertFalse(t.empty())
+
+        self.assertEqual(t.top(), d3)
+        self.assertEqual(t.pop(), d3)
+        self.assertEqual(t.pop(), d5)
+
+    def test_game(self):
+        g = tower.Game()
+        self.assertEqual(g.moves(), 0)
+        self.assertFalse(g.winner())
+
+    def test_format(self):
+        t = tower.Tower()
+        d3 = tower.Disk(3)
+        d5 = tower.Disk(5)
+        t.add(d5)
+        t.add(d3)
+
+        f = t.vertical_format(6, 3)
+        self.assertEqual(f, ["      ", "[ 3 ] ", "[ 5 ] "])
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/00_Alternate_Languages/90_Tower/ruby/README.md b/00_Alternate_Languages/90_Tower/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/90_Tower/tower.bas b/00_Alternate_Languages/90_Tower/tower.bas
new file mode 100644
index 00000000..ee826c18
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/tower.bas
@@ -0,0 +1,125 @@
+10 PRINT TAB(33);"TOWERS"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+90 PRINT
+100 REM*** INITIALIZE
+110 DIM T(7,3)
+120 E=0
+130 FOR D=1 TO 7
+140 FOR N=1 TO 3
+150 T(D,N)=0
+160 NEXT N
+170 NEXT D
+180 PRINT "TOWERS OF HANOI PUZZLE.": PRINT
+200 PRINT "YOU MUST TRANSFER THE DISKS FROM THE LEFT TO THE RIGHT"
+205 PRINT "TOWER, ONE AT A TIME, NEVER PUTTING A LARGER DISK ON A"
+210 PRINT "SMALLER DISK.": PRINT
+215 INPUT "HOW MANY DISKS DO YOU WANT TO MOVE (7 IS MAX)";S
+220 PRINT
+230 M=0
+240 FOR Q=1 TO 7
+250 IF Q=S THEN 350
+260 NEXT Q
+270 E=E+1
+280 IF E>2 THEN 310
+290 PRINT "SORRY, BUT I CAN'T DO THAT JOB FOR YOU.": GOTO 215
+310 PRINT "ALL RIGHT, WISE GUY, IF YOU CAN'T PLAY THE GAME RIGHT, I'LL"
+320 PRINT "JUST TAKE MY PUZZLE AND GO HOME.  SO LONG.": STOP
+340 REM *** STORE DISKS FROM SMALLEST TO LARGEST
+350 PRINT "IN THIS PROGRAM, WE SHALL REFER TO DISKS BY NUMERICAL CODE."
+355 PRINT "3 WILL REPRESENT THE SMALLEST DISK, 5 THE NEXT SIZE,"
+360 PRINT "7 THE NEXT, AND SO ON, UP TO 15.  IF YOU DO THE PUZZLE WITH"
+365 PRINT "2 DISKS, THEIR CODE NAMES WOULD BE 13 AND 15.  WITH 3 DISKS"
+370 PRINT "THE CODE NAMES WOULD BE 11, 13 AND 15, ETC.  THE NEEDLES"
+375 PRINT "ARE NUMBERED FROM LEFT TO RIGHT, 1 TO 3.  WE WILL"
+380 PRINT "START WITH THE DISKS ON NEEDLE 1, AND ATTEMPT TO MOVE THEM"
+385 PRINT "TO NEEDLE 3."
+390 PRINT: PRINT "GOOD LUCK!": PRINT
+400 Y=7: D=15
+420 FOR X=S TO 1 STEP -1
+430 T(Y,1)=D: D=D-2: Y=Y-1
+460 NEXT X
+470 GOSUB 1230
+480 PRINT "WHICH DISK WOULD YOU LIKE TO MOVE";:E=0
+500 INPUT D
+510 IF (D-3)*(D-5)*(D-7)*(D-9)*(D-11)*(D-13)*(D-15)=0 THEN 580
+520 PRINT "ILLEGAL ENTRY... YOU MAY ONLY TYPE 3,5,7,9,11,13, OR 15."
+530 E=E+1: IF E>1 THEN 560
+550 GOTO 500
+560 PRINT "STOP WASTING MY TIME.  GO BOTHER SOMEONE ELSE.": STOP
+580 REM *** CHECK IF REQUESTED DISK IS BELOW ANOTHER
+590 FOR R=1 TO 7
+600 FOR C=1 TO 3
+610 IF T(R,C)=D THEN 640
+620 NEXT C: NEXT R
+640 FOR Q=R TO 1 STEP -1
+645 IF T(Q,C)=0 THEN 660
+650 IF T(Q,C)1 THEN 780
+750 PRINT "I'LL ASSUME YOU HIT THE WRONG KEY THIS TIME.  BUT WATCH IT,"
+760 PRINT "I ONLY ALLOW ONE MISTAKE.": GOTO 705
+780 PRINT "I TRIED TO WARN YOU, BUT YOU WOULDN'T LISTEN."
+790 PRINT "BYE BYE, BIG SHOT.":STOP
+800 FOR R=1 TO 7
+810 IF T(R,N)<>0 THEN 840
+820 NEXT R
+830 GOTO 880
+835 REM *** CHECK IF DISK TO BE PLACED ON A LARGER ONE
+840 IF D0 THEN 970
+950 NEXT U
+960 U=7: GOTO 980
+965 REM *** MOVE DISK AND SET OLD LOCATION TO 0
+970 U=U-1
+980 T(U,N)=T(V,W): T(V,W)=0
+995 REM *** PRINT OUT CURRENT STATUS
+1000 GOSUB 1230
+1018 REM *** CHECK IF DONE
+1020 M=M+1
+1030 FOR R=1 TO 7: FOR C=1 TO 2
+1050 IF T(R,C)<>0 THEN 1090
+1060 NEXT C: NEXT R
+1080 GOTO 1120
+1090 IF M<=128 THEN 480
+1100 PRINT "SORRY, BUT I HAVE ORDERS TO STOP IF YOU MAKE MORE THAN"
+1110 PRINT "128 MOVES.": STOP
+1120 IF M<>2^S-1 THEN 1140
+1130 PRINT:PRINT "CONGRATULATIONS!!":PRINT
+1140 PRINT "YOU HAVE PERFORMED THE TASK IN";M;"MOVES."
+1150 PRINT: PRINT "TRY AGAIN (YES OR NO)";: INPUT A$
+1160 IF A$="NO" THEN 1390
+1170 IF A$="YES" THEN 90
+1180 PRINT: PRINT "'YES' OR 'NO' PLEASE";: INPUT A$: GOTO 1160
+1230 REM *** PRINT SUBROUTINE
+1240 FOR K=1 TO 7
+1250 Z=10
+1260 FOR J=1 TO 3
+1270 IF T(K,J)=0 THEN 1330
+1280 PRINT TAB(Z-INT(T(K,J)/2));
+1290 FOR V=1 TO T(K,J)
+1300 PRINT "*";
+1310 NEXT V
+1320 GOTO 1340
+1330 PRINT TAB(Z);"*";
+1340 Z=Z+21
+1350 NEXT J
+1360 PRINT
+1370 NEXT K
+1380 RETURN
+1390 PRINT: PRINT "THANKS FOR THE GAME!": PRINT: END
diff --git a/00_Alternate_Languages/90_Tower/vbnet/README.md b/00_Alternate_Languages/90_Tower/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/90_Tower/vbnet/Tower.sln b/00_Alternate_Languages/90_Tower/vbnet/Tower.sln
new file mode 100644
index 00000000..059a8d70
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/vbnet/Tower.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Tower", "Tower.vbproj", "{9B62545A-F076-4390-864B-ABE6FC20CC62}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9B62545A-F076-4390-864B-ABE6FC20CC62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9B62545A-F076-4390-864B-ABE6FC20CC62}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9B62545A-F076-4390-864B-ABE6FC20CC62}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9B62545A-F076-4390-864B-ABE6FC20CC62}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/90_Tower/vbnet/Tower.vbproj b/00_Alternate_Languages/90_Tower/vbnet/Tower.vbproj
new file mode 100644
index 00000000..d5d8396b
--- /dev/null
+++ b/00_Alternate_Languages/90_Tower/vbnet/Tower.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Tower
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/91_Train/README.md b/00_Alternate_Languages/91_Train/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/91_Train/csharp/README.md b/00_Alternate_Languages/91_Train/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/91_Train/csharp/Train.sln b/00_Alternate_Languages/91_Train/csharp/Train.sln
new file mode 100644
index 00000000..29c49c59
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/csharp/Train.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31129.286
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrainGame", "Train\TrainGame.csproj", "{42617537-4E7C-4082-A17B-7F18DFA04C35}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TrainTests", "TrainTests\TrainTests.csproj", "{B967AA46-78F2-44F8-A30D-85D35F625991}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{42617537-4E7C-4082-A17B-7F18DFA04C35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{42617537-4E7C-4082-A17B-7F18DFA04C35}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{42617537-4E7C-4082-A17B-7F18DFA04C35}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{42617537-4E7C-4082-A17B-7F18DFA04C35}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B967AA46-78F2-44F8-A30D-85D35F625991}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B967AA46-78F2-44F8-A30D-85D35F625991}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B967AA46-78F2-44F8-A30D-85D35F625991}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B967AA46-78F2-44F8-A30D-85D35F625991}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {919F73B8-DE34-4992-9B05-E1FEC2D2F7C6}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/91_Train/csharp/Train/TrainGame.cs b/00_Alternate_Languages/91_Train/csharp/Train/TrainGame.cs
new file mode 100644
index 00000000..98e0db68
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/csharp/Train/TrainGame.cs
@@ -0,0 +1,93 @@
+using System;
+using System.Linq;
+
+namespace Train
+{
+    public class TrainGame
+    {
+        private Random Rnd { get; } = new Random();
+        private readonly int ALLOWED_PERCENTAGE_DIFFERENCE = 5;
+
+        static void Main()
+        {
+            TrainGame train = new TrainGame();
+            train.GameLoop();
+        }
+
+        public void GameLoop()
+        {
+            DisplayIntroText();
+
+            do
+            {
+                PlayGame();
+            } while (TryAgain());
+        }
+
+        private void PlayGame()
+        {
+            int carSpeed = (int)GenerateRandomNumber(40, 25);
+            int timeDifference = (int)GenerateRandomNumber(5, 15);
+            int trainSpeed = (int)GenerateRandomNumber(20, 19);
+
+            Console.WriteLine($"A CAR TRAVELING {carSpeed} MPH CAN MAKE A CERTAIN TRIP IN");
+            Console.WriteLine($"{timeDifference} HOURS LESS THAN A TRAIN TRAVELING AT {trainSpeed} MPH");
+            Console.WriteLine("HOW LONG DOES THE TRIP TAKE BY CAR?");
+
+            double userInputCarJourneyDuration = double.Parse(Console.ReadLine());
+            double actualCarJourneyDuration = CalculateCarJourneyDuration(carSpeed, timeDifference, trainSpeed);
+            int percentageDifference = CalculatePercentageDifference(userInputCarJourneyDuration, actualCarJourneyDuration);
+
+            if (IsWithinAllowedDifference(percentageDifference, ALLOWED_PERCENTAGE_DIFFERENCE))
+            {
+                Console.WriteLine($"GOOD! ANSWER WITHIN {percentageDifference} PERCENT.");
+            }
+            else
+            {
+                Console.WriteLine($"SORRY.  YOU WERE OFF BY {percentageDifference} PERCENT.");
+            }
+            Console.WriteLine($"CORRECT ANSWER IS {actualCarJourneyDuration} HOURS.");
+        }
+
+        public static bool IsWithinAllowedDifference(int percentageDifference, int allowedDifference)
+        {
+            return percentageDifference <= allowedDifference;
+        }
+
+        private static int CalculatePercentageDifference(double userInputCarJourneyDuration, double carJourneyDuration)
+        {
+            return (int)(Math.Abs((carJourneyDuration - userInputCarJourneyDuration) * 100 / userInputCarJourneyDuration) + .5);
+        }
+
+        public static double CalculateCarJourneyDuration(double carSpeed, double timeDifference, double trainSpeed)
+        {
+            return timeDifference * trainSpeed / (carSpeed - trainSpeed);
+        }
+
+        public double GenerateRandomNumber(int baseSpeed, int multiplier)
+        {
+            return multiplier * Rnd.NextDouble() + baseSpeed;
+        }
+
+        private bool TryAgain()
+        {
+            Console.WriteLine("ANOTHER PROBLEM (YES OR NO)? ");
+            return IsInputYes(Console.ReadLine());
+        }
+
+        public static bool IsInputYes(string consoleInput)
+        {
+            var options = new string[] { "Y", "YES" };
+            return options.Any(o => o.Equals(consoleInput, StringComparison.CurrentCultureIgnoreCase));
+        }
+
+        private void DisplayIntroText()
+        {
+            Console.WriteLine("TRAIN");
+            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine();
+            Console.WriteLine("TIME - SPEED DISTANCE EXERCISE");
+            Console.WriteLine();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/91_Train/csharp/Train/TrainGame.csproj b/00_Alternate_Languages/91_Train/csharp/Train/TrainGame.csproj
new file mode 100644
index 00000000..c73e0d16
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/csharp/Train/TrainGame.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    netcoreapp3.1
+  
+
+
diff --git a/00_Alternate_Languages/91_Train/csharp/TrainTests/TrainGameTests.cs b/00_Alternate_Languages/91_Train/csharp/TrainTests/TrainGameTests.cs
new file mode 100644
index 00000000..a9804283
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/csharp/TrainTests/TrainGameTests.cs
@@ -0,0 +1,53 @@
+using Train;
+using Xunit;
+
+namespace TrainTests
+{
+    public class TrainGameTests
+    {
+        [Fact]
+        public void MiniumRandomNumber()
+        {
+            TrainGame game = new TrainGame();
+            Assert.True(game.GenerateRandomNumber(10, 10) >= 10);
+        }
+
+        [Fact]
+        public void MaximumRandomNumber()
+        {
+            TrainGame game = new TrainGame();
+            Assert.True(game.GenerateRandomNumber(10, 10) <= 110);
+        }
+
+        [Fact]
+        public void IsInputYesWhenY()
+        {
+            Assert.True(TrainGame.IsInputYes("y"));
+        }
+
+        [Fact]
+        public void IsInputYesWhenNotY()
+        {
+            Assert.False(TrainGame.IsInputYes("a"));
+        }
+
+        [Fact]
+        public void CarDurationTest()
+        {
+            Assert.Equal(1, TrainGame.CalculateCarJourneyDuration(30, 1, 15) );
+        }
+
+        [Fact]
+        public void IsWithinAllowedDifference()
+        {
+            Assert.True(TrainGame.IsWithinAllowedDifference(5,5));
+        }
+
+
+        [Fact]
+        public void IsNotWithinAllowedDifference()
+        {
+            Assert.False(TrainGame.IsWithinAllowedDifference(6, 5));
+        }
+    }
+}
diff --git a/00_Alternate_Languages/91_Train/csharp/TrainTests/TrainTests.csproj b/00_Alternate_Languages/91_Train/csharp/TrainTests/TrainTests.csproj
new file mode 100644
index 00000000..fb6ab9fb
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/csharp/TrainTests/TrainTests.csproj
@@ -0,0 +1,26 @@
+
+
+  
+    netcoreapp3.1
+
+    false
+  
+
+  
+    
+    
+    
+      runtime; build; native; contentfiles; analyzers; buildtransitive
+      all
+    
+    
+      runtime; build; native; contentfiles; analyzers; buildtransitive
+      all
+    
+  
+
+  
+    
+  
+
+
diff --git a/00_Alternate_Languages/91_Train/java/README.md b/00_Alternate_Languages/91_Train/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/91_Train/java/src/Train.java b/00_Alternate_Languages/91_Train/java/src/Train.java
new file mode 100644
index 00000000..0fc5ff12
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/java/src/Train.java
@@ -0,0 +1,109 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Train
+ * 

+ * Based on the Basic program Train here + * https://github.com/coding-horror/basic-computer-games/blob/main/91%20Train/train.bas + *

+ * Note: The idea was to create a version of the 1970's Basic program in Java, without introducing + * new features - no additional text, error checking, etc has been added. + */ +public class Train { + + private final Scanner kbScanner; + + public Train() { + kbScanner = new Scanner(System.in); + } + + public void process() { + + intro(); + + boolean gameOver = false; + + do { + double carMph = (int) (25 * Math.random() + 40); + double hours = (int) (15 * Math.random() + 5); + double train = (int) (19 * Math.random() + 20); + + System.out.println(" A CAR TRAVELING " + (int) carMph + " MPH CAN MAKE A CERTAIN TRIP IN"); + System.out.println((int) hours + " HOURS LESS THAN A TRAIN TRAVELING AT " + (int) train + " MPH."); + + double howLong = Double.parseDouble(displayTextAndGetInput("HOW LONG DOES THE TRIP TAKE BY CAR? ")); + + double hoursAnswer = hours * train / (carMph - train); + int percentage = (int) (Math.abs((hoursAnswer - howLong) * 100 / howLong) + .5); + if (percentage > 5) { + System.out.println("SORRY. YOU WERE OFF BY " + percentage + " PERCENT."); + } else { + System.out.println("GOOD! ANSWER WITHIN " + percentage + " PERCENT."); + } + System.out.println("CORRECT ANSWER IS " + hoursAnswer + " HOURS."); + + System.out.println(); + if (!yesEntered(displayTextAndGetInput("ANOTHER PROBLEM (YES OR NO)? "))) { + gameOver = true; + } + + } while (!gameOver); + + + } + + private void intro() { + System.out.println("TRAIN"); + System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println("TIME - SPEED DISTANCE EXERCISE"); + System.out.println(); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + + /** + * Checks whether player entered Y or YES to a question. + * + * @param text player string from kb + * @return true of Y or YES was entered, otherwise false + */ + private boolean yesEntered(String text) { + return stringIsAnyValue(text, "Y", "YES"); + } + + /** + * Check whether a string equals one of a variable number of values + * Useful to check for Y or YES for example + * Comparison is case insensitive. + * + * @param text source string + * @param values a range of values to compare against the source string + * @return true if a comparison was found in one of the variable number of strings passed + */ + private boolean stringIsAnyValue(String text, String... values) { + + return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text)); + + } + + /** + * Program startup. + * + * @param args not used (from command line). + */ + public static void main(String[] args) { + Train train = new Train(); + train.process(); + } +} diff --git a/00_Alternate_Languages/91_Train/javascript/README.md b/00_Alternate_Languages/91_Train/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/91_Train/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/91_Train/javascript/train.html b/00_Alternate_Languages/91_Train/javascript/train.html new file mode 100644 index 00000000..3aee95e2 --- /dev/null +++ b/00_Alternate_Languages/91_Train/javascript/train.html @@ -0,0 +1,9 @@ + + +TRAIN + + +


+
+
+
diff --git a/00_Alternate_Languages/91_Train/javascript/train.js b/00_Alternate_Languages/91_Train/javascript/train.js
new file mode 100644
index 00000000..b05e6791
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/javascript/train.js
@@ -0,0 +1,80 @@
+// TRAIN
+//
+// 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 control section
+async function main()
+{
+    print(tab(33) + "TRAIN\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("TIME - SPEED DISTANCE EXERCISE\n");
+    print("\n ");
+    while (1) {
+        c = Math.floor(25 * Math.random()) + 40;
+        d = Math.floor(15 * Math.random()) + 5;
+        t = Math.floor(19 * Math.random()) + 20;
+        print(" A CAR TRAVELING " + c + " MPH CAN MAKE A CERTAIN TRIP IN\n");
+        print(d + " HOURS LESS THAN A TRAIN TRAVELING AT " + t + " MPH.\n");
+        print("HOW LONG DOES THE TRIP TAKE BY CAR");
+        a = parseFloat(await input());
+        v = d * t / (c - t);
+        e = Math.floor(Math.abs((v - a) * 100 / a) + 0.5);
+        if (e > 5) {
+            print("SORRY.  YOU WERE OFF BY " + e + " PERCENT.\n");
+        } else {
+            print("GOOD! ANSWER WITHIN " + e + " PERCENT.\n");
+        }
+        print("CORRECT ANSWER IS " + v + " HOURS.\n");
+        print("\n");
+        print("ANOTHER PROBLEM (YES OR NO)\n");
+        str = await input();
+        print("\n");
+        if (str.substr(0, 1) != "Y")
+            break;
+    }
+}
+
+main();
diff --git a/68_Orbit/pascal/README.md b/00_Alternate_Languages/91_Train/pascal/README.md
similarity index 100%
rename from 68_Orbit/pascal/README.md
rename to 00_Alternate_Languages/91_Train/pascal/README.md
diff --git a/00_Alternate_Languages/91_Train/perl/README.md b/00_Alternate_Languages/91_Train/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/91_Train/perl/train.pl b/00_Alternate_Languages/91_Train/perl/train.pl
new file mode 100644
index 00000000..f2a4c1d5
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/perl/train.pl
@@ -0,0 +1,34 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+print ' 'x33 ."TRAIN\n";
+print ' 'x15 ."CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+print "TIME - SPEED DISTANCE EXERCISE\n"; print "\n";
+
+
+my $A= ""; #We must declare this before...
+do {
+	my $C= int(25*rand(1))+40;
+	my $D= int(15*rand(1))+5;
+	my $T= int(19*rand(1))+20;
+
+	print " A CAR TRAVELING $C MPH CAN MAKE A CERTAIN TRIP IN\n";
+	print "$D HOURS LESS THAN A TRAIN TRAVELING AT $T MPH.\n";
+	print "HOW LONG DOES THE TRIP TAKE BY CAR\n";
+	chomp ($A = );
+
+	my $V= $D*$T/($C-$T);
+	my $E= int(abs(($V-$A)*100/$A)+.5);
+	if ($E>5) {
+		print "SORRY.  YOU WERE OFF BY $E PERCENT.\n";
+		} else {
+		print "GOOD! ANSWER WITHIN $E PERCENT.\n";
+		}
+
+	print "CORRECT ANSWER IS $V HOURS.\n";
+	print "\n";
+	print "ANOTHER PROBLEM (YES OR NO)\n";
+	chomp ($A = uc()); #Uppercased
+	} until ($A ne "YES");
diff --git a/00_Alternate_Languages/91_Train/python/README.md b/00_Alternate_Languages/91_Train/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/91_Train/python/train.py b/00_Alternate_Languages/91_Train/python/train.py
new file mode 100644
index 00000000..bf4329d2
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/python/train.py
@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+# TRAIN
+#
+# Converted from BASIC to Python by Trevor Hobson
+
+import random
+
+
+def play_game():
+    """Play one round of the game"""
+    car_speed = random.randint(40, 65)
+    time_difference = random.randint(5, 20)
+    train_speed = random.randint(20, 39)
+    print("\nA car travelling", car_speed, "MPH can make a certain trip in")
+    print(time_difference, "hours less than a train travelling at", train_speed, "MPH")
+    time_answer = 0
+    while time_answer == 0:
+        try:
+            time_answer = float(input("How long does the trip take by car "))
+        except ValueError:
+            print("Please enter a number.")
+    car_time = time_difference * train_speed / (car_speed - train_speed)
+    error_percent = int(abs((car_time - time_answer) * 100 / time_answer) + 0.5)
+    if error_percent > 5:
+        print("Sorry. You were off by", error_percent, "percent.")
+        print("Correct answer is", round(car_time, 6), "hours")
+    else:
+        print("Good! Answer within", error_percent, "percent.")
+
+
+def main():
+    print(" " * 33 + "TRAIN")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n")
+    print("Time - speed distance exercise")
+
+    keep_playing = True
+    while keep_playing:
+        play_game()
+        keep_playing = input("\nAnother problem (yes or no) ").lower().startswith("y")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/91_Train/ruby/README.md b/00_Alternate_Languages/91_Train/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/91_Train/ruby/train.rb b/00_Alternate_Languages/91_Train/ruby/train.rb
new file mode 100644
index 00000000..6499cb24
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/ruby/train.rb
@@ -0,0 +1,58 @@
+def intro
+  puts "                                 TRAIN
+               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+
+
+
+TIME - SPEED DISTANCE EXERCISE
+
+"
+end
+
+def get_user_guess
+  while true
+    begin
+      number = Float(gets.chomp)
+      return number
+    rescue ArgumentError
+      # Ignored
+    end
+
+    puts "!NUMBER EXPECTED - RETRY INPUT LINE"
+    print "? "
+  end
+end
+
+def main
+  intro
+
+  loop do
+    car_speed = rand(25) + 40
+    car_time = rand(15) + 5
+    train_speed = rand(19) + 20
+
+    print " A CAR TRAVELING #{car_speed} MPH CAN MAKE A CERTAIN TRIP IN
+ #{car_time} HOURS LESS THAN A TRAIN TRAVELING AT #{train_speed} MPH.
+HOW LONG DOES THE TRIP TAKE BY CAR? "
+    guess = get_user_guess
+
+    answer = ((car_time * train_speed) / (car_speed - train_speed).to_f).round(5)
+    delta = (((answer - guess) * 100 / guess) + 0.5).abs.to_i
+
+    if delta > 5
+      puts "SORRY.  YOU WERE OFF BY #{delta} PERCENT."
+    else
+      puts "GOOD! ANSWER WITHIN #{delta} PERCENT."
+    end
+
+    print "CORRECT ANSWER IS #{answer == answer.to_i ? answer.to_i : answer} HOURS.
+
+ANOTHER PROBLEM (YES OR NO)? "
+    option = (gets || '').chomp.upcase
+    break unless option == 'YES'
+  end
+end
+
+trap "SIGINT" do puts; exit 130 end
+
+main
diff --git a/00_Alternate_Languages/91_Train/train.bas b/00_Alternate_Languages/91_Train/train.bas
new file mode 100644
index 00000000..b9817616
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/train.bas
@@ -0,0 +1,24 @@
+1 PRINT TAB(33);"TRAIN"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT: PRINT: PRINT
+4 PRINT "TIME - SPEED DISTANCE EXERCISE": PRINT
+10 C=INT(25*RND(1))+40
+15 D=INT(15*RND(1))+5
+20 T=INT(19*RND(1))+20
+25 PRINT " A CAR TRAVELING";C;"MPH CAN MAKE A CERTAIN TRIP IN"
+30 PRINT D;"HOURS LESS THAN A TRAIN TRAVELING AT";T;"MPH."
+35 PRINT "HOW LONG DOES THE TRIP TAKE BY CAR";
+40 INPUT A
+45 V=D*T/(C-T)
+50 E=INT(ABS((V-A)*100/A)+.5)
+55 IF E>5 THEN 70
+60 PRINT "GOOD! ANSWER WITHIN";E;"PERCENT."
+65 GOTO 80
+70 PRINT "SORRY.  YOU WERE OFF BY";E;"PERCENT."
+80 PRINT "CORRECT ANSWER IS";V;"HOURS."
+90 PRINT
+95 PRINT "ANOTHER PROBLEM (YES OR NO)";
+100 INPUT A$
+105 PRINT
+110 IF A$="YES" THEN 10
+999 END
diff --git a/00_Alternate_Languages/91_Train/vbnet/README.md b/00_Alternate_Languages/91_Train/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/91_Train/vbnet/Train.sln b/00_Alternate_Languages/91_Train/vbnet/Train.sln
new file mode 100644
index 00000000..ea959481
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/vbnet/Train.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Train", "Train.vbproj", "{05F1229A-9138-4B1D-9781-CE8C4F7A6151}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{05F1229A-9138-4B1D-9781-CE8C4F7A6151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{05F1229A-9138-4B1D-9781-CE8C4F7A6151}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{05F1229A-9138-4B1D-9781-CE8C4F7A6151}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{05F1229A-9138-4B1D-9781-CE8C4F7A6151}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/91_Train/vbnet/Train.vbproj b/00_Alternate_Languages/91_Train/vbnet/Train.vbproj
new file mode 100644
index 00000000..84f03013
--- /dev/null
+++ b/00_Alternate_Languages/91_Train/vbnet/Train.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Train
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/92_Trap/README.md b/00_Alternate_Languages/92_Trap/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/92_Trap/csharp/Program.cs b/00_Alternate_Languages/92_Trap/csharp/Program.cs
new file mode 100644
index 00000000..1769eb75
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/csharp/Program.cs
@@ -0,0 +1,119 @@
+using System;
+
+namespace trap_cs
+{
+  class Program
+  {
+    const int maxGuesses = 6;
+    const int maxNumber = 100;
+    static void Main(string[] args)
+    {
+      int lowGuess  = 0;
+      int highGuess = 0;
+
+      Random randomNumberGenerator = new ();
+
+      Print("TRAP");
+      Print("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+      Print();
+      Print();
+      Print();
+
+      PrintInstructions();
+
+      int numberToGuess = randomNumberGenerator.Next(1, maxNumber);
+
+      for (int nGuess = 1; nGuess <= maxGuesses + 1; nGuess++)
+      {
+        if (nGuess > maxGuesses)
+        {
+          Print(string.Format("SORRY, THAT'S {0} GUESSES. THE NUMBER WAS {1}", maxGuesses, numberToGuess));
+          Print();
+          break;
+        }
+
+        GetGuesses(nGuess, ref lowGuess, ref highGuess);
+
+        if(lowGuess == highGuess && lowGuess == numberToGuess)
+        {
+          Print("YOU GOT IT!!!");
+          Print();
+          Print("TRY AGAIN.");
+          Print();
+          break;
+        }
+        if (highGuess < numberToGuess)
+        {
+          Print("MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.");
+        }
+        else if (lowGuess > numberToGuess)
+        {
+          Print("MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.");
+        }
+        else
+        {
+          Print("YOU HAVE TRAPPED MY NUMBER.");
+        }
+      }
+    }
+
+// TRAP
+// REM - STEVE ULLMAN, 8 - 1 - 72
+    static void PrintInstructions()
+    {
+      Print("INSTRUCTIONS ?");
+
+      char response = Console.ReadKey().KeyChar;
+      if (response == 'Y')
+      {
+        Print(string.Format("I AM THINKING OF A NUMBER BETWEEN 1 AND {0}", maxNumber));
+        Print("TRY TO GUESS MY NUMBER. ON EACH GUESS,");
+        Print("YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP");
+        Print("MY NUMBER BETWEEN THE TWO NUMBERS. I WILL");
+        Print("TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY");
+        Print("NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF");
+        Print("MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.");
+        Print("IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE");
+        Print("YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.");
+        Print(string.Format("YOU GET {0} GUESSES TO GET MY NUMBER.", maxGuesses));
+      }
+    }
+    static void Print(string stringToPrint)
+    {
+      Console.WriteLine(stringToPrint);
+    }
+    static void Print()
+    {
+      Console.WriteLine();
+    }
+    static void GetGuesses(int nGuess, ref int lowGuess, ref int highGuess)
+    {
+      Print();
+      Print(string.Format("GUESS #{0}", nGuess));
+
+      lowGuess  = GetIntFromConsole("Type low guess");
+      highGuess = GetIntFromConsole("Type high guess");
+
+      if(lowGuess > highGuess)
+      {
+        int tempGuess = lowGuess;
+
+        lowGuess = highGuess;
+        highGuess = tempGuess;
+      }
+    }
+    static int GetIntFromConsole(string prompt)
+    {
+
+      Console.Write( prompt + " > ");
+      string intAsString = Console.ReadLine();
+
+      if(int.TryParse(intAsString, out int intValue) ==false)
+      {
+        intValue = 1;
+      }
+
+      return intValue;
+    }
+  }
+}
diff --git a/00_Alternate_Languages/92_Trap/csharp/README.md b/00_Alternate_Languages/92_Trap/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/92_Trap/csharp/Trap.csproj b/00_Alternate_Languages/92_Trap/csharp/Trap.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/csharp/Trap.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/92_Trap/csharp/Trap.sln b/00_Alternate_Languages/92_Trap/csharp/Trap.sln
new file mode 100644
index 00000000..6226bef3
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/csharp/Trap.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Trap", "Trap.csproj", "{4386B4A0-16A9-48E7-8FBA-E35D4C9FEDAA}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{4386B4A0-16A9-48E7-8FBA-E35D4C9FEDAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4386B4A0-16A9-48E7-8FBA-E35D4C9FEDAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4386B4A0-16A9-48E7-8FBA-E35D4C9FEDAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4386B4A0-16A9-48E7-8FBA-E35D4C9FEDAA}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/92_Trap/java/README.md b/00_Alternate_Languages/92_Trap/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/92_Trap/java/src/Trap.java b/00_Alternate_Languages/92_Trap/java/src/Trap.java
new file mode 100644
index 00000000..3643ed7e
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/java/src/Trap.java
@@ -0,0 +1,201 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Trap
+ * 

+ * Based on the Basic game of Trap here + * https://github.com/coding-horror/basic-computer-games/blob/main/92%20Trap/trap.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. + */ +public class Trap { + + public static final int HIGH_NUMBER_RANGE = 100; + public static final int MAX_GUESSES = 6; + + private enum GAME_STATE { + STARTING, + START_GAME, + GUESSING, + PLAY_AGAIN, + GAME_OVER + } + + // Used for keyboard input + private final Scanner kbScanner; + + // Current game state + private GAME_STATE gameState; + + // Players guess count; + private int currentPlayersGuess; + + // Computers random number + private int computersNumber; + + public Trap() { + + gameState = GAME_STATE.STARTING; + + // Initialise kb scanner + kbScanner = new Scanner(System.in); + } + + /** + * Main game loop + */ + public void play() { + + do { + switch (gameState) { + + // Show an introduction and optional instructions the first time the game is played. + case STARTING: + intro(); + if (yesEntered(displayTextAndGetInput("INSTRUCTIONS? "))) { + instructions(); + } + gameState = GAME_STATE.START_GAME; + break; + + // Start new game + case START_GAME: + computersNumber = randomNumber(); + currentPlayersGuess = 1; + gameState = GAME_STATE.GUESSING; + break; + + // Player guesses the number until they get it or run out of guesses + case GUESSING: + System.out.println(); + String playerRangeGuess = displayTextAndGetInput("GUESS # " + currentPlayersGuess + "? "); + int startRange = getDelimitedValue(playerRangeGuess, 0); + int endRange = getDelimitedValue(playerRangeGuess, 1); + + // Has the player won? + if (startRange == computersNumber && endRange == computersNumber) { + System.out.println("YOU GOT IT!!!"); + System.out.println(); + gameState = GAME_STATE.PLAY_AGAIN; + } else { + // show where the guess is at + System.out.println(showGuessResult(startRange, endRange)); + currentPlayersGuess++; + if (currentPlayersGuess > MAX_GUESSES) { + System.out.println("SORRY, THAT'S " + MAX_GUESSES + " GUESSES. THE NUMBER WAS " + + computersNumber); + gameState = GAME_STATE.PLAY_AGAIN; + } + } + break; + + // Play again, or exit game? + case PLAY_AGAIN: + System.out.println("TRY AGAIN"); + gameState = GAME_STATE.START_GAME; + } + } while (gameState != GAME_STATE.GAME_OVER); + } + + /** + * Show the players guess result + * + * @param start start range entered by player + * @param end end range + * @return text to indicate their progress. + */ + private String showGuessResult(int start, int end) { + + String status; + if (start <= computersNumber && computersNumber <= end) { + status = "YOU HAVE TRAPPED MY NUMBER."; + } else if (computersNumber < start) { + status = "MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS."; + } else { + status = "MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS."; + } + + return status; + } + + private void instructions() { + System.out.println("I AM THINKING OF A NUMBER BETWEEN 1 AND " + HIGH_NUMBER_RANGE); + System.out.println("TRY TO GUESS MY NUMBER. ON EACH GUESS,"); + System.out.println("YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP"); + System.out.println("MY NUMBER BETWEEN THE TWO NUMBERS. I WILL"); + System.out.println("TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY"); + System.out.println("NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF"); + System.out.println("MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS."); + System.out.println("IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE"); + System.out.println("YOUR GUESS FOR BOTH YOUR TRAP NUMBERS."); + System.out.println("YOU GET " + MAX_GUESSES + " GUESSES TO GET MY NUMBER."); + } + + private void intro() { + System.out.println("TRAP"); + System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println(); + System.out.println(); + } + + /** + * Accepts a string delimited by comma's and returns the nth delimited + * value (starting at count 0). + * + * @param text - text with values separated by comma's + * @param pos - which position to return a value for + * @return the int representation of the value + */ + private int getDelimitedValue(String text, int pos) { + String[] tokens = text.split(","); + return Integer.parseInt(tokens[pos]); + } + + /** + * Checks whether player entered Y or YES to a question. + * + * @param text player string from kb + * @return true of Y or YES was entered, otherwise false + */ + private boolean yesEntered(String text) { + return stringIsAnyValue(text, "Y", "YES"); + } + + /** + * Check whether a string equals one of a variable number of values + * Useful to check for Y or YES for example + * Comparison is case insensitive. + * + * @param text source string + * @param values a range of values to compare against the source string + * @return true if a comparison was found in one of the variable number of strings passed + */ + private boolean stringIsAnyValue(String text, String... values) { + + return Arrays.stream(values).anyMatch(str -> str.equalsIgnoreCase(text)); + } + + /* + * Print a message on the screen, then accept input from Keyboard. + * + * @param text message to be displayed on screen. + * @return what was typed by the player. + */ + private String displayTextAndGetInput(String text) { + System.out.print(text); + return kbScanner.next(); + } + + /** + * Generate random number + * Used as a single digit of the computer player + * + * @return random number + */ + private int randomNumber() { + return (int) (Math.random() + * (HIGH_NUMBER_RANGE) + 1); + } +} diff --git a/00_Alternate_Languages/92_Trap/java/src/TrapGame.java b/00_Alternate_Languages/92_Trap/java/src/TrapGame.java new file mode 100644 index 00000000..754446e2 --- /dev/null +++ b/00_Alternate_Languages/92_Trap/java/src/TrapGame.java @@ -0,0 +1,8 @@ +public class TrapGame { + + public static void main(String[] args) { + + Trap trap = new Trap(); + trap.play(); + } +} diff --git a/00_Alternate_Languages/92_Trap/javascript/README.md b/00_Alternate_Languages/92_Trap/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/92_Trap/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/92_Trap/javascript/trap.html b/00_Alternate_Languages/92_Trap/javascript/trap.html new file mode 100644 index 00000000..1084e1de --- /dev/null +++ b/00_Alternate_Languages/92_Trap/javascript/trap.html @@ -0,0 +1,9 @@ + + +TRAP + + +


+
+
+
diff --git a/00_Alternate_Languages/92_Trap/javascript/trap.js b/00_Alternate_Languages/92_Trap/javascript/trap.js
new file mode 100644
index 00000000..04745463
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/javascript/trap.js
@@ -0,0 +1,102 @@
+// TRAP
+//
+// 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 control section
+async function main()
+{
+    print(tab(34) + "TRAP\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    g = 6;
+    n = 100;
+    // Trap
+    // Steve Ullman, Aug/01/1972
+    print("INSTRUCTIONS");
+    str = await input();
+    if (str.substr(0, 1) == "Y") {
+        print("I AM THINKING OF A NUMBER BETWEEN 1 AND " + n + "\n");
+        print("TRY TO GUESS MY NUMBER. ON EACH GUESS,\n");
+        print("YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP\n");
+        print("MY NUMBER BETWEEN THE TWO NUMBERS. I WILL\n");
+        print("TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY\n");
+        print("NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF\n");
+        print("MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.\n");
+        print("IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE\n");
+        print("YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.\n");
+        print("YOU GET " + g + " GUESSES TO GET MY NUMBER.\n");
+    }
+    while (1) {
+        x = Math.floor(n * Math.random()) + 1;
+        for (q = 1; q <= g; q++) {
+            print("\n");
+            print("GUESS #" + q + " ");
+            str = await input();
+            a = parseInt(str);
+            b = parseInt(str.substr(str.indexOf(",") + 1));
+            if (a == b && x == a) {
+                print("YOU GOT IT!!!\n");
+                break;
+            }
+            if (a > b) {
+                r = a;
+                a = b;
+                b = r;
+            }
+            if (a <= x && x <= b) {
+                print("YOU HAVE TRAPPED MY NUMBER.\n");
+            } else if (x >= a) {
+                print("MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.\n");
+            } else {
+                print("MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.\n");
+            }
+        }
+        print("\n");
+        print("TRY AGAIN.\n");
+        print("\n");
+    }
+}
+
+main();
diff --git a/69_Pizza/pascal/README.md b/00_Alternate_Languages/92_Trap/pascal/README.md
similarity index 100%
rename from 69_Pizza/pascal/README.md
rename to 00_Alternate_Languages/92_Trap/pascal/README.md
diff --git a/00_Alternate_Languages/92_Trap/perl/README.md b/00_Alternate_Languages/92_Trap/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/92_Trap/perl/trap.pl b/00_Alternate_Languages/92_Trap/perl/trap.pl
new file mode 100644
index 00000000..c0f69c8c
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/perl/trap.pl
@@ -0,0 +1,60 @@
+#!/usr/bin/perl
+use strict;
+
+print ' 'x 34 . "TRAP\n";
+print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
+print "\n"; print "\n"; print "\n";
+my $G=6;
+my $N=100;
+# REM-TRAP;
+# REM-STEVE ULLMAN, 8-1-72;
+
+print "INSTRUCTIONS";
+print "? "; chomp(my $Z = uc());
+if (substr($Z,0,1) eq "Y") {
+	print "I AM THINKING OF A NUMBER BETWEEN 1 AND $N\n";
+	print "TRY TO GUESS MY NUMBER. ON EACH GUESS,\n";
+	print "YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP\n";
+	print "MY NUMBER BETWEEN THE TWO NUMBERS. I WILL\n";
+	print "TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY\n";
+	print "NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF\n";
+	print "MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS.\n";
+	print "IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE\n";
+	print "YOUR GUESS FOR BOTH YOUR TRAP NUMBERS.\n";
+	print "YOU GET $G GUESSES TO GET MY NUMBER.\n";
+	}
+
+while (1) {
+	my $Flag= 0;
+	my $X=int($N*rand(1))+1;
+	for (my $Q=1; $Q<=$G; $Q++) {
+		print "\n";
+		print "GUESS #$Q ";
+		print "? "; chomp(my $Pair= uc());
+		my ($A, $B)= split(",", $Pair);
+		if ($A eq $B && $X eq $A) { $Flag=1; last; }
+
+		if ($A>$B) { ($A,$B)= ($B,$A); }
+		if ($X>$B) {
+			print "MY NUMBER IS LARGER THAN YOUR TRAP NUMBERS.\n";
+			next;
+			}
+		if ($X<$A) {
+			print "MY NUMBER IS SMALLER THAN YOUR TRAP NUMBERS.\n";
+			next;
+			}
+		print "YOU HAVE TRAPPED MY NUMBER.\n";
+		}
+
+	if ($Flag==0) {
+		print "SORRY, THAT'S $G GUESSES. THE NUMBER WAS $X\n";
+		} else {
+		print "YOU GOT IT!!!\n";
+		}
+
+	print "\n";
+	print "TRY AGAIN.\n";
+	print "\n";
+	}
+
+exit;
diff --git a/00_Alternate_Languages/92_Trap/python/README.md b/00_Alternate_Languages/92_Trap/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/92_Trap/python/trap.py b/00_Alternate_Languages/92_Trap/python/trap.py
new file mode 100644
index 00000000..f1f294f7
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/python/trap.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# TRAP
+#
+# STEVE ULLMAN, 8-1-72
+# Converted from BASIC to Python by Trevor Hobson
+
+import random
+
+number_max = 100
+guess_max = 6
+
+
+def play_game():
+    """Play one round of the game"""
+
+    number_computer = random.randint(1, number_max)
+    turn = 0
+    while True:
+        turn += 1
+        user_guess = [-1, -1]
+        while user_guess == [-1, -1]:
+            try:
+                user_input = [
+                    int(item)
+                    for item in input("\nGuess # " + str(turn) + " ? ").split(",")
+                ]
+                if len(user_input) == 2:
+                    if sum(1 < x < number_max for x in user_input) == 2:
+                        user_guess = user_input
+                    else:
+                        raise ValueError
+                else:
+                    raise ValueError
+            except (ValueError, IndexError):
+                print("Please enter a valid guess.")
+        if user_guess[0] > user_guess[1]:
+            user_guess[0], user_guess[1] = user_guess[1], user_guess[0]
+        if user_guess[0] == user_guess[1] == number_computer:
+            print("You got it!!!")
+            break
+        elif user_guess[0] <= number_computer <= user_guess[1]:
+            print("You have trapped my number.")
+        elif number_computer < user_guess[0]:
+            print("My number is smaller than your trap numbers.")
+        else:
+            print("My number is larger than your trap numbers.")
+        if turn == guess_max:
+            print("That's", turn, "guesses. The number was", number_computer)
+            break
+
+
+def main():
+    print(" " * 34 + "TRAP")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n")
+    if input("Instructions ").lower().startswith("y"):
+        print("\nI am thinking of a number between 1 and", number_max)
+        print("try to guess my number. On each guess,")
+        print("you are to enter 2 numbers, trying to trap")
+        print("my number between the two numbers. I will")
+        print("tell you if you have trapped my number, if my")
+        print("number is larger than your two numbers, or if")
+        print("my number is smaller than your two numbers.")
+        print("If you want to guess one single number, type")
+        print("your guess for both your trap numbers.")
+        print("You get", guess_max, "guesses to get my number.")
+
+    keep_playing = True
+    while keep_playing:
+        play_game()
+        keep_playing = input("\nTry again. ").lower().startswith("y")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/92_Trap/ruby/README.md b/00_Alternate_Languages/92_Trap/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/92_Trap/ruby/trap.rb b/00_Alternate_Languages/92_Trap/ruby/trap.rb
new file mode 100644
index 00000000..d3a5b7c5
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/ruby/trap.rb
@@ -0,0 +1,98 @@
+#!/usr/bin/env ruby
+
+# Trap
+# Steve Ullman, 1972-08-01
+# Ruby version Glenn Vanderburg, 2022-03-04
+
+# Change these values to make the game easier or harder.
+GUESSES_PER_GAME = 6
+NUMBER_UPPER_BOUND = 100
+
+# Put everything in methods for order of presentation; we
+# want to be able to refer to methods before declaring them,
+# so the code reads nicely from top to bottom.
+def main
+  print_banner_and_instructions
+
+  loop do
+    play_a_game
+    break unless yes?("Try again?")
+  end
+end
+
+def yes?(prompt)
+  print "\n#{prompt} "
+  answer = gets
+  return answer.downcase.start_with?("y")
+end
+
+def print_banner_and_instructions
+  banner = "Creative Computing -- Morristown, New Jersey"
+
+  puts "Trap!".center(banner.size)
+  puts banner
+  2.times { puts }
+
+  return unless yes?("Instructions?")
+
+  puts <<~"END"
+    I am thinking of a number between 1 and #{NUMBER_UPPER_BOUND}.
+    Try to guess my number. On each guess,
+    you are to enter 2 numbers, trying to trap
+    my number between the two numbers. I will
+    tell you if you have trapped my number, if my
+    number is larger than your two numbers, or if
+    my number is smaller than your two numbers.
+    If you want to guess one single number, type
+    your guess for both your trap numbers.
+    You get #{GUESSES_PER_GAME} guesses to get my number.
+  END
+end
+
+def play_a_game
+  n = choose_number
+
+  GUESSES_PER_GAME.times do |i|
+    lower, upper = get_guesses("Guess ##{i+1}?")
+
+    case
+    when n < lower
+      puts "My number is smaller than your trap numbers."
+    when n > upper
+      puts "My number is larger than your trap numbers."
+    when lower != upper
+      puts "You have trapped my number."
+    else
+      puts "You got it!!!"
+      return
+    end
+  end
+
+  puts "Sorry, that's #{GUESSES_PER_GAME} guesses. Number was #{n}"
+end
+
+def choose_number
+  rand(NUMBER_UPPER_BOUND) + 1
+end
+
+def get_guesses(prompt)
+  loop do
+    print "\n#{prompt} "
+
+    # This is forgiving of input format; it ignores spaces and
+    # punctuation, returning only the strings of consecutive
+    # digits in the input line.
+    guesses = gets.scan(/\d+/)
+
+    if guesses.size != 2
+      puts "Please enter two numbers for each guess."
+    else
+      # convert the strings of digits to integers:
+      numbers = guesses.map(&:to_i)
+      # and return them, lowest number first:
+      return numbers.sort
+    end
+  end
+end
+
+main
diff --git a/00_Alternate_Languages/92_Trap/trap.bas b/00_Alternate_Languages/92_Trap/trap.bas
new file mode 100644
index 00000000..7827f8ca
--- /dev/null
+++ b/00_Alternate_Languages/92_Trap/trap.bas
@@ -0,0 +1,49 @@
+1 PRINT TAB(34);"TRAP"
+2 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+3 PRINT:PRINT:PRINT
+10 G=6
+20 N=100
+30 REM-TRAP
+40 REM-STEVE ULLMAN, 8-1-72
+50 PRINT "INSTRUCTIONS";
+60 INPUT Z$
+70 IF LEFT$(Z$,1)<>"Y" THEN 180
+80 PRINT "I AM THINKING OF A NUMBER BETWEEN 1 AND";N
+90 PRINT "TRY TO GUESS MY NUMBER. ON EACH GUESS,"
+100 PRINT "YOU ARE TO ENTER 2 NUMBERS, TRYING TO TRAP"
+110 PRINT "MY NUMBER BETWEEN THE TWO NUMBERS. I WILL"
+120 PRINT "TELL YOU IF YOU HAVE TRAPPED MY NUMBER, IF MY"
+130 PRINT "NUMBER IS LARGER THAN YOUR TWO NUMBERS, OR IF"
+140 PRINT "MY NUMBER IS SMALLER THAN YOUR TWO NUMBERS."
+150 PRINT "IF YOU WANT TO GUESS ONE SINGLE NUMBER, TYPE"
+160 PRINT "YOUR GUESS FOR BOTH YOUR TRAP NUMBERS."
+170 PRINT "YOU GET";G;"GUESSES TO GET MY NUMBER."
+180 X=INT(N*RND(1))+1
+190 FOR Q=1 TO G
+200 PRINT
+210 PRINT "GUESS #";Q;
+220 INPUT A,B
+230 IF A=B AND X=A THEN 400
+240 IF A <= B THEN 260
+250 GOSUB 360
+260 IF A <= X AND X <= B THEN 320
+270 IF X
+  
+    Exe
+    Trap
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/93_23_Matches/23matches.bas b/00_Alternate_Languages/93_23_Matches/23matches.bas
new file mode 100644
index 00000000..dc5b27a6
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/23matches.bas
@@ -0,0 +1,64 @@
+20 PRINT TAB(31);"23 MATCHES"
+30 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+40 PRINT:PRINT:PRINT
+80 PRINT " THIS IS A GAME CALLED '23 MATCHES'."
+90 PRINT
+100 PRINT "WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE"
+110 PRINT "MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE"
+120 PRINT "THE LAST MATCH."
+130 PRINT
+140 PRINT "LET'S FLIP A COIN TO SEE WHO GOES FIRST."
+150 PRINT "IF IT COMES UP HEADS, I WILL WIN THE TOSS."
+155 PRINT
+160 REM
+165 N = 23
+170 Q = INT(2*RND(5))
+180 IF Q = 1 THEN 210
+190 PRINT "TAILS! YOU GO FIRST. "
+195 PRINT
+200 GOTO 300
+210 PRINT "HEADS! I WIN! HA! HA!"
+220 PRINT "PREPARE TO LOSE, MEATBALL-NOSE!!"
+230 PRINT
+250 PRINT "I TAKE 2 MATCHES"
+260 N = N -2
+270 PRINT "THE NUMBER OF MATCHES IS NOW" N
+280 PRINT
+290 PRINT "YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES."
+300 PRINT "HOW MANY DO YOU WISH TO REMOVE",
+310 INPUT K
+320 IF K > 3 THEN 430
+330 IF K <= 0 THEN 430
+340 N = N - K
+350 PRINT "THERE ARE NOW";N;"MATCHES REMAINING."
+351 IF N = 4 THEN 381
+352 IF N = 3 THEN 383
+353 IF N = 2 THEN 385
+360 IF N <= 1 THEN  530
+370 Z = 4 - K
+372 GOTO 390
+380 PRINT
+381 Z = 3
+382 GOTO 390
+383 Z = 2
+384 GOTO 390
+385 Z = 1
+390 PRINT "MY TURN ! I REMOVE" Z "MATCHES"
+400 N = N - Z
+410 IF N <= 1 THEN 470
+420 GOTO 270
+430 PRINT "VERY FUNNY! DUMMY!"
+440 PRINT "DO YOU WANT TO PLAY OR GOOF AROUND?"
+450 PRINT "NOW, HOW MANY MATCHES DO YOU WANT",
+460 GOTO 310
+470 PRINT
+480 PRINT"YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!"
+490 PRINT "HA ! HA ! I BEAT YOU !!!"
+500 PRINT
+510 PRINT "GOOD BYE LOSER!"
+520 GOTO 560
+530 PRINT "YOU WON, FLOPPY EARS !"
+540 PRINT "THINK YOU'RE PRETTY SMART !"
+550 PRINT "LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!"
+560 STOP
+570 END
diff --git a/00_Alternate_Languages/93_23_Matches/README.md b/00_Alternate_Languages/93_23_Matches/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/93_23_Matches/csharp/23matches.csproj b/00_Alternate_Languages/93_23_Matches/csharp/23matches.csproj
new file mode 100644
index 00000000..11091f71
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/csharp/23matches.csproj
@@ -0,0 +1,9 @@
+
+
+  
+    Exe
+    netcoreapp3.1
+    _23matches
+  
+
+
diff --git a/00_Alternate_Languages/93_23_Matches/csharp/23matches.sln b/00_Alternate_Languages/93_23_Matches/csharp/23matches.sln
new file mode 100644
index 00000000..78fce16e
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/csharp/23matches.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.32002.261
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "23matches", "23matches.csproj", "{9DBE7354-0749-4750-9224-5F9F95C64905}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{9DBE7354-0749-4750-9224-5F9F95C64905}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9DBE7354-0749-4750-9224-5F9F95C64905}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9DBE7354-0749-4750-9224-5F9F95C64905}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9DBE7354-0749-4750-9224-5F9F95C64905}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {0A87AE2F-68AC-4354-9C8D-578209D41174}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/93_23_Matches/csharp/Goto.Program.cs b/00_Alternate_Languages/93_23_Matches/csharp/Goto.Program.cs
new file mode 100644
index 00000000..e23be8a4
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/csharp/Goto.Program.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Threading;
+
+namespace _23matches
+{
+    class Program
+    {
+        /// 
+        /// Mimics the "goto" version of the original program
+        /// 
+        /// 
+        static void Main(string[] args)
+        {
+            Random random = new Random();
+        StartNewGame:
+            Console.WriteLine("23 MATCHES".PadLeft(31));
+            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".PadLeft(15));
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("THIS IS A GAME CALLED '23 MATCHES'.");
+            Console.WriteLine();
+            Console.WriteLine("WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE");
+            Console.WriteLine("MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE");
+            Console.WriteLine("THE LAST MATCH.");
+            Console.WriteLine();
+            Console.WriteLine("Input exit to close the program.");
+            Console.WriteLine("Input cls Screen Clear.");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("LET'S FLIP A COIN TO SEE WHO GOES FIRST.");
+            Console.WriteLine("IF IT COMES UP HEADS, I WILL WIN THE TOSS.");
+            Console.WriteLine();
+        StartTheGame:
+            string command;
+            int N = 23;
+            int K = 0;
+            int Q = random.Next(2);
+            if (Q == 1)
+                goto ComputerFirst;
+            else
+                goto PlayerFirst;
+
+            ComputerFirst:
+            Console.WriteLine("HEADS! I WIN! HA! HA!");
+            Console.WriteLine("PREPARE TO LOSE, MEATBALL-NOSE!!");
+            Console.WriteLine();
+            int ain = random.Next(1, 3);
+            Console.WriteLine($"I TAKE {ain} MATCHES");
+            N = N - ain;
+            goto PlayersProceed;
+
+        PlayerFirst:
+            Console.WriteLine("TAILS! YOU GO FIRST. ");
+            Console.WriteLine();
+            goto PlayersSpeak;
+
+        PlayersProceed:
+            Console.WriteLine($"THE NUMBER OF MATCHES IS NOW {N}");
+            Console.WriteLine();
+            Console.WriteLine("YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.");
+            Console.WriteLine("HOW MANY DO YOU WISH TO REMOVE ");
+            goto PlayersSpeak;
+
+        PlayersSpeak:
+            command = Console.ReadLine().ToLower();
+            if (command.Equals("exit"))
+            {
+                System.Diagnostics.Process tt = System.Diagnostics.Process.GetProcessById(System.Diagnostics.Process.GetCurrentProcess().Id);
+                tt.Kill();
+            }
+            if (command.Equals("cls"))
+            {
+                Console.Clear();
+                goto PlayersProceed;
+            }
+            try
+            {
+                K = Convert.ToInt32(command);
+            }
+            catch (System.Exception)
+            {
+                goto PlayerInputError;
+            }
+            if (K > 3 || K <= 0)
+                goto PlayerInputError;
+            N = N - K;
+            Console.WriteLine($"THERE ARE NOW {N} MATCHES REMAINING.");
+            if (N == 4 || N == 3 || N == 2)
+                goto TheComputerSpeaks;
+            else if (N <= 1)
+                goto ThePlayerWins;
+            else
+                goto TheComputerSpeaks;
+
+            TheComputerSpeaks:
+            int Z = 4 - K;
+            Console.WriteLine($"MY TURN ! I REMOVE {Z} MATCHES");
+            N = N - Z;
+            if (N <= 1)
+                goto TheComputerWins;
+            else
+                goto PlayersProceed;
+
+            PlayerInputError:
+            Console.WriteLine("VERY FUNNY! DUMMY!");
+            Console.WriteLine("DO YOU WANT TO PLAY OR GOOF AROUND?");
+            Console.WriteLine("NOW, HOW MANY MATCHES DO YOU WANT ");
+            goto PlayersSpeak;
+        ThePlayerWins:
+            Console.WriteLine("YOU WON, FLOPPY EARS !");
+            Console.WriteLine("THINK YOU'RE PRETTY SMART !");
+            Console.WriteLine("LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!");
+            Console.WriteLine();
+            Console.WriteLine();
+            goto StartTheGame;
+        TheComputerWins:
+            Console.WriteLine();
+            Console.WriteLine("YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!");
+            Console.WriteLine("HA ! HA ! I BEAT YOU !!!");
+            Console.WriteLine();
+            Console.WriteLine("GOOD BYE LOSER!");
+            Console.WriteLine();
+            Console.WriteLine();
+            goto StartNewGame;
+
+        }
+    }
+}
diff --git a/00_Alternate_Languages/93_23_Matches/csharp/ObjectOrientedVersion.Program.cs b/00_Alternate_Languages/93_23_Matches/csharp/ObjectOrientedVersion.Program.cs
new file mode 100644
index 00000000..7b88d7b7
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/csharp/ObjectOrientedVersion.Program.cs
@@ -0,0 +1,161 @@
+using System;
+using System.Threading;
+
+namespace _23matches
+{
+    class ObjectOrientedVersion_Program
+    {
+        /// 
+        /// Object-oriented version
+        /// 
+        /// 
+        static void Main_Two(string[] args)
+        {
+            Game game = new Game();
+            game.GameRun();
+        }
+    }
+    public class Game
+    {
+        string command;
+        int N;
+        int K;
+        Random random = new Random();
+        public void GameRun()
+        {
+            StartNewGame();
+            StartTheGame();
+        }
+        void StartNewGame()
+        {
+            Console.WriteLine("23 MATCHES".PadLeft(31));
+            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".PadLeft(15));
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("THIS IS A GAME CALLED '23 MATCHES'.");
+            Console.WriteLine();
+            Console.WriteLine("WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE");
+            Console.WriteLine("MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE");
+            Console.WriteLine("THE LAST MATCH.");
+            Console.WriteLine();
+            Console.WriteLine("Input exit to close the program.");
+            Console.WriteLine("Input cls Screen Clear.");
+            Console.WriteLine();
+            Console.WriteLine();
+            Console.WriteLine("LET'S FLIP A COIN TO SEE WHO GOES FIRST.");
+            Console.WriteLine("IF IT COMES UP HEADS, I WILL WIN THE TOSS.");
+            Console.WriteLine();
+        }
+        void StartTheGame()
+        {
+            N = 23;
+            K = 0;
+            int Q = random.Next(2);
+            if (Q == 1)
+                ComputerFirst();
+            else
+            {
+                PlayerFirst();
+            }
+        }
+        void ComputerFirst()
+        {//210
+            Console.WriteLine("HEADS! I WIN! HA! HA!");
+            Console.WriteLine("PREPARE TO LOSE, MEATBALL-NOSE!!");
+            Console.WriteLine();
+            int ain = random.Next(1, 3);
+            Console.WriteLine($"I TAKE {ain} MATCHES");
+            N = N - ain;
+            PlayersProceed();
+        }
+        void PlayerFirst()
+        {
+            Console.WriteLine("TAILS! YOU GO FIRST. ");
+            Console.WriteLine();
+            PlayersSpeak();
+        }
+        void PlayersProceed()
+        {
+            Console.WriteLine($"THE NUMBER OF MATCHES IS NOW {N}");
+            Console.WriteLine();
+            PlayersSpeak();
+        }
+        void RemindsPlayersToEnter()
+        {
+            Console.WriteLine("YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.");
+            Console.WriteLine("HOW MANY DO YOU WISH TO REMOVE ");
+        }
+        void PlayersSpeak()
+        {
+            RemindsPlayersToEnter();
+            command = Console.ReadLine().ToLower();
+            if (command.Equals("exit"))
+            {
+                System.Diagnostics.Process tt = System.Diagnostics.Process.GetProcessById(System.Diagnostics.Process.GetCurrentProcess().Id);
+                tt.Kill();
+            }
+            if (command.Equals("cls"))
+            {
+                Console.Clear();
+                PlayersSpeak();
+            }
+            try
+            {
+                K = Convert.ToInt32(command);
+            }
+            catch (System.Exception)
+            {
+                PlayerInputError();
+            }
+            if (K > 3 || K <= 0)
+                PlayerInputError();
+            N = N - K;
+            Console.WriteLine($"THERE ARE NOW {N} MATCHES REMAINING.");
+            if (N == 4 || N == 3 || N == 2)
+                TheComputerSpeaks(N);
+            else if (N <= 1)
+                ThePlayerWins();
+            else
+                TheComputerSpeaks(4 - K);
+
+        }
+        void PlayerInputError()
+        {
+            Console.WriteLine("VERY FUNNY! DUMMY!");
+            Console.WriteLine("DO YOU WANT TO PLAY OR GOOF AROUND?");
+            Console.WriteLine("NOW, HOW MANY MATCHES DO YOU WANT ");
+            PlayersSpeak();
+        }
+        void TheComputerSpeaks(int ain)
+        {
+            int Z = ain;
+            Console.WriteLine($"MY TURN ! I REMOVE {Z} MATCHES");//390
+            N = N - Z;
+            if (N <= 1)
+                TheComputerWins();
+            else
+                PlayersProceed();
+        }
+        void ThePlayerWins()
+        {
+            Console.WriteLine("YOU WON, FLOPPY EARS !");
+            Console.WriteLine("THINK YOU'RE PRETTY SMART !");
+            Console.WriteLine("LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!");
+            Console.WriteLine();
+            Console.WriteLine();
+            StartTheGame();
+        }
+        void TheComputerWins()
+        {
+            Console.WriteLine();
+            Console.WriteLine("YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!");
+            Console.WriteLine("HA ! HA ! I BEAT YOU !!!");
+            Console.WriteLine();
+            Console.WriteLine("GOOD BYE LOSER!");
+            Console.WriteLine();
+            Console.WriteLine();
+            GameRun();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/93_23_Matches/csharp/README.md b/00_Alternate_Languages/93_23_Matches/csharp/README.md
new file mode 100644
index 00000000..fd759c06
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/csharp/README.md
@@ -0,0 +1,5 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
+
+The program is available in two versions, a "goto" version that mimics the original program and an "object-oriented" version.
diff --git a/00_Alternate_Languages/93_23_Matches/java/CoinSide.java b/00_Alternate_Languages/93_23_Matches/java/CoinSide.java
new file mode 100644
index 00000000..7126e9b4
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/java/CoinSide.java
@@ -0,0 +1,4 @@
+public enum CoinSide {
+    HEADS,
+    TAILS
+}
diff --git a/00_Alternate_Languages/93_23_Matches/java/Messages.java b/00_Alternate_Languages/93_23_Matches/java/Messages.java
new file mode 100644
index 00000000..73948691
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/java/Messages.java
@@ -0,0 +1,70 @@
+public class Messages {
+
+    // This is a utility class and contains only static members.
+    // Utility classes are not meant to be instantiated.
+    private Messages() {
+        throw new IllegalStateException("Utility class");
+    }
+
+    public static final String INTRO = """
+                                          23 MATCHES
+                          CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY
+
+
+
+             THIS IS A GAME CALLED '23 MATCHES'.
+
+            WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE
+            MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE
+            THE LAST MATCH.
+
+            LET'S FLIP A COIN TO SEE WHO GOES FIRST.
+            IF IT COMES UP HEADS, I WILL WIN THE TOSS.
+            """;
+
+    public static final String HEADS = """
+            HEADS! I WIN! HA! HA!
+            PREPARE TO LOSE, MEATBALL-NOSE!!
+
+            I TAKE 2 MATCHES
+            """;
+
+    public static final String TAILS = """
+            TAILS! YOU GO FIRST.
+            """;
+
+    public static final String MATCHES_LEFT = """
+            THE NUMBER OF MATCHES IS NOW %d
+
+            YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.
+            """;
+
+    public static final String REMOVE_MATCHES_QUESTION = "HOW MANY DO YOU WISH TO REMOVE? ";
+
+    public static final String REMAINING_MATCHES = """
+            THERE ARE NOW %d MATCHES REMAINING.
+            """;
+
+    public static final String INVALID = """
+            VERY FUNNY! DUMMY!
+            DO YOU WANT TO PLAY OR GOOF AROUND?
+            NOW, HOW MANY MATCHES DO YOU WANT?
+            """;
+
+    public static final String WIN = """
+            YOU WON, FLOPPY EARS !
+            THINK YOU'RE PRETTY SMART !
+            LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!
+            """;
+
+    public static final String CPU_TURN = """
+            MY TURN ! I REMOVE %d MATCHES.
+            """;
+
+    public static final String LOSE = """
+            YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!
+            HA ! HA ! I BEAT YOU !!!
+
+            GOOD BYE LOSER!
+            """;
+}
diff --git a/00_Alternate_Languages/93_23_Matches/java/README.md b/00_Alternate_Languages/93_23_Matches/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/93_23_Matches/java/TwentyThreeMatches.java b/00_Alternate_Languages/93_23_Matches/java/TwentyThreeMatches.java
new file mode 100644
index 00000000..f0c9836a
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/java/TwentyThreeMatches.java
@@ -0,0 +1,79 @@
+import java.util.Random;
+import java.util.Scanner;
+
+public class TwentyThreeMatches {
+
+    private static final int MATCH_COUNT_START = 23;
+    private static final Random RAND = new Random();
+    private final Scanner scan = new Scanner(System.in);
+
+    public void startGame() {
+        //Initialize values
+        int cpuRemoves = 0;
+        int matchesLeft = MATCH_COUNT_START;
+        int playerRemoves = 0;
+
+        //Flip coin and decide who goes first.
+        CoinSide coinSide = flipCoin();
+        if (coinSide == CoinSide.HEADS) {
+            System.out.println(Messages.HEADS);
+            matchesLeft -= 2;
+        } else {
+            System.out.println(Messages.TAILS);
+        }
+
+        // Game loop
+        while (true) {
+            //Show matches left if CPU went first or Player already removed matches
+            if (coinSide == CoinSide.HEADS) {
+                System.out.format(Messages.MATCHES_LEFT, matchesLeft);
+            }
+            coinSide = CoinSide.HEADS;
+
+            // Player removes matches
+            System.out.println(Messages.REMOVE_MATCHES_QUESTION);
+            playerRemoves = turnOfPlayer();
+            matchesLeft -= playerRemoves;
+            System.out.format(Messages.REMAINING_MATCHES, matchesLeft);
+
+            // If 1 match is left, the CPU has to take it. You win!
+            if (matchesLeft <= 1) {
+                System.out.println(Messages.WIN);
+                return;
+            }
+
+            // CPU removes matches
+            // At least two matches are left, because win condition above was not triggered.
+            if (matchesLeft <= 4) {
+                cpuRemoves = matchesLeft - 1;
+            } else {
+                cpuRemoves = 4 - playerRemoves;
+            }
+            System.out.format(Messages.CPU_TURN, cpuRemoves);
+            matchesLeft -= cpuRemoves;
+
+            // If 1 match is left, the Player has to take it. You lose!
+            if (matchesLeft <= 1) {
+                System.out.println(Messages.LOSE);
+                return;
+            }
+        }
+    }
+
+    private CoinSide flipCoin() {
+        return RAND.nextBoolean() ? CoinSide.HEADS : CoinSide.TAILS;
+    }
+
+    private int turnOfPlayer() {
+        while (true) {
+            int playerRemoves = scan.nextInt();
+            // Handle invalid entries
+            if ((playerRemoves > 3) || (playerRemoves <= 0)) {
+                System.out.println(Messages.INVALID);
+                continue;
+            }
+            return playerRemoves;
+        }
+    }
+
+}
diff --git a/00_Alternate_Languages/93_23_Matches/java/TwentyThreeMatchesGame.java b/00_Alternate_Languages/93_23_Matches/java/TwentyThreeMatchesGame.java
new file mode 100644
index 00000000..01735a91
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/java/TwentyThreeMatchesGame.java
@@ -0,0 +1,24 @@
+/**
+ * Game of 23 Matches
+ * 

+ * Based on the BASIC game of 23 Matches here + * https://github.com/coding-horror/basic-computer-games/blob/main/93%2023%20Matches/23matches.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 TwentyThreeMatchesGame { + + public static void main(String[] args) { + showIntro(); + TwentyThreeMatches game = new TwentyThreeMatches(); + game.startGame(); + } + + private static void showIntro() { + System.out.println(Messages.INTRO); + } + +} diff --git a/00_Alternate_Languages/93_23_Matches/javascript/23matches.html b/00_Alternate_Languages/93_23_Matches/javascript/23matches.html new file mode 100644 index 00000000..70d67217 --- /dev/null +++ b/00_Alternate_Languages/93_23_Matches/javascript/23matches.html @@ -0,0 +1,9 @@ + + +23 MATCHES + + +


+
+
+
diff --git a/00_Alternate_Languages/93_23_Matches/javascript/23matches.js b/00_Alternate_Languages/93_23_Matches/javascript/23matches.js
new file mode 100644
index 00000000..faf2b042
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/javascript/23matches.js
@@ -0,0 +1,122 @@
+// 23 MATCHES
+//
+// 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 control section
+async function main()
+{
+    print(tab(31) + "23 MATCHES\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print(" THIS IS A GAME CALLED '23 MATCHES'.\n");
+    print("\n");
+    print("WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE\n");
+    print("MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE\n");
+    print("THE LAST MATCH.\n");
+    print("\n");
+    print("LET'S FLIP A COIN TO SEE WHO GOES FIRST.\n");
+    print("IF IT COMES UP HEADS, I WILL WIN THE TOSS.\n");
+    print("\n");
+    n = 23;
+    q = Math.floor(2 * Math.random());
+    if (q != 1) {
+        print("TAILS! YOU GO FIRST. \n");
+        print("\n");
+    } else {
+        print("HEADS! I WIN! HA! HA!\n");
+        print("PREPARE TO LOSE, MEATBALL-NOSE!!\n");
+        print("\n");
+        print("I TAKE 2 MATCHES\n");
+        n -= 2;
+    }
+    while (1) {
+        if (q == 1) {
+            print("THE NUMBER OF MATCHES IS NOW " + n + "\n");
+            print("\n");
+            print("YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\n");
+        }
+        print("HOW MANY DO YOU WISH TO REMOVE ");
+        while (1) {
+            k = parseInt(await input());
+            if (k <= 0 || k > 3) {
+                print("VERY FUNNY! DUMMY!\n");
+                print("DO YOU WANT TO PLAY OR GOOF AROUND?\n");
+                print("NOW, HOW MANY MATCHES DO YOU WANT ");
+            } else {
+                break;
+            }
+        }
+        n -= k;
+        print("THERE ARE NOW " + n + " MATCHES REMAINING.\n");
+        if (n == 4) {
+            z = 3;
+        } else if (n == 3) {
+            z = 2;
+        } else if (n == 2) {
+            z = 1;
+        } else if (n > 1) {
+            z = 4 - k;
+        } else {
+            print("YOU WON, FLOPPY EARS !\n");
+            print("THINK YOU'RE PRETTY SMART !\n");
+            print("LETS PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF !!\n");
+            break;
+        }
+        print("MY TURN ! I REMOVE " + z + " MATCHES\n");
+        n -= z;
+        if (n <= 1) {
+            print("\n");
+            print("YOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\n");
+            print("HA ! HA ! I BEAT YOU !!!\n");
+            print("\n");
+            print("GOOD BYE LOSER!\n");
+            break;
+        }
+        q = 1;
+    }
+
+}
+
+main();
diff --git a/00_Alternate_Languages/93_23_Matches/javascript/README.md b/00_Alternate_Languages/93_23_Matches/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/70_Poetry/pascal/README.md b/00_Alternate_Languages/93_23_Matches/pascal/README.md
similarity index 100%
rename from 70_Poetry/pascal/README.md
rename to 00_Alternate_Languages/93_23_Matches/pascal/README.md
diff --git a/00_Alternate_Languages/93_23_Matches/perl/23matches.pl b/00_Alternate_Languages/93_23_Matches/perl/23matches.pl
new file mode 100644
index 00000000..c575d9cb
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/perl/23matches.pl
@@ -0,0 +1,86 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+print ' ' x 31 . "23 MATCHES\n";
+print ' ' x 15 . "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n";
+print "\n\n\n";
+
+print " THIS IS A GAME CALLED '23 MATCHES'.\n\n";
+
+print "WHEN IT IS YOUR TURN, YOU MAY TAKE ONE, TWO, OR THREE\n";
+print "MATCHES. THE OBJECT OF THE GAME IS NOT TO HAVE TO TAKE\n";
+print "THE LAST MATCH.\n\n";
+
+print "LET'S FLIP A COIN TO SEE WHO GOES FIRST.\n";
+print "IF IT COMES UP HEADS, I WILL WIN THE TOSS.\n\n";
+
+my $N = 23;
+my $Q = int( 2 * rand(5) );
+
+if ( $Q == 1 ) {
+    print "HEADS! I WIN! HA! HA!\n";
+    print "PREPARE TO LOSE, MEATBALL-NOSE!!\n\n";
+
+    print "I TAKE 2 MATCHES\n";
+    $N -= 2;
+
+    print "THE NUMBER OF MATCHES IS NOW $N\n\n";
+
+    print "YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\n";
+}
+else {
+    print "TAILS! YOU GO FIRST.\n\n";
+}
+
+print "HOW MANY DO YOU WISH TO REMOVE?\n";
+
+INPUT:
+{
+    chomp( my $K =  );
+
+    if ( $K > 3 or $K <= 0 ) {
+        print "VERY FUNNY! DUMMY!\n";
+        print "DO YOU WANT TO PLAY OR GOOF AROUND?\n";
+        print "NOW, HOW MANY MATCHES DO YOU WANT?\n";
+        redo INPUT;
+    }
+
+    $N -= $K;
+
+    print "THERE ARE NOW $N MATCHES REMAINING.\n";
+
+    my $Z;
+
+    if ( $N <= 1 ) {
+        print "YOU WON, FLOPPY EARS!\n";
+        print "THINK YOU'RE PRETTY SMART!\n";
+        print "LET'S PLAY AGAIN AND I'LL BLOW YOUR SHOES OFF!!\n";
+        exit;
+    }
+    elsif ( $N > 4 ) {
+        $Z = 4 - $K;
+    }
+    else {
+        $Z = $N - 1;
+    }
+
+    print "MY TURN! I REMOVE $Z MATCHES\n";
+
+    $N -= $Z;
+
+    if ( $N <= 1 ) {
+        print "\nYOU POOR BOOB! YOU TOOK THE LAST MATCH! I GOTCHA!!\n";
+        print "HA! HA! I BEAT YOU!!!\n\n";
+
+        print "GOOD BYE LOSER!\n";
+    }
+    else {
+        print "THE NUMBER OF MATCHES IS NOW $N\n\n";
+
+        print "YOUR TURN -- YOU MAY TAKE 1, 2 OR 3 MATCHES.\n";
+        print "HOW MANY DO YOU WISH TO REMOVE?\n";
+        redo INPUT;
+    }
+}
diff --git a/00_Alternate_Languages/93_23_Matches/perl/README.md b/00_Alternate_Languages/93_23_Matches/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/93_23_Matches/python/23matches.py b/00_Alternate_Languages/93_23_Matches/python/23matches.py
new file mode 100644
index 00000000..226b0f3a
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/python/23matches.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+# 23 Matches
+#
+# Converted from BASIC to Python by Trevor Hobson
+
+import random
+
+
+def play_game():
+    """Play one round of the game"""
+
+    matches = 23
+    humans_turn = random.randint(0, 1) == 1
+    if humans_turn:
+        print("Tails! You go first.\n")
+        prompt_human = "How many do you wish to remove "
+    else:
+        print("Heads! I win! Ha! Ha!")
+        print("Prepare to lose, meatball-nose!!")
+
+    choice_human = 2
+    while matches > 0:
+        if humans_turn:
+            choice_human = 0
+            if matches == 1:
+                choice_human = 1
+            while choice_human == 0:
+                try:
+                    choice_human = int(input(prompt_human))
+                    if choice_human not in [1, 2, 3] or choice_human > matches:
+                        choice_human = 0
+                        print("Very funny! Dummy!")
+                        print("Do you want to play or goof around?")
+                        prompt_human = "Now, how many matches do you want "
+                except ValueError:
+                    print("Please enter a number.")
+                    prompt_human = "How many do you wish to remove "
+            matches = matches - choice_human
+            if matches == 0:
+                print("You poor boob! You took the last match! I gotcha!!")
+                print("Ha ! Ha ! I beat you !!\n")
+                print("Good bye loser!")
+            else:
+                print("There are now", matches, "matches remaining.\n")
+        else:
+            choice_computer = 4 - choice_human
+            if matches == 1:
+                choice_computer = 1
+            elif 1 < matches < 4:
+                choice_computer = matches - 1
+            matches = matches - choice_computer
+            if matches == 0:
+                print("You won, floppy ears !")
+                print("Think you're pretty smart !")
+                print("Let's play again and I'll blow your shoes off !!")
+            else:
+                print("My turn ! I remove", choice_computer, "matches")
+                print("The number of matches is now", matches, "\n")
+        humans_turn = not humans_turn
+        prompt_human = "Your turn -- you may take 1, 2 or 3 matches.\nHow many do you wish to remove "
+
+
+def main():
+    print(" " * 31 + "23 MATCHHES")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n")
+    print("This is a game called '23 Matches'.\n")
+    print("When it is your turn, you may take one, two, or three")
+    print("matches. The object of the game is not to have to take")
+    print("the last match.\n")
+    print("Let's flip a coin to see who goes first.")
+    print("If it comes up heads, I will win the toss.\n")
+
+    keep_playing = True
+    while keep_playing:
+        play_game()
+        keep_playing = input("\nPlay again? (yes or no) ").lower().startswith("y")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/93_23_Matches/python/README.md b/00_Alternate_Languages/93_23_Matches/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/93_23_Matches/ruby/README.md b/00_Alternate_Languages/93_23_Matches/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/93_23_Matches/vbnet/README.md b/00_Alternate_Languages/93_23_Matches/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/93_23_Matches/vbnet/TwentyThreeMatches.sln b/00_Alternate_Languages/93_23_Matches/vbnet/TwentyThreeMatches.sln
new file mode 100644
index 00000000..a378cf3f
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/vbnet/TwentyThreeMatches.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "TwentyThreeMatches", "TwentyThreeMatches.vbproj", "{DEAA537A-6F73-4C2E-A85C-4B797B3D1900}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{DEAA537A-6F73-4C2E-A85C-4B797B3D1900}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DEAA537A-6F73-4C2E-A85C-4B797B3D1900}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DEAA537A-6F73-4C2E-A85C-4B797B3D1900}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DEAA537A-6F73-4C2E-A85C-4B797B3D1900}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/93_23_Matches/vbnet/TwentyThreeMatches.vbproj b/00_Alternate_Languages/93_23_Matches/vbnet/TwentyThreeMatches.vbproj
new file mode 100644
index 00000000..cf8620c9
--- /dev/null
+++ b/00_Alternate_Languages/93_23_Matches/vbnet/TwentyThreeMatches.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    TwentyThreeMatches
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/94_War/README.md b/00_Alternate_Languages/94_War/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/94_War/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/94_War/csharp/README.md b/00_Alternate_Languages/94_War/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/94_War/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/94_War/csharp/War.sln b/00_Alternate_Languages/94_War/csharp/War.sln
new file mode 100644
index 00000000..af1e88a5
--- /dev/null
+++ b/00_Alternate_Languages/94_War/csharp/War.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31112.23
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "War", "War\War.csproj", "{C13BE0FA-D8F7-4CA7-A95D-DA03A9DE8950}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WarTester", "WarTester\WarTester.csproj", "{B539F618-EE83-486C-9A6D-404E998BED2D}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{C13BE0FA-D8F7-4CA7-A95D-DA03A9DE8950}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C13BE0FA-D8F7-4CA7-A95D-DA03A9DE8950}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C13BE0FA-D8F7-4CA7-A95D-DA03A9DE8950}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C13BE0FA-D8F7-4CA7-A95D-DA03A9DE8950}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B539F618-EE83-486C-9A6D-404E998BED2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B539F618-EE83-486C-9A6D-404E998BED2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B539F618-EE83-486C-9A6D-404E998BED2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B539F618-EE83-486C-9A6D-404E998BED2D}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {3FA273C6-089E-4F3D-8DC0-F9143D1CDF3A}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/94_War/csharp/War/Cards.cs b/00_Alternate_Languages/94_War/csharp/War/Cards.cs
new file mode 100644
index 00000000..99e03020
--- /dev/null
+++ b/00_Alternate_Languages/94_War/csharp/War/Cards.cs
@@ -0,0 +1,170 @@
+using System;
+using System.Collections.Generic;
+
+
+
+namespace War
+{
+    // These enums define the card's suit and rank.
+    public enum Suit
+    {
+        clubs,
+        diamonds,
+        hearts,
+        spades
+    }
+
+    public enum Rank
+    {
+        // Skip 1 because ace is high.
+        two = 2,
+        three,
+        four,
+        five,
+        six,
+        seven,
+        eight,
+        nine,
+        ten,
+        jack,
+        queen,
+        king,
+        ace
+    }
+
+    // A class to represent a playing card.
+    public class Card
+    {
+        // A card is an immutable object (i.e. it can't be changed) so its suit
+        // and rank value are readonly; they can only be set in the constructor.
+        private readonly Suit suit;
+        private readonly Rank rank;
+
+        // These dictionaries are used to convert a suit or rank value into a string.
+        private readonly Dictionary suitNames = new Dictionary()
+        {
+            { Suit.clubs, "C"},
+            { Suit.diamonds, "D"},
+            { Suit.hearts, "H"},
+            { Suit.spades, "S"},
+        };
+
+        private readonly Dictionary rankNames = new Dictionary()
+        {
+            { Rank.two, "2"},
+            { Rank.three, "3"},
+            { Rank.four, "4"},
+            { Rank.five, "5"},
+            { Rank.six, "6"},
+            { Rank.seven, "7"},
+            { Rank.eight, "8"},
+            { Rank.nine, "9"},
+            { Rank.ten, "10"},
+            { Rank.jack, "J"},
+            { Rank.queen, "Q"},
+            { Rank.king, "K"},
+            { Rank.ace, "A"},
+        };
+
+        public Card(Suit suit, Rank rank)
+        {
+            this.suit = suit;
+            this.rank = rank;
+        }
+
+        // Relational Operator Overloading.
+        //
+        // You would normally expect the relational operators to consider both the suit and the
+        // rank of a card, but in this program suit doesn't matter so we define the operators to just
+        // compare rank.
+
+        // When adding relational operators we would normally include == and != but they are not
+        // relevant to this program so haven't been defined. Note that if they were defined we
+        // should also override the Equals() and GetHashCode() methods. See, for example:
+        // http://www.blackwasp.co.uk/CSharpRelationalOverload.aspx
+
+        // If the == and != operators were defined they would look like this:
+        //
+        //public static bool operator ==(Card lhs, Card rhs)
+        //{
+        //    return lhs.rank == rhs.rank;
+        //}
+        //
+        //public static bool operator !=(Card lhs, Card rhs)
+        //{
+        //    return !(lhs == rhs);
+        //}
+
+        public static bool operator <(Card lhs, Card rhs)
+        {
+            return lhs.rank < rhs.rank;
+        }
+
+        public static bool operator >(Card lhs, Card rhs)
+        {
+            return rhs < lhs;
+        }
+
+        public static bool operator <=(Card lhs, Card rhs)
+        {
+            return !(lhs > rhs);
+        }
+
+        public static bool operator >=(Card lhs, Card rhs)
+        {
+            return !(lhs < rhs);
+        }
+
+        public override string ToString()
+        {
+            // N.B. We are using string interpolation to create the card name.
+            return $"{suitNames[suit]}-{rankNames[rank]}";
+        }
+    }
+
+    // A class to represent a deck of cards.
+    public class Deck
+    {
+        public const int deckSize = 52;
+
+        private Card[] theDeck = new Card[deckSize];
+
+        public Deck()
+        {
+            // Populate theDeck with all the cards in order.
+            int i = 0;
+            for (Suit suit = Suit.clubs; suit <= Suit.spades; suit++)
+            {
+                for (Rank rank = Rank.two; rank <= Rank.ace; rank++)
+                {
+                    theDeck[i] = new Card(suit, rank);
+                    i++;
+                }
+            }
+        }
+
+        // Return the card at a particular position in the deck.
+        // N.B. As this is such a short method, we make it an
+        // expression-body method.
+        public Card GetCard(int i) => theDeck[i];
+
+        // Shuffle the cards, this uses the modern version of the
+        // Fisher-Yates shuffle, see:
+        // https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle#The_modern_algorithm
+        public void Shuffle()
+        {
+            var rand = new Random();
+
+            // Iterate backwards through the deck.
+            for (int i = deckSize - 1; i >= 1; i--)
+            {
+                int j = rand.Next(0, i);
+
+                // Swap the cards at i and j
+                Card temp = theDeck[j];
+                theDeck[j] = theDeck[i];
+                theDeck[i] = temp;
+            }
+        }
+    }
+}
diff --git a/00_Alternate_Languages/94_War/csharp/War/Program.cs b/00_Alternate_Languages/94_War/csharp/War/Program.cs
new file mode 100644
index 00000000..7ab335e3
--- /dev/null
+++ b/00_Alternate_Languages/94_War/csharp/War/Program.cs
@@ -0,0 +1,35 @@
+namespace War
+{
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            var ui = new UserInterface();
+            ui.WriteIntro();
+
+            var deck = new Deck();
+            deck.Shuffle();
+
+            int yourScore = 0;
+            int computersScore = 0;
+            bool usedAllCards = true;
+
+            for (int i = 0; i < Deck.deckSize; i += 2)
+            {
+                // Play the next hand.
+                var yourCard = deck.GetCard(i);
+                var computersCard = deck.GetCard(i + 1);
+
+                ui.WriteAResult(yourCard, computersCard, ref computersScore, ref yourScore);
+
+                if (!ui.AskAQuestion("DO YOU WANT TO CONTINUE? "))
+                {
+                    usedAllCards = false;
+                    break;
+                }
+            }
+
+            ui.WriteClosingRemarks(usedAllCards, yourScore, computersScore);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/94_War/csharp/War/UserInterface.cs b/00_Alternate_Languages/94_War/csharp/War/UserInterface.cs
new file mode 100644
index 00000000..ee93d9fa
--- /dev/null
+++ b/00_Alternate_Languages/94_War/csharp/War/UserInterface.cs
@@ -0,0 +1,83 @@
+using System;
+
+
+
+namespace War
+{
+    // This class displays all the text that the user sees when playing the game.
+    // It also handles asking the user a yes/no question and returning their answer.
+    public class UserInterface
+    {
+        public void WriteIntro()
+        {
+            Console.WriteLine("                                 WAR");
+            Console.WriteLine("               CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine();
+
+            Console.WriteLine("THIS IS THE CARD GAME OF WAR.  EACH CARD IS GIVEN BY SUIT-#");
+            Console.Write("AS S-7 FOR SPADE 7.  ");
+
+            if (AskAQuestion("DO YOU WANT DIRECTIONS? "))
+            {
+                Console.WriteLine("THE COMPUTER GIVES YOU AND IT A 'CARD'.  THE HIGHER CARD");
+                Console.WriteLine("(NUMERICALLY) WINS.  THE GAME ENDS WHEN YOU CHOOSE NOT TO");
+                Console.WriteLine("CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.");
+            }
+
+            Console.WriteLine();
+            Console.WriteLine();
+        }
+
+        public void WriteAResult(Card yourCard, Card computersCard, ref int computersScore, ref int yourScore)
+        {
+            Console.WriteLine($"YOU: {yourCard}     COMPUTER: {computersCard}");
+            if (yourCard < computersCard)
+            {
+                computersScore++;
+                Console.WriteLine($"THE COMPUTER WINS!!! YOU HAVE {yourScore} AND THE COMPUTER HAS {computersScore}");
+            }
+            else if (yourCard > computersCard)
+            {
+                yourScore++;
+                Console.WriteLine($"YOU WIN. YOU HAVE {yourScore} AND THE COMPUTER HAS {computersScore}");
+            }
+            else
+            {
+                Console.WriteLine("TIE.  NO SCORE CHANGE");
+            }
+        }
+
+        public bool AskAQuestion(string question)
+        {
+            // Repeat asking the question until the user answers "YES" or "NO".
+            while (true)
+            {
+                Console.Write(question);
+                string result = Console.ReadLine();
+
+                if (result.ToLower() == "yes")
+                {
+                    Console.WriteLine();
+                    return true;
+                }
+                else if (result.ToLower() == "no")
+                {
+                    Console.WriteLine();
+                    return false;
+                }
+
+                Console.WriteLine("YES OR NO, PLEASE.");
+            }
+        }
+
+        public void WriteClosingRemarks(bool usedAllCards, int yourScore, int computersScore)
+        {
+            if (usedAllCards)
+            {
+                Console.WriteLine("WE HAVE RUN OUT OF CARDS.");
+            }
+            Console.WriteLine($"FINAL SCORE:  YOU: {yourScore}  THE COMPUTER: {computersScore}");
+            Console.WriteLine("THANKS FOR PLAYING.  IT WAS FUN.");
+        }
+    }
+}
diff --git a/00_Alternate_Languages/94_War/csharp/War/War.csproj b/00_Alternate_Languages/94_War/csharp/War/War.csproj
new file mode 100644
index 00000000..c73e0d16
--- /dev/null
+++ b/00_Alternate_Languages/94_War/csharp/War/War.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    netcoreapp3.1
+  
+
+
diff --git a/00_Alternate_Languages/94_War/csharp/WarTester/Tests.cs b/00_Alternate_Languages/94_War/csharp/WarTester/Tests.cs
new file mode 100644
index 00000000..387b4547
--- /dev/null
+++ b/00_Alternate_Languages/94_War/csharp/WarTester/Tests.cs
@@ -0,0 +1,132 @@
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Text;
+using War;
+
+
+
+namespace WarTester
+{
+    [TestClass]
+    public class CardTest
+    {
+        private Card c1 = new Card(Suit.clubs, Rank.two);
+        private Card c2 = new Card(Suit.clubs, Rank.ten);
+        private Card c3 = new Card(Suit.diamonds, Rank.ten);
+        private Card c4 = new Card(Suit.diamonds, Rank.ten);
+
+        // Test the relational operators.
+
+        [TestMethod]
+        public void LessThanIsValid()
+        {
+            Assert.IsTrue(c1 < c2, "c1 < c2");  // Same suit, different rank.
+            Assert.IsFalse(c2 < c1, "c2 < c1"); // Same suit, different rank.
+
+            Assert.IsFalse(c3 < c4, "c3 < c4"); // Same suit, same rank.
+
+            Assert.IsTrue(c1 < c3, "c1 < c3");  // Different suit, different rank.
+            Assert.IsFalse(c3 < c1, "c3 < c1"); // Different suit, different rank.
+
+            Assert.IsFalse(c2 < c4, "c2 < c4"); // Different suit, same rank.
+            Assert.IsFalse(c4 < c2, "c4 < c2"); // Different suit, same rank.
+        }
+
+        [TestMethod]
+        public void GreaterThanIsValid()
+        {
+            Assert.IsFalse(c1 > c2, "c1 > c2"); // Same suit, different rank.
+            Assert.IsTrue(c2 > c1, "c2 > c1");  // Same suit, different rank.
+
+            Assert.IsFalse(c3 > c4, "c3 > c4"); // Same suit, same rank.
+
+            Assert.IsFalse(c1 > c3, "c1 > c3"); // Different suit, different rank.
+            Assert.IsTrue(c3 > c1, "c3 > c1");  // Different suit, different rank.
+
+            Assert.IsFalse(c2 > c4, "c2 > c4"); // Different suit, same rank.
+            Assert.IsFalse(c4 > c2, "c4 > c2"); // Different suit, same rank.
+        }
+
+        [TestMethod]
+        public void LessThanEqualsIsValid()
+        {
+            Assert.IsTrue(c1 <= c2, "c1 <= c2");  // Same suit, different rank.
+            Assert.IsFalse(c2 <= c1, "c2 <= c1"); // Same suit, different rank.
+
+            Assert.IsTrue(c3 <= c4, "c3 <= c4");  // Same suit, same rank.
+
+            Assert.IsTrue(c1 <= c3, "c1 <= c3");  // Different suit, different rank.
+            Assert.IsFalse(c3 <= c1, "c3 <= c1"); // Different suit, different rank.
+
+            Assert.IsTrue(c2 <= c4, "c2 <= c4");  // Different suit, same rank.
+            Assert.IsTrue(c4 <= c2, "c4 <= c2");  // Different suit, same rank.
+        }
+
+        [TestMethod]
+        public void GreaterThanEqualsIsValid()
+        {
+            Assert.IsFalse(c1 >= c2, "c1 >= c2"); // Same suit, different rank.
+            Assert.IsTrue(c2 >= c1, "c2 >= c1");  // Same suit, different rank.
+
+            Assert.IsTrue(c3 >= c4, "c3 >= c4");  // Same suit, same rank.
+
+            Assert.IsFalse(c1 >= c3, "c1 >= c3"); // Different suit, different rank.
+            Assert.IsTrue(c3 >= c1, "c3 >= c1");  // Different suit, different rank.
+
+            Assert.IsTrue(c2 >= c4, "c2 >= c4");  // Different suit, same rank.
+            Assert.IsTrue(c4 >= c2, "c4 >= c2");  // Different suit, same rank.
+        }
+
+        [TestMethod]
+        public void ToStringIsValid()
+        {
+            var s1 = c1.ToString();
+            var s2 = c3.ToString();
+            var s3 = new Card(Suit.hearts, Rank.queen).ToString();
+            var s4 = new Card(Suit.spades, Rank.ace).ToString();
+
+            Assert.IsTrue(s1 == "C-2", "s1 invalid");
+            Assert.IsTrue(s2 == "D-10", "s2 invalid");
+            Assert.IsTrue(s3 == "H-Q", "s3 invalid");
+            Assert.IsTrue(s4 == "S-A", "s4 invalid");
+        }
+    }
+
+    [TestClass]
+    public class DeckTest
+    {
+        private readonly string cardNamesInOrder = "C-2C-3C-4C-5C-6C-7C-8C-9C-10C-JC-QC-KC-AD-2D-3D-4D-5D-6D-7D-8D-9D-10D-JD-QD-KD-AH-2H-3H-4H-5H-6H-7H-8H-9H-10H-JH-QH-KH-AS-2S-3S-4S-5S-6S-7S-8S-9S-10S-JS-QS-KS-A";
+
+        //Helper method. Adds the names of all the cards together into a single string.
+        private string ConcatenateTheDeck(Deck d)
+        {
+            StringBuilder sb = new StringBuilder();
+
+            for (int i = 0; i < Deck.deckSize; i++)
+            {
+                sb.Append(d.GetCard(i));
+            }
+
+            return sb.ToString();
+        }
+
+        [TestMethod]
+        public void InitialDeckContainsCardsInOrder()
+        {
+            Deck d = new Deck();
+            string allTheCards = ConcatenateTheDeck(d);
+
+            Assert.IsTrue(allTheCards == cardNamesInOrder);
+        }
+
+        [TestMethod]
+        public void ShufflingChangesDeck()
+        {
+            // I'm not sure how to test that shuffling has worked other than to check that the cards aren't in the initial order.
+            Deck d = new Deck();
+            d.Shuffle();
+            string allTheCards = ConcatenateTheDeck(d);
+
+            Assert.IsTrue(allTheCards != cardNamesInOrder);
+        }
+    }
+}
diff --git a/00_Alternate_Languages/94_War/csharp/WarTester/WarTester.csproj b/00_Alternate_Languages/94_War/csharp/WarTester/WarTester.csproj
new file mode 100644
index 00000000..9d1808d6
--- /dev/null
+++ b/00_Alternate_Languages/94_War/csharp/WarTester/WarTester.csproj
@@ -0,0 +1,29 @@
+
+
+  
+    netcoreapp3.1
+
+    false
+
+    AnyCPU
+  
+
+  
+    true
+  
+
+  
+    
+    
+    
+    
+      all
+      runtime; build; native; contentfiles; analyzers; buildtransitive
+    
+  
+
+  
+    
+  
+
+
diff --git a/00_Alternate_Languages/94_War/d/.gitignore b/00_Alternate_Languages/94_War/d/.gitignore
new file mode 100644
index 00000000..d969f6b2
--- /dev/null
+++ b/00_Alternate_Languages/94_War/d/.gitignore
@@ -0,0 +1,2 @@
+*.exe
+*.obj
diff --git a/00_Alternate_Languages/94_War/d/README.md b/00_Alternate_Languages/94_War/d/README.md
new file mode 100644
index 00000000..2bc48a12
--- /dev/null
+++ b/00_Alternate_Languages/94_War/d/README.md
@@ -0,0 +1,125 @@
+Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).
+
+## Running the code
+
+Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:
+```shell
+dmd -preview=dip1000 -run war.d
+```
+
+[Other compilers](https://dlang.org/download.html) also exist.
+
+## Specialties explained
+
+This game code contains some specialties that you might want to know more about. Here goes.
+
+### Suits
+
+Most modern consoles are capable of displaying more than just ASCII, and so I have chosen to display the actual ♠, ♥, ♦
+and ♣ instead of substituting them by letters like the BASIC original did. Only the Windows console needs a nudge in
+the right direction with these instructions:
+```d
+SetConsoleOutputCP(CP_UTF8); // Set code page
+SetConsoleOutputCP(GetACP);  // Restore the default
+```
+Instead of cluttering the `main()` function with these lesser important details, we can move them into a
+[module constructor and module destructor](https://dlang.org/spec/module.html#staticorder), which run before and after
+`main()` respectively. And because order of declaration is irrelevant in a D module, we can push those all the way
+down to the bottom of the file. This is of course only necessary on Windows (and won't even work anywhere else) so
+we'll need to wrap this in a `version (Windows)` conditional code block:
+```d
+version (Windows)
+{
+    import core.sys.windows.windows;
+
+    shared static this() @trusted
+    {
+        SetConsoleOutputCP(CP_UTF8);
+    }
+
+    shared static ~this() @trusted
+    {
+        SetConsoleOutputCP(GetACP);
+    }
+}
+```
+Although it doesn't matter much in this single-threaded program, the `shared` attribute makes that these
+constructors/destructors are run once per program invocation; non-shared module constructors and module destructors are
+run for every thread. The `@trusted` annotation is necessary because these are system API calls; The compiler cannot
+check these for memory-safety, and so we must indicate that we have reviewed the safety manually.
+
+### Uniform Function Call Syntax
+
+In case you wonder why this line works:
+```d
+if ("Do you want instructions?".yes)
+    // ...
+```
+then it is because this is equivalent to
+```d
+if (yes("Do you want instructions?"))
+    // ...
+```
+where `yes()` is a Boolean function that is defined below `main()`. This is made possible by the language feature that
+is called [uniform function call syntax (UFCS)](https://dlang.org/spec/function.html#pseudo-member). UFCS works by
+passing what is in front of the dot as the first parameter to the function, and it was invented to make it possible to
+call free functions on objects as if they were member functions. UFCS can also be used to obtain a more natural order
+of function calls, such as this line inside `yes()`:
+```d
+return trustedReadln.strip.toLower.startsWith("y");
+```
+which reads easier than the equivalent
+```d
+return startsWith(toLower(strip(trustedReadln())), "y");
+```
+
+### Type a lot or not?
+
+It would have been straight forward to define the `cards` array explicitly like so:
+```d
+const cards = ["2♠", "2♥", "2♦", "2♣", "3♠", "3♥", "3♦", "3♣",
+               "4♠", "4♥", "4♦", "4♣", "5♠", "5♥", "5♦", "5♣",
+               "6♠", "6♥", "6♦", "6♣", "7♠", "7♥", "7♦", "7♣",
+               "8♠", "8♥", "8♦", "8♣", "9♠", "9♥", "9♦", "9♣",
+               "10♠", "10♥", "10♦", "10♣", "J♥", "J♦", "J♣", "J♣",
+               "Q♠", "Q♥", "Q♦", "Q♣", "K♠", "K♥", "K♦", "K♣",
+               "A♠", "A♥", "A♦", "A♣"];
+```
+but that's tedious, difficult to spot errors in (*can you?*) and looks like something a computer can automate. Indeed
+it can:
+```d
+static const cards = cartesianProduct(["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"],
+                                      ["♠", "♥", "♦", "♣"]).map!(a => a.expand.only.join).array;
+```
+The function [`cartesianProduct`](https://dlang.org/phobos/std_algorithm_setops.html#cartesianProduct) takes two
+ranges, like the horizontal and vertical headers of a spreadsheet, and fills the table with the combinations that form
+the coordinates of the cells. But the output of that function is in the form of an array of
+[`Tuple`](https://dlang.org/phobos/std_typecons.html#Tuple)s, which looks like `[Tuple!(string, string)("2", "♠"),
+Tuple!(string, string)("2", "♥"), ... etc]`. [`map`](https://dlang.org/phobos/std_algorithm_iteration.html#map)
+comes to the rescue, converting each Tuple to a string, by calling
+[`expand`](https://dlang.org/phobos/std_typecons.html#.Tuple.expand), then
+[`only`](https://dlang.org/phobos/std_range.html#only) and then [`join`](https://dlang.org/phobos/std_array.html#join)
+on them. The result is a lazily evaluated range of strings. Finally,
+[`array`](https://dlang.org/phobos/std_array.html#array) turns the range into a random access array. The `static`
+attribute makes that all this is performed at compile-time, so the result is exactly the same as the manually entered
+data, but without the typo's.
+
+### Shuffle the cards or not?
+
+The original BASIC code works with a constant array of cards, ordered by increasing numerical value, and indexing it
+with indices that have been shuffled. This is efficient because in comparing who wins, the indices can be compared
+directly, since a higher index correlates to a card with a higher numerical value (when divided by the number of suits,
+4). Some of the other reimplementations in other languages have been written in a lesser efficient way by shuffling the
+array of cards itself. This then requires the use of a lookup table or searching for equality in an auxiliary array
+when comparing cards.
+
+I find the original more elegant, so that's what you see here:
+```d
+const indices = iota(0, cards.length).array.randomShuffle;
+```
+[`iota`](https://dlang.org/phobos/std_range.html#iota) produces a range of integers, in this case starting at 0 and
+increasing up to the number of cards in the deck (exclusive). [`array`](https://dlang.org/phobos/std_array.html#array)
+turns the range into an array, so that [`randomShuffle`](https://dlang.org/phobos/std_random.html#randomShuffle) can
+do its work.
diff --git a/00_Alternate_Languages/94_War/d/war.d b/00_Alternate_Languages/94_War/d/war.d
new file mode 100644
index 00000000..d5a453fa
--- /dev/null
+++ b/00_Alternate_Languages/94_War/d/war.d
@@ -0,0 +1,80 @@
+@safe: // Make @safe the default for this file, enforcing memory-safety.
+import std;
+
+void main()
+{
+    enum width = 50;
+    writeln(center("War", width));
+    writeln(center("(After Creative Computing  Morristown, New Jersey)\n\n", width));
+    writeln(wrap("This is the card game of war.  Each card is given by suit-# " ~
+                 "as 7♠ for seven of spades.  ", width));
+
+    if ("Do you want instructions?".yes)
+        writeln("\n", wrap("The computer gives you and it a 'card'.  The higher card " ~
+                           "(numerically) wins.  The game ends when you choose not to " ~
+                           "continue or when you have finished the pack.\n", width));
+
+    static const cards = cartesianProduct(["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"],
+                                          ["♠", "♥", "♦", "♣"]).map!(a => a.expand.only.join).array;
+    const indices = iota(0, cards.length).array.randomShuffle;
+    int yourScore = 0, compScore = 0, i = 0;
+    while (i < indices.length)
+    {
+        size_t your = indices[i++], comp = indices[i++];
+        writeln("\nYou: ", cards[your].leftJustify(9), "Computer: ", cards[comp]);
+        your /= 4; comp /= 4;
+        if (your == comp)
+            writeln("Tie. No score change.");
+        else if (your < comp)
+            writeln("The computer wins!!! You have ", yourScore,
+                    " and the computer has ", ++compScore, ".");
+        else
+            writeln("You win. You have ", ++yourScore,
+                    " and the computer has ", compScore, ".");
+        if (i == indices.length)
+            writeln("\nWe have run out of cards. Final score: You: ", yourScore,
+                    ", the computer: ", compScore, ".");
+        else if (!"Do you want to continue?".yes)
+            break;
+    }
+    writeln("\nThanks for playing. It was fun.");
+}
+
+/// Returns whether question was answered positively.
+bool yes(string question)
+{
+    writef!"%s "(question);
+    try
+        return trustedReadln.strip.toLower.startsWith("y");
+    catch (Exception)   // readln throws on I/O and Unicode errors, which we handle here.
+        return false;
+}
+
+/** An @trusted wrapper around readln.
+*
+* This is the only function that formally requires manual review for memory-safety.
+* [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com)
+* which would remove the need to have any @trusted code in this program.
+*/
+string trustedReadln() @trusted
+{
+    return readln;
+}
+
+version (Windows)
+{
+    // Make the Windows console do a better job at printing UTF-8 strings,
+    // and restore the default upon termination.
+
+    import core.sys.windows.windows;
+
+    shared static this() @trusted
+    {
+        SetConsoleOutputCP(CP_UTF8);
+    }
+
+    shared static ~this() @trusted
+    {
+        SetConsoleOutputCP(GetACP);
+    }
+}
diff --git a/00_Alternate_Languages/94_War/java/README.md b/00_Alternate_Languages/94_War/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/94_War/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/94_War/java/War.java b/00_Alternate_Languages/94_War/java/War.java
new file mode 100644
index 00000000..ce5f3560
--- /dev/null
+++ b/00_Alternate_Languages/94_War/java/War.java
@@ -0,0 +1,198 @@
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Scanner;
+
+/**
+ * Converted FROM BASIC to Java by Nahid Mondol.
+ *
+ * Based on Trevor Hobsons approach.
+ */
+public class War {
+
+    private static final int CARD_DECK_SIZE = 52;
+    private static int playerTotalScore = 0;
+    private static int computerTotalScore = 0;
+    private static boolean invalidInput;
+    private static Scanner userInput = new Scanner(System.in);
+
+    // Simple approach for storing a deck of cards.
+    // Suit-Value, ex: 2 of Spades = S-2, King of Diamonds = D-K, etc...
+    private static ArrayList deckOfCards = new ArrayList(
+            Arrays.asList("S-2", "H-2", "C-2", "D-2", "S-3", "H-3", "C-3", "D-3", "S-4", "H-4", "C-4", "D-4", "S-5",
+                    "H-5", "C-5", "D-5", "S-6", "H-6", "C-6", "D-6", "S-7", "H-7", "C-7", "D-7", "S-8", "H-8", "C-8",
+                    "D-8", "S-9", "H-9", "C-9", "D-9", "S-10", "H-10", "C-10", "D-10", "S-J", "H-J", "C-J", "D-J",
+                    "S-Q", "H-Q", "C-Q", "D-Q", "S-K", "H-K", "C-K", "D-K", "S-A", "H-A", "C-A", "D-A"));
+
+    public static void main(String[] args) {
+        introMessage();
+        showDirectionsBasedOnInput();
+        playGame();
+    }
+
+    private static void introMessage() {
+        System.out.println("\t         WAR");
+        System.out.println("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+        System.out.println("THIS IS THE CARD GAME OF WAR. EACH CARD IS GIVEN BY SUIT-#");
+        System.out.print("AS S-7 FOR SPADE 7. DO YOU WANT DIRECTIONS? ");
+    }
+
+    private static void showDirectionsBasedOnInput() {
+        // Stay in loop until player chooses an option.
+        invalidInput = true;
+        while (invalidInput) {
+            switch (userInput.nextLine().toLowerCase()) {
+                case "yes":
+                    System.out.println("THE COMPUTER GIVES YOU AND IT A 'CARD'. THE HIGHER CARD");
+                    System.out.println("(NUMERICALLY) WINS. THE GAME ENDS WHEN YOU CHOOSE NOT TO ");
+                    System.out.println("CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\n");
+                    invalidInput = false;
+                    break;
+                case "no":
+                    System.out.println();
+                    invalidInput = false;
+                    break;
+                default:
+                    System.out.print("YES OR NO, PLEASE.   ");
+            }
+        }
+    }
+
+    private static void playGame() {
+
+        // Checks to see if the player ends the game early.
+        // Ending early will cause a different output to appear.
+        boolean gameEndedEarly = false;
+
+        // Shuffle the deck of cards.
+        Collections.shuffle(deckOfCards);
+
+        // Since the deck is already suffled, pull each card until the deck is empty or
+        // until the user quits.
+        outerloop:
+        for (int i = 1; i <= CARD_DECK_SIZE; i += 2) {
+            System.out.println("YOU: " + deckOfCards.get(i - 1) + "\t " + "COMPUTER: " + deckOfCards.get(i));
+            getWinner(deckOfCards.get(i - 1), deckOfCards.get(i));
+
+            invalidInput = true;
+            while (invalidInput) {
+                if (endedEarly()) {
+                    // Player ended game early.
+                    // Break out of game loop and show end game output.
+                    gameEndedEarly = true;
+                    break outerloop;
+                }
+            }
+        }
+
+        endGameOutput(gameEndedEarly);
+    }
+
+    /**
+     * Outputs the winner of the current round.
+     *
+     * @param playerCard   Players card.
+     * @param computerCard Computers card.
+     */
+    private static void getWinner(String playerCard, String computerCard) {
+
+        // Return the number value of the card pulled.
+        String playerCardScore = (playerCard.length() == 3) ? Character.toString(playerCard.charAt(2))
+                : playerCard.substring(2, 4);
+        String computerCardScore = (computerCard.length() == 3) ? Character.toString(computerCard.charAt(2))
+                : computerCard.substring(2, 4);
+
+        if (checkCourtCards(playerCardScore) > checkCourtCards(computerCardScore)) {
+            System.out.println("YOU WIN.   YOU HAVE " + playerWonRound() + "   COMPUTER HAS " + getComputerScore());
+        } else if (checkCourtCards(playerCardScore) < checkCourtCards(computerCardScore)) {
+            System.out.println(
+                    "COMPUTER WINS!!!   YOU HAVE " + getPlayerScore() + "   COMPUTER HAS " + computerWonRound());
+        } else {
+            System.out.println("TIE.  NO SCORE CHANGE");
+        }
+
+        System.out.print("DO YOU WANT TO CONTINUE? ");
+    }
+
+    /**
+     * @param cardScore Score of the card being pulled.
+     * @return an integer value of the current card's score.
+     */
+    private static int checkCourtCards(String cardScore) {
+        switch (cardScore) {
+            case "J":
+                return Integer.parseInt("11");
+            case "Q":
+                return Integer.parseInt("12");
+            case "K":
+                return Integer.parseInt("13");
+            case "A":
+                return Integer.parseInt("14");
+            default:
+                return Integer.parseInt(cardScore);
+        }
+    }
+
+    /**
+     * @return true if the player ended the game early. false otherwise.
+     */
+    private static boolean endedEarly() {
+        switch (userInput.nextLine().toLowerCase()) {
+            case "yes":
+                invalidInput = false;
+                return false;
+            case "no":
+                invalidInput = false;
+                return true;
+            default:
+                invalidInput = true;
+                System.out.print("YES OR NO, PLEASE.   ");
+                return false;
+        }
+    }
+
+    /**
+     * Show output based on if the game was ended early or not.
+     *
+     * @param endedEarly true if the game was ended early, false otherwise.
+     */
+    private static void endGameOutput(boolean endedEarly) {
+        if (endedEarly) {
+            System.out.println("YOU HAVE ENDED THE GAME. FINAL SCORE:  YOU: " + getPlayerScore() + " COMPUTER: "
+                    + getComputerScore());
+            System.out.println("THANKS FOR PLAYING.  IT WAS FUN.");
+        } else {
+            System.out.println("WE HAVE RUN OUT OF CARDS. FINAL SCORE:  YOU: " + getPlayerScore() + " COMPUTER: "
+                    + getComputerScore());
+            System.out.println("THANKS FOR PLAYING.  IT WAS FUN.");
+        }
+    }
+
+    /**
+     * Increment the player's total score if they have won the round.
+     */
+    private static int playerWonRound() {
+        return playerTotalScore += 1;
+    }
+
+    /**
+     * Get the player's total score.
+     */
+    private static int getPlayerScore() {
+        return playerTotalScore;
+    }
+
+    /**
+     * Increment the computer's total score if they have won the round.
+     */
+    private static int computerWonRound() {
+        return computerTotalScore += 1;
+    }
+
+    /**
+     * Get the computer's total score.
+     */
+    private static int getComputerScore() {
+        return computerTotalScore;
+    }
+}
diff --git a/00_Alternate_Languages/94_War/javascript/README.md b/00_Alternate_Languages/94_War/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/94_War/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/94_War/javascript/war.html b/00_Alternate_Languages/94_War/javascript/war.html
new file mode 100644
index 00000000..67cab7d2
--- /dev/null
+++ b/00_Alternate_Languages/94_War/javascript/war.html
@@ -0,0 +1,9 @@
+
+
+WAR
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/94_War/javascript/war.js b/00_Alternate_Languages/94_War/javascript/war.js
new file mode 100644
index 00000000..72774260
--- /dev/null
+++ b/00_Alternate_Languages/94_War/javascript/war.js
@@ -0,0 +1,164 @@
+// WAR
+//
+// Original conversion from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str) {
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function tab(space) {
+    let str = "";
+    while (space-- > 0) {
+        str += " ";
+    }
+    return str;
+}
+
+function input() {
+    return new Promise(function (resolve) {
+        const 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_element.addEventListener("keydown", function (event) {
+            if (event.keyCode == 13) {
+                const input_str = input_element.value;
+                document.getElementById("output").removeChild(input_element);
+                print(input_str);
+                print("\n");
+                resolve(input_str);
+            }
+        });
+    });
+}
+
+async function askYesOrNo(question) {
+    while (1) {
+        print(question);
+        const str = (await input()).toUpperCase();
+        if (str === "YES") {
+            return true;
+        }
+        else if (str === "NO") {
+            return false;
+        }
+        else {
+            print("YES OR NO, PLEASE.  ");
+        }
+    }
+}
+
+async function askAboutInstructions() {
+    const playerWantsInstructions = await askYesOrNo("DO YOU WANT DIRECTIONS");
+    if (playerWantsInstructions) {
+        print("THE COMPUTER GIVES YOU AND IT A 'CARD'.  THE HIGHER CARD\n");
+        print("(NUMERICALLY) WINS.  THE GAME ENDS WHEN YOU CHOOSE NOT TO\n");
+        print("CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\n");
+    }
+    print("\n");
+    print("\n");
+}
+
+function createGameDeck(cards, gameSize) {
+    const deck = [];
+    const deckSize = cards.length;
+    for (let j = 0; j < gameSize; j++) {
+        let card;
+
+        // Compute a new card index until we find one that isn't already in the new deck
+        do {
+            card = Math.floor(deckSize * Math.random());
+        } while (deck.includes(card));
+        deck.push(card);
+    }
+    return deck;
+}
+
+function computeCardValue(cardIndex) {
+    return Math.floor(cardIndex / 4);
+}
+
+function printGameOver(playerScore, computerScore) {
+    print("\n");
+    print("\n");
+    print(`WE HAVE RUN OUT OF CARDS.  FINAL SCORE:  YOU: ${playerScore}  THE COMPUTER: ${computerScore}\n`);
+    print("\n");
+}
+
+function printTitle() {
+    print(tab(33) + "WAR\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("THIS IS THE CARD GAME OF WAR.  EACH CARD IS GIVEN BY SUIT-#\n");
+    print("AS S-7 FOR SPADE 7.  ");
+}
+
+function printCards(playerCard, computerCard) {
+    print("\n");
+    print(`YOU: ${playerCard}\tCOMPUTER: ${computerCard}\n`);
+}
+
+const cards = [
+    "S-2", "H-2", "C-2", "D-2",
+    "S-3", "H-3", "C-3", "D-3",
+    "S-4", "H-4", "C-4", "D-4",
+    "S-5", "H-5", "C-5", "D-5",
+    "S-6", "H-6", "C-6", "D-6",
+    "S-7", "H-7", "C-7", "D-7",
+    "S-8", "H-8", "C-8", "D-8",
+    "S-9", "H-9", "C-9", "D-9",
+    "S-10", "H-10", "C-10", "D-10",
+    "S-J", "H-J", "C-J", "D-J",
+    "S-Q", "H-Q", "C-Q", "D-Q",
+    "S-K", "H-K", "C-K", "D-K",
+    "S-A", "H-A", "C-A", "D-A"
+];
+
+// Main control section
+async function main() {
+    printTitle();
+    await askAboutInstructions();
+
+    let computerScore = 0;
+    let playerScore = 0;
+
+    // Generate a random deck
+    const gameSize = cards.length;    // Number of cards to shuffle into the game deck.  Can be <= cards.length.
+    const deck = createGameDeck(cards, gameSize);
+    let shouldContinuePlaying = true;
+
+    while (deck.length > 0 && shouldContinuePlaying) {
+        const playerCard = deck.shift();    // Take a card
+        const computerCard = deck.shift();    // Take a card
+        printCards(cards[playerCard], cards[computerCard]);
+
+        const playerCardValue = computeCardValue(playerCard);
+        const computerCardValue = computeCardValue(computerCard);
+        if (playerCardValue < computerCardValue) {
+            computerScore++;
+            print("THE COMPUTER WINS!!! YOU HAVE " + playerScore + " AND THE COMPUTER HAS " + computerScore + "\n");
+        } else if (playerCardValue > computerCardValue) {
+            playerScore++;
+            print("YOU WIN. YOU HAVE " + playerScore + " AND THE COMPUTER HAS " + computerScore + "\n");
+        } else {
+            print("TIE.  NO SCORE CHANGE.\n");
+        }
+
+        if (deck.length === 0) {
+            printGameOver(playerScore, computerScore);
+        }
+        else {
+            shouldContinuePlaying = await askYesOrNo("DO YOU WANT TO CONTINUE");
+        }
+    }
+    print("THANKS FOR PLAYING.  IT WAS FUN.\n");
+    print("\n");
+}
+
+main();
diff --git a/00_Alternate_Languages/94_War/kotlin/README.md b/00_Alternate_Languages/94_War/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/00_Alternate_Languages/94_War/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/00_Alternate_Languages/94_War/kotlin/War.kt b/00_Alternate_Languages/94_War/kotlin/War.kt
new file mode 100644
index 00000000..0b8b9ee3
--- /dev/null
+++ b/00_Alternate_Languages/94_War/kotlin/War.kt
@@ -0,0 +1,108 @@
+/**
+ * Converted FROM BASIC to Kotlin by John Long, with hints from the Java by Nahid Mondol.
+ *
+ */
+
+val suits = listOf("S", "H", "C", "D")
+val ranks = listOf("2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A")
+
+// Create the deck programmatically
+val fullDeck = suits.flatMap { suit ->
+    ranks.map { rank ->
+        Card(suit, rank)
+    }
+}
+
+class Card(private val suit: String, private val rank: String) {
+    // Allow comparison of cards to each other
+    operator fun compareTo(other: Card): Int = this.rankValue.compareTo(other.rankValue)
+    // We can figure relative rank by the order in the ranks value
+    private val rankValue: Int = ranks.indexOf(rank)
+    override fun toString(): String = "$suit-$rank"
+}
+
+fun main() {
+    introMessage()
+    showDirectionsBasedOnInput()
+    playGame()
+    println("THANKS FOR PLAYING.  IT WAS FUN.")
+}
+
+private fun introMessage() {
+    println("\t         WAR")
+    println("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    println("THIS IS THE CARD GAME OF WAR. EACH CARD IS GIVEN BY SUIT-#")
+    print("AS S-7 FOR SPADE 7. DO YOU WANT DIRECTIONS? ")
+}
+
+private fun showDirectionsBasedOnInput() {
+    if (getYesOrNo()) {
+        println("THE COMPUTER GIVES YOU AND IT A 'CARD'. THE HIGHER CARD")
+        println("(NUMERICALLY) WINS. THE GAME ENDS WHEN YOU CHOOSE NOT TO ")
+        println("CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\n")
+    }
+}
+
+// Stay in loop until player chooses an option, then return "true" for yes or "false" for no
+private fun getYesOrNo() = generateSequence { readln() }.firstNotNullOf { it.asYesOrNo }
+
+// Since this returns null for an incorrect value, above firstNotNullOf will keep looping until
+// we get something valid
+private val String.asYesOrNo: Boolean?
+    get() =
+        when (this.lowercase()) {
+            "yes" -> true
+            "no" -> false
+            else -> {
+                println("YES OR NO, PLEASE.   ")
+                null
+            }
+        }
+
+
+private fun playGame() {
+    // Shuffle the deck than break it into 26 pairs
+    val pairs = fullDeck.shuffled().chunked(2)
+    val score = Score(0, 0)
+    val lastPlayerCard = pairs.last().first()
+    // We use "destructuring" to extract the pair of cards directly to a variable here
+    pairs.forEach { (playerCard, computerCard) ->
+        println("YOU: $playerCard\tCOMPUTER: $computerCard")
+        when {
+            playerCard > computerCard -> score.playerWins()
+            computerCard > playerCard -> score.computerWins()
+            else -> println("TIE.  NO SCORE CHANGE.")
+        }
+        // Doesn't make sense to ask to continue if we have no more cards left to deal
+        if (playerCard != lastPlayerCard) {
+            println("DO YOU WANT TO CONTINUE")
+            if (!getYesOrNo()) {
+                return
+            }
+        }
+    }
+    score.printFinalScore()
+    return
+}
+
+
+class Score(private var player: Int, private var computer: Int) {
+    fun playerWins() {
+        player++
+        printScore("YOU WIN.")
+    }
+
+    fun computerWins() {
+        computer++
+        printScore("THE COMPUTER WINS!!!")
+    }
+
+    private fun printScore(text: String) {
+        println("$text YOU HAVE $player AND THE COMPUTER HAS $computer")
+    }
+
+    // Only print if you go through the whole deck
+    fun printFinalScore() {
+        println("WE HAVE RUN OUT OF CARDS.  FINAL SCORE:   YOU: $player  THE COMPUTER:$computer")
+    }
+}
diff --git a/71_Poker/pascal/README.md b/00_Alternate_Languages/94_War/pascal/README.md
similarity index 100%
rename from 71_Poker/pascal/README.md
rename to 00_Alternate_Languages/94_War/pascal/README.md
diff --git a/00_Alternate_Languages/94_War/perl/README.md b/00_Alternate_Languages/94_War/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/94_War/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/94_War/perl/war.pl b/00_Alternate_Languages/94_War/perl/war.pl
new file mode 100644
index 00000000..367a1185
--- /dev/null
+++ b/00_Alternate_Languages/94_War/perl/war.pl
@@ -0,0 +1,153 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use Getopt::Long 2.33 qw{ :config auto_version };
+use List::Util qw{ shuffle };
+use Pod::Usage;
+use Term::ReadLine;     # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+my %opt;
+
+GetOptions( \%opt,
+    qw{ unicode! },
+    help => sub { pod2usage( { -verbose => 2 } ) },
+) or pod2usage( { -verbose => 0 } );
+
+my @cards;
+my $current_rank_value = 1;
+my %rank_value;
+my @suits = $opt{unicode} ?
+    ( map { chr } 0x2660 .. 0x2663 ) :
+    ( qw{ S H D C } );
+foreach my $rank ( ( 2 .. 10 ), qw{ J Q K A } ) {
+    $rank_value{$rank} = $current_rank_value++;
+    foreach my $suit ( @suits ) {
+        push @cards, "$suit-$rank";
+    }
+}
+
+$opt{unicode}
+    and binmode STDOUT, ':encoding(utf-8)';
+
+@cards = shuffle( @cards );
+
+print <<'EOD';
+                                 WAR
+               Creative Computing  Morristown, New Jersey
+
+
+
+This is the card game of War.  Each card is given by suit-#
+EOD
+
+# Create the readline object.
+state $term = Term::ReadLine->new( 'word' );
+
+my $resp = $term->readline(
+    "as $suits[0]-7 for Spade 7.  Do you want directions? [y/N]: " );
+exit unless defined $resp;
+if ( $resp =~ m/ \A y /smxi ) {
+    print <<'EOD';
+The computer gives you and it a 'card'.  The higher card
+(numerically) wins.  The game ends when you choose not to
+continue or when you have finished the pack.
+
+EOD
+}
+
+my $your_score = my $computer_score = 0;
+
+while ( 1 ) {
+    my ( $you, $computer ) = splice @cards, 0, 2;
+    say '';
+    say "You: $you; computer: $computer";
+    my $result = $rank_value{ substr $you, 2 } <=>
+        $rank_value{ substr $computer, 2 };
+    if ( $result < 0 ) {
+        $computer_score++;
+        say "The computer wins!!!  ",
+            "You have $your_score and the computer has $computer_score";
+    } elsif ( $result > 0 ) {
+        $your_score++;
+        say "You win.  ",
+            "You have $your_score and the computer has $computer_score";
+    } else {
+        say 'Tie.  No score change.';
+    }
+
+    last unless @cards;
+
+    $resp = $term->readline( 'Do you want to continue? [Y/n]: ' );
+    last unless defined $resp;
+    last if $resp =~ m/ \A n /smxi;
+}
+
+say "We have run out of cards.  ",
+    "Final score:  you: $your_score;  the computer: $computer_score"
+    unless @cards;
+say '';
+say 'Thanks for playing.  It was fun.';
+__END__
+
+=head1 TITLE
+
+war.pl - Play the game 'War' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ war.pl
+ war.pl --help
+ war.pl --version
+
+=head1 OPTIONS
+
+=head2 --help
+
+This option displays the documentation for this script. The script then
+exits.
+
+=head2 --unicode
+
+If this Boolean option is asserted, the suits are designated by their
+Unicode glyphs rather than by ASCII letters. For these to display
+properly your terminal must properly interpret Unicode.
+
+The default is C<--no-unicode>.
+
+=head2 --version
+
+This option displays the version of this script. The script then exits.
+
+=head1 DETAILS
+
+This Perl script is a port of C, which is the 94th entry in Basic
+Computer Games.
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :
diff --git a/00_Alternate_Languages/94_War/python/README.md b/00_Alternate_Languages/94_War/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/94_War/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/94_War/python/war.py b/00_Alternate_Languages/94_War/python/war.py
new file mode 100644
index 00000000..682771f8
--- /dev/null
+++ b/00_Alternate_Languages/94_War/python/war.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python3
+# WAR
+#
+# Converted from BASIC to Python by Trevor Hobson
+
+import random
+
+
+def card_value(input):
+    return ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"].index(
+        input.split("-")[1]
+    )
+
+
+cards = [
+    "S-2",
+    "H-2",
+    "C-2",
+    "D-2",
+    "S-3",
+    "H-3",
+    "C-3",
+    "D-3",
+    "S-4",
+    "H-4",
+    "C-4",
+    "D-4",
+    "S-5",
+    "H-5",
+    "C-5",
+    "D-5",
+    "S-6",
+    "H-6",
+    "C-6",
+    "D-6",
+    "S-7",
+    "H-7",
+    "C-7",
+    "D-7",
+    "S-8",
+    "H-8",
+    "C-8",
+    "D-8",
+    "S-9",
+    "H-9",
+    "C-9",
+    "D-9",
+    "S-10",
+    "H-10",
+    "C-10",
+    "D-10",
+    "S-J",
+    "H-J",
+    "C-J",
+    "D-J",
+    "S-Q",
+    "H-Q",
+    "C-Q",
+    "D-Q",
+    "S-K",
+    "H-K",
+    "C-K",
+    "D-K",
+    "S-A",
+    "H-A",
+    "C-A",
+    "D-A",
+]
+
+
+def play_game():
+    """Play one round of the game"""
+
+    random.shuffle(cards)
+    score_you = 0
+    score_computer = 0
+    cards_left = 52
+    for round in range(26):
+        print()
+        card_you = cards[round]
+        card_computer = cards[round * 2]
+        print("You:", card_you, " " * (8 - len(card_you)) + "Computer:", card_computer)
+        value_you = card_value(card_you)
+        value_computer = card_value(card_computer)
+        if value_you > value_computer:
+            score_you += 1
+            print(
+                "You win. You have", score_you, "and the computer has", score_computer
+            )
+        elif value_computer > value_you:
+            score_computer += 1
+            print(
+                "The computer wins!!! You have",
+                score_you,
+                "and the computer has",
+                score_computer,
+            )
+        else:
+            print("Tie. No score change.")
+        cards_left -= 2
+        if cards_left > 2:
+            if input("Do you want to continue ").lower().startswith("n"):
+                break
+    if cards_left == 0:
+        print(
+            "\nWe have run out of cards. Final score: You:",
+            score_you,
+            "the computer:",
+            score_computer,
+        )
+    print("\nThanks for playing. It was fun.")
+
+
+def main():
+    print(" " * 33 + "WAR")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n")
+    print("This is the card game of war. Each card is given by suit-#")
+    print("as S-7 for Spade 7.")
+    if input("Do you want directions ").lower().startswith("y"):
+        print("The computer gives you and it a 'card'. The higher card")
+        print("(numerically) wins. The game ends when you choose not to")
+        print("continue or when you have finished the pack.")
+
+    keep_playing = True
+    while keep_playing:
+        play_game()
+        keep_playing = input("\nPlay again? (yes or no) ").lower().startswith("y")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/94_War/ruby/README.md b/00_Alternate_Languages/94_War/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/94_War/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/94_War/ruby/war.rb b/00_Alternate_Languages/94_War/ruby/war.rb
new file mode 100644
index 00000000..cf7e8a59
--- /dev/null
+++ b/00_Alternate_Languages/94_War/ruby/war.rb
@@ -0,0 +1,118 @@
+#!/usr/bin/env ruby
+# reinterpreted from BASIC by stephan.com
+class War
+  class Card
+    class CardError < StandardError; end
+
+    SUITS = %i[spades hearts clubs diamonds].freeze
+    PIPS = %i[ace deuce trey four five six seven eight nine ten jack king queen].freeze
+    CARDS = SUITS.product(PIPS).freeze
+    VALUES = PIPS.zip(1..13).to_h.freeze
+
+    attr_reader :value
+
+    def initialize(suit, pip)
+      @suit = suit
+      @pip = pip
+      raise CardError, 'invalid suit' unless SUITS.include? @suit
+      raise CardError, 'invalid pip' unless PIPS.include? @pip
+
+      @value = VALUES[pip]
+    end
+
+    def <=>(other)
+      @value <=> other.value
+    end
+
+    def >(other)
+      @value > other.value
+    end
+
+    def <(other)
+      @value < other.value
+    end
+
+    def to_s
+      "the #{@pip} of #{@suit}"
+    end
+
+    def self.shuffle
+      CARDS.map { |suit, pip| new(suit, pip) }.shuffle
+    end
+  end
+
+  def initialize
+    @your_score = 0
+    @computer_score = 0
+    @your_deck = Card.shuffle
+    @computer_deck = Card.shuffle
+  end
+
+  def play
+    intro
+
+    loop do
+      puts "\nYou: #{@your_score} Computer: #{@computer_score}"
+      round @your_deck.shift, @computer_deck.shift
+      break if empty?
+
+      puts 'Do you want to continue?'
+      break unless yesno
+    end
+
+    outro
+  end
+
+  private
+
+  def round(your_card, computer_card)
+    puts "You: #{your_card} vs Computer: #{computer_card}"
+    return puts 'Tie. No score change.' if your_card == computer_card
+
+    if computer_card > your_card
+      puts "Computer wins with #{computer_card}"
+      @computer_score += 1
+    else
+      puts "You win with #{your_card}"
+      @your_score += 1
+    end
+  end
+
+  def yesno
+    loop do
+      wants = gets.strip
+      return true if wants.downcase == 'yes'
+      return false if wants.downcase == 'no'
+
+      puts 'Yes or no, please.'
+    end
+  end
+
+  def intro
+    puts 'War'.center(80)
+    puts 'stephan.com'.center(80)
+    puts
+    puts 'This is the card game of war.'
+    puts 'Do you want directions'
+    directions if yesno
+  end
+
+  def directions
+    puts 'The computer gives you and it a \'card\'.  The higher card'
+    puts '(numerically) wins.  The game ends when you choose not to'
+    puts 'continue or when you have finished the pack.'
+    puts
+  end
+
+  def outro
+    puts "We've run out of cards" if empty?
+    puts "Final score:\nYou: #{@your_score}\nComputer: #{@computer_score}"
+    puts 'Thanks for playing!'
+  end
+
+  def empty?
+    @your_deck.empty? || @computer_deck.empty?
+  end
+end
+
+War.new.play
diff --git a/00_Alternate_Languages/94_War/rust/README.md b/00_Alternate_Languages/94_War/rust/README.md
new file mode 100644
index 00000000..7e85f9a1
--- /dev/null
+++ b/00_Alternate_Languages/94_War/rust/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Rust](https://www.rust-lang.org/) by Anthony Rubick [AnthonyMichaelTDM](https://github.com/AnthonyMichaelTDM)
diff --git a/00_Alternate_Languages/94_War/rust/src/main.rs b/00_Alternate_Languages/94_War/rust/src/main.rs
new file mode 100644
index 00000000..fb8a55fc
--- /dev/null
+++ b/00_Alternate_Languages/94_War/rust/src/main.rs
@@ -0,0 +1,158 @@
+use rand::prelude::{thread_rng, SliceRandom};
+use std::io;
+
+//DATA
+struct CARD {
+    suit: u8, //1-4     1=hearts    2=diamonds     3=clubs     4=spades
+    value: u8, //2-14   2,3,4,5,6,7,8,9,10,jack,queen,king,ace
+}
+impl CARD {
+    /**
+     * creates a new card from the passed card name
+     */
+    fn new(suit:u8,value:u8) -> CARD {
+        return CARD { suit: suit, value: value };
+    }
+}
+impl ToString for CARD {
+    /**
+     * returns string representation of the Card
+     */
+    fn to_string(&self) -> String {
+        let mut name: String;
+        //value
+        name = match self.value {
+            2..=10 => self.value.to_string() + " of ",
+            11 => String::from("Jack of "),
+            12 => String::from("Queen of "),
+            13 => String::from("King of "),
+            14 => String::from("Ace of "),
+            _ => panic!("card has an invalid value"),
+        };
+        //suit
+        name += match self.suit {
+            1=>"Hearts",
+            2=>"Diamonds",
+            3=>"Clubs",
+            4=>"Spades",
+            _ => panic!("card has an invalid suit"),
+        };
+        return name;
+    }
+}
+struct GAME {
+    deck: Vec, //cards in the deck
+    player_score: usize, //human player score
+    computer_score:usize,//computer score
+}
+impl GAME {
+    /**
+     * creates a new game, filling a deck with 52 cards, and setting scores to 0
+     */
+    fn new() -> GAME{
+        //DATA
+        let mut game = GAME{deck: Vec::new(), player_score: 0, computer_score: 0};
+        //fill deck
+        for suit in 1..=4 { //4 suits
+            for value in 2..=14 { //13 cards
+                game.deck.push( CARD::new(suit,value) );
+            }
+        }
+        //shuffle deck
+        game.deck.shuffle(&mut thread_rng());
+        //return game
+        return game;
+    }
+
+    /**
+     * fully play game
+     */
+    fn play_game(&mut self) {
+        //DATA
+        let mut human_card: CARD;
+        let mut computer_card: CARD;
+
+        //game loop
+        while self.deck.len() >=2 {
+            //draw cards
+            human_card = self.deck.pop().expect("DECK IS EMPTY!");
+            computer_card = self.deck.pop().expect("DECK IS EMPTY!");
+
+            //print cards
+            println!("\nYou: {}\t\tComputer: {}",human_card.to_string(), computer_card.to_string());
+
+            //determine winner
+            if human_card.value > computer_card.value { //human wins
+                self.player_score += 1;
+                println!("You win. You have {} and the computer has {}", human_card.value, computer_card.value);
+            }
+            else if human_card.value < computer_card.value { //computer wins
+                self.computer_score += 1;
+                println!("The computer wins!!! You have {} and the computer has {}", human_card.value, computer_card.value);
+            }
+            else { //tie
+                println!("Tie. No score change.")
+            }
+            if !get_yes_no_from_user_input("Do you want to continue? y/n") {break;}
+        }
+        if self.deck.is_empty() {
+            println!("WE HAVE RUN OUT OF CARDS.  FINAL SCORE:  YOU: {} THE COMPUTER: {}",self.player_score, self.computer_score);
+        }
+        println!("\nThanks for playing. It was fun.");
+    }
+}
+
+fn main() {
+    //print welcome message
+    welcome();
+
+    //game loop
+    let mut game = GAME::new();
+    loop {
+        game.play_game();
+        if !get_yes_no_from_user_input("\nPlay again? (yes or no) ") {break;}
+        game = GAME::new();
+    }
+}
+
+/**
+ * print welcome message
+ */
+fn welcome() {
+    println!("
+                                War\n
+              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n
+    This is the card game of war. Each card is given by # of suit
+    ex: Ace of Spades\n
+    ");
+    if get_yes_no_from_user_input("Do you want directions?") {
+        println!("
+        The computer gives you and it a 'card'. The higher card
+        (numerically) wins. The game ends when you choose not to
+        continue or when you have finished the pack.\n
+        ");
+    }
+}
+
+/**
+ * returns true if user input starts with y or Y,
+ * false otherwise
+ */
+fn get_yes_no_from_user_input(prompt: &str) -> bool {
+    let mut raw_input = String::new(); // temporary variable for user input that can be parsed later
+
+    //print prompt
+    println!("{}", prompt);
+    //read user input from standard input, and store it to raw_input
+    //raw_input.clear(); //clear input
+    io::stdin().read_line(&mut raw_input).expect( "CANNOT READ INPUT!");
+
+    //from input, try to read a valid character
+    if let Some(i) = raw_input.trim().chars().nth(0) {
+        if i == 'y' || i == 'Y' {
+            return true;
+        }
+    }
+    //default case
+    return false;
+}
diff --git a/00_Alternate_Languages/94_War/vbnet/README.md b/00_Alternate_Languages/94_War/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/94_War/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/94_War/vbnet/War.sln b/00_Alternate_Languages/94_War/vbnet/War.sln
new file mode 100644
index 00000000..3c0895ad
--- /dev/null
+++ b/00_Alternate_Languages/94_War/vbnet/War.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "War", "War.vbproj", "{36D070A1-08CB-424E-AB8E-E782B0A6654B}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{36D070A1-08CB-424E-AB8E-E782B0A6654B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{36D070A1-08CB-424E-AB8E-E782B0A6654B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{36D070A1-08CB-424E-AB8E-E782B0A6654B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{36D070A1-08CB-424E-AB8E-E782B0A6654B}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/94_War/vbnet/War.vbproj b/00_Alternate_Languages/94_War/vbnet/War.vbproj
new file mode 100644
index 00000000..e62cda47
--- /dev/null
+++ b/00_Alternate_Languages/94_War/vbnet/War.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    War
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/94_War/war.bas b/00_Alternate_Languages/94_War/war.bas
new file mode 100644
index 00000000..388b0ec4
--- /dev/null
+++ b/00_Alternate_Languages/94_War/war.bas
@@ -0,0 +1,68 @@
+10 PRINT TAB(33);"WAR"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT: PRINT: PRINT
+100 PRINT "THIS IS THE CARD GAME OF WAR.  EACH CARD IS GIVEN BY SUIT-#"
+110 PRINT "AS S-7 FOR SPADE 7.  ";
+120 PRINT "DO YOU WANT DIRECTIONS";
+130 INPUT B$
+140 IF B$="NO" THEN 210
+150 IF B$="YES" THEN 180
+160 PRINT "YES OR NO, PLEASE.  ";
+170 GOTO 120
+180 PRINT "THE COMPUTER GIVES YOU AND IT A 'CARD'.  THE HIGHER CARD"
+190 PRINT "(NUMERICALLY) WINS.  THE GAME ENDS WHEN YOU CHOOSE NOT TO"
+200 PRINT "CONTINUE OR WHEN YOU HAVE FINISHED THE PACK."
+210 PRINT
+220 PRINT
+230 DIM A$(52),L(54)
+240 FOR I=1 TO 52
+250 READ A$(I)
+260 NEXT I
+270 REM
+280 FOR J=1 TO 52
+290 LET L(J)=INT(52*RND(1))+1
+295 IF J=1 THEN 350
+300 FOR K=1 TO J-1
+310 IF L(K)<>L(J) THEN 340
+320 REM
+330 GOTO 290
+340 NEXT K
+350 NEXT J
+360 P=P+1
+370 M1=L(P)
+380 P=P+1
+390 M2=L(P)
+400 PRINT
+420 PRINT "YOU: ";A$(M1),"COMPUTER: ";A$(M2)
+430 N1=INT((M1-.5)/4)
+440 N2=INT((M2-.5)/4)
+450 IF N1>=N2 THEN 490
+460 A1=A1+1
+470 PRINT "THE COMPUTER WINS!!! YOU HAVE";B1;"AND THE COMPUTER HAS";A1
+480 GOTO 540
+490 IF N1=N2 THEN 530
+500 B1=B1+1
+510 PRINT "YOU WIN. YOU HAVE";B1;"AND THE COMPUTER HAS";A1
+520 GOTO 540
+530 PRINT "TIE.  NO SCORE CHANGE."
+540 IF L(P+1)=0 THEN 610
+550 PRINT "DO YOU WANT TO CONTINUE";
+560 INPUT V$
+570 IF V$="YES" THEN 360
+580 IF V$="NO" THEN 650
+590 PRINT "YES OR NO, PLEASE.  ";
+600 GOTO 540
+610 PRINT
+620 PRINT
+630 PRINT "WE HAVE RUN OUT OF CARDS.  FINAL SCORE:  YOU: ";B1;
+640 PRINT "  THE COMPUTER: ";A1:PRINT
+650 PRINT "THANKS FOR PLAYING.  IT WAS FUN."
+655 PRINT
+660 DATA "S-2","H-2","C-2","D-2","S-3","H-3","C-3","D-3"
+670 DATA "S-4","H-4","C-4","D-4","S-5","H-5","C-5","D-5"
+680 DATA "S-6","H-6","C-6","D-6","S-7","H-7","C-7","D-7"
+690 DATA "S-8","H-8","C-8","D-8","S-9","H-9","C-9","D-9"
+700 DATA "S-10","H-10","C-10","D-10","S-J","H-J","C-J","D-J"
+710 DATA "S-Q","H-Q","C-Q","D-Q","S-K","H-K","C-K","D-K"
+720 DATA "S-A","H-A","C-A","D-A"
+999 END
diff --git a/00_Alternate_Languages/95_Weekday/README.md b/00_Alternate_Languages/95_Weekday/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/95_Weekday/csharp/Program.cs b/00_Alternate_Languages/95_Weekday/csharp/Program.cs
new file mode 100644
index 00000000..e19be76d
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/csharp/Program.cs
@@ -0,0 +1,203 @@
+using System.Text;
+
+namespace Weekday
+{
+    class Weekday
+    {
+        private void DisplayIntro()
+        {
+            Console.WriteLine("");
+            Console.WriteLine("SYNONYM".PadLeft(23));
+            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+            Console.WriteLine("");
+            Console.WriteLine("Weekday is a computer demonstration that");
+            Console.WriteLine("gives facts about a date of interest to you.");
+            Console.WriteLine("");
+        }
+
+        private bool ValidateDate(string InputDate, out DateTime ReturnDate)
+        {
+            // The expectation is that the input is in the format D,M,Y
+            // but any valid date format (other than with commas) will work
+            string DateString = InputDate.Replace(",", "/");
+
+            return (DateTime.TryParse(DateString, out ReturnDate));
+        }
+
+        private DateTime PromptForADate(string Prompt)
+        {
+            bool Success = false;
+            string LineInput = String.Empty;
+            DateTime TodaysDate = DateTime.MinValue;
+
+            // Get the date for input and validate it
+            while (!Success)
+            {
+                Console.Write(Prompt);
+                LineInput = Console.ReadLine().Trim().ToLower();
+
+                Success = ValidateDate(LineInput, out TodaysDate);
+
+                if (!Success)
+                {
+                    Console.WriteLine("*** Invalid date.  Please try again.");
+                    Console.WriteLine("");
+                }
+            }
+
+            return TodaysDate;
+        }
+
+        private void CalculateDateDiff(DateTime TodaysDate, DateTime BirthDate, Double Factor, out int AgeInYears, out int AgeInMonths, out int AgeInDays)
+        {
+            // leveraged Stack Overflow answer: https://stackoverflow.com/a/3055445
+
+            // Convert to number of days since Birth Date, multiple by factor then store as new FactorDate
+            TimeSpan TimeDiff = TodaysDate.Subtract(BirthDate);
+            Double NumberOfDays = TimeDiff.Days * Factor;
+            DateTime FactorDate = BirthDate.AddDays(NumberOfDays);
+
+            // Compute difference between FactorDate (which is TodaysDate * Factor) and BirthDate
+            AgeInMonths = FactorDate.Month - BirthDate.Month;
+            AgeInYears = FactorDate.Year - BirthDate.Year;
+
+            if (FactorDate.Day < BirthDate.Day)
+            {
+                AgeInMonths--;
+            }
+
+            if (AgeInMonths < 0)
+            {
+                AgeInYears--;
+                AgeInMonths += 12;
+            }
+
+            AgeInDays = (FactorDate - BirthDate.AddMonths((AgeInYears * 12) + AgeInMonths)).Days;
+
+        }
+
+        private void WriteColumnOutput(string Message, int Years, int Months, int Days)
+        {
+
+            Console.WriteLine("{0,-25} {1,-10:N0} {2,-10:N0} {3,-10:N0}", Message, Years, Months, Days);
+
+        }
+
+        private void DisplayOutput(DateTime TodaysDate, DateTime BirthDate)
+        {
+            Console.WriteLine("");
+
+            // Not allowed to play if the current year is before 1582
+            if (TodaysDate.Year < 1582)
+            {
+                Console.WriteLine("Not prepared to give day of week prior to MDLXXXII.");
+                return;
+            }
+
+            // Share which day of the week the BirthDate was on
+            Console.Write(" {0} ", BirthDate.ToString("d"));
+
+            string DateVerb = "";
+            if (BirthDate.CompareTo(TodaysDate) < 0)
+            {
+                DateVerb = "was a ";
+            }
+            else if (BirthDate.CompareTo(TodaysDate) == 0)
+            {
+                DateVerb = "is a ";
+            }
+            else
+            {
+                DateVerb = "will be a ";
+            }
+            Console.Write("{0}", DateVerb);
+
+            // Special warning if their birth date was on a Friday the 13th!
+            if (BirthDate.DayOfWeek.ToString().Equals("Friday") && BirthDate.Day == 13)
+            {
+                Console.WriteLine("{0} the Thirteenth---BEWARE", BirthDate.DayOfWeek.ToString());
+            }
+            else
+            {
+                Console.WriteLine("{0}", BirthDate.DayOfWeek.ToString());
+            }
+
+            // If today's date is the same month & day as the birth date then wish them a happy birthday!
+            if (BirthDate.Month == TodaysDate.Month && BirthDate.Day == TodaysDate.Day)
+            {
+                Console.WriteLine("");
+                Console.Write("***Happy Birthday***");
+            }
+
+            Console.WriteLine("");
+
+            // Only show the date calculations if BirthDate is before TodaysDate
+            if (DateVerb.Trim().Equals("was a"))
+            {
+
+                Console.WriteLine("{0,-24} {1,-10} {2,-10} {3,-10}", " ", "Years", "Months", "Days");
+
+                int TheYears = 0, TheMonths = 0, TheDays = 0;
+                int FlexYears = 0, FlexMonths = 0, FlexDays = 0;
+
+                CalculateDateDiff(TodaysDate, BirthDate, 1, out TheYears, out TheMonths, out TheDays);
+                WriteColumnOutput("Your age if birthdate", TheYears, TheMonths, TheDays);
+
+                FlexYears = TheYears;
+                FlexMonths = TheMonths;
+                FlexDays = TheDays;
+                CalculateDateDiff(TodaysDate, BirthDate, .35, out FlexYears, out FlexMonths, out FlexDays);
+                WriteColumnOutput("You have slept", FlexYears, FlexMonths, FlexDays);
+
+                FlexYears = TheYears;
+                FlexMonths = TheMonths;
+                FlexDays = TheDays;
+                CalculateDateDiff(TodaysDate, BirthDate, .17, out FlexYears, out FlexMonths, out FlexDays);
+                WriteColumnOutput("You have eaten", FlexYears, FlexMonths, FlexDays);
+
+                FlexYears = TheYears;
+                FlexMonths = TheMonths;
+                FlexDays = TheDays;
+                CalculateDateDiff(TodaysDate, BirthDate, .23, out FlexYears, out FlexMonths, out FlexDays);
+                string FlexPhrase = "You have played";
+                if (TheYears > 3)
+                    FlexPhrase = "You have played/studied";
+                if (TheYears > 9)
+                    FlexPhrase = "You have worked/played";
+                WriteColumnOutput(FlexPhrase, FlexYears, FlexMonths, FlexDays);
+
+                FlexYears = TheYears;
+                FlexMonths = TheMonths;
+                FlexDays = TheDays;
+                CalculateDateDiff(TodaysDate, BirthDate, .25, out FlexYears, out FlexMonths, out FlexDays);
+                WriteColumnOutput("You have relaxed", FlexYears, FlexMonths, FlexDays);
+
+                Console.WriteLine("");
+                Console.WriteLine("* You may retire in {0} *".PadLeft(38), BirthDate.Year + 65);
+            }
+        }
+
+        public void PlayTheGame()
+        {
+            DateTime TodaysDate = DateTime.MinValue;
+            DateTime BirthDate = DateTime.MinValue;
+
+            DisplayIntro();
+
+            TodaysDate = PromptForADate("Enter today's date in the form: 3,24,1978  ? ");
+            BirthDate = PromptForADate("Enter day of birth (or other day of interest)? ");
+
+            DisplayOutput(TodaysDate, BirthDate);
+
+        }
+    }
+    class Program
+    {
+        static void Main(string[] args)
+        {
+
+            new Weekday().PlayTheGame();
+
+        }
+    }
+}
diff --git a/00_Alternate_Languages/95_Weekday/csharp/README.md b/00_Alternate_Languages/95_Weekday/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/95_Weekday/csharp/Weekday.csproj b/00_Alternate_Languages/95_Weekday/csharp/Weekday.csproj
new file mode 100644
index 00000000..d3fe4757
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/csharp/Weekday.csproj
@@ -0,0 +1,9 @@
+
+  
+    Exe
+    net6.0
+    10
+    enable
+    enable
+  
+
diff --git a/00_Alternate_Languages/95_Weekday/csharp/Weekday.sln b/00_Alternate_Languages/95_Weekday/csharp/Weekday.sln
new file mode 100644
index 00000000..4aad7c31
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/csharp/Weekday.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Weekday", "Weekday.csproj", "{6E93B1EC-5E19-47DB-821A-D19F1D0DA982}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6E93B1EC-5E19-47DB-821A-D19F1D0DA982}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6E93B1EC-5E19-47DB-821A-D19F1D0DA982}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6E93B1EC-5E19-47DB-821A-D19F1D0DA982}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6E93B1EC-5E19-47DB-821A-D19F1D0DA982}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/95_Weekday/java/README.md b/00_Alternate_Languages/95_Weekday/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/95_Weekday/java/Weekday.java b/00_Alternate_Languages/95_Weekday/java/Weekday.java
new file mode 100644
index 00000000..9ca3db11
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/java/Weekday.java
@@ -0,0 +1,280 @@
+import java.util.Scanner;
+
+/**
+ * WEEKDAY
+ *
+ * Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)
+ *
+ */
+public class Weekday {
+
+	//TABLE OF VALUES FOR THE MONTHS TO BE USED IN CALCULATIONS.
+	//Dummy value added at index 0, so we can reference directly by the month number value
+	private final static int[] t = new int[]{-1, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
+
+	public static void main(String[] args) {
+		printIntro();
+
+		Scanner scanner = new Scanner(System.in);
+		System.out.print("ENTER TODAY'S DATE IN THE FORM: 3,24,1979 ");
+		DateStruct todaysDate = readDate(scanner);
+
+		System.out.print("ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST) ");
+		DateStruct dateOfInterest = readDate(scanner);
+
+		int I1 = (dateOfInterest.year - 1500) / 100;
+		//TEST FOR DATE BEFORE CURRENT CALENDAR.
+		if ((dateOfInterest.year - 1582) >= 0) {
+			int A = I1 * 5 + (I1 + 3) / 4;
+			int I2 = (A - b(A) * 7);
+			int Y2 = (dateOfInterest.year / 100);
+			int Y3 = (dateOfInterest.year - Y2 * 100);
+			A = Y3 / 4 + Y3 + dateOfInterest.day + t[dateOfInterest.month] + I2;
+			calculateAndPrintDayOfWeek(I1, A, todaysDate, dateOfInterest, Y3);
+
+			if ((todaysDate.year * 12 + todaysDate.month) * 31 + todaysDate.day
+					== (dateOfInterest.year * 12 + dateOfInterest.month) * 31 + dateOfInterest.day) {
+				return; //stop the program
+			}
+
+			int I5 = todaysDate.year - dateOfInterest.year;
+			System.out.print("\n");
+			int I6 = todaysDate.month - dateOfInterest.month;
+			int I7 = todaysDate.day - dateOfInterest.day;
+			if (I7 < 0) {
+				I6 = I6 - 1;
+				I7 = I7 + 30;
+			}
+			if (I6 < 0) {
+				I5 = I5 - 1;
+				I6 = I6 + 12;
+			}
+			if (I5 < 0) {
+				return; //do nothing. end the program
+			} else {
+				if (I7 != 0) {
+					printHeadersAndAge(I5, I6, I7);
+				} else {
+					if (I6 != 0) {
+						printHeadersAndAge(I5, I6, I7);
+					} else {
+						System.out.println("***HAPPY BIRTHDAY***");
+						printHeadersAndAge(I5, I6, I7);
+					}
+				}
+			}
+
+			int A8 = (I5 * 365) + (I6 * 30) + I7 + (I6 / 2);
+			int K5 = I5;
+			int K6 = I6;
+			int K7 = I7;
+			//CALCULATE RETIREMENT DATE.
+			int E = dateOfInterest.year + 65;
+			// CALCULATE TIME SPENT IN THE FOLLOWING FUNCTIONS.
+			float F = 0.35f;
+			System.out.printf("%-28s", "YOU HAVE SLEPT");
+			DateStruct scratchDate = new DateStruct(K6, K7, K5); //K5 is a temp year, K6 is month, K7 is day
+			printStatisticRow(F, A8, scratchDate);
+			K5 = scratchDate.year;
+			K6 = scratchDate.month;
+			K7 = scratchDate.day;
+
+			F = 0.17f;
+			System.out.printf("%-28s", "YOU HAVE EATEN");
+
+			scratchDate = new DateStruct(K6, K7, K5);
+			printStatisticRow(F, A8, scratchDate);
+			K5 = scratchDate.year;
+			K6 = scratchDate.month;
+			K7 = scratchDate.day;
+
+			F = 0.23f;
+			if (K5 > 3) {
+				if (K5 > 9) {
+					System.out.printf("%-28s", "YOU HAVE WORKED/PLAYED");
+				} else {
+					System.out.printf("%-28s", "YOU HAVE PLAYED/STUDIED");
+				}
+			} else {
+				System.out.printf("%-28s", "YOU HAVE PLAYED");
+			}
+
+			scratchDate = new DateStruct(K6, K7, K5);
+			printStatisticRow(F, A8, scratchDate);
+			K5 = scratchDate.year;
+			K6 = scratchDate.month;
+			K7 = scratchDate.day;
+
+			if (K6 == 12) {
+				K5 = K5 + 1;
+				K6 = 0;
+			}
+			System.out.printf("%-28s%14s%14s%14s%n", "YOU HAVE RELAXED", K5, K6, K7);
+			System.out.printf("%16s***  YOU MAY RETIRE IN %s ***%n", " ", E);
+			System.out.printf("%n%n%n%n%n");
+		} else {
+			System.out.println("NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII.");
+		}
+	}
+
+
+	private static void printStatisticRow(float F, int A8, DateStruct scratchDate) {
+		int K1 = (int) (F * A8);
+		int I5 = K1 / 365;
+		K1 = K1 - (I5 * 365);
+		int I6 = K1 / 30;
+		int I7 = K1 - (I6 * 30);
+		int K5 = scratchDate.year - I5;
+		int K6 = scratchDate.month - I6;
+		int K7 = scratchDate.day - I7;
+		if (K7 < 0) {
+			K7 = K7 + 30;
+			K6 = K6 - 1;
+		}
+		if (K6 <= 0) {
+			K6 = K6 + 12;
+			K5 = K5 - 1;
+		}
+		//to return the updated values of K5, K6, K7 we send them through the scratchDate
+		scratchDate.year = K5;
+		scratchDate.month = K6;
+		scratchDate.day = K7;
+		System.out.printf("%14s%14s%14s%n", I5, I6, I7);
+	}
+
+	private static void printHeadersAndAge(int I5, int I6, int I7) {
+		System.out.printf("%14s%14s%14s%14s%14s%n", " ", " ", "YEARS", "MONTHS", "DAYS");
+		System.out.printf("%14s%14s%14s%14s%14s%n", " ", " ", "-----", "------", "----");
+		System.out.printf("%-28s%14s%14s%14s%n", "YOUR AGE (IF BIRTHDATE)", I5, I6, I7);
+	}
+
+	private static void calculateAndPrintDayOfWeek(int i1, int a, DateStruct dateStruct, DateStruct dateOfInterest, int y3) {
+		int b = (a - b(a) * 7) + 1;
+		if (dateOfInterest.month > 2) {
+			printDayOfWeek(dateStruct, dateOfInterest, b);
+		} else {
+			if (y3 == 0) {
+				int aa = i1 - 1;
+				int t1 = aa - a(aa) * 4;
+				if (t1 == 0) {
+					if (b != 0) {
+						b = b - 1;
+						printDayOfWeek(dateStruct, dateOfInterest, b);
+					} else {
+						b = 6;
+						b = b - 1;
+						printDayOfWeek(dateStruct, dateOfInterest, b);
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * PRINT THE DAY OF THE WEEK THE DATE FALLS ON.
+	 */
+	private static void printDayOfWeek(DateStruct dateStruct, DateStruct dateOfInterest, int b) {
+		if (b == 0) {
+			b = 7;
+		}
+		if ((dateStruct.year * 12 + dateStruct.month) * 31
+				+ dateStruct.day
+				<
+				(dateOfInterest.year * 12
+						+ dateOfInterest.month) * 31 + dateOfInterest.day) {
+			System.out.printf("%s / %s / %s WILL BE A ", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year);
+		} else if ((dateStruct.year * 12 + dateStruct.month) * 31
+				+ dateStruct.day == (dateOfInterest.year * 12 + dateOfInterest.month)
+				* 31 + dateOfInterest.day) {
+			System.out.printf("%s / %s / %s IS A ", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year);
+		} else {
+			System.out.printf("%s / %s / %s WAS A ", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year);
+		}
+		switch (b) {
+			case 1:
+				System.out.println("SUNDAY.");
+				break;
+			case 2:
+				System.out.println("MONDAY.");
+				break;
+			case 3:
+				System.out.println("TUESDAY.");
+				break;
+			case 4:
+				System.out.println("WEDNESDAY.");
+				break;
+			case 5:
+				System.out.println("THURSDAY.");
+				break;
+			case 6:
+				if (dateOfInterest.day == 13) {
+					System.out.println("FRIDAY THE THIRTEENTH---BEWARE!");
+				} else {
+					System.out.println("FRIDAY.");
+				}
+				break;
+			case 7:
+				System.out.println("SATURDAY.");
+				break;
+		}
+	}
+
+	private static int a(int a) {
+		return a / 4;
+	}
+
+	private static int b(int a) {
+		return a / 7;
+	}
+
+
+	private static void printIntro() {
+		System.out.println("                                WEEKDAY");
+		System.out.println("              CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY");
+		System.out.println("\n\n\n");
+		System.out.println("WEEKDAY IS A COMPUTER DEMONSTRATION THAT");
+		System.out.println("GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.");
+		System.out.println("\n");
+	}
+
+	/**
+	 * Read user input for a date, do some validation and return a simple date structure
+	 */
+	private static DateStruct readDate(Scanner scanner) {
+		boolean done = false;
+		int mm = 0, dd = 0, yyyy = 0;
+		while (!done) {
+			String input = scanner.next();
+			String[] tokens = input.split(",");
+			if (tokens.length < 3) {
+				System.out.println("DATE EXPECTED IN FORM: 3,24,1979 - RETRY INPUT LINE");
+			} else {
+				try {
+					mm = Integer.parseInt(tokens[0]);
+					dd = Integer.parseInt(tokens[1]);
+					yyyy = Integer.parseInt(tokens[2]);
+					done = true;
+				} catch (NumberFormatException nfe) {
+					System.out.println("NUMBER EXPECTED - RETRY INPUT LINE");
+				}
+			}
+		}
+		return new DateStruct(mm, dd, yyyy);
+	}
+
+	/**
+	 * Convenience date structure to hold user date input
+	 */
+	private static class DateStruct {
+		int month;
+		int day;
+		int year;
+
+		public DateStruct(int month, int day, int year) {
+			this.month = month;
+			this.day = day;
+			this.year = year;
+		}
+	}
+
+}
diff --git a/00_Alternate_Languages/95_Weekday/javascript/README.md b/00_Alternate_Languages/95_Weekday/javascript/README.md
new file mode 100644
index 00000000..49b7ece6
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/javascript/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells)
diff --git a/00_Alternate_Languages/95_Weekday/javascript/weekday.html b/00_Alternate_Languages/95_Weekday/javascript/weekday.html
new file mode 100644
index 00000000..928df878
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/javascript/weekday.html
@@ -0,0 +1,9 @@
+
+
+WEEKDAY
+
+
+

+
+
+
diff --git a/00_Alternate_Languages/95_Weekday/javascript/weekday.js b/00_Alternate_Languages/95_Weekday/javascript/weekday.js
new file mode 100644
index 00000000..6070c71c
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/javascript/weekday.js
@@ -0,0 +1,428 @@
+// WEEKDAY
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+/**
+ * Print given string to the end of the "output" element.
+ * @param str
+ */
+function print(str) {
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+/**
+ * Obtain user input
+ * @returns {Promise}
+ */
+function input() {
+    return new Promise(function (resolve) {
+        const 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_element.addEventListener("keydown", function (event) {
+            if (event.keyCode === 13) {
+                const input_str = input_element.value;
+                document.getElementById("output").removeChild(input_element);
+                print(input_str);
+                print("\n");
+                resolve(input_str);
+            }
+        });
+    });
+}
+
+/**
+ * Create a string consisting of the given number of spaces
+ * @param spaceCount
+ * @returns {string}
+ */
+function tab(spaceCount) {
+    let str = "";
+    while (spaceCount-- > 0)
+        str += " ";
+    return str;
+}
+
+const MONTHS_PER_YEAR = 12;
+const DAYS_PER_COMMON_YEAR = 365;
+const DAYS_PER_IDEALISED_MONTH = 30;
+const MAXIMUM_DAYS_PER_MONTH = 31;
+// In a common (non-leap) year the day of the week for the first of each month moves by the following amounts.
+const COMMON_YEAR_MONTH_OFFSET = [0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5];
+
+/**
+ * Date representation.
+ */
+class DateStruct {
+    #year;
+    #month;
+    #day;
+
+    /**
+     * Build a DateStruct
+     * @param {number} year
+     * @param {number} month
+     * @param {number} day
+     */
+    constructor(year, month, day) {
+        this.#year = year;
+        this.#month = month;
+        this.#day = day;
+    }
+
+    get year() {
+        return this.#year;
+    }
+
+    get month() {
+        return this.#month;
+    }
+
+    get day() {
+        return this.#day;
+    }
+
+    /**
+     * Determine if the date could be a Gregorian date.
+     * Be aware the Gregorian calendar was not introduced in all places at once,
+     * see https://en.wikipedia.org/wiki/Gregorian_calendar
+     * @returns {boolean} true if date could be Gregorian; otherwise false.
+     */
+    isGregorianDate() {
+        let result = false;
+        if (this.#year > 1582) {
+            result = true;
+        } else if (this.#year === 1582) {
+            if (this.#month > 10) {
+                result = true;
+            } else if (this.#month === 10 && this.#day >= 15) {
+                result = true;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * The following performs a hash on the day parts which guarantees that
+     * 1. different days will return different numbers
+     * 2. the numbers returned are ordered.
+     * @returns {number}
+     */
+    getNormalisedDay() {
+        return (this.year * MONTHS_PER_YEAR + this.month) * MAXIMUM_DAYS_PER_MONTH + this.day;
+    }
+
+    /**
+     * Determine the day of the week.
+     * This calculation returns a number between 1 and 7 where Sunday=1, Monday=2, ..., Saturday=7.
+     * @returns {number} Value between 1 and 7 representing Sunday to Saturday.
+     */
+    getDayOfWeek() {
+        // Calculate an offset based on the century part of the year.
+        const centuriesSince1500 = Math.floor((this.year - 1500) / 100);
+        let centuryOffset = centuriesSince1500 * 5 + (centuriesSince1500 + 3) / 4;
+        centuryOffset = Math.floor(centuryOffset % 7);
+
+        // Calculate an offset based on the shortened two digit year.
+        // January 1st moves forward by approximately 1.25 days per year
+        const yearInCentury = this.year % 100;
+        const yearInCenturyOffsets = yearInCentury / 4 + yearInCentury;
+
+        // combine offsets with day and month
+        let dayOfWeek = centuryOffset + yearInCenturyOffsets + this.day + COMMON_YEAR_MONTH_OFFSET[this.month - 1];
+
+        dayOfWeek = Math.floor(dayOfWeek % 7) + 1;
+        if (this.month <= 2 && this.isLeapYear()) {
+            dayOfWeek--;
+        }
+        if (dayOfWeek === 0) {
+            dayOfWeek = 7;
+        }
+        return dayOfWeek;
+    }
+
+    /**
+     * Determine if the given year is a leap year.
+     * @returns {boolean}
+     */
+    isLeapYear() {
+        if ((this.year % 4) !== 0) {
+            return false;
+        } else if ((this.year % 100) !== 0) {
+            return true;
+        } else if ((this.year % 400) !== 0) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns a US formatted date, i.e. Month/Day/Year.
+     * @returns {string}
+     */
+    toString() {
+        return this.#month + "/" + this.#day + "/" + this.#year;
+    }
+}
+
+/**
+ * Duration representation.
+ * Note: this class only handles positive durations well
+ */
+class Duration {
+    #years;
+    #months;
+    #days;
+
+    /**
+     * Build a Duration
+     * @param {number} years
+     * @param {number} months
+     * @param {number} days
+     */
+    constructor(years, months, days) {
+        this.#years = years;
+        this.#months = months;
+        this.#days = days;
+        this.#fixRanges();
+    }
+
+    get years() {
+        return this.#years;
+    }
+
+    get months() {
+        return this.#months;
+    }
+
+    get days() {
+        return this.#days;
+    }
+
+    clone() {
+        return new Duration(this.#years, this.#months, this.#days);
+    }
+
+    /**
+     * Adjust Duration by removing years, months and days from supplied Duration.
+     * This is a naive calculation which assumes all months are 30 days.
+     * @param {Duration} timeToRemove
+     */
+    remove(timeToRemove) {
+        this.#years -= timeToRemove.years;
+        this.#months -= timeToRemove.months;
+        this.#days -= timeToRemove.days;
+        this.#fixRanges();
+    }
+
+    /**
+     * Move days and months into expected range.
+     */
+    #fixRanges() {
+        if (this.#days < 0) {
+            this.#days += DAYS_PER_IDEALISED_MONTH;
+            this.#months--;
+        }
+        if (this.#months < 0) {
+            this.#months += MONTHS_PER_YEAR;
+            this.#years--;
+        }
+    }
+
+    /**
+     * Computes an approximation of the days covered by the duration.
+     * The calculation assumes all years are 365 days, months are 30 days each,
+     * and adds on an extra bit the more months that have passed.
+     * @returns {number}
+     */
+    getApproximateDays() {
+        return (
+            (this.#years * DAYS_PER_COMMON_YEAR)
+            + (this.#months * DAYS_PER_IDEALISED_MONTH)
+            + this.#days
+            + Math.floor(this.#months / 2)
+        );
+    }
+
+    /**
+     * Returns a formatted duration with tab separated values, i.e. Years\tMonths\tDays.
+     * @returns {string}
+     */
+    toString() {
+        return this.#years + "\t" + this.#months + "\t" + this.#days;
+    }
+
+    /**
+     * Determine approximate Duration between two dates.
+     * This is a naive calculation which assumes all months are 30 days.
+     * @param {DateStruct} date1
+     * @param {DateStruct} date2
+     * @returns {Duration}
+     */
+    static between(date1, date2) {
+        let years = date1.year - date2.year;
+        let months = date1.month - date2.month;
+        let days = date1.day - date2.day;
+        return new Duration(years, months, days);
+    }
+
+    /**
+     * Calculate years, months and days as factor of days.
+     * This is a naive calculation which assumes all months are 30 days.
+     * @param dayCount Total day to convert to a duration
+     * @param factor   Factor to apply when calculating the duration
+     * @returns {Duration}
+     */
+    static fromDays(dayCount, factor) {
+        let totalDays = Math.floor(factor * dayCount);
+        const years = Math.floor(totalDays / DAYS_PER_COMMON_YEAR);
+        totalDays -= years * DAYS_PER_COMMON_YEAR;
+        const months = Math.floor(totalDays / DAYS_PER_IDEALISED_MONTH);
+        const days = totalDays - (months * DAYS_PER_IDEALISED_MONTH);
+        return new Duration(years, months, days);
+    }
+}
+
+// Main control section
+async function main() {
+    /**
+     * Reads a date, and extracts the date information.
+     * This expects date parts to be comma separated, using US date ordering,
+     * i.e. Month,Day,Year.
+     * @returns {Promise}
+     */
+    async function inputDate() {
+        let dateString = await input();
+        const month = parseInt(dateString);
+        const day = parseInt(dateString.substr(dateString.indexOf(",") + 1));
+        const year = parseInt(dateString.substr(dateString.lastIndexOf(",") + 1));
+        return new DateStruct(year, month, day);
+    }
+
+    /**
+     * Obtain text for the day of the week.
+     * @param {DateStruct} date
+     * @returns {string}
+     */
+    function getDayOfWeekText(date) {
+        const dayOfWeek = date.getDayOfWeek();
+        let dayOfWeekText = "";
+        switch (dayOfWeek) {
+            case 1:
+                dayOfWeekText = "SUNDAY.";
+                break;
+            case 2:
+                dayOfWeekText = "MONDAY.";
+                break;
+            case 3:
+                dayOfWeekText = "TUESDAY.";
+                break;
+            case 4:
+                dayOfWeekText = "WEDNESDAY.";
+                break;
+            case 5:
+                dayOfWeekText = "THURSDAY.";
+                break;
+            case 6:
+                if (date.day === 13) {
+                    dayOfWeekText = "FRIDAY THE THIRTEENTH---BEWARE!";
+                } else {
+                    dayOfWeekText = "FRIDAY.";
+                }
+                break;
+            case 7:
+                dayOfWeekText = "SATURDAY.";
+                break;
+        }
+        return dayOfWeekText;
+    }
+
+    print(tab(32) + "WEEKDAY\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("WEEKDAY IS A COMPUTER DEMONSTRATION THAT\n");
+    print("GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.\n");
+    print("\n");
+    print("ENTER TODAY'S DATE IN THE FORM: 3,24,1979  ");
+    const today = await inputDate();
+    // This program determines the day of the week
+    //  for a date after 1582
+    print("ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST)");
+    const dateOfBirth = await inputDate();
+    print("\n");
+    // Test for date before current calendar.
+    if (!dateOfBirth.isGregorianDate()) {
+        print("NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO X.XV.MDLXXXII.\n");
+    } else {
+        const normalisedToday = today.getNormalisedDay();
+        const normalisedDob = dateOfBirth.getNormalisedDay();
+
+        let dayOfWeekText = getDayOfWeekText(dateOfBirth);
+        if (normalisedToday < normalisedDob) {
+            print(dateOfBirth + " WILL BE A " + dayOfWeekText + "\n");
+        } else if (normalisedToday === normalisedDob) {
+            print(dateOfBirth + " IS A " + dayOfWeekText + "\n");
+        } else {
+            print(dateOfBirth + " WAS A " + dayOfWeekText + "\n");
+        }
+
+        if (normalisedToday !== normalisedDob) {
+            print("\n");
+            let differenceBetweenDates = Duration.between(today, dateOfBirth);
+            if (differenceBetweenDates.years >= 0) {
+                if (differenceBetweenDates.days === 0 && differenceBetweenDates.months === 0) {
+                    print("***HAPPY BIRTHDAY***\n");
+                }
+                print("                        \tYEARS\tMONTHS\tDAYS\n");
+                print("                        \t-----\t------\t----\n");
+                print("YOUR AGE (IF BIRTHDATE) \t" + differenceBetweenDates + "\n");
+
+                const approximateDaysBetween = differenceBetweenDates.getApproximateDays();
+                const unaccountedTime = differenceBetweenDates.clone();
+
+                // 35% sleeping
+                const sleepTimeSpent = Duration.fromDays(approximateDaysBetween, 0.35);
+                print("YOU HAVE SLEPT \t\t\t" + sleepTimeSpent + "\n");
+                unaccountedTime.remove(sleepTimeSpent);
+
+                // 17% eating
+                const eatenTimeSpent = Duration.fromDays(approximateDaysBetween, 0.17);
+                print("YOU HAVE EATEN \t\t\t" + eatenTimeSpent + "\n");
+                unaccountedTime.remove(eatenTimeSpent);
+
+                // 23% working, studying or playing
+                const workPlayTimeSpent = Duration.fromDays(approximateDaysBetween, 0.23);
+                if (unaccountedTime.years <= 3) {
+                    print("YOU HAVE PLAYED \t\t" + workPlayTimeSpent + "\n");
+                } else if (unaccountedTime.years <= 9) {
+                    print("YOU HAVE PLAYED/STUDIED \t" + workPlayTimeSpent + "\n");
+                } else {
+                    print("YOU HAVE WORKED/PLAYED \t\t" + workPlayTimeSpent + "\n");
+                }
+                unaccountedTime.remove(workPlayTimeSpent);
+
+                // Remaining time spent relaxing
+                print("YOU HAVE RELAXED \t\t" + unaccountedTime + "\n");
+
+                const retirementYear = dateOfBirth.year + 65;
+                print("\n");
+                print(tab(16) + "***  YOU MAY RETIRE IN " + retirementYear + " ***\n");
+                print("\n");
+            }
+        }
+    }
+    print("\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("\n");
+}
+
+main();
diff --git a/72_Queen/pascal/README.md b/00_Alternate_Languages/95_Weekday/pascal/README.md
similarity index 100%
rename from 72_Queen/pascal/README.md
rename to 00_Alternate_Languages/95_Weekday/pascal/README.md
diff --git a/00_Alternate_Languages/95_Weekday/perl/README.md b/00_Alternate_Languages/95_Weekday/perl/README.md
new file mode 100644
index 00000000..ac8ee399
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/perl/README.md
@@ -0,0 +1,20 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
+
+I have replaced the manual date logic with Perl built-ins to the extent
+possible. Unfortunately the kind of date math involved in the "time
+spent doing ..." functionality is not well-defined, so I have been
+forced to retain the original logic here. Sigh.
+
+You can use any punctuation character you please in the date
+input. So something like 2/29/2020 is perfectly acceptable.
+
+It would also have been nice to produce a localized version that
+supports day/month/year or year-month-day input, but that didn't happen.
+
+Also nice would have been language-specific output -- especially if it
+could have accommodated regional differences in which day of the week or
+month is unlucky.
+
+Tom Wyant
diff --git a/00_Alternate_Languages/95_Weekday/perl/weekday.pl b/00_Alternate_Languages/95_Weekday/perl/weekday.pl
new file mode 100644
index 00000000..e1820af6
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/perl/weekday.pl
@@ -0,0 +1,249 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'state' and 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use Term::ReadLine;     # Prompt and return user input
+use Time::Local qw{ timelocal };    # date-time to epoch
+# FIXME timelocal() is too smart for its own good in the interpretation
+# of years, and caused a bunch of Y2020 problems in Perl code that used
+# it. I believe that this script avoids these problems (which only occur
+# if the year is less than 1000), but it is probably safer in general to
+# use timelocal_modern() or timelocal_posix(). These are also exported
+# by Time::Local, but only by versions 1.28 and 1.30 respectively. This
+# means that they only come (by default) with Perl 5.30 and 5.34
+# respectively. Now, Time::Local is a dual-life module, meaning it can
+# be upgraded from the version packaged with older Perls. But I did not
+# want to assume that it HAD been upgraded. Caveat coder.
+use Time::Piece;    # O-O epoch to date-time, plus formatting
+
+our $VERSION = '0.000_01';
+
+print <<'EOD';
+
+                                WEEKDAY
+               Creative Computing  Morristown, New Jersey
+
+
+
+WEEKDAY is a computer demonstration that
+gives facts about a date of interest to you.
+
+EOD
+
+my $now = localtime;
+my $default_date = join ',', map { $now->$_() } qw{ mon mday year };
+
+my $today = get_date(
+    "Enter today's date in the form month,day,year (default: $default_date): ",
+    "Please enter month,day,year or return for default\n",
+    $default_date,
+);
+
+my $birthday = get_date(
+    'Ender day of birth (or other day of interest): ',
+    "Please enter month,day,year\n",
+);
+
+say '';
+printf "%d/%d/%d %s a %s\n", $birthday->mon, $birthday->mday,
+    $birthday->year, tense( $today, $birthday),
+    ( $birthday->mday == 13 && $birthday->wday == 6 ) ?
+        $birthday->fullday . ' the thirteenth --- Beware!' :
+        $birthday->fullday . '.';
+
+if ( $birthday->epoch <= $today->epoch ) {
+
+    say '*** Happy Birthday! ***'
+        if $birthday->mon == $today->mon &&
+            $birthday->mday == $today->mday;
+
+    print <<'EOD';
+                        Years   Months  Days
+                        -----   ------  ----
+EOD
+
+    my @delta = map { $today->$_() - $birthday->$_() } qw{ year mon mday };
+    if ( $delta[2] < 0 ) {
+        $delta[2] += 30;
+        $delta[1] -= 1;
+    }
+    if ( $delta[1] < 0 ) {
+        $delta[1] += 12;
+        $delta[0] -= 1;
+    }
+    my @residue = @delta;
+
+    my $delta_days = 365 * $delta[0] + 30 * $delta[1] + $delta[2];
+
+    display_ymd( 'Your age (if birthdate)', compute_ymd( $delta_days ) );
+    display_ymd( 'You have slept', compute_ymd( $delta_days, 0.35,
+            \@residue ) );
+    display_ymd( 'You have eaten', compute_ymd( $delta_days, 0.17,
+            \@residue ) );
+    display_ymd(
+        $residue[0] > 9 ? 'You have worked/played' :
+        $residue[0] > 3 ? 'You have played/studied' :
+            'You have played',
+        compute_ymd( $delta_days, 0.23,
+            \@residue ) );
+    display_ymd( 'You have relaxed', \@residue );
+
+    say '';
+    say "\t\t*** You may retire in @{[ $birthday->year + 65 ]} ***";
+}
+
+say '';
+
+sub compute_ymd {
+    my ( $delta_days, $fract, $residue ) = @ARG;
+    my $days = defined $fract ? int ( $delta_days * $fract ) : $delta_days;
+    my $years = int( $days / 365 );
+    $days -= $years * 365;
+    my $months = int( $days / 30 );
+    $days -= $months * 30;
+
+    if ( $residue ) {
+        $residue->[2] -= $days;
+        if ( $residue->[2] < 0 ) {
+            $residue->[2] += 30;
+            $residue->[1] -= 1;
+        }
+        $residue->[1] -= $months;
+        if ( $residue->[1] < 0 ) {
+            $residue->[1] += 12;
+            $residue->[0] -= 1;
+        }
+        $residue->[0] -= $years;
+    }
+
+    return [ $years, $months, $days ];
+}
+
+sub display_ymd {
+    my ( $label, $ymd ) = @ARG;
+    printf "%-24s%4d%6d%8d\n", $label, @{ $ymd };
+    return;
+}
+
+sub get_date {
+    my ( $prompt, $warning, $default ) = @ARG;
+    my ( $month, $day, $year ) = split qr< [[:punct:]] >smx, get_input(
+        $prompt,
+        sub {
+            return 0 unless m/ \A (?: [0-9]+ [[:punct:]] ){2} ( [0-9]+ ) \z /smx;
+            return 1 if $1 >= 1582;
+            warn "Not prepared to give day of week prior to MDLXXXII.\n";
+            return 0;
+        },
+        $warning,
+        $default,
+    );
+    return localtime timelocal( 0, 0, 0, $day, $month - 1, $year );
+}
+
+sub tense {
+    my ( $today, $birthday ) = @ARG;
+    my $cmp = $birthday->epoch <=> $today->epoch
+        or return 'is';
+    return $cmp < 0 ? 'was' : 'will be';
+}
+
+# Get input from the user. The arguments are:
+# * The prompt
+# * A reference to validation code. This code receives the response in
+#   $ARG and returns true for a valid response.
+# * A warning to print if the response is not valid. This must end in a
+#   return.
+# * A default to return if the user simply presses .
+# The first valid response is returned. An end-of-file terminates the
+# script.
+sub get_input {
+    my ( $prompt, $validate, $warning, $default ) = @ARG;
+
+    # If no validator is passed, default to one that always returns
+    # true.
+    $validate ||= sub { 1 };
+
+    # Create the readline object. The 'state' causes the variable to be
+    # initialized only once, no matter how many times this subroutine is
+    # called. The do { ... } is a compound statement used because we
+    # need to tweak the created object before we store it.
+    state $term = do {
+        my $obj = Term::ReadLine->new( 'reverse' );
+        $obj->ornaments( 0 );
+        $obj;
+    };
+
+    while ( 1 ) {   # Iterate indefinitely
+
+        # Read the input into the topic variable, localized to prevent
+        # Spooky Action at a Distance. We exit on undef, which signals
+        # end-of-file.
+        exit unless defined( local $ARG = $term->readline( $prompt ) );
+
+        # Return the default if it exists AND we got an empty line
+        return $default if defined( $default ) && $ARG eq '';
+
+        # Return the input if it is valid.
+        return $ARG if $validate->();
+
+        # Issue the warning, and go around the merry-go-round again.
+        warn $warning;
+    }
+}
+
+__END__
+
+=head1 TITLE
+
+weekday - Play the game 'Weekday' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ weekday.pl
+
+=head1 DETAILS
+
+This Perl script is a port of weekday.bas, which is the 95th entry in
+Basic Computer Games.
+
+I have replaced the manual date logic with Perl built-ins to the extent
+possible. Unfortunately the kind of date math involved in the "time
+spent doing ..." functionality is not well-defined, so I have been
+forced to retain the original logic here. Sigh.
+
+You can use any punctuation character you please in the date
+input. So something like 2/29/2020 is perfectly acceptable.
+
+It would also have been nice to produce a localized version that
+supports day/month/year or year-month-day input, but that didn't happen.
+
+Also nice would have been language-specific output -- especially if it
+could have accommodated regional differences in which day of the week or
+month is unlucky.
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :
diff --git a/00_Alternate_Languages/95_Weekday/python/README.md b/00_Alternate_Languages/95_Weekday/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/95_Weekday/python/weekday.py b/00_Alternate_Languages/95_Weekday/python/weekday.py
new file mode 100644
index 00000000..808e43e5
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/python/weekday.py
@@ -0,0 +1,285 @@
+"""
+WEEKDAY
+
+Calculates which weekday an entered date is.
+
+Also estimates how long a person has done certain activities, if they
+entered their birthday.
+
+Also calculates the year of retirement, assuming retiring at age 65.
+
+Ported by Dave LeCompte.
+"""
+
+import datetime
+
+GET_TODAY_FROM_SYSTEM = True
+
+
+def print_with_tab(space_count, s):
+    if space_count > 0:
+        spaces = " " * space_count
+    else:
+        spaces = ""
+    print(spaces + s)
+
+
+def get_date_from_user(prompt):
+    while True:
+        print(prompt)
+        date_str = input()
+        try:
+            month_num, day_num, year_num = (int(x) for x in date_str.split(","))
+        except Exception:
+            print("I COULDN'T UNDERSTAND THAT. TRY AGAIN.")
+        return month_num, day_num, year_num
+
+
+def get_date_from_system():
+    dt = datetime.datetime.today()
+    return dt.month, dt.day, dt.year
+
+
+def get_day_of_week(weekday_index, day):
+    day_names = {
+        1: "SUNDAY",
+        2: "MONDAY",
+        3: "TUESDAY",
+        4: "WEDNESDAY",
+        5: "THURSDAY",
+        6: "FRIDAY",
+        7: "SATURDAY",
+    }
+
+    if weekday_index == 6 and day == 13:
+        return "FRIDAY THE THIRTEENTH---BEWARE!"
+    return day_names[weekday_index]
+
+
+def previous_day(b):
+    if b == 0:
+        b = 6
+    return b - 1
+
+
+def is_leap_year(year):
+    if (year % 4) != 0:
+        return False
+    if (year % 100) != 0:
+        return True
+    if (year % 400) != 0:
+        return False
+    return True
+
+
+def adjust_day_for_leap_year(b, year):
+    if is_leap_year(year):
+        b = previous_day(b)
+    return b
+
+
+def adjust_weekday(b, month, year):
+    if month <= 2:
+        b = adjust_day_for_leap_year(b, year)
+    if b == 0:
+        b = 7
+    return b
+
+
+def calc_day_value(year, month, day):
+    return (year * 12 + month) * 31 + day
+
+
+def deduct_time(frac, days, years_remain, months_remain, days_remain):
+    # CALCULATE TIME IN YEARS, MONTHS, AND DAYS
+    days_available = int(frac * days)
+    years_used = int(days_available / 365)
+    days_available -= years_used * 365
+    months_used = int(days_available / 30)
+    days_used = days_available - (months_used * 30)
+    years_remain = years_remain - years_used
+    months_remain = months_remain - months_used
+    days_remain = days_remain - days_used
+
+    while days_remain < 0:
+        days_remain += 30
+        months_remain -= 1
+
+    while months_remain < 0 and years_remain > 0:
+        months_remain += 12
+        years_remain -= 1
+    return years_remain, months_remain, days_remain, years_used, months_used, days_used
+
+
+def time_report(msg, years, months, days):
+    leading_spaces = 23 - len(msg)
+    print_with_tab(leading_spaces, msg + f"\t{years}\t{months}\t{days}")
+
+
+def make_occupation_label(years):
+    if years <= 3:
+        return "PLAYED"
+    elif years <= 9:
+        return "PLAYED/STUDIED"
+    else:
+        return "WORKED/PLAYED"
+
+
+def calculate_day_of_week(year, month, day):
+    # Initial values for months
+    month_table = [0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5]
+
+    i1 = int((year - 1500) / 100)
+    a = i1 * 5 + (i1 + 3) / 4
+    i2 = int(a - int(a / 7) * 7)
+    y2 = int(year / 100)
+    y3 = int(year - y2 * 100)
+    a = y3 / 4 + y3 + day + month_table[month - 1] + i2
+    b = int(a - int(a / 7) * 7) + 1
+    b = adjust_weekday(b, month, year)
+
+    return b
+
+
+def end():
+    for i in range(5):
+        print()
+
+
+def main():
+    print_with_tab(32, "WEEKDAY")
+    print_with_tab(15, "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY")
+    print()
+    print()
+    print()
+    print("WEEKDAY IS A COMPUTER DEMONSTRATION THAT")
+    print("GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.")
+    print()
+
+    if GET_TODAY_FROM_SYSTEM:
+        month_today, day_today, year_today = get_date_from_system()
+    else:
+        month_today, day_today, year_today = get_date_from_user(
+            "ENTER TODAY'S DATE IN THE FORM: 3,24,1979"
+        )
+
+    # This program determines the day of the week
+    # for a date after 1582
+
+    print()
+
+    month, day, year = get_date_from_user(
+        "ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST) (like MM,DD,YYYY)"
+    )
+
+    print()
+
+    # Test for date before current calendar
+    if year < 1582:
+        print("NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII.")
+        end()
+        return
+
+    b = calculate_day_of_week(year, month, day)
+
+    today_day_value = calc_day_value(year_today, month_today, day_today)
+    target_day_value = calc_day_value(year, month, day)
+
+    is_today = False
+
+    if today_day_value < target_day_value:
+        label = "WILL BE A"
+    elif today_day_value == target_day_value:
+        label = "IS A"
+        is_today = True
+    else:
+        label = "WAS A"
+
+    day_name = get_day_of_week(b, day)
+
+    # print the day of the week the date falls on.
+    print(f"{month}/{day}/{year} {label} {day_name}.")
+
+    if is_today:
+        # nothing to report for today
+        end()
+        return
+
+    print()
+
+    el_years = year_today - year
+    el_months = month_today - month
+    el_days = day_today - day
+
+    if el_days < 0:
+        el_months = el_months - 1
+        el_days = el_days + 30
+    if el_months < 0:
+        el_years = el_years - 1
+        el_months = el_months + 12
+    if el_years < 0:
+        # target date is in the future
+        end()
+        return
+
+    if (el_months == 0) and (el_days == 0):
+        print("***HAPPY BIRTHDAY***")
+
+    # print report
+    print_with_tab(23, "\tYEARS\tMONTHS\tDAYS")
+    print_with_tab(23, "\t-----\t------\t----")
+    print(f"YOUR AGE (IF BIRTHDATE)\t{el_years}\t{el_months}\t{el_days}")
+
+    life_days = (el_years * 365) + (el_months * 30) + el_days + int(el_months / 2)
+    rem_years = el_years
+    rem_months = el_months
+    rem_days = el_days
+
+    rem_years, rem_months, rem_days, used_years, used_months, used_days = deduct_time(
+        0.35, life_days, rem_years, rem_months, rem_days
+    )
+    time_report("YOU HAVE SLEPT", used_years, used_months, used_days)
+    rem_years, rem_months, rem_days, used_years, used_months, used_days = deduct_time(
+        0.17, life_days, rem_years, rem_months, rem_days
+    )
+    time_report("YOU HAVE EATEN", used_years, used_months, used_days)
+
+    label = make_occupation_label(rem_years)
+    rem_years, rem_months, rem_days, used_years, used_months, used_days = deduct_time(
+        0.23, life_days, rem_years, rem_months, rem_days
+    )
+    time_report("YOU HAVE " + label, used_years, used_months, used_days)
+    time_report("YOU HAVE RELAXED", rem_years, rem_months, rem_days)
+
+    print()
+
+    # Calculate retirement date
+    e = year + 65
+    print_with_tab(16, f"***  YOU MAY RETIRE IN {e} ***")
+    end()
+
+
+def test_weekday_calc(year, month, day):
+    dt = datetime.date(year, month, day)
+    python_weekday = dt.weekday()  # Monday = 0, Sunday = 6
+
+    basic_weekday = calculate_day_of_week(year, month, day)  # Sunday = 1, Saturday = 7
+
+    if ((python_weekday + 2) % 7) != (basic_weekday % 7):
+        print(f"testing yr {year} month {month} day {day}")
+        print(f"python says {python_weekday}")
+        print(f"BASIC says {basic_weekday}")
+        assert False
+
+
+def test_harness():
+    for yr in range(1600, 2021):
+        for m in range(1, 12):
+            for d in range(1, 28):
+                test_weekday_calc(yr, m, d)
+
+
+if __name__ == "__main__":
+    main()
+
+    # test_harness()
diff --git a/00_Alternate_Languages/95_Weekday/ruby/README.md b/00_Alternate_Languages/95_Weekday/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/95_Weekday/vbnet/README.md b/00_Alternate_Languages/95_Weekday/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/95_Weekday/vbnet/Weekday.sln b/00_Alternate_Languages/95_Weekday/vbnet/Weekday.sln
new file mode 100644
index 00000000..7bbbb17a
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/vbnet/Weekday.sln
@@ -0,0 +1,22 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30114.105
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Weekday", "Weekday.vbproj", "{3BE031BE-D032-477A-A419-48FA7D3C2DD2}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{3BE031BE-D032-477A-A419-48FA7D3C2DD2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3BE031BE-D032-477A-A419-48FA7D3C2DD2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3BE031BE-D032-477A-A419-48FA7D3C2DD2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3BE031BE-D032-477A-A419-48FA7D3C2DD2}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/95_Weekday/vbnet/Weekday.vbproj b/00_Alternate_Languages/95_Weekday/vbnet/Weekday.vbproj
new file mode 100644
index 00000000..dfa9996c
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/vbnet/Weekday.vbproj
@@ -0,0 +1,8 @@
+
+  
+    Exe
+    Weekday
+    net6.0
+    16.9
+  
+
diff --git a/00_Alternate_Languages/95_Weekday/weekday.bas b/00_Alternate_Languages/95_Weekday/weekday.bas
new file mode 100644
index 00000000..33f982e8
--- /dev/null
+++ b/00_Alternate_Languages/95_Weekday/weekday.bas
@@ -0,0 +1,150 @@
+10 PRINT TAB(32);"WEEKDAY"
+20 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+30 PRINT:PRINT:PRINT
+100 PRINT "WEEKDAY IS A COMPUTER DEMONSTRATION THAT"
+110 PRINT"GIVES FACTS ABOUT A DATE OF INTEREST TO YOU."
+120 PRINT
+130 PRINT "ENTER TODAY'S DATE IN THE FORM: 3,24,1979  ";
+140 INPUT M1,D1,Y1
+150 REM THIS PROGRAM DETERMINES THE DAY OF THE WEEK
+160 REM  FOR A DATE AFTER 1582
+170 DEF FNA(A)=INT(A/4)
+180 DIM T(12)
+190 DEF FNB(A)=INT(A/7)
+200 REM SPACE OUTPUT AND READ IN INITIAL VALUES FOR MONTHS.
+210 FOR I= 1 TO 12
+220 READ T(I)
+230 NEXT I
+240 PRINT"ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST)";
+250 INPUT M,D,Y
+260 PRINT
+270 LET I1 = INT((Y-1500)/100)
+280 REM TEST FOR DATE BEFORE CURRENT CALENDAR.
+290 IF Y-1582 <0 THEN 1300
+300 LET A = I1*5+(I1+3)/4
+310 LET I2=INT(A-FNB(A)*7)
+320 LET Y2=INT(Y/100)
+330 LET Y3 =INT(Y-Y2*100)
+340 LET A =Y3/4+Y3+D+T(M)+I2
+350 LET B=INT(A-FNB(A)*7)+1
+360 IF M > 2 THEN 470
+370 IF Y3 = 0 THEN 440
+380 LET T1=INT(Y-FNA(Y)*4)
+390 IF T1 <> 0 THEN 470
+400 IF B<>0 THEN 420
+410 LET B=6
+420 LET B = B-1
+430 GOTO 470
+440 LET A = I1-1
+450 LET T1=INT(A-FNA(A)*4)
+460 IF T1 = 0 THEN 400
+470 IF B <>0 THEN 490
+480 LET B = 7
+490 IF (Y1*12+M1)*31+D1<(Y*12+M)*31+D THEN 550
+500 IF (Y1*12+M1)*31+D1=(Y*12+M)*31+D THEN 530
+510 PRINT M;"/";D;"/";Y;" WAS A ";
+520 GOTO 570
+530 PRINT M;"/";D;"/";Y;" IS A ";
+540 GOTO 570
+550 PRINT M;"/";D;"/";Y;" WILL BE A ";
+560 REM PRINT THE DAY OF THE WEEK THE DATE FALLS ON.
+570 IF B <>1 THEN 590
+580 PRINT "SUNDAY."
+590 IF B<>2 THEN 610
+600 PRINT "MONDAY."
+610 IF B<>3 THEN 630
+620 PRINT "TUESDAY."
+630 IF B<>4 THEN 650
+640 PRINT "WEDNESDAY."
+650 IF B<>5 THEN 670
+660 PRINT "THURSDAY."
+670 IF B<>6 THEN 690
+680 GOTO 1250
+690 IF B<>7 THEN 710
+700 PRINT "SATURDAY."
+710 IF (Y1*12+M1)*31+D1=(Y*12+M)*31+D THEN 1120
+720 LET I5=Y1-Y
+730 PRINT
+740 LET I6=M1-M
+750 LET I7=D1-D
+760 IF I7>=0 THEN 790
+770 LET I6= I6-1
+780 LET I7=I7+30
+790 IF I6>=0 THEN 820
+800 LET I5=I5-1
+810 LET I6=I6+12
+820 IF I5<0 THEN 1310
+830 IF I7 <> 0 THEN 850
+835 IF I6 <> 0 THEN 850
+840 PRINT"***HAPPY BIRTHDAY***"
+850 PRINT " "," ","YEARS","MONTHS","DAYS"
+855 PRINT " "," ","-----","------","----"
+860 PRINT "YOUR AGE (IF BIRTHDATE) ",I5,I6,I7
+870 LET A8 = (I5*365)+(I6*30)+I7+INT(I6/2)
+880 LET K5 = I5
+890 LET K6 = I6
+900 LET K7 = I7
+910 REM CALCULATE RETIREMENT DATE.
+920 LET E = Y+65
+930 REM CALCULATE TIME SPENT IN THE FOLLOWING FUNCTIONS.
+940 LET F = .35
+950 PRINT "YOU HAVE SLEPT ",
+960 GOSUB 1370
+970 LET F = .17
+980 PRINT "YOU HAVE EATEN ",
+990 GOSUB 1370
+1000 LET F = .23
+1010 IF K5 > 3 THEN 1040
+1020 PRINT "YOU HAVE PLAYED",
+1030 GOTO 1080
+1040 IF K5 > 9 THEN 1070
+1050 PRINT "YOU HAVE PLAYED/STUDIED",
+1060 GOTO  1080
+1070 PRINT "YOU HAVE WORKED/PLAYED",
+1080 GOSUB 1370
+1085 GOTO 1530
+1090 PRINT "YOU HAVE RELAXED ",K5,K6,K7
+1100 PRINT
+1110 PRINT TAB(16);"***  YOU MAY RETIRE IN";E;" ***"
+1120 PRINT
+1140 PRINT
+1200 PRINT
+1210 PRINT
+1220 PRINT
+1230 PRINT
+1240 END
+1250 IF D=13 THEN 1280
+1260 PRINT "FRIDAY."
+1270 GOTO 710
+1280 PRINT "FRIDAY THE THIRTEENTH---BEWARE!"
+1290 GOTO 710
+1300 PRINT "NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII. "
+1310 GOTO 1140
+1320 REM TABLE OF VALUES FOR THE MONTHS TO BE USED IN CALCULATIONS.
+1330 DATA 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5
+1340 REM THIS IS THE CURRENT DATE USED IN THE CALCULATIONS.
+1350 REM THIS IS THE DATE TO BE CALCULATED ON.
+1360 REM CALCULATE TIME IN YEARS, MONTHS, AND DAYS
+1370 LET K1=INT(F*A8)
+1380 LET I5 = INT(K1/365)
+1390 LET K1 = K1- (I5*365)
+1400 LET I6 = INT(K1/30)
+1410 LET I7 = K1 -(I6*30)
+1420 LET K5 = K5-I5
+1430 LET K6 =K6-I6
+1440 LET K7 = K7-I7
+1450 IF K7>=0 THEN 1480
+1460 LET K7=K7+30
+1470 LET K6=K6-1
+1480 IF K6>0 THEN 1510
+1490 LET K6=K6+12
+1500 LET K5=K5-1
+1510 PRINT I5,I6,I7
+1520 RETURN
+1530 IF K6=12 THEN 1550
+1540 GOTO 1090
+1550 LET K5=K5+1
+1560 LET K6=0
+1570 GOTO 1090
+1580 REM
+1590 END
diff --git a/00_Alternate_Languages/96_Word/README.md b/00_Alternate_Languages/96_Word/README.md
new file mode 100644
index 00000000..50a7a8b4
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/README.md
@@ -0,0 +1,9 @@
+Please refer to the `readme.md` in the parent folder. 
+
+Each subfolder represents a port of this program to a language which is _not_ one of the agreed upon 10 languages, which are intended to meet these three criteria:
+
+1. Popular (by TIOBE index)
+2. Memory safe
+3. Generally considered a 'scripting' language
+
+We welcome additional ports, but these additional ports are for educational purposes only.
\ No newline at end of file
diff --git a/00_Alternate_Languages/96_Word/csharp/Program.cs b/00_Alternate_Languages/96_Word/csharp/Program.cs
new file mode 100644
index 00000000..76fb3582
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/csharp/Program.cs
@@ -0,0 +1,163 @@
+using System;
+using System.Linq;
+using System.Text;
+
+namespace word
+{
+    class Word
+    {
+        // Here's the list of potential words that could be selected
+        // as the winning word.
+        private string[] words = { "DINKY", "SMOKE", "WATER", "GRASS", "TRAIN", "MIGHT", "FIRST",
+         "CANDY", "CHAMP", "WOULD", "CLUMP", "DOPEY" };
+
+        /// 
+        /// Outputs the instructions of the game.
+        /// 
+        private void intro()
+        {
+            Console.WriteLine("WORD".PadLeft(37));
+            Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".PadLeft(59));
+
+            Console.WriteLine("I am thinking of a word -- you guess it. I will give you");
+            Console.WriteLine("clues to help you get it. Good luck!!");
+        }
+
+        /// 
+        /// This allows the user to enter a guess - doing some basic validation
+        /// on those guesses.
+        /// 
+        /// The guess entered by the user
+        private string get_guess()
+        {
+            string guess = "";
+
+            while (guess.Length == 0)
+            {
+                Console.WriteLine($"{Environment.NewLine}Guess a five letter word. ");
+                guess = Console.ReadLine().ToUpper();
+
+                if ((guess.Length != 5) || (guess.Equals("?")) || (!guess.All(char.IsLetter)))
+                {
+                    guess = "";
+                    Console.WriteLine("You must guess a give letter word. Start again.");
+                }
+            }
+
+            return guess;
+        }
+
+        /// 
+        /// This checks the user's guess against the target word - capturing
+        /// any letters that match up between the two as well as the specific
+        /// letters that are correct.
+        /// 
+        /// The user's guess
+        /// The 'winning' word
+        /// A string showing which specific letters have already been guessed
+        /// The integer value showing the number of character matches between guess and target
+        private int check_guess(string guess, string target, StringBuilder progress)
+        {
+            // Go through each letter of the guess and see which
+            // letters match up to the target word.
+            // For each position that matches, update the progress
+            // to reflect the guess
+            int matches = 0;
+            string common_letters = "";
+
+            for (int ctr = 0; ctr < 5; ctr++)
+            {
+                // First see if this letter appears anywhere in the target
+                // and, if so, add it to the common_letters list.
+                if (target.Contains(guess[ctr]))
+                {
+                    common_letters.Append(guess[ctr]);
+                }
+                // Then see if this specific letter matches the
+                // same position in the target. And, if so, update
+                // the progress tracker
+                if (guess[ctr].Equals(target[ctr]))
+                {
+                    progress[ctr] = guess[ctr];
+                    matches++;
+                }
+            }
+
+            Console.WriteLine($"There were {matches} matches and the common letters were... {common_letters}");
+            Console.WriteLine($"From the exact letter matches, you know......... {progress}");
+            return matches;
+        }
+
+        /// 
+        /// This plays one full game.
+        /// 
+        private void play_game()
+        {
+            string guess_word, target_word;
+            StringBuilder guess_progress = new StringBuilder("-----");
+            Random rand = new Random();
+            int count = 0;
+
+            Console.WriteLine("You are starting a new game...");
+
+            // Randomly select a word from the list of words
+            target_word = words[rand.Next(words.Length)];
+
+            // Just run as an infinite loop until one of the
+            // endgame conditions are met.
+            while (true)
+            {
+                // Ask the user for their guess
+                guess_word = get_guess();
+                count++;
+
+                // If they enter a question mark, then tell them
+                // the answer and quit the game
+                if (guess_word.Equals("?"))
+                {
+                    Console.WriteLine($"The secret word is {target_word}");
+                    return;
+                }
+
+                // Otherwise, check the guess against the target - noting progress
+                if (check_guess(guess_word, target_word, guess_progress) == 0)
+                {
+                    Console.WriteLine("If you give up, type '?' for your next guess.");
+                }
+
+                // Once they've guess the word, end the game.
+                if (guess_progress.Equals(guess_word))
+                {
+                    Console.WriteLine($"You have guessed the word.  It took {count} guesses!");
+                    return;
+                }
+            }
+        }
+
+        /// 
+        /// The main entry point for the class - just keeps
+        /// playing the game until the user decides to quit.
+        /// 
+        public void play()
+        {
+            intro();
+
+            bool keep_playing = true;
+
+            while (keep_playing)
+            {
+                play_game();
+                Console.WriteLine($"{Environment.NewLine}Want to play again? ");
+                keep_playing = Console.ReadLine().StartsWith("y", StringComparison.CurrentCultureIgnoreCase);
+            }
+        }
+    }
+
+    class Program
+    {
+        static void Main(string[] args)
+        {
+            new Word().play();
+        }
+    }
+}
diff --git a/00_Alternate_Languages/96_Word/csharp/README.md b/00_Alternate_Languages/96_Word/csharp/README.md
new file mode 100644
index 00000000..4daabb5c
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/csharp/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Microsoft C#](https://docs.microsoft.com/en-us/dotnet/csharp/)
diff --git a/00_Alternate_Languages/96_Word/csharp/word.csproj b/00_Alternate_Languages/96_Word/csharp/word.csproj
new file mode 100644
index 00000000..c73e0d16
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/csharp/word.csproj
@@ -0,0 +1,8 @@
+
+
+  
+    Exe
+    netcoreapp3.1
+  
+
+
diff --git a/00_Alternate_Languages/96_Word/csharp/word.sln b/00_Alternate_Languages/96_Word/csharp/word.sln
new file mode 100644
index 00000000..77360e81
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/csharp/word.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Word", "Word.csproj", "{E2CF183B-EBC3-497C-8D34-32EBEE4E2B73}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{E2CF183B-EBC3-497C-8D34-32EBEE4E2B73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E2CF183B-EBC3-497C-8D34-32EBEE4E2B73}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E2CF183B-EBC3-497C-8D34-32EBEE4E2B73}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E2CF183B-EBC3-497C-8D34-32EBEE4E2B73}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {B4D37881-6972-406B-978F-C1B60BA42638}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/96_Word/d/.gitignore b/00_Alternate_Languages/96_Word/d/.gitignore
new file mode 100644
index 00000000..d969f6b2
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/d/.gitignore
@@ -0,0 +1,2 @@
+*.exe
+*.obj
diff --git a/00_Alternate_Languages/96_Word/d/README.md b/00_Alternate_Languages/96_Word/d/README.md
new file mode 100644
index 00000000..764cb141
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/d/README.md
@@ -0,0 +1,15 @@
+Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).
+
+The Basic original required words to be exactly five letters in length for the program to behave correctly.
+This version does not replicate that limitation, and the test for that requirement is commented out.
+
+## Running the code
+
+Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:
+```shell
+dmd -dip1000 -run word.d
+```
+
+[Other compilers](https://dlang.org/download.html) also exist.
diff --git a/00_Alternate_Languages/96_Word/java/README.md b/00_Alternate_Languages/96_Word/java/README.md
new file mode 100644
index 00000000..51edd8d4
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/java/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Oracle Java](https://openjdk.java.net/)
diff --git a/00_Alternate_Languages/96_Word/java/Word.java b/00_Alternate_Languages/96_Word/java/Word.java
new file mode 100644
index 00000000..d8bde3d9
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/java/Word.java
@@ -0,0 +1,223 @@
+import java.util.Arrays;
+import java.util.Scanner;
+
+/**
+ * Game of Word
+ * 

+ * Based on the BASIC game of Word here + * https://github.com/coding-horror/basic-computer-games/blob/main/96%20Word/word.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 Word { + + private final static String[] WORDS = { + + "DINKY", "SMOKE", "WATER", "GRASS", "TRAIN", "MIGHT", + "FIRST", "CANDY", "CHAMP", "WOULD", "CLUMP", "DOPEY" + + }; + + private final Scanner scan; // For user input + + private enum Step { + INITIALIZE, MAKE_GUESS, USER_WINS + } + + public Word() { + + scan = new Scanner(System.in); + + } // End of constructor Word + + public void play() { + + showIntro(); + startGame(); + + } // End of method play + + private void showIntro() { + + System.out.println(" ".repeat(32) + "WORD"); + System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + System.out.println("\n\n"); + + System.out.println("I AM THINKING OF A WORD -- YOU GUESS IT. I WILL GIVE YOU"); + System.out.println("CLUES TO HELP YOU GET IT. GOOD LUCK!!"); + System.out.println("\n"); + + } // End of method showIntro + + private void startGame() { + + char[] commonLetters = new char[8]; + char[] exactLetters = new char[8]; + + int commonIndex = 0; + int ii = 0; // Loop iterator + int jj = 0; // Loop iterator + int numGuesses = 0; + int numMatches = 0; + int wordIndex = 0; + + Step nextStep = Step.INITIALIZE; + + String commonString = ""; + String exactString = ""; + String guessWord = ""; + String secretWord = ""; + String userResponse = ""; + + // Begin outer while loop + while (true) { + + switch (nextStep) { + + case INITIALIZE: + + System.out.println("\n"); + System.out.println("YOU ARE STARTING A NEW GAME..."); + + // Select a secret word from the list + wordIndex = (int) (Math.random() * WORDS.length); + secretWord = WORDS[wordIndex]; + + numGuesses = 0; + + Arrays.fill(exactLetters, 1, 6, '-'); + Arrays.fill(commonLetters, 1, 6, '\0'); + + nextStep = Step.MAKE_GUESS; + break; + + case MAKE_GUESS: + + System.out.print("GUESS A FIVE LETTER WORD? "); + guessWord = scan.nextLine().toUpperCase(); + + numGuesses++; + + // Win condition + if (guessWord.equals(secretWord)) { + nextStep = Step.USER_WINS; + continue; + } + + Arrays.fill(commonLetters, 1, 8, '\0'); + + // Surrender condition + if (guessWord.equals("?")) { + System.out.println("THE SECRET WORD IS " + secretWord); + System.out.println(""); + nextStep = Step.INITIALIZE; // Play again + continue; + } + + // Check for valid input + if (guessWord.length() != 5) { + System.out.println("YOU MUST GUESS A 5 LETTER WORD. START AGAIN."); + numGuesses--; + nextStep = Step.MAKE_GUESS; // Guess again + continue; + } + + numMatches = 0; + commonIndex = 1; + + for (ii = 1; ii <= 5; ii++) { + + for (jj = 1; jj <= 5; jj++) { + + if (secretWord.charAt(ii - 1) != guessWord.charAt(jj - 1)) { + continue; + } + + // Avoid out of bounds errors + if (commonIndex <= 5) { + commonLetters[commonIndex] = guessWord.charAt(jj - 1); + commonIndex++; + } + + if (ii == jj) { + exactLetters[jj] = guessWord.charAt(jj - 1); + } + + // Avoid out of bounds errors + if (numMatches < 5) { + numMatches++; + } + } + } + + exactString = ""; + commonString = ""; + + // Build the exact letters string + for (ii = 1; ii <= 5; ii++) { + exactString += exactLetters[ii]; + } + + // Build the common letters string + for (ii = 1; ii <= numMatches; ii++) { + commonString += commonLetters[ii]; + } + + System.out.println("THERE WERE " + numMatches + " MATCHES AND THE COMMON LETTERS WERE..." + + commonString); + + System.out.println("FROM THE EXACT LETTER MATCHES, YOU KNOW................" + exactString); + + // Win condition + if (exactString.equals(secretWord)) { + nextStep = Step.USER_WINS; + continue; + } + + // No matches + if (numMatches <= 1) { + System.out.println(""); + System.out.println("IF YOU GIVE UP, TYPE '?' FOR YOUR NEXT GUESS."); + } + + System.out.println(""); + nextStep = Step.MAKE_GUESS; + break; + + case USER_WINS: + + System.out.println("YOU HAVE GUESSED THE WORD. IT TOOK " + numGuesses + " GUESSES!"); + System.out.println(""); + + System.out.print("WANT TO PLAY AGAIN? "); + userResponse = scan.nextLine(); + + if (userResponse.toUpperCase().equals("YES")) { + nextStep = Step.INITIALIZE; // Play again + } else { + return; // Quit game + } + break; + + default: + System.out.println("INVALID STEP"); + break; + + } + + } // End outer while loop + + } // End of method startGame + + public static void main(String[] args) { + + Word word = new Word(); + word.play(); + + } // End of method main + +} // End of class Word diff --git a/00_Alternate_Languages/96_Word/javascript/README.md b/00_Alternate_Languages/96_Word/javascript/README.md new file mode 100644 index 00000000..49b7ece6 --- /dev/null +++ b/00_Alternate_Languages/96_Word/javascript/README.md @@ -0,0 +1,3 @@ +Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html) + +Conversion to [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Shells) diff --git a/00_Alternate_Languages/96_Word/javascript/word.html b/00_Alternate_Languages/96_Word/javascript/word.html new file mode 100644 index 00000000..ddc88134 --- /dev/null +++ b/00_Alternate_Languages/96_Word/javascript/word.html @@ -0,0 +1,9 @@ + + +WORD + + +


+
+
+
diff --git a/00_Alternate_Languages/96_Word/javascript/word.js b/00_Alternate_Languages/96_Word/javascript/word.js
new file mode 100644
index 00000000..3d7e3a5a
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/javascript/word.js
@@ -0,0 +1,148 @@
+// WORD
+//
+// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
+//
+
+function print(str)
+{
+    document.getElementById("output").appendChild(document.createTextNode(str));
+}
+
+function input()
+{
+
+    return new Promise(function (resolve) {
+                       const 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_element.addEventListener("keydown", function (event) {
+                                                      if (event.keyCode === 13) {
+                                                          const input_str = input_element.value;
+                                                          document.getElementById("output").removeChild(input_element);
+                                                          print(input_str);
+                                                          print("\n");
+                                                          resolve(input_str);
+                                                      }
+                                                      });
+                       });
+}
+
+function tab(space)
+{
+    let str = "";
+    while (space-- > 0)
+        str += " ";
+    return str;
+}
+
+// These are the words that the game knows about> If you want a bigger challenge you could add more words to the array
+const WORDS = ["DINKY", "SMOKE", "WATER", "GLASS", "TRAIN",
+             "MIGHT", "FIRST", "CANDY", "CHAMP", "WOULD",
+             "CLUMP", "DOPEY"];
+const WORD_COUNT = WORDS.length;
+
+// Main control section
+async function main()
+{
+    print(tab(33) + "WORD\n");
+    print(tab(15) + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n");
+    print("\n");
+    print("\n");
+    print("\n");
+    print("I AM THINKING OF A WORD -- YOU GUESS IT.  I WILL GIVE YOU\n");
+    print("CLUES TO HELP YOU GET IT.  GOOD LUCK!!\n");
+    print("\n");
+    print("\n");
+    outer: while (1) {
+        print("\n");
+        print("\n");
+        print("YOU ARE STARTING A NEW GAME...\n");
+
+        const secretWord = WORDS[Math.floor(Math.random() * WORD_COUNT)];
+
+        let guessCount = 0;
+        // This array holds the letters which have been found in the correct position across all guesses
+        // For instance if the word is "PLAIN" and the guesses so far are
+        // "SHALL" ("A" correct) and "CLIMB" ("L" correct) then it will hold "-LA--"
+        const knownLetters = [];
+        for (let i = 0; i < 5; i++)
+            knownLetters[i] = "-";
+
+        let guess = undefined;
+        while (1) {
+            print("GUESS A FIVE LETTER WORD");
+            guess = (await input()).toUpperCase();
+            guessCount++;
+            if (secretWord === guess) {
+                // The player has guessed correctly
+                break;
+            }
+
+            if (guess.charAt(0) === "?") {
+                // Player has given up
+                print("THE SECRET WORD IS " + secretWord + "\n");
+                print("\n");
+                // Start a new game by going to the start of the outer while loop
+                continue outer;
+            }
+
+            if (guess.length !== 5) {
+                print("YOU MUST GUESS A 5 LETTER WORD.  START AGAIN.\n");
+                print("\n");
+                guessCount--;
+                continue;
+            }
+
+            // Two things happen in this double loop:
+            // 1. Letters which are in both the guessed and secret words are put in the lettersInCommon array
+            // 2. Letters which are in the correct position in the guessed word are added to the knownLetters array
+            let lettersInCommonCount = 0;
+            const lettersInCommon = [];
+            for (let i = 0; i < 5; i++) {// loop round characters in secret word
+                let secretWordCharacter = secretWord.charAt(i);
+                for (let j = 0; j < 5; j++) {// loop round characters in guessed word
+                    let guessedWordCharacter = guess.charAt(j);
+                    if (secretWordCharacter === guessedWordCharacter) {
+                        lettersInCommon[lettersInCommonCount] = guessedWordCharacter;
+                        if (i === j) {
+                            // Letter is in the exact position so add to the known letters array
+                            knownLetters[j] = guessedWordCharacter;
+                        }
+                        lettersInCommonCount++;
+                    }
+                }
+            }
+
+            const lettersInCommonText = lettersInCommon.join("");
+            print("THERE WERE " + lettersInCommonCount + " MATCHES AND THE COMMON LETTERS WERE... " + lettersInCommonText + "\n");
+
+            const knownLettersText = knownLetters.join("");
+            print("FROM THE EXACT LETTER MATCHES, YOU KNOW............ " + knownLettersText + "\n");
+
+            if (knownLettersText === secretWord) {
+                guess = knownLettersText;
+                break;
+            }
+
+            if (lettersInCommonCount <= 1) {
+                print("\n");
+                print("IF YOU GIVE UP, TYPE '?' FOR YOUR NEXT GUESS.\n");
+                print("\n");
+            }
+        }
+
+        print("YOU HAVE GUESSED THE WORD.  IT TOOK " + guessCount + " GUESSES!\n");
+        print("\n");
+
+        print("WANT TO PLAY AGAIN");
+        const playAgainResponse = (await input()).toUpperCase();
+        if (playAgainResponse !== "YES")
+            break;
+    }
+}
+
+main();
diff --git a/73_Reverse/pascal/README.md b/00_Alternate_Languages/96_Word/pascal/README.md
similarity index 100%
rename from 73_Reverse/pascal/README.md
rename to 00_Alternate_Languages/96_Word/pascal/README.md
diff --git a/00_Alternate_Languages/96_Word/perl/README.md b/00_Alternate_Languages/96_Word/perl/README.md
new file mode 100644
index 00000000..e69c8b81
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/perl/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Perl](https://www.perl.org/)
diff --git a/00_Alternate_Languages/96_Word/perl/word.pl b/00_Alternate_Languages/96_Word/perl/word.pl
new file mode 100644
index 00000000..5369cc71
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/perl/word.pl
@@ -0,0 +1,169 @@
+#!/usr/bin/env perl
+
+use 5.010;      # To get 'state' and 'say'
+
+use strict;     # Require explicit declaration of variables
+use warnings;   # Enable optional compiler warnings
+
+use English;    # Use more friendly names for Perl's magic variables
+use Term::ReadLine;     # Prompt and return user input
+
+our $VERSION = '0.000_01';
+
+print <<'EOD';
+                                 WORD
+               Creative Computing  Morristown, New Jersey
+
+
+
+I am thinking of a word -- you guess it.  I will give you
+clues to help you get it.  Good luck!!
+
+
+EOD
+
+# Read the content of __DATA__, remove the trailing newlines, and store
+# each line into @words. Stop at __END__, since Perl does not see this
+# as an end-of-file.
+my @words;
+while (  ) {
+    chomp;
+    last if $ARG eq '__END__';
+    push @words, lc $ARG;   # Normalize case to lower.
+}
+
+# This loop represents an actual game. We execute it until the player
+# does something that makes us explicitly break out.
+while ( 1 ) {
+    print <<'EOD';
+
+
+You are starting a new game ...
+EOD
+
+    # Choose a random target word. The rand() function returns a number
+    # from 0 to its argument, and coerces its argument to a scalar. In
+    # scalar context, an array evaluates to the number of elements it
+    # contains.
+    my $target = $words[ rand @words ];
+
+    # We generalize the code by using the actual length of the target.
+    my $target_length = length $target;
+
+    my $count = 0;      # Number of guesses
+
+    # Make an array of the individual letters in the target. We will
+    # iterate over this to determine matching letters.
+    my @target_array = split qr<>, $target;
+
+    # Make a hash of those letters. We will use this to determine common
+    # letters. Any true value will do for the value of the hash. By
+    # making use of this hash we avoid the nested loops of the original
+    # BASIC program.
+    my %target_hash = map { $ARG => 1 } @target_array;
+
+    # We keep prompting the player until we get a response that causes
+    # us to break out of the loop.
+    while ( 1 ) {
+
+        # Create the readline object. The state keyword means the
+        # variable is only initialized once, no matter how many times
+        # execution passes this point.
+        state $term = Term::ReadLine->new( 'word' );
+
+        # Read the next guess. A return of undef means end-of-file.
+        my $guess = $term->readline( "Guess a $target_length letter word: " );
+        exit unless defined $guess;
+
+        last if $guess eq '?';  # A question mark means we give up
+        if ( length( $guess ) != $target_length ) {
+            # Wrong length. Ask again.
+            say "You must guess a $target_length letter word.  Try again.";
+            redo;       # Redo the innermost loop
+        }
+
+        $guess = lc $guess;     # Lower-case the guess
+        $count++;       # Count another guess
+
+        if ( $guess eq $target ) {
+            # We guessed the word.
+            say "You have guessed the word. It took $count guesses!";
+            my $answer = $term->readline( 'Want to play again? [y/N]: ');
+            exit unless defined $guess; # End of file
+            exit unless $guess =~ m/ \A y /smxi;
+            last;       # Exit the innermost loop.
+        }
+
+        my @common_letters; # Letters common to guess and target
+        my $match = '-' x length $target;   # Assume no matches
+        my $inx = 0;    # Iterator
+        foreach my $letter ( split qr<>, $guess ) {
+            if ( $target_hash{$letter} ) {
+                # If the letter is in the hash, it occurs in the target
+                push @common_letters, $letter;
+                # If it is at the current position in the target, it is
+                # an actual match.
+                $target_array[$inx] eq $letter
+                    and substr $match, $inx, 1, $letter;
+            }
+            $inx++;
+        }
+
+        say 'There were ', scalar @common_letters,
+            ' matches and the common letters were... ', @common_letters;
+        say "From the exact letter matches, you know................ $match";
+        say '';
+        say q;
+        redo;
+    }
+
+}
+__DATA__
+dinky
+smoke
+water
+grass
+train
+might
+first
+candy
+champ
+would
+clump
+dopey
+__END__
+
+=head1 TITLE
+
+word.pl - Play the game 'word' from Basic Computer Games
+
+=head1 SYNOPSIS
+
+ word.pl
+
+=head1 DETAILS
+
+This Perl script is a port of C, which is the 96th entry in Basic
+Computer Games.
+
+=head1 PORTED BY
+
+Thomas R. Wyant, III F
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2022 by Thomas R. Wyant, III
+
+This program is free software; you can redistribute it and/or modify it
+under the same terms as Perl 5.10.0. For more details, see the Artistic
+License 1.0 at
+L, and/or the
+Gnu GPL at L.
+
+This program is distributed in the hope that it will be useful, but
+without any warranty; without even the implied warranty of
+merchantability or fitness for a particular purpose.
+
+=cut
+
+# ex: set expandtab tabstop=4 textwidth=72 :
diff --git a/00_Alternate_Languages/96_Word/python/README.md b/00_Alternate_Languages/96_Word/python/README.md
new file mode 100644
index 00000000..781945ec
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/python/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Python](https://www.python.org/about/)
diff --git a/00_Alternate_Languages/96_Word/python/word.py b/00_Alternate_Languages/96_Word/python/word.py
new file mode 100644
index 00000000..10d1fd20
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/python/word.py
@@ -0,0 +1,86 @@
+#!/usr/bin/env python3
+# WORD
+#
+# Converted from BASIC to Python by Trevor Hobson
+
+import random
+
+words = [
+    "DINKY",
+    "SMOKE",
+    "WATER",
+    "GRASS",
+    "TRAIN",
+    "MIGHT",
+    "FIRST",
+    "CANDY",
+    "CHAMP",
+    "WOULD",
+    "CLUMP",
+    "DOPEY",
+]
+
+
+def play_game():
+    """Play one round of the game"""
+
+    random.shuffle(words)
+    target_word = words[0]
+    guess_count = 0
+    guess_progress = ["-"] * 5
+
+    print("You are starting a new game...")
+    while True:
+        guess_word = ""
+        while guess_word == "":
+            guess_word = input("\nGuess a five letter word. ").upper()
+            if guess_word == "?":
+                break
+            elif not guess_word.isalpha() or len(guess_word) != 5:
+                guess_word = ""
+                print("You must guess a five letter word. Start again.")
+        guess_count += 1
+        if guess_word == "?":
+            print("The secret word is", target_word)
+            break
+        else:
+            common_letters = ""
+            matches = 0
+            for i in range(5):
+                for j in range(5):
+                    if guess_word[i] == target_word[j]:
+                        matches += 1
+                        common_letters = common_letters + guess_word[i]
+                        if i == j:
+                            guess_progress[j] = guess_word[i]
+            print(
+                "There were",
+                matches,
+                "matches and the common letters were... " + common_letters,
+            )
+            print(
+                "From the exact letter matches, you know............ "
+                + "".join(guess_progress)
+            )
+            if "".join(guess_progress) == guess_word:
+                print("\nYou have guessed the word. It took", guess_count, "guesses!")
+                break
+            elif matches == 0:
+                print("\nIf you give up, type '?' for you next guess.")
+
+
+def main():
+    print(" " * 33 + "WORD")
+    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n")
+
+    print("I am thinking of a word -- you guess it. I will give you")
+    print("clues to help you get it. Good luck!!\n")
+
+    keep_playing = True
+    while keep_playing:
+        play_game()
+        keep_playing = input("\nWant to play again? ").lower().startswith("y")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/00_Alternate_Languages/96_Word/ruby/README.md b/00_Alternate_Languages/96_Word/ruby/README.md
new file mode 100644
index 00000000..fb32811e
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/ruby/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Ruby](https://www.ruby-lang.org/en/)
diff --git a/00_Alternate_Languages/96_Word/ruby/word.rb b/00_Alternate_Languages/96_Word/ruby/word.rb
new file mode 100644
index 00000000..1f0eead5
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/ruby/word.rb
@@ -0,0 +1,66 @@
+#!/usr/bin/env ruby
+# WORD
+#
+# Converted from BASIC to Ruby
+
+
+WORDS = ["DINKY", "SMOKE", "WATER", "GRASS", "TRAIN", "MIGHT",
+         "FIRST","CANDY", "CHAMP", "WOULD", "CLUMP", "DOPEY"]
+
+def game_loop
+  target_word = WORDS.sample.downcase
+  guess_count = 0
+  guess_progress = ["-"] * 5
+
+  puts "You are starting a new game..."
+  while true
+    guess_word = ""
+    while guess_word == ""
+      puts "Guess a five letter word. "
+      guess_word = gets.chomp
+      if guess_word == "?"
+        break
+      elsif !guess_word.match(/^[[:alpha:]]+$/) || guess_word.length != 5
+        guess_word = ""
+        puts "You must guess a five letter word. Start again."
+      end
+    end
+    guess_count += 1
+    if guess_word == "?"
+      puts "The secret word is #{target_word}"
+      break
+    else
+      common_letters = ""
+      matches = 0
+      5.times do |i|
+        5.times do |j|
+          if guess_word[i] == target_word[j]
+            matches += 1
+            common_letters = common_letters + guess_word[i]
+            guess_progress[j] = guess_word[i] if i == j
+          end
+        end
+      end
+      puts "There were #{matches} matches and the common letters were... #{common_letters}"
+      puts "From the exact letter matches, you know............ #{guess_progress.join}"
+      if guess_progress.join == guess_word
+        puts "You have guessed the word. It took #{guess_count} guesses!"
+        break
+      elsif matches < 2
+        puts "If you give up, type '?' for you next guess."
+      end
+    end
+  end
+end
+
+puts " " * 33 + "WORD"
+puts " " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n"
+puts "I am thinking of a word -- you guess it. I will give you"
+puts "clues to help you get it. Good luck!!\n"
+
+keep_playing = true
+while keep_playing
+  game_loop
+  puts "\n Want to play again? "
+  keep_playing = gets.chomp.downcase.index("y") == 0
+end
diff --git a/00_Alternate_Languages/96_Word/vbnet/Program.vb b/00_Alternate_Languages/96_Word/vbnet/Program.vb
new file mode 100644
index 00000000..4aa585cb
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/vbnet/Program.vb
@@ -0,0 +1,145 @@
+Imports System
+Imports System.Text
+Imports System.Text.RegularExpressions
+
+Module Word
+    ' Here's the list of potential words that could be selected
+    ' as the winning word.
+    Dim words As String() = {"DINKY", "SMOKE", "WATER", "GRASS", "TRAIN", "MIGHT", "FIRST",
+         "CANDY", "CHAMP", "WOULD", "CLUMP", "DOPEY"}
+
+    ' 
+    ' Outputs the instructions of the game.
+    ' 
+    Private Sub intro()
+        Console.WriteLine("WORD".PadLeft(37))
+        Console.WriteLine("CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY".PadLeft(59))
+
+        Console.WriteLine("I am thinking of a word -- you guess it. I will give you")
+        Console.WriteLine("clues to help you get it. Good luck!!")
+    End Sub
+
+    ' 
+    ' This allows the user to enter a guess - doing some basic validation
+    ' on those guesses.
+    ' 
+    ' The guess entered by the user
+    Private Function get_guess() As String
+        Dim guess As String = ""
+
+        While (guess.Length = 0)
+            Console.WriteLine($"{Environment.NewLine}Guess a five letter word. ")
+            guess = Console.ReadLine().ToUpper()
+
+            If ((guess.Length <> 5) Or guess.Equals("?") Or Not Regex.IsMatch(guess, "^[A-Z]+$")) Then
+                guess = ""
+                Console.WriteLine("You must guess a give letter word. Start again.")
+            End If
+        End While
+
+        Return guess
+    End Function
+
+    ' 
+    ' This checks the user's guess against the target word - capturing
+    ' any letters that match up between the two as well as the specific
+    ' letters that are correct.
+    ' 
+    ' The user's guess
+    ' The 'winning' word
+    ' A string showing which specific letters have already been guessed
+    ' The integer value showing the number of character matches between guess and target
+    Private Function check_guess(guess As String, target As String, progress As StringBuilder) As Integer
+        ' Go through each letter of the guess And see which
+        ' letters match up to the target word.
+        ' For each position that matches, update the progress
+        ' to reflect the guess
+        Dim matches As Integer = 0
+        Dim common_letters As String = ""
+
+        For ctr As Integer = 0 To 4
+
+            ' First see if this letter appears anywhere in the target
+            ' And, if so, add it to the common_letters list.
+            If (target.Contains(guess(ctr))) Then
+                common_letters.Append(guess(ctr))
+            End If
+            ' Then see if this specific letter matches the
+            ' same position in the target. And, if so, update
+            ' the progress tracker
+            If (guess(ctr).Equals(target(ctr))) Then
+                progress(ctr) = guess(ctr)
+                matches += 1
+            End If
+        Next
+
+        Console.WriteLine($"There were {matches} matches and the common letters were... {common_letters}")
+        Console.WriteLine($"From the exact letter matches, you know......... {progress}")
+        Return matches
+    End Function
+
+    ' 
+    ' This plays one full game.
+    ' 
+    Private Sub play_game()
+        Dim guess_word As String, target_word As String
+        Dim guess_progress As StringBuilder = New StringBuilder("-----")
+        Dim rand As Random = New Random()
+        Dim count As Integer = 0
+
+        Console.WriteLine("You are starting a new game...")
+
+        ' Randomly select a word from the list of words
+        target_word = words(rand.Next(words.Length))
+
+        ' Just run as an infinite loop until one of the
+        ' endgame conditions are met.
+        While (True)
+            ' Ask the user for their guess
+            guess_word = get_guess()
+            count += 1
+
+            ' If they enter a question mark, then tell them
+            ' the answer and quit the game
+            If (guess_word.Equals("?")) Then
+                Console.WriteLine($"The secret word is {target_word}")
+                Return
+            End If
+
+            ' Otherwise, check the guess against the target - noting progress
+            If (check_guess(guess_word, target_word, guess_progress) = 0) Then
+                Console.WriteLine("If you give up, type '?' for your next guess.")
+            End If
+
+            ' Once they've guess the word, end the game.
+            If (guess_progress.Equals(guess_word)) Then
+                Console.WriteLine($"You have guessed the word.  It took {count} guesses!")
+                Return
+            End If
+
+        End While
+    End Sub
+
+    ' 
+    ' The main entry point for the class - just keeps
+    ' playing the game until the user decides to quit.
+    ' 
+    Public Sub play()
+        intro()
+
+        Dim keep_playing As Boolean = True
+
+        While (keep_playing)
+            play_game()
+            Console.WriteLine($"{Environment.NewLine}Want to play again? ")
+            keep_playing = Console.ReadLine().StartsWith("y", StringComparison.CurrentCultureIgnoreCase)
+        End While
+
+    End Sub
+End Module
+
+Module Program
+    Sub Main(args As String())
+        Word.play()
+    End Sub
+End Module
diff --git a/00_Alternate_Languages/96_Word/vbnet/README.md b/00_Alternate_Languages/96_Word/vbnet/README.md
new file mode 100644
index 00000000..98b702c7
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/vbnet/README.md
@@ -0,0 +1,3 @@
+Original BASIC source [downloaded from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Visual Basic .NET](https://en.wikipedia.org/wiki/Visual_Basic_.NET)
diff --git a/00_Alternate_Languages/96_Word/vbnet/word.sln b/00_Alternate_Languages/96_Word/vbnet/word.sln
new file mode 100644
index 00000000..73674ee4
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/vbnet/word.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31321.278
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "Word", "Word.vbproj", "{F0D2422C-983F-4DF3-9D17-D2480839DF07}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{F0D2422C-983F-4DF3-9D17-D2480839DF07}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F0D2422C-983F-4DF3-9D17-D2480839DF07}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F0D2422C-983F-4DF3-9D17-D2480839DF07}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F0D2422C-983F-4DF3-9D17-D2480839DF07}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {179D39EB-C497-4336-B795-49CC799929BB}
+	EndGlobalSection
+EndGlobal
diff --git a/00_Alternate_Languages/96_Word/vbnet/word.vbproj b/00_Alternate_Languages/96_Word/vbnet/word.vbproj
new file mode 100644
index 00000000..f80094e4
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/vbnet/word.vbproj
@@ -0,0 +1,10 @@
+
+
+  
+    Exe
+    Word
+    netcoreapp3.1
+    16.9
+  
+
+
diff --git a/00_Alternate_Languages/96_Word/word.bas b/00_Alternate_Languages/96_Word/word.bas
new file mode 100644
index 00000000..46e69061
--- /dev/null
+++ b/00_Alternate_Languages/96_Word/word.bas
@@ -0,0 +1,65 @@
+2 PRINT TAB(33);"WORD"
+3 PRINT TAB(15);"CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
+4 PRINT: PRINT: PRINT
+5 DIM S(7),A(7),L(7),D(7),P(7)
+10 PRINT "I AM THINKING OF A WORD -- YOU GUESS IT.  I WILL GIVE YOU"
+15 PRINT "CLUES TO HELP YOU GET IT.  GOOD LUCK!!": PRINT: PRINT
+20 REM
+30 PRINT: PRINT: PRINT "YOU ARE STARTING A NEW GAME..."
+35 RESTORE
+40 READ N
+50 C=INT(RND(1)*N+1)
+60 FOR I=1 TO C
+70 READ S$
+80 NEXT I
+90 G=0
+95 S(0)=LEN(S$)
+100 FOR I=1 TO LEN(S$): S(I)=ASC(MID$(S$,I,1)): NEXT I
+110 FOR I=1 TO 5
+120 A(I)=45
+130 NEXT I
+140 FOR J=1 TO 5
+144 P(J)=0
+146 NEXT J
+150 PRINT "GUESS A FIVE LETTER WORD";
+160 INPUT L$
+170 G=G+1
+172 IF S$=L$ THEN 500
+173 FOR I=1 TO 7: P(I)=0: NEXT I
+175 L(0)=LEN(L$)
+180 FOR I=1 TO LEN(L$): L(I)=ASC(MID$(L$,I,1)): NEXT I
+190 IF L(1)=63 THEN 300
+200 IF L(0)<>5 THEN 400
+205 M=0: Q=1
+210 FOR I=1 TO 5
+220 FOR J=1 TO 5
+230 IF S(I)<>L(J) THEN 260
+231 P(Q)=L(J)
+232 Q=Q+1
+233 IF I<>J THEN 250
+240 A(J)=L(J)
+250 M=M+1
+260 NEXT J
+265 NEXT I
+270 A(0)=5
+272 P(0)=M
+275 A$="": FOR I=1 TO A(0): A$=A$+CHR$(A(I)): NEXT I
+277 P$="": FOR I=1 TO P(0): P$=P$+CHR$(P(I)): NEXT I
+280 PRINT "THERE WERE";M;"MATCHES AND THE COMMON LETTERS WERE...";P$
+285 PRINT "FROM THE EXACT LETTER MATCHES, YOU KNOW................";A$
+286 IF A$=S$ THEN 500
+287 IF M>1 THEN 289
+288 PRINT: PRINT "IF YOU GIVE UP, TYPE '?' FOR YOUR NEXT GUESS."
+289 PRINT
+290 GOTO 150
+300 S$="": FOR I=1 TO 7: S$=S$+CHR$(S(I)): NEXT I
+310 PRINT "THE SECRET WORD IS ";S$: PRINT
+320 GOTO 30
+400 PRINT "YOU MUST GUESS A 5 LETTER WORD.  START AGAIN."
+410 PRINT: G=G-1: GOTO 150
+500 PRINT "YOU HAVE GUESSED THE WORD.  IT TOOK";G;"GUESSES!": PRINT
+510 INPUT "WANT TO PLAY AGAIN";Q$
+520 IF Q$="YES" THEN 30
+530 DATA 12,"DINKY","SMOKE","WATER","GRASS","TRAIN","MIGHT","FIRST"
+540 DATA "CANDY","CHAMP","WOULD","CLUMP","DOPEY"
+999 END
diff --git a/02_Amazing/kotlin/README.md b/02_Amazing/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/02_Amazing/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/02_Amazing/lua/README.md b/02_Amazing/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/02_Amazing/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/03_Animal/lua/README.md b/03_Animal/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/03_Animal/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/04_Awari/kotlin/README.md b/04_Awari/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/04_Awari/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/04_Awari/lua/README.md b/04_Awari/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/04_Awari/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/05_Bagels/kotlin/README.md b/05_Bagels/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/05_Bagels/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/05_Bagels/lua/README.md b/05_Bagels/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/05_Bagels/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/06_Banner/kotlin/README.md b/06_Banner/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/06_Banner/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/06_Banner/lua/README.md b/06_Banner/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/06_Banner/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/07_Basketball/kotlin/README.md b/07_Basketball/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/07_Basketball/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/07_Basketball/lua/README.md b/07_Basketball/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/07_Basketball/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/08_Batnum/kotlin/README.md b/08_Batnum/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/08_Batnum/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/08_Batnum/lua/README.md b/08_Batnum/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/08_Batnum/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/09_Battle/kotlin/README.md b/09_Battle/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/09_Battle/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/09_Battle/lua/README.md b/09_Battle/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/09_Battle/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/10_Blackjack/kotlin/README.md b/10_Blackjack/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/10_Blackjack/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/10_Blackjack/lua/README.md b/10_Blackjack/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/10_Blackjack/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/11_Bombardment/kotlin/README.md b/11_Bombardment/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/11_Bombardment/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/11_Bombardment/lua/README.md b/11_Bombardment/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/11_Bombardment/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/12_Bombs_Away/kotlin/README.md b/12_Bombs_Away/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/12_Bombs_Away/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/12_Bombs_Away/lua/README.md b/12_Bombs_Away/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/12_Bombs_Away/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/13_Bounce/kotlin/README.md b/13_Bounce/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/13_Bounce/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/13_Bounce/lua/README.md b/13_Bounce/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/13_Bounce/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/14_Bowling/kotlin/README.md b/14_Bowling/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/14_Bowling/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/14_Bowling/lua/README.md b/14_Bowling/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/14_Bowling/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/15_Boxing/kotlin/README.md b/15_Boxing/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/15_Boxing/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/15_Boxing/lua/README.md b/15_Boxing/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/15_Boxing/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/16_Bug/kotlin/README.md b/16_Bug/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/16_Bug/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/16_Bug/lua/README.md b/16_Bug/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/16_Bug/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/17_Bullfight/kotlin/README.md b/17_Bullfight/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/17_Bullfight/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/17_Bullfight/lua/README.md b/17_Bullfight/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/17_Bullfight/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/18_Bullseye/kotlin/README.md b/18_Bullseye/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/18_Bullseye/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/18_Bullseye/lua/README.md b/18_Bullseye/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/18_Bullseye/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/19_Bunny/kotlin/README.md b/19_Bunny/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/19_Bunny/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/19_Bunny/lua/README.md b/19_Bunny/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/19_Bunny/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/20_Buzzword/kotlin/README.md b/20_Buzzword/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/20_Buzzword/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/20_Buzzword/lua/README.md b/20_Buzzword/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/20_Buzzword/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/21_Calendar/kotlin/README.md b/21_Calendar/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/21_Calendar/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/21_Calendar/lua/README.md b/21_Calendar/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/21_Calendar/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/22_Change/kotlin/README.md b/22_Change/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/22_Change/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/22_Change/lua/README.md b/22_Change/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/22_Change/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/23_Checkers/kotlin/README.md b/23_Checkers/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/23_Checkers/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/23_Checkers/lua/README.md b/23_Checkers/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/23_Checkers/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/24_Chemist/kotlin/README.md b/24_Chemist/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/24_Chemist/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/24_Chemist/lua/README.md b/24_Chemist/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/24_Chemist/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/25_Chief/kotlin/README.md b/25_Chief/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/25_Chief/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/25_Chief/lua/README.md b/25_Chief/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/25_Chief/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/26_Chomp/kotlin/README.md b/26_Chomp/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/26_Chomp/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/26_Chomp/lua/README.md b/26_Chomp/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/26_Chomp/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/27_Civil_War/kotlin/README.md b/27_Civil_War/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/27_Civil_War/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/27_Civil_War/lua/README.md b/27_Civil_War/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/27_Civil_War/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/28_Combat/kotlin/README.md b/28_Combat/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/28_Combat/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/28_Combat/lua/README.md b/28_Combat/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/28_Combat/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/29_Craps/kotlin/README.md b/29_Craps/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/29_Craps/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/29_Craps/lua/README.md b/29_Craps/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/29_Craps/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/30_Cube/kotlin/README.md b/30_Cube/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/30_Cube/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/30_Cube/lua/README.md b/30_Cube/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/30_Cube/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/31_Depth_Charge/kotlin/README.md b/31_Depth_Charge/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/31_Depth_Charge/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/31_Depth_Charge/lua/README.md b/31_Depth_Charge/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/31_Depth_Charge/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/32_Diamond/kotlin/README.md b/32_Diamond/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/32_Diamond/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/32_Diamond/lua/README.md b/32_Diamond/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/32_Diamond/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/33_Dice/kotlin/README.md b/33_Dice/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/33_Dice/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/33_Dice/lua/README.md b/33_Dice/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/33_Dice/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/34_Digits/kotlin/README.md b/34_Digits/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/34_Digits/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/34_Digits/lua/README.md b/34_Digits/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/34_Digits/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/35_Even_Wins/kotlin/README.md b/35_Even_Wins/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/35_Even_Wins/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/35_Even_Wins/lua/README.md b/35_Even_Wins/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/35_Even_Wins/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/36_Flip_Flop/kotlin/README.md b/36_Flip_Flop/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/36_Flip_Flop/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/36_Flip_Flop/lua/README.md b/36_Flip_Flop/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/36_Flip_Flop/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/37_Football/kotlin/README.md b/37_Football/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/37_Football/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/37_Football/lua/README.md b/37_Football/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/37_Football/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/38_Fur_Trader/kotlin/README.md b/38_Fur_Trader/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/38_Fur_Trader/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/38_Fur_Trader/lua/README.md b/38_Fur_Trader/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/38_Fur_Trader/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/39_Golf/kotlin/README.md b/39_Golf/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/39_Golf/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/39_Golf/lua/README.md b/39_Golf/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/39_Golf/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/40_Gomoko/kotlin/README.md b/40_Gomoko/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/40_Gomoko/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/40_Gomoko/lua/README.md b/40_Gomoko/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/40_Gomoko/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/41_Guess/kotlin/README.md b/41_Guess/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/41_Guess/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/41_Guess/lua/README.md b/41_Guess/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/41_Guess/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/42_Gunner/kotlin/README.md b/42_Gunner/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/42_Gunner/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/42_Gunner/lua/README.md b/42_Gunner/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/42_Gunner/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/43_Hammurabi/kotlin/README.md b/43_Hammurabi/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/43_Hammurabi/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/43_Hammurabi/lua/README.md b/43_Hammurabi/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/43_Hammurabi/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/44_Hangman/kotlin/README.md b/44_Hangman/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/44_Hangman/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/44_Hangman/lua/README.md b/44_Hangman/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/44_Hangman/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/45_Hello/kotlin/README.md b/45_Hello/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/45_Hello/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/45_Hello/lua/README.md b/45_Hello/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/45_Hello/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/46_Hexapawn/kotlin/README.md b/46_Hexapawn/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/46_Hexapawn/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/46_Hexapawn/lua/README.md b/46_Hexapawn/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/46_Hexapawn/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/47_Hi-Lo/lua/README.md b/47_Hi-Lo/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/47_Hi-Lo/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/48_High_IQ/kotlin/README.md b/48_High_IQ/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/48_High_IQ/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/48_High_IQ/lua/README.md b/48_High_IQ/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/48_High_IQ/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/49_Hockey/kotlin/README.md b/49_Hockey/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/49_Hockey/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/49_Hockey/lua/README.md b/49_Hockey/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/49_Hockey/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/50_Horserace/kotlin/README.md b/50_Horserace/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/50_Horserace/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/50_Horserace/lua/README.md b/50_Horserace/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/50_Horserace/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/51_Hurkle/kotlin/README.md b/51_Hurkle/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/51_Hurkle/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/51_Hurkle/lua/README.md b/51_Hurkle/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/51_Hurkle/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/52_Kinema/kotlin/README.md b/52_Kinema/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/52_Kinema/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/52_Kinema/lua/README.md b/52_Kinema/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/52_Kinema/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/53_King/kotlin/README.md b/53_King/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/53_King/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/53_King/lua/README.md b/53_King/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/53_King/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/54_Letter/kotlin/README.md b/54_Letter/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/54_Letter/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/54_Letter/lua/README.md b/54_Letter/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/54_Letter/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/55_Life/kotlin/README.md b/55_Life/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/55_Life/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/55_Life/lua/README.md b/55_Life/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/55_Life/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/56_Life_for_Two/kotlin/README.md b/56_Life_for_Two/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/56_Life_for_Two/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/56_Life_for_Two/lua/README.md b/56_Life_for_Two/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/56_Life_for_Two/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/57_Literature_Quiz/kotlin/README.md b/57_Literature_Quiz/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/57_Literature_Quiz/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/57_Literature_Quiz/lua/README.md b/57_Literature_Quiz/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/57_Literature_Quiz/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/58_Love/kotlin/README.md b/58_Love/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/58_Love/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/58_Love/lua/README.md b/58_Love/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/58_Love/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/59_Lunar_LEM_Rocket/kotlin/README.md b/59_Lunar_LEM_Rocket/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/59_Lunar_LEM_Rocket/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/59_Lunar_LEM_Rocket/lua/README.md b/59_Lunar_LEM_Rocket/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/59_Lunar_LEM_Rocket/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/60_Mastermind/kotlin/README.md b/60_Mastermind/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/60_Mastermind/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/60_Mastermind/lua/README.md b/60_Mastermind/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/60_Mastermind/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/61_Math_Dice/kotlin/README.md b/61_Math_Dice/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/61_Math_Dice/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/61_Math_Dice/lua/README.md b/61_Math_Dice/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/61_Math_Dice/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/62_Mugwump/kotlin/README.md b/62_Mugwump/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/62_Mugwump/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/62_Mugwump/lua/README.md b/62_Mugwump/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/62_Mugwump/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/63_Name/kotlin/README.md b/63_Name/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/63_Name/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/63_Name/lua/README.md b/63_Name/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/63_Name/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/64_Nicomachus/kotlin/README.md b/64_Nicomachus/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/64_Nicomachus/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/64_Nicomachus/lua/README.md b/64_Nicomachus/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/64_Nicomachus/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/65_Nim/kotlin/README.md b/65_Nim/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/65_Nim/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/65_Nim/lua/README.md b/65_Nim/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/65_Nim/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/66_Number/kotlin/README.md b/66_Number/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/66_Number/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/66_Number/lua/README.md b/66_Number/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/66_Number/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/67_One_Check/kotlin/README.md b/67_One_Check/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/67_One_Check/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/67_One_Check/lua/README.md b/67_One_Check/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/67_One_Check/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/68_Orbit/kotlin/README.md b/68_Orbit/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/68_Orbit/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/68_Orbit/lua/README.md b/68_Orbit/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/68_Orbit/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/69_Pizza/kotlin/README.md b/69_Pizza/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/69_Pizza/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/69_Pizza/lua/README.md b/69_Pizza/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/69_Pizza/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/70_Poetry/kotlin/README.md b/70_Poetry/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/70_Poetry/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/70_Poetry/lua/README.md b/70_Poetry/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/70_Poetry/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/71_Poker/kotlin/README.md b/71_Poker/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/71_Poker/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/71_Poker/lua/README.md b/71_Poker/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/71_Poker/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/72_Queen/kotlin/README.md b/72_Queen/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/72_Queen/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/72_Queen/lua/README.md b/72_Queen/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/72_Queen/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/73_Reverse/kotlin/README.md b/73_Reverse/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/73_Reverse/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/73_Reverse/lua/README.md b/73_Reverse/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/73_Reverse/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/74_Rock_Scissors_Paper/kotlin/README.md b/74_Rock_Scissors_Paper/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/74_Rock_Scissors_Paper/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/74_Rock_Scissors_Paper/lua/README.md b/74_Rock_Scissors_Paper/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/74_Rock_Scissors_Paper/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/75_Roulette/kotlin/README.md b/75_Roulette/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/75_Roulette/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/75_Roulette/lua/README.md b/75_Roulette/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/75_Roulette/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/76_Russian_Roulette/kotlin/README.md b/76_Russian_Roulette/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/76_Russian_Roulette/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/76_Russian_Roulette/lua/README.md b/76_Russian_Roulette/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/76_Russian_Roulette/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/77_Salvo/kotlin/README.md b/77_Salvo/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/77_Salvo/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/77_Salvo/lua/README.md b/77_Salvo/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/77_Salvo/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/78_Sine_Wave/kotlin/README.md b/78_Sine_Wave/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/78_Sine_Wave/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/78_Sine_Wave/lua/README.md b/78_Sine_Wave/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/78_Sine_Wave/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/78_Sine_Wave/pascal/README.md b/78_Sine_Wave/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/78_Sine_Wave/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/79_Slalom/kotlin/README.md b/79_Slalom/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/79_Slalom/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/79_Slalom/lua/README.md b/79_Slalom/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/79_Slalom/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/79_Slalom/pascal/README.md b/79_Slalom/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/79_Slalom/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/80_Slots/kotlin/README.md b/80_Slots/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/80_Slots/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/80_Slots/lua/README.md b/80_Slots/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/80_Slots/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/80_Slots/pascal/README.md b/80_Slots/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/80_Slots/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/81_Splat/kotlin/README.md b/81_Splat/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/81_Splat/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/81_Splat/lua/README.md b/81_Splat/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/81_Splat/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/81_Splat/pascal/README.md b/81_Splat/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/81_Splat/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/82_Stars/kotlin/README.md b/82_Stars/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/82_Stars/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/82_Stars/lua/README.md b/82_Stars/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/82_Stars/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/82_Stars/pascal/README.md b/82_Stars/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/82_Stars/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/83_Stock_Market/kotlin/README.md b/83_Stock_Market/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/83_Stock_Market/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/83_Stock_Market/lua/README.md b/83_Stock_Market/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/83_Stock_Market/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/83_Stock_Market/pascal/README.md b/83_Stock_Market/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/83_Stock_Market/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/84_Super_Star_Trek/kotlin/README.md b/84_Super_Star_Trek/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/84_Super_Star_Trek/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/84_Super_Star_Trek/lua/README.md b/84_Super_Star_Trek/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/84_Super_Star_Trek/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/84_Super_Star_Trek/pascal/README.md b/84_Super_Star_Trek/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/84_Super_Star_Trek/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/85_Synonym/lua/README.md b/85_Synonym/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/85_Synonym/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/85_Synonym/pascal/README.md b/85_Synonym/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/85_Synonym/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/86_Target/kotlin/README.md b/86_Target/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/86_Target/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/86_Target/lua/README.md b/86_Target/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/86_Target/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/86_Target/pascal/README.md b/86_Target/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/86_Target/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/87_3-D_Plot/kotlin/README.md b/87_3-D_Plot/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/87_3-D_Plot/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/87_3-D_Plot/lua/README.md b/87_3-D_Plot/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/87_3-D_Plot/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/87_3-D_Plot/pascal/README.md b/87_3-D_Plot/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/87_3-D_Plot/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/88_3-D_Tic-Tac-Toe/kotlin/README.md b/88_3-D_Tic-Tac-Toe/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/88_3-D_Tic-Tac-Toe/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/88_3-D_Tic-Tac-Toe/lua/README.md b/88_3-D_Tic-Tac-Toe/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/88_3-D_Tic-Tac-Toe/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/88_3-D_Tic-Tac-Toe/pascal/README.md b/88_3-D_Tic-Tac-Toe/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/88_3-D_Tic-Tac-Toe/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/89_Tic-Tac-Toe/go/README.md b/89_Tic-Tac-Toe/go/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/89_Tic-Tac-Toe/go/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/89_Tic-Tac-Toe/lua/README.md b/89_Tic-Tac-Toe/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/89_Tic-Tac-Toe/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/89_Tic-Tac-Toe/pascal/README.md b/89_Tic-Tac-Toe/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/89_Tic-Tac-Toe/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/90_Tower/kotlin/README.md b/90_Tower/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/90_Tower/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/90_Tower/lua/README.md b/90_Tower/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/90_Tower/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/90_Tower/pascal/README.md b/90_Tower/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/90_Tower/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/91_Train/kotlin/README.md b/91_Train/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/91_Train/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/91_Train/lua/README.md b/91_Train/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/91_Train/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/91_Train/pascal/README.md b/91_Train/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/91_Train/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/92_Trap/kotlin/README.md b/92_Trap/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/92_Trap/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/92_Trap/lua/README.md b/92_Trap/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/92_Trap/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/92_Trap/pascal/README.md b/92_Trap/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/92_Trap/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/93_23_Matches/kotlin/README.md b/93_23_Matches/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/93_23_Matches/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/93_23_Matches/lua/README.md b/93_23_Matches/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/93_23_Matches/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/93_23_Matches/pascal/README.md b/93_23_Matches/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/93_23_Matches/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/94_War/lua/README.md b/94_War/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/94_War/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/94_War/pascal/README.md b/94_War/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/94_War/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/95_Weekday/kotlin/README.md b/95_Weekday/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/95_Weekday/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/95_Weekday/lua/README.md b/95_Weekday/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/95_Weekday/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/95_Weekday/pascal/README.md b/95_Weekday/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/95_Weekday/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/96_Word/kotlin/README.md b/96_Word/kotlin/README.md
new file mode 100644
index 00000000..f43a5b70
--- /dev/null
+++ b/96_Word/kotlin/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Kotlin](https://kotlinlang.org/)
diff --git a/96_Word/lua/README.md b/96_Word/lua/README.md
new file mode 100644
index 00000000..c063f42f
--- /dev/null
+++ b/96_Word/lua/README.md
@@ -0,0 +1,3 @@
+Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
+
+Conversion to [Lua](https://www.lua.org/)
diff --git a/96_Word/pascal/README.md b/96_Word/pascal/README.md
deleted file mode 100644
index aa1b3ae5..00000000
--- a/96_Word/pascal/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
-
-Conversion to [Pascal](https://en.wikipedia.org/wiki/Pascal_(programming_language))
diff --git a/Sudoku/pascal/sudoku.pas b/Sudoku/pascal/sudoku.pas
deleted file mode 100644
index c5a61762..00000000
--- a/Sudoku/pascal/sudoku.pas
+++ /dev/null
@@ -1,382 +0,0 @@
-program sudoku;
-uses crt,strings;
-type
-short=1..9;
-var
-j,n,l,o,p,q,limk1,limk2,limi1,limi2:short;
-ch:string[1];
-x,y,no1,no2,i,s,k:integer;
-b,t,v:boolean;
-key,yn:char;
-M:array [1..9,1..9] of string[1];
-xy:array [1..2,1..81] of integer;
-cht:array [1..6] of string[4];
-label
-theend,randoms,repeatative1,repeatative2,saisir,game;
-begin
-
-clrscr;
-gotoxy(11,11);
-write('*Welcome to Sudoku Game!*');
-gotoxy(11,12);
-write('(Press ENTER to start...)');
-gotoxy(56,11);
-write('�������');
-gotoxy(56,12);
-write('�     �');
-gotoxy(56,13);
-write('�     �');
-gotoxy(56,14);
-write('�������');
-gotoxy(9,24);
-write('All rights reserved to CrYmFoX 2016.');
-gotoxy(10,22);
-write('Created By Sameur Ben Hmouda.');
-repeat
-gotoxy(59,12);
-yn:=readkey;
-until yn=chr(13);
-
-game:
-
-clrscr;
-
-
-writeln(' _____________________________________________________ ');
-writeln('|     |     |     |     |     |     |     |     |     |');
-writeln('|_____|_____|_____|_____|_____|_____|_____|_____|_____|');
-writeln('|     |     |     |     |     |     |     |     |     |');
-writeln('|_____|_____|_____|_____|_____|_____|_____|_____|_____|');
-writeln('|     |     |     |     |     |     |     |     |     |');
-writeln('|_____|_____|_____|_____|_____|_____|_____|_____|_____|');
-writeln('|     |     |     |     |     |     |     |     |     |');
-writeln('|_____|_____|_____|_____|_____|_____|_____|_____|_____|');
-writeln('|     |     |     |     |     |     |     |     |     |');
-writeln('|_____|_____|_____|_____|_____|_____|_____|_____|_____|');
-writeln('|     |     |     |     |     |     |     |     |     |');
-writeln('|_____|_____|_____|_____|_____|_____|_____|_____|_____|');
-writeln('|     |     |     |     |     |     |     |     |     |');
-writeln('|_____|_____|_____|_____|_____|_____|_____|_____|_____|');
-writeln('|     |     |     |     |     |     |     |     |     |');
-writeln('|_____|_____|_____|_____|_____|_____|_____|_____|_____|');
-writeln('|     |     |     |     |     |     |     |     |     |');
-writeln('|_____|_____|_____|_____|_____|_____|_____|_____|_____|');
-
-gotoxy(60,3);
-write('+Instructions+');
-gotoxy(57,5);
-write('*Keys to move:');
-gotoxy(58,6);
-write('Up=Z / Down=S / Left=Q');
-gotoxy(58,7);
-write('/ Right=D.');
-gotoxy(57,9);
-write('*Enter numbers from');
-gotoxy(58,10);
-write('1 to 9 and press');
-gotoxy(58,11);
-write('"Space" to erase.');
-gotoxy(57,13);
-write('-----------------------');
-gotoxy(57,15);
-write('*Press "P" to exit.');
-gotoxy(57,17);
-write('-----------------------');
-gotoxy(63,19);
-write('Enjoy! ^-^');
-
-repeatative2:
-for k:=1 to 9 do
-for i:=1 to 9 do
-M[i,k]:=' ';
-
-randomize;
-for k:=1 to 9 do
-begin
-if k in [1..3] then
-begin
-limk1:=1;
-limk2:=3;
-end
-else if k in [4..6] then
-begin
-limk1:=4;
-limk2:=6;
-end
-else
-begin
-limk1:=7;
-limk2:=9
-end;
-
-no2:=0;
-repeatative1:
-no2:=no2+1;
-for i:=1 to 9 do
-begin
-if i in [1..3] then
-begin
-limi1:=1;
-limi2:=3;
-end
-else if i in [4..6] then
-begin
-limi1:=4;
-limi2:=6;
-end
-else
-begin
-limi1:=7;
-limi2:=9
-end;
-
-no1:=0;
-randoms:
-no1:=no1+1;
-str(random(9)+1,ch);
-b:=true;
-for j:=1 to 9 do
-b:=b and (ch <> M[j,k]);
-for l:=1 to 9 do
-b:=b and (ch <> M[i,l]);
-for p:=limk1 to limk2 do
-for q:=limi1 to limi2 do
-b:=b and (ch <> M[q,p]);
-if b=true then
-M[i,k]:=ch
-else
-begin
-if no1=100 then
-begin
-for o:=1 to 9 do
-M[o,k]:=' ';
-if no2 <> 100 then
-goto repeatative1
-else
-goto repeatative2
-end;
-goto randoms
-end;
-end;
-end;
-
-for i:=1 to 38 do
-begin
-limi1:=random(9)+1;
-limi2:=random(9)+1;
-M[limi1,limi2]:=' ';
-end;
-
-
-x:=4;
-for k:=1 to 9 do
-begin
-y:=2;
-for i:=1 to 9 do
-begin
-gotoxy(x,y);
-write(M[i,k]);
-y:=y+2
-end;
-x:=x+6
-end;
-
-s:=0;
-for k:=1 to 9 do
-for i:=1 to 9 do
-if M[i,k] <> ' ' then
-begin
-s:=s+1;
-xy[1,s]:=(k-1)*6+4;
-xy[2,s]:=(i-1)*2+2;
-end;
-
-
-x:=28;
-y:=10;
-gotoxy(x,y);
-saisir:
-
-key:=readkey;
-case key of
-'z' : begin
-gotoxy(2,22);
-write('                                                   ');
-y:=y-2
-end;
-'s' : begin
-gotoxy(2,22);
-write('                                                   ');
-y:=y+2
-end;
-'d' : begin
-gotoxy(2,22);
-write('                                                   ');
-x:=x+6
-end;
-'q' : begin
-gotoxy(2,22);
-write('                                                   ');
-x:=x-6
-end;
-'p' : goto TheEnd;
-' ' : begin
-gotoxy(2,22);
-write('                                                   ');
-
-b:=false;
-for k:=1 to 81 do
-begin
-str(xy[1,k],cht[1]);
-str(xy[2,k],cht[2]);
-cht[3]:=concat(cht[1],cht[2]);
-str(x,cht[4]);
-str(y,cht[5]);
-cht[6]:=concat(cht[4],cht[5]);
-b:=b or (cht[3]=cht[6]);
-end;
-if b=false then
-begin
-M[((y-2) div 2)+1,((x-4) div 6)+1]:=key;
-gotoxy(x,y);
-write(' ');
-gotoxy(x,y);
-end;
-end;
-'1' .. '9' : begin
-gotoxy(2,22);
-write('                                                   ');
-b:=false;
-for k:=1 to 81 do
-begin
-str(xy[1,k],cht[1]);
-str(xy[2,k],cht[2]);
-cht[3]:=concat(cht[1],cht[2]);
-str(x,cht[4]);
-str(y,cht[5]);
-cht[6]:=concat(cht[4],cht[5]);
-b:=b or (cht[3]=cht[6]);
-end;
-if ((x-4) div 6)+1 in [1..3] then
-begin
-limk1:=1;
-limk2:=3;
-end
-else if ((x-4) div 6)+1 in [4..6] then
-begin
-limk1:=4;
-limk2:=6;
-end
-else
-begin
-limk1:=7;
-limk2:=9
-end;
-if ((y-2) div 2)+1 in [1..3] then
-begin
-limi1:=1;
-limi2:=3;
-end
-else if ((y-2) div 2)+1 in [4..6] then
-begin
-limi1:=4;
-limi2:=6;
-end
-else
-begin
-limi1:=7;
-limi2:=9
-end;
-t:=true;
-for j:=1 to 9 do
-t:=t and (key <> M[j,((x-4) div 6)+1]);
-for l:=1 to 9 do
-t:=t and (key <> M[((y-2) div 2)+1,l]);
-for s:=limk1 to limk2 do
-for o:=limi1 to limi2 do
-t:=t and (key <> M[o,s]);
-
-
-if (b=false) and (t=true) then
-begin
-M[((y-2) div 2)+1,((x-4) div 6)+1]:=key;
-gotoxy(x,y);
-write(key);
-gotoxy(x,y);
-end;
-if (b=false) and (t=false) then
-if key=M[((y-2) div 2)+1,((x-4) div 6)+1] then
-begin
-gotoxy(x,y);
-gotoxy(2,22);
-write('#You already entered this number!#');
-gotoxy(x,y);
-end
-else
-begin
-gotoxy(x,y);
-gotoxy(2,22);
-write('#The number you entered is not correct, try again#');
-gotoxy(x,y);
-end;
-end;
-end;
-
-for i:=1 to 6 do
-delete(cht[i],1,length(cht[i]));
-
-case y of
-0 : y:=2;
-20 : y:=18;
-end;
-case x of
--2 : x:=4;
-58 : x:=52;
-end;
-
-gotoxy(x,y);
-
-v:=true;
-for k:=1 to 9 do
-for i:=1 to 9 do
-v:=v and (M[i,k] <> ' ');
-
-if v=false then
-goto saisir
-else
-begin
-clrscr;
-gotoxy(17,11);
-write('Excellent! You have solved the puzzle!');
-gotoxy(17,13);
-write('Would you like to play again? (Y/N)... < >');
-repeat
-gotoxy(57,13);
-yn:=readkey;
-until (upcase(yn)='Y') or (upcase(yn)='N');
-write(yn);
-if upcase(yn)='Y' then
-goto game
-else
-begin
-gotoxy(15,22);
-write('You chose to quit the game, please press ENTER...');
-repeat
-gotoxy(64,22);
-yn:=readkey;
-until yn=chr(13);
-end;
-end;
-
-
-
-TheEnd:
-clrscr;
-gotoxy(20,16);
-write('The game is over, please press ENTER... ');
-repeat
-gotoxy(59,16);
-yn:=readkey;
-until yn=chr(13);
-
-end.