diff --git a/01 Acey Ducey/perl/aceyducey.pl b/01 Acey Ducey/perl/aceyducey.pl new file mode 100644 index 00000000..e2de13df --- /dev/null +++ b/01 Acey Ducey/perl/aceyducey.pl @@ -0,0 +1,174 @@ +#!/usr/bin/perl + +use strict; +use warnings; + +# The List::Util module is part of the core Perl distribution. Using this +# means we don't need to re-invent the wheel and create a way to shuffle +# a list. +use List::Util qw(shuffle); + +# Rather than put in a number of print (or say) statements here, we use a +# "here document". This is very useful for long strings of text. In this +# case, everything between the end of the "print" line and the line with +# "END_INSTRUCTIONS" on it will be printed verbatim. +print << 'END_INSTRUCTIONS'; + +Acey-Ducey +Adapted from Creative Computing, Morristown, New Jersey + + +Acey-Ducey is played as follows. The dealer (computer) deals two cards face up. +You have an option to bet or not bet, depending on whether or not you feel that +the next card drawn will have a value between the first two. Aces are low. + +Bets must be in whole-dollar amounts only. + +If you do not want to bet, input a 0. If you want to quit, input a -1. + +END_INSTRUCTIONS + +my @cards = (1 .. 13); # That is, Ace through King. +my $keepPlaying = 1; + +GAME: +while ($keepPlaying) +{ + my $playerBalance = 100; # The player starts with $100 + + HAND: + while (1) + { + print "\nYou now have $playerBalance dollars.\n\n"; + + # We'll create a new array that is a shuffled version of the deck. + my @shuffledDeck = shuffle(@cards); + + # Then, by taking the two "top cards" off the deck, we're guaranteed + # that those will be unique. This way we don't have to keep drawing + # if we get, say, two queens. We sort them as we pull them to make + # sure that the first card is lower than the second one. + my ($firstCard, $secondCard) = sort { $a <=> $b } @shuffledDeck[ 0 .. 1 ]; + + print "I drew ", nameOfCard($firstCard), " and ", nameOfCard($secondCard), ".\n"; + + my $bet = getValidBet($playerBalance); + if ($bet == 0) + { + print "Chicken!\n\n"; + next HAND; + } + + if ($bet < 0) + { + last GAME; + } + + # Now we re-shuffle the whole deck again and choose a third card. + # (Note: This is how the odds get stacked in favor of the dealer since + # the third card can be exactly the same as the first or second.) + @shuffledDeck = shuffle(@cards); + my $thirdCard = $shuffledDeck[0]; + + print "I drew ", nameOfCard($thirdCard), "!\n"; + + if (($firstCard < $thirdCard) && ($thirdCard < $secondCard)) + { + print "You win!\n\n"; + $playerBalance += $bet; + } + else + { + print "You lose!\n\n"; + $playerBalance -= $bet; + } + + if ($playerBalance <= 0) + { + print "Sorry, buddy, you blew your wad!\n\n"; + last HAND; + } + } + + $keepPlaying = promptUserToKeepPlaying(); +} + +print "Thanks for playing!\n"; + +############### +sub getValidBet +{ + my $maxBet = shift; + + print "\nWhat's your bet? "; + + my $input = ; + chomp $input; + + # This regular expression will validate that the player entered an integer. + # The !~ match operate *negates* the match, so if the player did NOT enter + # an integer, they'll be given an error and prompted again. + if ($input !~ /^ # Match the beginning of the string + [+-]? # Optional plus or minus... + \d+ # followed by one more more digits... + $ # and then the end of the string + /x # The x modifier ignores whitespace in this regex... + ) + { + print "Sorry, numbers only!\n"; + $input = getValidBet($maxBet); + } + + if ($input > $maxBet) + { + print "Sorry, my friend, you can't bet more money than you have.\n"; + print "You only have $maxBet dollars to spend!\n"; + $input = getValidBet($maxBet); + } + + if ($input != int($input)) + { + print "Sorry, you must bet in whole dollars. No change!\n"; + $input = getValidBet($maxBet); + } + + return $input; +} + +# Since arrays in Perl are 0-based, we need to convert the value that we drew from +# the array to its proper position in the deck. +sub nameOfCard +{ + my $value = shift; + + # Note that the Joker isn't used in this game, but since arrays in Perl are + # 0-based, it's useful to have something there to represent the "0th" + # position. This way the rest of the elements match their expected values + # (e.g., element 1 is Ace, element 7 is 7, and element 12 is Queen). + + my @cardlist = qw(Joker Ace 2 3 4 5 6 7 8 9 10 Jack Queen King); + return $cardlist[$value]; +} + +sub promptUserToKeepPlaying +{ + print "Try again (Y/N)? "; + my $input = ; + chomp $input; + + my $keepGoing; + if (uc($input) eq 'Y') + { + $keepGoing = 1; + } + elsif (uc($input) eq 'N') + { + $keepGoing = 0; + } + else + { + $keepGoing = promptUserToKeepPlaying(); + } + + return $keepGoing; +} diff --git a/15 Boxing/java/Basic.java b/15 Boxing/java/Basic.java new file mode 100644 index 00000000..3822e3f3 --- /dev/null +++ b/15 Boxing/java/Basic.java @@ -0,0 +1,45 @@ +import java.util.Scanner; + +/** + * It provide some kind of BASIC language behaviour simulations. + */ +final class Basic { + + public static int randomOf(int base) { + return (int)Math.round(Math.floor(base* Math.random() + 1)); + } + + /** + * The Console "simulate" the message error when input does not match with the expected type. + * Specifically for this game if you enter an String when and int was expected. + */ + public static class Console { + private final Scanner input = new Scanner(System.in); + + public String readLine() { + return input.nextLine(); + } + + public int readInt() { + int ret = -1; + boolean failedInput = true; + do { + boolean b = input.hasNextInt(); + if (b) { + ret = input.nextInt(); + failedInput = false; + } else { + input.next(); // discard read + System.out.print("!NUMBER EXPECTED - RETRY INPUT LINE\n? "); + } + + } while (failedInput); + + return ret; + } + + public void print(String message, Object... args) { + System.out.printf(message, args); + } + } +} \ No newline at end of file diff --git a/15 Boxing/java/Boxing.java b/15 Boxing/java/Boxing.java new file mode 100644 index 00000000..64b20155 --- /dev/null +++ b/15 Boxing/java/Boxing.java @@ -0,0 +1,227 @@ +/** + * Boxing + * + *

+ * Based on the Basic game of BatNum here + * https://github.com/coding-horror/basic-computer-games/tree/main/15%20Boxing + *

+ */ +public class Boxing { + + private static final Basic.Console console = new Basic.Console(); + + private GameSession session; + + public void play() { + showIntro(); + + loadPlayers(); + + console.print("%s'S ADVANTAGE IS %d AND VULNERABILITY IS SECRET.\n", session.getOpponent().getName(), session.getOpponent().getBestPunch().getCode()); + + + for (int roundNro = 1; roundNro <= 3; roundNro++) { + if (session.isOver()) + break; + + session.resetPoints(); + console.print("\nROUND %d BEGINS...%n", roundNro); + + for (int majorPunches = 1; majorPunches <= 7; majorPunches++) { + long i = Basic.randomOf(10); + + if (i > 5) { + boolean stopPunches = opponentPunch(); + if (stopPunches ) break; + } else { + playerPunch(); + } + } + showRoundWinner(roundNro); + } + showWinner(); + } + + private boolean opponentPunch() { + final Punch punch = Punch.random(); + + if (punch == session.getOpponent().getBestPunch()) session.addOpponentPoints(2); + + if (punch == Punch.FULL_SWING) { + console.print("%s TAKES A FULL SWING AND", session.getOpponent().getName()); + long r6 = Basic.randomOf(60); + + if (session.getPlayer().hitVulnerability(Punch.FULL_SWING) || r6 < 30) { + console.print(" POW!!!!! HE HITS HIM RIGHT IN THE FACE!\n"); + if (session.getPoints(session.getOpponent()) > 35) { + + session.setKnocked(); + return true; + } + session.addOpponentPoints(15); + } else { + console.print(" IT'S BLOCKED!\n"); + } + } + + if (punch == Punch.HOOK || punch == Punch.UPPERCUT) { + if (punch == Punch.HOOK) { + console.print("%s GETS %s IN THE JAW (OUCH!)\n", session.getOpponent().getName(), session.getPlayer().getName()); + + session.addOpponentPoints(7); + console.print("....AND AGAIN!\n"); + + session.addOpponentPoints(5); + if (session.getPoints(session.getOpponent()) > 35) { + session.setKnocked(); + return true; + } + console.print("\n"); + + } + console.print("%s IS ATTACKED BY AN UPPERCUT (OH,OH)...\n", session.getPlayer().getName()); + long q4 = Basic.randomOf(200); + if (session.getPlayer().hitVulnerability(Punch.UPPERCUT) || q4 <= 75) { + console.print("AND %s CONNECTS...\n", session.getOpponent().getName()); + + session.addOpponentPoints(8); + } else { + console.print(" BLOCKS AND HITS %s WITH A HOOK.\n", session.getOpponent().getName()); + + session.addPlayerPoints(5); + } + } + else { + console.print("%s JABS AND ", session.getOpponent().getName()); + long z4 = Basic.randomOf(7); + if (session.getPlayer().hitVulnerability(Punch.JAB)) + + session.addOpponentPoints(5); + else if (z4 > 4) { + console.print(" BLOOD SPILLS !!!\n"); + + session.addOpponentPoints(5); + } else { + console.print("IT'S BLOCKED!\n"); + } + } + return true; + } + + private void playerPunch() { + console.print("%s'S PUNCH? ", session.getPlayer().getName()); + final Punch punch = Punch.fromCode(console.readInt()); + + if (punch == session.getPlayer().getBestPunch()) session.addPlayerPoints(2); + + switch (punch) { + case FULL_SWING -> { + console.print("%s SWINGS AND ", session.getPlayer().getName()); + if (session.getOpponent().getBestPunch() == Punch.JAB) { + console.print("HE CONNECTS!\n"); + if (session.getPoints(session.getPlayer()) <= 35) session.addPlayerPoints(15); + } else { + long x3 = Basic.randomOf(30); + if (x3 < 10) { + console.print("HE CONNECTS!\n"); + if (session.getPoints(session.getPlayer()) <= 35) session.addPlayerPoints(15); + } else { + console.print("HE MISSES \n"); + if (session.getPoints(session.getPlayer()) != 1) console.print("\n\n"); + } + } + } + case HOOK -> { + console.print("\n%s GIVES THE HOOK... ", session.getPlayer().getName()); + long h1 = Basic.randomOf(2); + if (session.getOpponent().getBestPunch() == Punch.HOOK) { + + session.addPlayerPoints(7); + } else if (h1 == 1) { + console.print("BUT IT'S BLOCKED!!!!!!!!!!!!!\n"); + } else { + console.print("CONNECTS...\n"); + + session.addPlayerPoints(7); + } + } + case UPPERCUT -> { + console.print("\n%s TRIES AN UPPERCUT ", session.getPlayer().getName()); + long d5 = Basic.randomOf(100); + if (session.getOpponent().getBestPunch() == Punch.UPPERCUT || d5 < 51) { + console.print("AND HE CONNECTS!\n"); + + session.addPlayerPoints(4); + } else { + console.print("AND IT'S BLOCKED (LUCKY BLOCK!)\n"); + } + } + default -> { + console.print("%s JABS AT %s'S HEAD \n", session.getPlayer().getName(), session.getOpponent().getName()); + if (session.getOpponent().getBestPunch() == Punch.JAB) { + + session.addPlayerPoints(3); + } else { + long c = Basic.randomOf(8); + if (c < 4) { + console.print("IT'S BLOCKED.\n"); + } else { + + session.addPlayerPoints(3); + } + } + } + } + } + + private void showRoundWinner(int roundNro) { + if (session.isRoundWinner(session.getPlayer())) { + console.print("\n %s WINS ROUND %d\n", session.getPlayer().getName(), roundNro); + session.addRoundWind(session.getPlayer()); + } else { + console.print("\n %s WINS ROUND %d\n", session.getOpponent().getName(), roundNro); + session.addRoundWind(session.getOpponent()); + } + } + + private void showWinner() { + if (session.isGameWinner(session.getOpponent())) { + console.print("%s WINS (NICE GOING, " + session.getOpponent().getName() + ").", session.getOpponent().getName()); + } else if (session.isGameWinner(session.getPlayer())) { + console.print("%s AMAZINGLY WINS!!", session.getPlayer().getName()); + } else if (session.isPlayerKnocked()) { + console.print("%s IS KNOCKED COLD AND %s IS THE WINNER AND CHAMP!", session.getPlayer().getName(), session.getOpponent().getName()); + } else { + console.print("%s IS KNOCKED COLD AND %s IS THE WINNER AND CHAMP!", session.getOpponent().getName(), session.getPlayer().getName()); + } + + console.print("\n\nAND NOW GOODBYE FROM THE OLYMPIC ARENA.\n"); + } + + private void loadPlayers() { + console.print("WHAT IS YOUR OPPONENT'S NAME? "); + final String opponentName = console.readLine(); + + console.print("INPUT YOUR MAN'S NAME? "); + final String playerName = console.readLine(); + + console.print("DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\n"); + console.print("WHAT IS YOUR MANS BEST? "); + + final int b = console.readInt(); + + console.print("WHAT IS HIS VULNERABILITY? "); + final int d = console.readInt(); + + final Player player = new Player(playerName, Punch.fromCode(b), Punch.fromCode(d)); + final Player opponent = new Player(opponentName); + + session = new GameSession(player, opponent); + } + + private void showIntro () { + console.print(" BOXING\n"); + console.print(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n"); + console.print("BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)\n\n"); + } +} \ No newline at end of file diff --git a/15 Boxing/java/BoxingGame.java b/15 Boxing/java/BoxingGame.java new file mode 100644 index 00000000..5e5f897b --- /dev/null +++ b/15 Boxing/java/BoxingGame.java @@ -0,0 +1,6 @@ +public class BoxingGame { + + public static void main(String[] args) { + new Boxing().play(); + } +} diff --git a/15 Boxing/java/GameSession.java b/15 Boxing/java/GameSession.java new file mode 100644 index 00000000..3a2c77a5 --- /dev/null +++ b/15 Boxing/java/GameSession.java @@ -0,0 +1,67 @@ +/** + * Game Session + * The session store the state of the game + */ +public class GameSession { + private final Player player; + private final Player opponent; + private int opponentRoundWins = 0; + private int playerRoundWins = 0; + + int playerPoints = 0; + int opponentPoints = 0; + boolean knocked = false; + + GameSession(Player player, Player opponent) { + this.player = player; + this.opponent = opponent; + } + + public Player getPlayer() { return player;} + public Player getOpponent() { return opponent;} + + public void setKnocked() { + knocked = true; + } + + public void resetPoints() { + playerPoints = 0; + opponentPoints = 0; + } + + public void addPlayerPoints(int ptos) { playerPoints+=ptos;} + public void addOpponentPoints(int ptos) { opponentPoints+=ptos;} + + public int getPoints(Player player) { + if(player.isPlayer()) + return playerPoints; + else + return opponentPoints; + } + + public void addRoundWind(Player player) { + if(player.isPlayer()) playerRoundWins++; else opponentRoundWins++; + } + + public boolean isOver() { + return (opponentRoundWins >= 2 || playerRoundWins >= 2); + } + + public boolean isRoundWinner(Player player) { + if (player.isPlayer()) + return playerPoints > opponentPoints; + else + return opponentPoints > playerPoints; + } + + public boolean isGameWinner(Player player) { + if (player.isPlayer()) + return playerRoundWins > 2; + else + return opponentRoundWins > 2; + } + + public boolean isPlayerKnocked() { + return knocked; + } +} \ No newline at end of file diff --git a/15 Boxing/java/Player.java b/15 Boxing/java/Player.java new file mode 100644 index 00000000..2462b9d0 --- /dev/null +++ b/15 Boxing/java/Player.java @@ -0,0 +1,42 @@ +/** + * The Player class model the user and compuer player + */ +public class Player { + private final String name; + private final Punch bestPunch; + private final Punch vulnerability; + private boolean isPlayer = false; + + public Player(String name, Punch bestPunch, Punch vulnerability) { + this.name = name; + this.bestPunch = bestPunch; + this.vulnerability = vulnerability; + this.isPlayer = true; + } + + /** + * Player with random Best Punch and Vulnerability + */ + public Player(String name) { + this.name = name; + + int b1; + int d1; + + do { + b1 = Basic.randomOf(4); + d1 = Basic.randomOf(4); + } while (b1 == d1); + + this.bestPunch = Punch.fromCode(b1); + this.vulnerability = Punch.fromCode(d1); + } + + public boolean isPlayer() { return isPlayer; } + public String getName() { return name; } + public Punch getBestPunch() { return bestPunch; } + + public boolean hitVulnerability(Punch punch) { + return vulnerability == punch; + } +} \ No newline at end of file diff --git a/15 Boxing/java/Punch.java b/15 Boxing/java/Punch.java new file mode 100644 index 00000000..24745b92 --- /dev/null +++ b/15 Boxing/java/Punch.java @@ -0,0 +1,27 @@ +import java.util.Arrays; + +/** + * Types of Punches + */ +public enum Punch { + FULL_SWING(1), + HOOK(2), + UPPERCUT(3), + JAB(4); + + private final int code; + + Punch(int code) { + this.code = code; + } + + int getCode() { return code;} + + public static Punch fromCode(int code) { + return Arrays.stream(Punch.values()).filter(p->p.code == code).findAny().orElse(null); + } + + public static Punch random() { + return Punch.fromCode(Basic.randomOf(4)); + } +} diff --git a/32 Diamond/java/Diamond.java b/32 Diamond/java/Diamond.java new file mode 100644 index 00000000..da56efe4 --- /dev/null +++ b/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/33 Dice/perl/dice.pl b/33 Dice/perl/dice.pl new file mode 100644 index 00000000..cb051b0a --- /dev/null +++ b/33 Dice/perl/dice.pl @@ -0,0 +1,42 @@ +#!/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/37 Football/javascript/.DS_Store b/37 Football/javascript/.DS_Store new file mode 100644 index 00000000..5008ddfc Binary files /dev/null and b/37 Football/javascript/.DS_Store differ diff --git a/39 Golf/javascript/golf.html b/39 Golf/javascript/golf.html new file mode 100644 index 00000000..bf43de8e --- /dev/null +++ b/39 Golf/javascript/golf.html @@ -0,0 +1,9 @@ + + +GOLF + + +


+
+
+
diff --git a/39 Golf/javascript/golf.js b/39 Golf/javascript/golf.js
new file mode 100644
index 00000000..814d589e
--- /dev/null
+++ b/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/45 Hello/java/Hello.java b/45 Hello/java/Hello.java
new file mode 100644
index 00000000..7807a2dd
--- /dev/null
+++ b/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/47 Hi-Lo/perl/hi-lo.pl b/47 Hi-Lo/perl/hi-lo.pl new file mode 100644 index 00000000..08173a56 --- /dev/null +++ b/47 Hi-Lo/perl/hi-lo.pl @@ -0,0 +1,45 @@ +#!/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/52 Kinema/perl/kinema.pl b/52 Kinema/perl/kinema.pl new file mode 100644 index 00000000..ef607983 --- /dev/null +++ b/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/56 Life for Two/javascript/lifefortwo.html b/56 Life for Two/javascript/lifefortwo.html new file mode 100644 index 00000000..fbd70636 --- /dev/null +++ b/56 Life for Two/javascript/lifefortwo.html @@ -0,0 +1,9 @@ + + +LIFE FOR TWO + + +


+
+
+
diff --git a/56 Life for Two/javascript/lifefortwo.js b/56 Life for Two/javascript/lifefortwo.js
new file mode 100644
index 00000000..a8c90e50
--- /dev/null
+++ b/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/58 Love/perl/love.pl b/58 Love/perl/love.pl
new file mode 100644
index 00000000..9e9f95cc
--- /dev/null
+++ b/58 Love/perl/love.pl	
@@ -0,0 +1,54 @@
+#!/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/60 Mastermind/javascript/mastermind.html b/60 Mastermind/javascript/mastermind.html
new file mode 100644
index 00000000..e1835c05
--- /dev/null
+++ b/60 Mastermind/javascript/mastermind.html	
@@ -0,0 +1,9 @@
+
+
+MASTERMIND
+
+
+

+
+
+
diff --git a/60 Mastermind/javascript/mastermind.js b/60 Mastermind/javascript/mastermind.js
new file mode 100644
index 00000000..40d8139e
--- /dev/null
+++ b/60 Mastermind/javascript/mastermind.js	
@@ -0,0 +1,361 @@
+// 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;
+            }
+            // 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/66 Number/java/main.class b/66 Number/java/main.class
new file mode 100644
index 00000000..c3df4ebf
--- /dev/null
+++ b/66 Number/java/main.class	
@@ -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/74 Rock Scissors Paper/perl/rockscissors.pl b/74 Rock Scissors Paper/perl/rockscissors.pl
new file mode 100644
index 00000000..ac83f5cf
--- /dev/null
+++ b/74 Rock Scissors Paper/perl/rockscissors.pl	
@@ -0,0 +1,56 @@
+#!/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/84 Super Star Trek/csharp/Command.cs b/84 Super Star Trek/csharp/Commands/Command.cs
similarity index 95%
rename from 84 Super Star Trek/csharp/Command.cs
rename to 84 Super Star Trek/csharp/Commands/Command.cs
index 33d9fd01..f0d569f8 100644
--- a/84 Super Star Trek/csharp/Command.cs	
+++ b/84 Super Star Trek/csharp/Commands/Command.cs	
@@ -1,6 +1,6 @@
 using System.ComponentModel;
 
-namespace SuperStarTrek
+namespace SuperStarTrek.Commands
 {
     internal enum Command
     {
diff --git a/84 Super Star Trek/csharp/CommandExtensions.cs b/84 Super Star Trek/csharp/Commands/CommandExtensions.cs
similarity index 91%
rename from 84 Super Star Trek/csharp/CommandExtensions.cs
rename to 84 Super Star Trek/csharp/Commands/CommandExtensions.cs
index 2b69ea31..f8f7e9da 100644
--- a/84 Super Star Trek/csharp/CommandExtensions.cs	
+++ b/84 Super Star Trek/csharp/Commands/CommandExtensions.cs	
@@ -1,7 +1,7 @@
 using System.Reflection;
 using System.ComponentModel;
 
-namespace SuperStarTrek
+namespace SuperStarTrek.Commands
 {
     internal static class CommandExtensions
     {
diff --git a/84 Super Star Trek/csharp/Commands/CommandResult.cs b/84 Super Star Trek/csharp/Commands/CommandResult.cs
new file mode 100644
index 00000000..1b02780c
--- /dev/null
+++ b/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/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs
index d97b8198..f2e1c819 100644
--- a/84 Super Star Trek/csharp/Game.cs	
+++ b/84 Super Star Trek/csharp/Game.cs	
@@ -3,6 +3,7 @@ using SuperStarTrek.Objects;
 using SuperStarTrek.Resources;
 using SuperStarTrek.Space;
 using SuperStarTrek.Systems;
+using SuperStarTrek.Systems.ComputerFunctions;
 using static System.StringComparison;
 
 namespace SuperStarTrek
@@ -11,12 +12,12 @@ namespace SuperStarTrek
     {
         private readonly Output _output;
         private readonly Input _input;
+        private readonly Random _random;
 
         private int _initialStardate;
         private int _finalStarDate;
-        private double _currentStardate;
+        private float _currentStardate;
         private Coordinates _currentQuadrant;
-        private Coordinates _currentSector;
         private Galaxy _galaxy;
         private int _initialKlingonCount;
         private Enterprise _enterprise;
@@ -25,19 +26,17 @@ namespace SuperStarTrek
         {
             _output = new Output();
             _input = new Input(_output);
+            _random = new Random();
         }
 
-        public double Stardate => _currentStardate;
+        public float Stardate => _currentStardate;
+        public float StardatesRemaining => _finalStarDate - _currentStardate;
 
         public void DoIntroduction()
         {
             _output.Write(Strings.Title);
 
-            _output.Write("Do you need instructions (Y/N)? ");
-            var response = Console.ReadLine();
-            _output.WriteLine();
-
-            if (!response.Equals("N", InvariantCultureIgnoreCase))
+            if (_input.GetYesNo("Do you need instructions", Input.YesNoMode.FalseOnN))
             {
                 _output.Write(Strings.Instructions);
 
@@ -47,8 +46,61 @@ namespace SuperStarTrek
 
         public void Play()
         {
-            var quadrant = Initialise();
+            Initialise();
             var gameOver = false;
+            var newQuadrantText = Strings.StartText;
+
+            while (!gameOver)
+            {
+                _enterprise.Quadrant.Display(Strings.NowEntering);
+
+                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(
@@ -62,36 +114,21 @@ namespace SuperStarTrek
 
             _input.WaitForAnyKeyButEnter("when ready to accept command");
 
-            _enterprise.Enter(quadrant, Strings.StartText);
-
-            while (!gameOver)
-            {
-                var command = _input.GetCommand();
-
-                gameOver = command == Command.XXX || _enterprise.Execute(command);
-            }
+            _enterprise.StartIn(BuildCurrentQuadrant());
         }
 
-        private Quadrant Initialise()
-        {
-            var random = new Random();
-
-            _currentStardate = _initialStardate = random.GetInt(20, 40) * 100;
-            _finalStarDate = _initialStardate + random.GetInt(25, 35);
-
-            _currentQuadrant = random.GetCoordinate();
-            _currentSector = random.GetCoordinate();
-
-            _galaxy = new Galaxy();
-            _initialKlingonCount = _galaxy.KlingonCount;
-
-            _enterprise = new Enterprise(3000, random.GetCoordinate());
-            _enterprise.Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output))
-                .Add(new ShieldControl(_enterprise, _output, _input));
-
-            return new Quadrant(_galaxy[_currentQuadrant], _enterprise);
-        }
+        private Quadrant BuildCurrentQuadrant() =>
+           new Quadrant(_galaxy[_currentQuadrant], _enterprise, _random, _galaxy, _input, _output);
 
         public 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/84 Super Star Trek/csharp/Input.cs b/84 Super Star Trek/csharp/Input.cs
index 98e5b297..3011738b 100644
--- a/84 Super Star Trek/csharp/Input.cs	
+++ b/84 Super Star Trek/csharp/Input.cs	
@@ -1,5 +1,7 @@
 using System;
 using System.Linq;
+using SuperStarTrek.Commands;
+using SuperStarTrek.Space;
 using static System.StringComparison;
 
 namespace SuperStarTrek
@@ -25,14 +27,14 @@ namespace SuperStarTrek
             return Console.ReadLine();
         }
 
-        public double GetNumber(string prompt)
+        public float GetNumber(string prompt)
         {
             _output.Prompt(prompt);
 
             while (true)
             {
                 var response = Console.ReadLine();
-                if (double.TryParse(response, out var value))
+                if (float.TryParse(response, out var value))
                 {
                     return value;
                 }
@@ -42,7 +44,14 @@ namespace SuperStarTrek
             }
         }
 
-        public bool TryGetNumber(string prompt, double minValue, double maxValue, out double value)
+        public (float X, float Y) GetCoordinates(string prompt)
+        {
+            _output.Prompt($"{prompt} (X,Y)");
+            var responses = ReadNumbers(2);
+            return (responses[0], responses[1]);
+        }
+
+        public bool TryGetNumber(string prompt, float minValue, float maxValue, out float value)
         {
             value = GetNumber($"{prompt} ({minValue}-{maxValue})");
 
@@ -58,7 +67,7 @@ namespace SuperStarTrek
             {
                 var response = GetString("Command");
 
-                if (response != "" &&
+                if (response.Length >= 3 &&
                     Enum.TryParse(response.Substring(0, 3), ignoreCase: true, out Command parsedCommand))
                 {
                     return parsedCommand;
@@ -72,5 +81,79 @@ namespace SuperStarTrek
                 _output.WriteLine();
             }
         }
+
+        public 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;
+        }
+
+        public 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;
+        }
+
+        public enum YesNoMode
+        {
+            TrueOnY,
+            FalseOnN
+        }
     }
 }
diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs
index 4f6055cc..4adf81df 100644
--- a/84 Super Star Trek/csharp/Objects/Enterprise.cs	
+++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs	
@@ -1,6 +1,8 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 using System.Text;
+using SuperStarTrek.Commands;
 using SuperStarTrek.Resources;
 using SuperStarTrek.Space;
 using SuperStarTrek.Systems;
@@ -10,84 +12,71 @@ 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;
-        private ShieldControl _shieldControl;
 
-        public Enterprise(int maxEnergy, Coordinates sector)
+        public Enterprise(int maxEnergy, Coordinates sector, Output output, Random random, Input input)
         {
-            Sector = sector;
+            SectorCoordinates = sector;
             TotalEnergy = _maxEnergy = maxEnergy;
 
             _systems = new List();
             _commandExecutors = new Dictionary();
+            _output = output;
+            _random = random;
+            _input = input;
         }
 
-        public Coordinates Quadrant => _quadrant.Coordinates;
-        public Coordinates Sector { get; }
-        public string Condition => GetCondition();
-        public double Shields => _shieldControl.Energy;
-        public double Energy => TotalEnergy - Shields;
-        public double TotalEnergy { get; private set; }
-        public int TorpedoCount { get; }
+        public Quadrant Quadrant => _quadrant;
+        public Coordinates QuadrantCoordinates => _quadrant.Coordinates;
+        public Coordinates SectorCoordinates { get; private set; }
 
-        public bool IsDocked { get; private set; }
+        public string Condition => GetCondition();
+        public LibraryComputer Computer => (LibraryComputer)_commandExecutors[Command.COM];
+        public ShieldControl ShieldControl => (ShieldControl)_commandExecutors[Command.SHE];
+        public float Energy => TotalEnergy - ShieldControl.ShieldEnergy;
+        public float TotalEnergy { get; private set; }
+        public int DamagedSystemCount => _systems.Count(s => s.IsDamaged);
+        public IEnumerable Systems => _systems;
+        public PhotonTubes PhotonTubes => (PhotonTubes)_commandExecutors[Command.TOR];
+        public bool IsDocked => _quadrant.EnterpriseIsNextToStarbase;
+        public bool IsStranded => TotalEnergy < 10 || Energy < 10 && ShieldControl.IsDamaged;
 
         public Enterprise Add(Subsystem system)
         {
             _systems.Add(system);
             _commandExecutors[system.Command] = system;
 
-            if (system is ShieldControl shieldControl) { _shieldControl = shieldControl; }
-
             return this;
         }
 
-        public string GetDamageReport()
-        {
-            var report = new StringBuilder();
-            report.AppendLine().AppendLine().AppendLine("Device             State of Repair");
-            foreach (var system in _systems)
-            {
-                report.Append(system.Name.PadRight(25)).AppendLine(system.Condition.ToString(" 0.00;-0.00"));
-            }
-            report.AppendLine();
-            return report.ToString();
-        }
-
-        public void Enter(Quadrant quadrant, string entryTextFormat)
+        public void StartIn(Quadrant quadrant)
         {
             _quadrant = quadrant;
-
-            var _output = new Output();
-            _output.Write(entryTextFormat, quadrant);
-
-            if (quadrant.HasKlingons)
-            {
-                _output.Write(Strings.CombatArea);
-                if (Shields <= 200) { _output.Write(Strings.LowShields); }
-            }
-
-            IsDocked = quadrant.EnterpriseIsNextToStarbase;
-
-            Execute(Command.SRS);
+            quadrant.Display(Strings.StartText);
         }
 
         private string GetCondition() =>
             (_quadrant.HasKlingons, Energy / _maxEnergy) switch
             {
                 (true, _) => "*Red*",
-                (_, < 0.1) => "Yellow",
+                (_, < 0.1f) => "Yellow",
                 _ => "Green"
             };
 
-        public bool Execute(Command command)
+        public CommandResult Execute(Command command)
         {
-            _commandExecutors[command].ExecuteCommand(_quadrant);
-            return false;
+            if (command == Command.XXX) { return CommandResult.GameOver; }
+
+            return _commandExecutors[command].ExecuteCommand(_quadrant);
         }
 
+        public void Refuel() => TotalEnergy = _maxEnergy;
+
         internal bool Recognises(string command)
         {
             throw new NotImplementedException();
@@ -99,5 +88,143 @@ namespace SuperStarTrek.Objects
         }
 
         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/84 Super Star Trek/csharp/Objects/Klingon.cs b/84 Super Star Trek/csharp/Objects/Klingon.cs
index fdf47031..4e277b07 100644
--- a/84 Super Star Trek/csharp/Objects/Klingon.cs	
+++ b/84 Super Star Trek/csharp/Objects/Klingon.cs	
@@ -1,14 +1,42 @@
+using SuperStarTrek.Commands;
+using SuperStarTrek.Space;
+
 namespace SuperStarTrek.Objects
 {
     internal class Klingon
     {
-        private double _energy;
+        private readonly Random _random;
 
-        public Klingon()
+        public Klingon(Coordinates sector, Random random)
         {
-            _energy = new Random().GetDouble(100, 300);
+            Sector = sector;
+            _random = random;
+            Energy = _random.GetFloat(100, 300);
         }
 
+        public float Energy { get; private set; }
+        public Coordinates Sector { get; private set; }
+
         public override string ToString() => "+K+";
+
+        public 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/84 Super Star Trek/csharp/Objects/Starbase.cs b/84 Super Star Trek/csharp/Objects/Starbase.cs
index 33110837..4befa73a 100644
--- a/84 Super Star Trek/csharp/Objects/Starbase.cs	
+++ b/84 Super Star Trek/csharp/Objects/Starbase.cs	
@@ -1,7 +1,44 @@
+using SuperStarTrek.Resources;
+using SuperStarTrek.Space;
+
 namespace SuperStarTrek.Objects
 {
     internal class Starbase
     {
+        private readonly Input _input;
+        private readonly Output _output;
+        private readonly float _repairDelay;
+
+        public 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/84 Super Star Trek/csharp/Output.cs b/84 Super Star Trek/csharp/Output.cs
index 77e5e919..ed960eea 100644
--- a/84 Super Star Trek/csharp/Output.cs	
+++ b/84 Super Star Trek/csharp/Output.cs	
@@ -4,12 +4,37 @@ namespace SuperStarTrek
 {
     internal class Output
     {
-        public void Write(string text) => Console.Write(text);
-        public void Write(string format, params object[] args) => Console.Write(format, args);
-        public void WriteLine(string text = "") => Console.WriteLine(text);
+        public Output Write(string text)
+        {
+            Console.Write(text);
+            return this;
+        }
 
-        public void NextLine() => Console.WriteLine();
+        public Output Write(string format, params object[] args)
+        {
+            Console.Write(format, args);
+            return this;
+        }
+
+        public Output WriteLine(string text = "")
+        {
+            Console.WriteLine(text);
+            return this;
+        }
+
+
+        public Output NextLine()
+        {
+            Console.WriteLine();
+            return this;
+        }
+
+
+        public Output Prompt(string text = "")
+        {
+            Console.Write($"{text}? ");
+            return this;
+        }
 
-        public void Prompt(string text = "") => Console.Write($"{text}? ");
     }
 }
diff --git a/84 Super Star Trek/csharp/Program.cs b/84 Super Star Trek/csharp/Program.cs
index 30360ee0..7f8395a6 100644
--- a/84 Super Star Trek/csharp/Program.cs	
+++ b/84 Super Star Trek/csharp/Program.cs	
@@ -29,6 +29,7 @@ namespace SuperStarTrek
     {
         static void Main()
         {
+            var foo = Utils.DirectionAndDistance.From(1,1).To(4,5);
             var game = new Game();
 
             game.DoIntroduction();
diff --git a/84 Super Star Trek/csharp/Random.cs b/84 Super Star Trek/csharp/Random.cs
index 9b7e1bff..5ed47805 100644
--- a/84 Super Star Trek/csharp/Random.cs	
+++ b/84 Super Star Trek/csharp/Random.cs	
@@ -6,20 +6,20 @@ namespace SuperStarTrek
     {
         private static readonly System.Random _random = new();
 
-        public Coordinates GetCoordinate() => new Coordinates(Get1To8Inclusive(), Get1To8Inclusive());
+        public 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.
-        public int Get1To8Inclusive() => (int)(_random.NextDouble() * 7.98 + 1.01);
+        public int Get1To8Inclusive() => (int)(GetFloat() * 7.98 + 1.01);
 
         public int GetInt(int inclusiveMinValue, int exclusiveMaxValue) =>
             _random.Next(inclusiveMinValue, exclusiveMaxValue);
 
-        public double GetDouble() => _random.NextDouble();
+        public float GetFloat() => (float)_random.NextDouble();
 
-        public double GetDouble(double inclusiveMinValue, double exclusiveMaxValue)
-            => _random.NextDouble() * (exclusiveMaxValue - inclusiveMinValue) + inclusiveMinValue;
+        public float GetFloat(float inclusiveMinValue, float exclusiveMaxValue)
+            => GetFloat() * (exclusiveMaxValue - inclusiveMinValue) + inclusiveMinValue;
     }
 }
diff --git a/84 Super Star Trek/csharp/Resources/AcceptCommand.txt b/84 Super Star Trek/csharp/Resources/AcceptCommand.txt
deleted file mode 100644
index e69de29b..00000000
diff --git a/84 Super Star Trek/csharp/Resources/ComputerFunctions.txt b/84 Super Star Trek/csharp/Resources/ComputerFunctions.txt
new file mode 100644
index 00000000..4827b0fe
--- /dev/null
+++ b/84 Super Star Trek/csharp/Resources/ComputerFunctions.txt	
@@ -0,0 +1,9 @@
+
+Functions available from Library-Computer:
+   0 = Cumulative galactic record
+   1 = Status report
+   2 = Photon torpedo data
+   3 = Starbase nav data
+   4 = Direction/distance calculator
+   5 = Galaxy 'region name' map
+
diff --git a/84 Super Star Trek/csharp/Resources/Congratulations.txt b/84 Super Star Trek/csharp/Resources/Congratulations.txt
new file mode 100644
index 00000000..767f8653
--- /dev/null
+++ b/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/84 Super Star Trek/csharp/Resources/CourtMartial.txt b/84 Super Star Trek/csharp/Resources/CourtMartial.txt
new file mode 100644
index 00000000..7d05a5b8
--- /dev/null
+++ b/84 Super Star Trek/csharp/Resources/CourtMartial.txt	
@@ -0,0 +1,3 @@
+
+Starfleet Command reviewing your record to consider
+court martial!
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Resources/Destroyed.txt b/84 Super Star Trek/csharp/Resources/Destroyed.txt
new file mode 100644
index 00000000..881d7b49
--- /dev/null
+++ b/84 Super Star Trek/csharp/Resources/Destroyed.txt	
@@ -0,0 +1 @@
+The Enterprise has been destroyed.  The Federation will be conquered.
diff --git a/84 Super Star Trek/csharp/Resources/EndOfMission.txt b/84 Super Star Trek/csharp/Resources/EndOfMission.txt
new file mode 100644
index 00000000..f6995e31
--- /dev/null
+++ b/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/84 Super Star Trek/csharp/Resources/Instructions.txt b/84 Super Star Trek/csharp/Resources/Instructions.txt
index fd74857e..34b4169c 100644
--- a/84 Super Star Trek/csharp/Resources/Instructions.txt	
+++ b/84 Super Star Trek/csharp/Resources/Instructions.txt	
@@ -1,3 +1,4 @@
+
       INSTRUCTIONS FOR 'SUPER STAR TREK'
 
 1. When you see "Command ?" printed, enter one of the legal
diff --git a/84 Super Star Trek/csharp/Resources/NoEnemyShips.txt b/84 Super Star Trek/csharp/Resources/NoEnemyShips.txt
new file mode 100644
index 00000000..394f1057
--- /dev/null
+++ b/84 Super Star Trek/csharp/Resources/NoEnemyShips.txt	
@@ -0,0 +1,2 @@
+Science Officer Spock reports, 'Sensors show no enemy ships
+                                in this quadrant'
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Resources/NoStarbase.txt b/84 Super Star Trek/csharp/Resources/NoStarbase.txt
new file mode 100644
index 00000000..5bb4e5fb
--- /dev/null
+++ b/84 Super Star Trek/csharp/Resources/NoStarbase.txt	
@@ -0,0 +1 @@
+Mr. Spock reports, 'Sensors show no starbases in this quadrant.'
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Resources/NowEntering.txt b/84 Super Star Trek/csharp/Resources/NowEntering.txt
new file mode 100644
index 00000000..915b526f
--- /dev/null
+++ b/84 Super Star Trek/csharp/Resources/NowEntering.txt	
@@ -0,0 +1,2 @@
+Now entering {0} quadrant . . .
+
diff --git a/84 Super Star Trek/csharp/Resources/PermissionDenied.txt b/84 Super Star Trek/csharp/Resources/PermissionDenied.txt
new file mode 100644
index 00000000..c24d9da7
--- /dev/null
+++ b/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/84 Super Star Trek/csharp/Resources/Protected.txt b/84 Super Star Trek/csharp/Resources/Protected.txt
new file mode 100644
index 00000000..27c4a5f8
--- /dev/null
+++ b/84 Super Star Trek/csharp/Resources/Protected.txt	
@@ -0,0 +1 @@
+Starbase shields protect the Enterprise
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Resources/RegionNames.txt b/84 Super Star Trek/csharp/Resources/RegionNames.txt
new file mode 100644
index 00000000..f84fe43b
--- /dev/null
+++ b/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
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Resources/RelievedOfCommand.txt b/84 Super Star Trek/csharp/Resources/RelievedOfCommand.txt
new file mode 100644
index 00000000..8086e3ca
--- /dev/null
+++ b/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!!
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Resources/RepairEstimate.txt b/84 Super Star Trek/csharp/Resources/RepairEstimate.txt
new file mode 100644
index 00000000..12e167a5
--- /dev/null
+++ b/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/84 Super Star Trek/csharp/Resources/RepairPrompt.txt b/84 Super Star Trek/csharp/Resources/RepairPrompt.txt
new file mode 100644
index 00000000..feffdb27
--- /dev/null
+++ b/84 Super Star Trek/csharp/Resources/RepairPrompt.txt	
@@ -0,0 +1 @@
+Will you authorize the repair order (Y/N)
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Resources/ReplayPrompt.txt b/84 Super Star Trek/csharp/Resources/ReplayPrompt.txt
index 52aca0d1..3ca3a102 100644
--- a/84 Super Star Trek/csharp/Resources/ReplayPrompt.txt	
+++ b/84 Super Star Trek/csharp/Resources/ReplayPrompt.txt	
@@ -1,3 +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'
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Resources/Stranded.txt b/84 Super Star Trek/csharp/Resources/Stranded.txt
new file mode 100644
index 00000000..07c37952
--- /dev/null
+++ b/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/84 Super Star Trek/csharp/Resources/Strings.cs b/84 Super Star Trek/csharp/Resources/Strings.cs
index 930f1663..ddb768ca 100644
--- a/84 Super Star Trek/csharp/Resources/Strings.cs	
+++ b/84 Super Star Trek/csharp/Resources/Strings.cs	
@@ -7,14 +7,29 @@ namespace SuperStarTrek.Resources
     internal static class Strings
     {
         public static string CombatArea => GetResource();
+        public static string ComputerFunctions => GetResource();
+        public static string Congratulations => GetResource();
+        public static string CourtMartial => GetResource();
+        public static string Destroyed => GetResource();
+        public static string EndOfMission => GetResource();
         public static string Enterprise => GetResource();
         public static string Instructions => GetResource();
         public static string LowShields => GetResource();
+        public static string NoEnemyShips => GetResource();
+        public static string NoStarbase => GetResource();
+        public static string NowEntering => GetResource();
         public static string Orders => GetResource();
+        public static string PermissionDenied => GetResource();
+        public static string Protected => GetResource();
+        public static string RegionNames => GetResource();
+        public static string RelievedOfCommand => GetResource();
+        public static string RepairEstimate => GetResource();
+        public static string RepairPrompt => GetResource();
         public static string ReplayPrompt => GetResource();
         public static string ShieldsDropped => GetResource();
         public static string ShortRangeSensorsOut => GetResource();
         public static string StartText => GetResource();
+        public static string Stranded => GetResource();
         public static string Title => GetResource();
 
         private static string GetResource([CallerMemberName] string name = "")
diff --git a/84 Super Star Trek/csharp/Space/Coordinate.cs b/84 Super Star Trek/csharp/Space/Coordinate.cs
deleted file mode 100644
index b3328c24..00000000
--- a/84 Super Star Trek/csharp/Space/Coordinate.cs	
+++ /dev/null
@@ -1,27 +0,0 @@
-using System;
-
-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
-    {
-        public Coordinates(int x, int y)
-        {
-            X = Validated(x, nameof(x));
-            Y = Validated(y, nameof(y));
-        }
-
-        public int X { get; }
-        public int Y { get; }
-
-        private int Validated(int value, string argumentName)
-        {
-            if (value >= 1 && value <= 8) { return value; }
-
-            throw new ArgumentOutOfRangeException(argumentName, value, "Must be 1 to 8 inclusive");
-        }
-
-        public override string ToString() => $"{X} , {Y}";
-    }
-}
diff --git a/84 Super Star Trek/csharp/Space/Coordinates.cs b/84 Super Star Trek/csharp/Space/Coordinates.cs
new file mode 100644
index 00000000..1619d387
--- /dev/null
+++ b/84 Super Star Trek/csharp/Space/Coordinates.cs	
@@ -0,0 +1,67 @@
+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
+    {
+        public Coordinates(int x, int y)
+        {
+            X = Validated(x, nameof(x));
+            Y = Validated(y, nameof(y));
+
+            RegionIndex = (X << 1) + (Y >> 2);
+            SubRegionIndex = Y % 4;
+        }
+
+        public int X { get; }
+        public int Y { get; }
+        public int RegionIndex { get; }
+        public int SubRegionIndex { get; }
+
+        private 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/84 Super Star Trek/csharp/Space/Course.cs b/84 Super Star Trek/csharp/Space/Course.cs
index dd9ecfba..a46385c3 100644
--- a/84 Super Star Trek/csharp/Space/Course.cs	
+++ b/84 Super Star Trek/csharp/Space/Course.cs	
@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 
 namespace SuperStarTrek.Space
 {
@@ -24,7 +25,7 @@ namespace SuperStarTrek.Space
             (0, 1)
         };
 
-        public Course(double direction)
+        internal Course(float direction)
         {
             if (direction < 1 || direction > 9)
             {
@@ -44,7 +45,53 @@ namespace SuperStarTrek.Space
             DeltaY = baseCardinal.DeltaY + (nextCardinal.DeltaY - baseCardinal.DeltaY) * fractionalDirection;
         }
 
-        public double DeltaX { get; }
-        public double DeltaY { get; }
+        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 (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 == -1)
+            {
+                newQuadrant -= 1;
+                newSector = 7;
+            }
+
+            return newQuadrant switch
+            {
+                < 0 => (false, 0, 0),
+                > 7 => (false, 7, 7),
+                _ => (true, newQuadrant, newSector)
+            };
+        }
     }
 }
diff --git a/84 Super Star Trek/csharp/Space/Galaxy.cs b/84 Super Star Trek/csharp/Space/Galaxy.cs
index 171ecdea..63838567 100644
--- a/84 Super Star Trek/csharp/Space/Galaxy.cs	
+++ b/84 Super Star Trek/csharp/Space/Galaxy.cs	
@@ -1,17 +1,37 @@
+using System.Collections;
+using System.Collections.Generic;
 using System.Linq;
+using SuperStarTrek.Objects;
+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;
+        private readonly Random _random;
 
-        public Galaxy()
+        static Galaxy()
         {
-            var random = new Random();
+            _regionNames = Strings.RegionNames.Split(new[] { ' ', '\n' }, RemoveEmptyEntries | TrimEntries);
+            _subRegionIdentifiers = new[] { "I", "II", "III", "IV" };
+        }
 
-            _quadrants = Enumerable.Range(1, 8).Select(x =>
-                Enumerable.Range(1, 8).Select(y => QuadrantInfo.Create(new Coordinates(x, y), "")).ToArray())
+        public Galaxy(Random random)
+        {
+            _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)))
+                    .ToArray())
                 .ToArray();
 
             if (StarbaseCount == 0)
@@ -26,9 +46,22 @@ namespace SuperStarTrek.Space
             }
         }
 
-        public QuadrantInfo this[Coordinates coordinate] => _quadrants[coordinate.X - 1][coordinate.Y - 1];
+        public QuadrantInfo this[Coordinates coordinate] => _quadrants[coordinate.X][coordinate.Y];
 
         public int KlingonCount => _quadrants.SelectMany(q => q).Sum(q => q.KlingonCount);
         public int StarbaseCount => _quadrants.SelectMany(q => q).Count(q => q.HasStarbase);
+        public IEnumerable> Quadrants => _quadrants;
+
+        private static string GetQuadrantName(Coordinates coordinates) =>
+            $"{_regionNames[coordinates.RegionIndex]} {_subRegionIdentifiers[coordinates.SubRegionIndex]}";
+
+        public 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/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs
index 2aa45b6d..b333cb7e 100644
--- a/84 Super Star Trek/csharp/Space/Quadrant.cs	
+++ b/84 Super Star Trek/csharp/Space/Quadrant.cs	
@@ -1,7 +1,9 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using SuperStarTrek.Commands;
 using SuperStarTrek.Objects;
+using SuperStarTrek.Resources;
 
 namespace SuperStarTrek.Space
 {
@@ -10,42 +12,56 @@ namespace SuperStarTrek.Space
         private readonly QuadrantInfo _info;
         private readonly Random _random;
         private readonly Dictionary _sectors;
-        private readonly Coordinates _enterpriseSector;
-        private readonly Coordinates _starbaseSector;
+        private readonly Enterprise _enterprise;
+        private readonly Output _output;
+        private bool _displayed = false;
 
-        public Quadrant(QuadrantInfo info, Enterprise enterprise)
+        public Quadrant(
+            QuadrantInfo info,
+            Enterprise enterprise,
+            Random random,
+            Galaxy galaxy,
+            Input input,
+            Output output)
         {
             _info = info;
-            _random = new Random();
+            _random = random;
+            _output = output;
+            Galaxy = galaxy;
 
-            _enterpriseSector = enterprise.Sector;
-            _sectors = new Dictionary { [enterprise.Sector] = enterprise };
-            PositionObject(() => new Klingon(), _info.KlingonCount);
+            info.MarkAsKnown();
+            _sectors = new() { [enterprise.SectorCoordinates] = _enterprise = enterprise };
+            PositionObject(sector => new Klingon(sector, _random), _info.KlingonCount);
             if (_info.HasStarbase)
             {
-                _starbaseSector = PositionObject(() => new Starbase());
+                Starbase = PositionObject(sector => new Starbase(sector, _random, input, output));
             }
-            PositionObject(() => new Star(), _info.StarCount);
+            PositionObject(_ => new Star(), _info.StarCount);
         }
 
         public Coordinates Coordinates => _info.Coordinates;
         public bool HasKlingons => _info.KlingonCount > 0;
+        public int KlingonCount => _info.KlingonCount;
         public bool HasStarbase => _info.HasStarbase;
+        public Starbase Starbase { get; }
+        internal Galaxy Galaxy { get; }
         public bool EnterpriseIsNextToStarbase =>
             _info.HasStarbase &&
-            Math.Abs(_enterpriseSector.X - _starbaseSector.X) <= 1 &&
-            Math.Abs(_enterpriseSector.Y - _starbaseSector.Y) <= 1;
+            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 Coordinates PositionObject(Func objectFactory)
+        private T PositionObject(Func objectFactory)
         {
             var sector = GetRandomEmptySector();
-            _sectors[sector] = objectFactory.Invoke();
-            return sector;
+            _sectors[sector] = objectFactory.Invoke(sector);
+            return (T)_sectors[sector];
         }
 
-        private void PositionObject(Func objectFactory, int count)
+        private void PositionObject(Func objectFactory, int count)
         {
             for (int i = 0; i < count; i++)
             {
@@ -53,6 +69,91 @@ namespace SuperStarTrek.Space
             }
         }
 
+        internal void Display(string textFormat)
+        {
+            if (_displayed) { return; }
+
+            _output.Write(textFormat, this);
+
+            if (_info.KlingonCount > 0)
+            {
+                _output.Write(Strings.CombatArea);
+                if (_enterprise.ShieldControl.ShieldEnergy <= 200) { _output.Write(Strings.LowShields); }
+            }
+
+            _enterprise.Execute(Command.SRS);
+
+            _displayed = true;
+        }
+
+        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)
@@ -65,15 +166,21 @@ namespace SuperStarTrek.Space
             }
         }
 
-        public IEnumerable GetDisplayLines() => Enumerable.Range(1, 8).Select(x => GetDisplayLine(x));
+        public IEnumerable GetDisplayLines() => Enumerable.Range(0, 8).Select(x => GetDisplayLine(x));
 
         private string GetDisplayLine(int x)
             => string.Join(
                 " ",
                 Enumerable
-                    .Range(1, 8)
+                    .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/84 Super Star Trek/csharp/Space/QuadrantInfo.cs b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs
index ed9ed3fa..70447250 100644
--- a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs	
+++ b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs	
@@ -1,7 +1,11 @@
+using SuperStarTrek.Objects;
+
 namespace SuperStarTrek.Space
 {
     internal class QuadrantInfo
     {
+        private bool _isKnown;
+
         private QuadrantInfo(Coordinates coordinates, string name, int klingonCount, int starCount, bool hasStarbase)
         {
             Coordinates = coordinates;
@@ -20,14 +24,14 @@ namespace SuperStarTrek.Space
         public static QuadrantInfo Create(Coordinates coordinates, string name)
         {
             var random = new Random();
-            var klingonCount = random.GetDouble() switch
+            var klingonCount = random.GetFloat() switch
             {
-                > 0.98 => 3,
-                > 0.95 => 2,
-                > 0.80 => 1,
+                > 0.98f => 3,
+                > 0.95f => 2,
+                > 0.80f => 1,
                 _ => 0
             };
-            var hasStarbase = random.GetDouble() > 0.96;
+            var hasStarbase = random.GetFloat() > 0.96f;
             var starCount = random.Get1To8Inclusive();
 
             return new QuadrantInfo(coordinates, name, klingonCount, starCount, hasStarbase);
@@ -36,5 +40,25 @@ namespace SuperStarTrek.Space
         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/84 Super Star Trek/csharp/StringExtensions.cs b/84 Super Star Trek/csharp/StringExtensions.cs
new file mode 100644
index 00000000..02e9794f
--- /dev/null
+++ b/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" : "");
+    }
+}
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs
new file mode 100644
index 00000000..400c1f62
--- /dev/null
+++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/ComputerFunction.cs	
@@ -0,0 +1,18 @@
+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);
+    }
+}
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/CumulativeGalacticRecord.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/CumulativeGalacticRecord.cs
new file mode 100644
index 00000000..f02677ca
--- /dev/null
+++ b/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));
+    }
+}
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs
new file mode 100644
index 00000000..ff6239ed
--- /dev/null
+++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs	
@@ -0,0 +1,33 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems.ComputerFunctions
+{
+    internal class DirectionDistanceCalculator : NavigationCalculator
+    {
+        private readonly Enterprise _enterprise;
+        private readonly Input _input;
+
+        public DirectionDistanceCalculator(Enterprise enterprise, Output output, Input input)
+            : base("Starbase nav data", 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"));
+        }
+    }
+}
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/GalacticReport.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/GalacticReport.cs
new file mode 100644
index 00000000..8b26cc2e
--- /dev/null
+++ b/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
+    {
+        public 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("     ----- ----- ----- ----- ----- ----- ----- -----");
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/GalaxyRegionMap.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/GalaxyRegionMap.cs
new file mode 100644
index 00000000..f6fe0305
--- /dev/null
+++ b/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'));
+    }
+}
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/NavigationCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/NavigationCalculator.cs
new file mode 100644
index 00000000..680f3d18
--- /dev/null
+++ b/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}");
+    }
+}
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs
new file mode 100644
index 00000000..0d2c5b50
--- /dev/null
+++ b/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;
+
+        public 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);
+        }
+    }
+}
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/StatusReport.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/StatusReport.cs
new file mode 100644
index 00000000..f80ba7bb
--- /dev/null
+++ b/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;
+
+        public 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);
+        }
+    }
+}
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs
new file mode 100644
index 00000000..09c71859
--- /dev/null
+++ b/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;
+
+        public 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);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/84 Super Star Trek/csharp/Systems/DamageControl.cs b/84 Super Star Trek/csharp/Systems/DamageControl.cs
new file mode 100644
index 00000000..6ce41bbe
--- /dev/null
+++ b/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;
+
+        public 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;
+        }
+
+        public 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/84 Super Star Trek/csharp/Systems/LibraryComputer.cs b/84 Super Star Trek/csharp/Systems/LibraryComputer.cs
new file mode 100644
index 00000000..b2e47d2a
--- /dev/null
+++ b/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;
+
+        public 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/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs b/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs
new file mode 100644
index 00000000..84ed7a87
--- /dev/null
+++ b/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs	
@@ -0,0 +1,39 @@
+
+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 LongRangeSensors : Subsystem
+    {
+        private readonly Galaxy _galaxy;
+        private readonly Output _output;
+
+        public 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/84 Super Star Trek/csharp/Systems/PhaserControl.cs b/84 Super Star Trek/csharp/Systems/PhaserControl.cs
new file mode 100644
index 00000000..18566294
--- /dev/null
+++ b/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;
+
+        public 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/84 Super Star Trek/csharp/Systems/PhotonTubes.cs b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs
new file mode 100644
index 00000000..a807d16c
--- /dev/null
+++ b/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;
+
+        public PhotonTubes(int tubeCount, Enterprise enterprise, Output output, Input input)
+            : base("Photon Tubes", Command.TOR, output)
+        {
+            TorpedoCount = _tubeCount = tubeCount;
+            _enterprise = enterprise;
+            _output = output;
+            _input = input;
+        }
+
+        public 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/84 Super Star Trek/csharp/Systems/ShieldControl.cs b/84 Super Star Trek/csharp/Systems/ShieldControl.cs
index e7aca413..a7518359 100644
--- a/84 Super Star Trek/csharp/Systems/ShieldControl.cs	
+++ b/84 Super Star Trek/csharp/Systems/ShieldControl.cs	
@@ -1,3 +1,4 @@
+using SuperStarTrek.Commands;
 using SuperStarTrek.Objects;
 using SuperStarTrek.Space;
 
@@ -10,36 +11,35 @@ namespace SuperStarTrek.Systems
         private readonly Input _input;
 
         public ShieldControl(Enterprise enterprise, Output output, Input input)
-            : base("Shield Control", Command.SHE)
+            : base("Shield Control", Command.SHE, output)
         {
             _enterprise = enterprise;
             _output = output;
             _input = input;
         }
 
-        public double Energy { get; private set; }
+        public float ShieldEnergy { get; set; }
 
-        public override void ExecuteCommand(Quadrant quadrant)
+        protected override bool CanExecuteCommand() => IsOperational("{name} inoperable");
+
+        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
         {
-            if (Condition < 0)
-            {
-                _output.WriteLine("Shield Control inoperable");
-                return;
-            }
-
             _output.WriteLine($"Energy available = {_enterprise.TotalEnergy}");
             var requested = _input.GetNumber($"Number of units to shields");
 
             if (Validate(requested))
             {
-                Energy = requested;
-                return;
+                ShieldEnergy = requested;
+            }
+            else
+            {
+                _output.WriteLine("");
             }
 
-            _output.WriteLine("");
+            return CommandResult.Ok;
         }
 
-        private bool Validate(double requested)
+        private bool Validate(float requested)
         {
             if (requested > _enterprise.TotalEnergy)
             {
@@ -47,7 +47,11 @@ namespace SuperStarTrek.Systems
                 return false;
             }
 
-            return requested >= 0 && requested != Energy;
+            return requested >= 0 && requested != ShieldEnergy;
         }
+
+        internal void AbsorbHit(int hitStrength) => ShieldEnergy -= hitStrength;
+
+        internal void DropShields() => ShieldEnergy = 0;
     }
 }
diff --git a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs
index d22dda70..ad3929d1 100644
--- a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs	
+++ b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs	
@@ -2,6 +2,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using SuperStarTrek.Commands;
 using SuperStarTrek.Objects;
 using SuperStarTrek.Resources;
 using SuperStarTrek.Space;
@@ -16,7 +17,7 @@ namespace SuperStarTrek.Systems
         private readonly Output _output;
 
         public ShortRangeSensors(Enterprise enterprise, Galaxy galaxy, Game game, Output output)
-            : base("Short Range Sensors", Command.SRS)
+            : base("Short Range Sensors", Command.SRS, output)
         {
             _enterprise = enterprise;
             _galaxy = galaxy;
@@ -24,7 +25,7 @@ namespace SuperStarTrek.Systems
             _output = output;
         }
 
-        public override void ExecuteCommand(Quadrant quadrant)
+        protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
         {
             if (_enterprise.IsDocked)
             {
@@ -42,17 +43,19 @@ namespace SuperStarTrek.Systems
                 .ToList()
                 .ForEach(l => _output.WriteLine(l));
             _output.WriteLine("---------------------------------");
+
+            return CommandResult.Ok;
         }
 
         public IEnumerable GetStatusLines()
         {
             yield return $"Stardate           {_game.Stardate}";
             yield return $"Condition          {_enterprise.Condition}";
-            yield return $"Quadrant           {_enterprise.Quadrant}";
-            yield return $"Sector             {_enterprise.Sector}";
-            yield return $"Photon torpedoes   {_enterprise.TorpedoCount}";
-            yield return $"Total energy       {Math.Ceiling(_enterprise.Energy)}";
-            yield return $"Shields            {(int)_enterprise.Shields}";
+            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/84 Super Star Trek/csharp/Systems/Subsystem.cs b/84 Super Star Trek/csharp/Systems/Subsystem.cs
index ae2ef7d6..9e5f3570 100644
--- a/84 Super Star Trek/csharp/Systems/Subsystem.cs	
+++ b/84 Super Star Trek/csharp/Systems/Subsystem.cs	
@@ -1,20 +1,66 @@
+using System;
+using SuperStarTrek.Commands;
 using SuperStarTrek.Space;
 
 namespace SuperStarTrek.Systems
 {
     internal abstract class Subsystem
     {
-        protected Subsystem(string name, Command command)
+        private readonly Output _output;
+
+        protected Subsystem(string name, Command command, Output output)
         {
             Name = name;
             Command = command;
             Condition = 0;
+            _output = output;
         }
 
         public string Name { get; }
-        public double Condition { get; }
+        public float Condition { get; private set; }
+        public bool IsDamaged => Condition < 0;
         public Command Command { get; }
 
-        public abstract void ExecuteCommand(Quadrant quadrant);
+        protected virtual bool CanExecuteCommand() => true;
+
+        protected bool IsOperational(string notOperationalMessage)
+        {
+            if (IsDamaged)
+            {
+                _output.WriteLine(notOperationalMessage.Replace("{name}", Name));
+                return false;
+            }
+
+            return true;
+        }
+
+        public CommandResult ExecuteCommand(Quadrant quadrant)
+            => CanExecuteCommand() ? ExecuteCommandCore(quadrant) : CommandResult.Ok;
+
+        protected abstract CommandResult ExecuteCommandCore(Quadrant quadrant);
+
+        public virtual void Repair()
+        {
+            if (IsDamaged)
+            {
+                Condition = 0;
+            }
+        }
+
+        public 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/84 Super Star Trek/csharp/Systems/WarpEngines.cs b/84 Super Star Trek/csharp/Systems/WarpEngines.cs
new file mode 100644
index 00000000..0dcf396c
--- /dev/null
+++ b/84 Super Star Trek/csharp/Systems/WarpEngines.cs	
@@ -0,0 +1,82 @@
+using System;
+using SuperStarTrek.Commands;
+using SuperStarTrek.Objects;
+using SuperStarTrek.Space;
+
+namespace SuperStarTrek.Systems
+{
+    internal class WarpEngines : Subsystem
+    {
+        private readonly Enterprise _enterprise;
+        private readonly Output _output;
+        private readonly Input _input;
+
+        public 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();
+                }
+
+                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/84 Super Star Trek/csharp/Utils/DirectionAndDistance.cs b/84 Super Star Trek/csharp/Utils/DirectionAndDistance.cs
new file mode 100644
index 00000000..3fa9f4b8
--- /dev/null
+++ b/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;
+        }
+
+        public static DirectionAndDistance From(Coordinates coordinates) => From(coordinates.X, coordinates.Y);
+
+        public static DirectionAndDistance From(float x, float y) => new DirectionAndDistance(x, y);
+
+        public (float Direction, float Distance) To(Coordinates coordinates) => To(coordinates.X, coordinates.Y);
+
+        public (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 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 float GetDistance(float deltaX, float deltaY) =>
+            (float)Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2));
+    }
+}
\ No newline at end of file
diff --git a/87 3-D Plot/java/Plot3D.java b/87 3-D Plot/java/Plot3D.java
new file mode 100644
index 00000000..a12848d8
--- /dev/null
+++ b/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/95 Weekday/java/Weekday.java b/95 Weekday/java/Weekday.java new file mode 100644 index 00000000..9ca3db11 --- /dev/null +++ b/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; + } + } + +}