From 06c8d2be697f2908dbf2e43ea8e80c1c23deac99 Mon Sep 17 00:00:00 2001 From: Taciano Dreckmann Perez Date: Mon, 21 Feb 2022 21:42:22 +0100 Subject: [PATCH] added 84_Super_Star_Trek Java port --- .../java/SuperStarTrekGame.java | 1239 +++++++++++++++++ .../java/SuperStarTrekInstructions.java | 162 +++ 2 files changed, 1401 insertions(+) create mode 100644 84_Super_Star_Trek/java/SuperStarTrekGame.java create mode 100644 84_Super_Star_Trek/java/SuperStarTrekInstructions.java diff --git a/84_Super_Star_Trek/java/SuperStarTrekGame.java b/84_Super_Star_Trek/java/SuperStarTrekGame.java new file mode 100644 index 00000000..213b2a0b --- /dev/null +++ b/84_Super_Star_Trek/java/SuperStarTrekGame.java @@ -0,0 +1,1239 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Random; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * SUPER STARTREK - MAY 16,1978 + * **** **** STAR TREK **** **** + * **** SIMULATION OF A MISSION OF THE STARSHIP ENTERPRISE, + * **** AS SEEN ON THE STAR TREK TV SHOW. + * **** ORIGINAL PROGRAM BY MIKE MAYFIELD, MODIFIED VERSION + * **** PUBLISHED IN DEC'S "101 BASIC GAMES", BY DAVE AHL. + * **** MODIFICATIONS TO THE LATTER (PLUS DEBUGGING) BY BOB + * *** LEEDOM - APRIL & DECEMBER 1974, + * *** WITH A LITTLE HELP FROM HIS FRIENDS . . . + * + * Ported to Java in Jan-Feb 2022 by + * Taciano Dreckmann Perez (taciano.perez@gmail.com) + */ +public class SuperStarTrekGame { + + // markers + static final String MARKER_EMPTY = " "; + static final String MARKER_ENTERPRISE = "<*>"; + static final String MARKER_KLINGON = "+K+"; + static final String MARKER_STARBASE = ">!<"; + static final String MARKER_STAR = " * "; + + // commands + static final int COMMAND_NAV = 1; + static final int COMMAND_SRS = 2; + static final int COMMAND_LRS = 3; + static final int COMMAND_PHA = 4; + static final int COMMAND_TOR = 5; + static final int COMMAND_SHE = 6; + static final int COMMAND_DAM = 7; + static final int COMMAND_COM = 8; + static final int COMMAND_XXX = 9; + + // computer commands + static final int COMPUTER_COMMAND_CUMULATIVE_GALACTIC_RECORD = 1; + static final int COMPUTER_COMMAND_STATUS_REPORT = 2; + static final int COMPUTER_COMMAND_PHOTON_TORPEDO_DATA = 3; + static final int COMPUTER_COMMAND_STARBASE_NAV_DATA = 4; + static final int COMPUTER_COMMAND_DIR_DIST_CALC = 5; + static final int COMPUTER_COMMAND_GALAXY_MAP = 6; + + // devices + static final int DEVICE_WARP_ENGINES = 1; + static final int DEVICE_SHORT_RANGE_SENSORS = 2; + static final int DEVICE_LONG_RANGE_SENSORS = 3; + static final int DEVICE_PHASER_CONTROL = 4; + static final int DEVICE_PHOTON_TUBES = 5; + static final int DEVICE_DAMAGE_CONTROL = 6; + static final int DEVICE_SHIELD_CONTROL = 7; + static final int DEVICE_LIBRARY_COMPUTER = 8; + + // other constants + static final String QUADRANT_ROW = " "; + static final String COMMANDS = "NAVSRSLRSPHATORSHEDAMCOMXXX"; + static final Random random = new Random(); + + // game state + final int galaxy[][] = new int[9][9]; // 8x8 galaxy map G + final int cardinalDirections[][] = new int[10][3]; // 9x2 vectors in cardinal directions C + final int klingonQuadrants[][] = new int[4][4]; // 3x3 position of klingons K + final int chartedGalaxy[][] = new int[9][9]; // 8x8 charted galaxy map Z + final double deviceStatus[] = new double[9]; // 8 device damage stats D + String quadrantMap = QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + QUADRANT_ROW + leftStr(QUADRANT_ROW, 17); // current quadrant map + double stardate = toInt(random() * 20 + 20); // T + int energy = 3000; // E + boolean shipDocked = false; // D0 + int torpedoes = 10; // P + int shields = 0; // S + int missionDuration = 25 + toInt(random() * 10); // T9 (mission duration in stardates) + int basesInGalaxy = 0; // B9 + int remainingKlingons; // K7 + int klingonsInGalaxy = 0; // K9 + int quadrantX; // Q1 + int quadrantY; // Q2 + int sectorX; // S1 + int sectorY; // S2 + int klingons = 0; //K3 + int starbases = 0; // B3 + int stars = 0; // S3 + int starbaseX = 0; // X coordinate of starbase + int starbaseY = 0; // Y coord of starbase + double repairCost; // damage repair cost D4 + boolean restart = false; + + // initial values + final double initialStardate = stardate; // T0 + final int initialEnergy = energy; // E0 + final int initialTorpedoes = torpedoes; // P0 + final int avgKlingonShieldEnergy = 200; // S9 + + public static void main(String[] args) { + final SuperStarTrekGame game = new SuperStarTrekGame(); + printBanner(); + while (true) { + game.setup(); + game.enterNewQuadrant(); + game.restart = false; + game.commandLoop(); + } + } + + static void printBanner() { // 220 + IntStream.range(1, 10).forEach(i -> { + println(""); + }); + println( + """ + ,------*------, + ,------------- '--- ------' + '-------- --' / / + ,---' '-------/ /--, + '----------------' + + THE USS ENTERPRISE --- NCC-1701" + + """ + ); + } + + double fnd(int i) { // 470 + return Math.sqrt((klingonQuadrants[i][1] - sectorX) ^ 2 + (klingonQuadrants[i][2] - sectorY) ^ 2); + } + + static int fnr() { // 475 + // Generate a random integer from 1 to 8 inclusive. + return toInt(random() * 7 + 1); + } + + void setup() { + this.initEnterprisePosition(); + this.setupWhatExistsInTheGalaxy(); + } + + void initEnterprisePosition() { // 480 + quadrantX = fnr(); + quadrantY = fnr(); + sectorX = fnr(); + sectorY = fnr(); + IntStream.range(1, 9).forEach(i -> { + cardinalDirections[i][1] = 0; + cardinalDirections[i][2] = 0; + }); + cardinalDirections[3][1] = -1; + cardinalDirections[2][1] = -1; + cardinalDirections[4][1] = -1; + cardinalDirections[4][2] = -1; + cardinalDirections[5][2] = -1; + cardinalDirections[6][2] = -1; + cardinalDirections[1][2] = 1; + cardinalDirections[2][2] = 1; + cardinalDirections[6][1] = 1; + cardinalDirections[7][1] = 1; + cardinalDirections[8][1] = 1; + cardinalDirections[8][2] = 1; + cardinalDirections[9][2] = 1; + IntStream.range(1, 8).forEach(i -> deviceStatus[i] = 0); + } + + void setupWhatExistsInTheGalaxy() { // 810 + // KLINGONS, STARBASES, STARS + IntStream.range(1, 8).forEach(x -> { + IntStream.range(1, 8).forEach(y -> { + klingons = 0; + chartedGalaxy[x][y] = 0; + float random = random(); + if (random > .98) { + klingons = 3; + klingonsInGalaxy = +3; + } else if (random > .95) { + klingons = 2; + klingonsInGalaxy = +2; + } else if (random > .80) { + klingons = 1; + klingonsInGalaxy = +1; + } + starbases = 0; + if (random() > .96) { + starbases = 1; + basesInGalaxy = +1; + } + galaxy[x][y] = klingons * 100 + starbases * 10 + fnr(); + }); + }); + if (klingonsInGalaxy > missionDuration) missionDuration = klingonsInGalaxy + 1; + if (basesInGalaxy == 0) { + if (galaxy[quadrantX][quadrantY] < 200) { + galaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY] + 120; + klingonsInGalaxy = +1; + } + basesInGalaxy = 1; + galaxy[quadrantX][quadrantY] = +10; + quadrantX = fnr(); + quadrantY = fnr(); + } + remainingKlingons = klingonsInGalaxy; + println("YOUR ORDERS ARE AS FOLLOWS:\n" + + " DESTROY THE " + klingonsInGalaxy + " KLINGON WARSHIP" + ((klingonsInGalaxy == 1) ? "" : "S") + " WHICH HAVE INVADED\n" + + " THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS\n" + + " ON STARDATE " + initialStardate + missionDuration + " THIS GIVES YOU " + missionDuration + " DAYS. THERE " + ((basesInGalaxy == 1) ? "IS" : "ARE") + "\n" + + " " + basesInGalaxy + " STARBASE" + ((basesInGalaxy == 1) ? "" : "S") + " IN THE GALAXY FOR RESUPPLYING YOUR SHIP"); + } + + void enterNewQuadrant() { // 1320 + // ANY TIME NEW QUADRANT ENTERED + klingons = 0; + starbases = 0; + stars = 0; + repairCost = .5 * random(); + chartedGalaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY]; + if (!(quadrantX < 1 || quadrantX > 8 || quadrantY < 1 || quadrantY > 8)) { + final String quadrantName = getQuadrantName(false, quadrantX, quadrantY); + if (initialStardate == stardate) { + println("YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED\n" + + "IN THE GALACTIC QUADRANT, '" + quadrantName + "'."); + } else { + println("NOW ENTERING " + quadrantName + " QUADRANT . . ."); + } + println(""); + klingons = (int) Math.round(galaxy[quadrantX][quadrantY] * .01); + starbases = (int) Math.round(galaxy[quadrantX][quadrantY] * .1) - 10 * klingons; + stars = galaxy[quadrantX][quadrantY] - 100 * klingons - 10 * starbases; + if (klingons != 0) { + println("COMBAT AREA CONDITION RED"); + if (shields <= 200) { + println(" SHIELDS DANGEROUSLY LOW"); + } + } + IntStream.range(1, 3).forEach(i -> { + klingonQuadrants[i][1] = 0; + klingonQuadrants[i][2] = 0; + }); + } + IntStream.range(1, 3).forEach(i -> { + klingonQuadrants[i][3] = 0; + }); + // POSITION ENTERPRISE IN QUADRANT + insertMarker(MARKER_ENTERPRISE, sectorX, sectorY); + // position Klingons + if (klingons >= 1) { + for (int i = 1; i <= klingons; i++) { + final int[] emptyCoordinate = findEmptyPlaceInQuadrant(quadrantMap); + insertMarker(MARKER_KLINGON, emptyCoordinate[0], emptyCoordinate[1]); + klingonQuadrants[i][1] = emptyCoordinate[0]; + klingonQuadrants[i][2] = emptyCoordinate[1]; + klingonQuadrants[i][3] = (int) Math.round(avgKlingonShieldEnergy * (0.5 + random())); + } + } + // position Bases + if (starbases >= 1) { + final int[] emptyCoordinate = findEmptyPlaceInQuadrant(quadrantMap); + starbaseX = emptyCoordinate[0]; + starbaseY = emptyCoordinate[1]; + insertMarker(MARKER_STARBASE, emptyCoordinate[0], emptyCoordinate[1]); + } + // position stars + for (int i = 1; i <= stars; i++) { + final int[] emptyCoordinate = findEmptyPlaceInQuadrant(quadrantMap); + insertMarker(MARKER_STAR, emptyCoordinate[0], emptyCoordinate[1]); + } + shortRangeSensorScan(); // 1980 + } + + void commandLoop() { + while (!this.restart) { + checkShipEnergy(); // 1990 + String cmdStr = ""; + while ("".equals(cmdStr)) cmdStr = inputStr("COMMAND"); + boolean foundCommand = false; + for (int i = 1; i <= 9; i++) { + if (leftStr(cmdStr, 3).equals(midStr(COMMANDS, 3 * i - 2, 3))) { + switch (i) { + case COMMAND_NAV: + navigation(); + foundCommand = true; + break; + case COMMAND_SRS: + shortRangeSensorScan(); + foundCommand = true; + break; + case COMMAND_LRS: + longRangeSensorScan(); + foundCommand = true; + break; + case COMMAND_PHA: + firePhasers(); + foundCommand = true; + break; + case COMMAND_TOR: + firePhotonTorpedo(); + foundCommand = true; + break; + case COMMAND_SHE: + shieldControl(); + foundCommand = true; + break; + case COMMAND_DAM: + damageControl(); + foundCommand = true; + break; + case COMMAND_COM: + libraryComputer(); + foundCommand = true; + break; + case COMMAND_XXX: + endGameFail(false); + foundCommand = true; + break; + default: + printCommandOptions(); + foundCommand = true; + } + } + } + if (!foundCommand) printCommandOptions(); + } + } + + void checkShipEnergy() { + int totalEnergy = (shields + energy); + if (totalEnergy < 10 && (energy <= 10 || deviceStatus[DEVICE_SHIELD_CONTROL] != 0)) { + println("\n** FATAL ERROR ** YOU'VE JUST STRANDED YOUR SHIP IN "); + println("SPACE"); + println("YOU HAVE INSUFFICIENT MANEUVERING ENERGY,"); + println(" AND SHIELD CONTROL"); + println("IS PRESENTLY INCAPABLE OF CROSS"); + println("-CIRCUITING TO ENGINE ROOM!!"); + endGameFail(false); + } + } + + void printCommandOptions() { + println("ENTER ONE OF THE FOLLOWING:"); + println(" NAV (TO SET COURSE)"); + println(" SRS (FOR SHORT RANGE SENSOR SCAN)"); + println(" LRS (FOR LONG RANGE SENSOR SCAN)"); + println(" PHA (TO FIRE PHASERS)"); + println(" TOR (TO FIRE PHOTON TORPEDOES)"); + println(" SHE (TO RAISE OR LOWER SHIELDS)"); + println(" DAM (FOR DAMAGE CONTROL REPORTS)"); + println(" COM (TO CALL ON LIBRARY-COMPUTER)"); + println(" XXX (TO RESIGN YOUR COMMAND)\n"); + } + + void navigation() { // 2290 + float course = toInt(inputFloat("COURSE (0-9)")); + if (course == 9) course = 1; + if (course < 1 || course >= 9) { + println(" LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'"); + return; + } + println("WARP FACTOR (0-" + ((deviceStatus[DEVICE_WARP_ENGINES] < 0) ? "0.2" : "8") + ")"); + float warp = inputFloat(""); + if (deviceStatus[DEVICE_WARP_ENGINES] < 0 && warp > .2) { + // 2470 + println("WARP ENGINES ARE DAMAGED. MAXIMUM SPEED = WARP 0.2"); + return; + } + if (warp == 0) return; + if (warp > 0 && warp <= 8) { + // 2490 + int n = toInt(warp * 8); + if (energy - n >= 0) { + klingonsMoveAndFire(); + repairDamagedDevices(course, warp, n); + moveStarship(course, warp, n); + } else { + println("ENGINEERING REPORTS 'INSUFFICIENT ENERGY AVAILABLE"); + println(" FOR MANEUVERING AT WARP" + warp + "!'"); + if (shields < n - energy || deviceStatus[DEVICE_SHIELD_CONTROL] < 0) return; + println("DEFLECTOR CONTROL ROOM ACKNOWLEDGES" + shields + "UNITS OF ENERGY"); + println(" PRESENTLY DEPLOYED TO SHIELDS."); + return; + } + } else { + println(" CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE"); + println(" WARP " + warp + "!'"); + return; + } + } + + void klingonsMoveAndFire() { // 2590 + // KLINGONS MOVE/FIRE ON MOVING STARSHIP . . . + for (int i = 1; i <= klingons; i++) { + if (klingonQuadrants[i][3] == 0) continue; + insertMarker(MARKER_EMPTY, klingonQuadrants[i][1], klingonQuadrants[i][2]); + final int[] newCoords = findEmptyPlaceInQuadrant(quadrantMap); + klingonQuadrants[i][1] = newCoords[0]; + klingonQuadrants[i][2] = newCoords[1]; + insertMarker(MARKER_KLINGON, klingonQuadrants[i][1], klingonQuadrants[i][2]); + } + klingonsShoot(); + } + + void repairDamagedDevices(final float course, final float warp, final int N) { + // repair damaged devices and print damage report + for (int i = 1; i <= 8; i++) { + if (deviceStatus[i] < 0) { + deviceStatus[i] += Math.min(warp, 1); + if ((deviceStatus[i] > -.1) && (deviceStatus[i] < 0)) { + deviceStatus[i] = -.1; + break; + } else if (deviceStatus[i] >= 0) { + println("DAMAGE CONTROL REPORT: "); + println(tab(8) + printDeviceName(i) + " REPAIR COMPLETED."); + } + } + } + if (random() > .2) moveStarship(course, warp, N); // 80% chance no damage nor repair + int randomDevice = fnr(); // random device + if (random() >= .6) { // 40% chance of repair of random device + deviceStatus[randomDevice] = deviceStatus[randomDevice] + random() * 3 + 1; + println("DAMAGE CONTROL REPORT: " + printDeviceName(randomDevice) + " STATE OF REPAIR IMPROVED\n"); + } else { // 60% chance of damage of random device + deviceStatus[randomDevice] = deviceStatus[randomDevice] - (random() * 5 + 1); // + println("DAMAGE CONTROL REPORT: " + printDeviceName(randomDevice) + " DAMAGED"); + } + } + + void moveStarship(final float course, final float warp, final int n) { // 3070 + insertMarker(MARKER_EMPTY, toInt(sectorX), toInt(sectorY)); + int ic1 = toInt(course); + float x1 = cardinalDirections[ic1][1] + (cardinalDirections[ic1 + 1][1] - cardinalDirections[ic1][1]) * (course - ic1); + float x = sectorX; + float y = sectorY; + float x2 = cardinalDirections[ic1][2] + (cardinalDirections[ic1 + 1][2] - cardinalDirections[ic1][2]) * (course - ic1); + final int initialQuadrantX = quadrantX; + final int initialQuadrantY = quadrantY; + for (int i = 1; i <= n; i++) { + sectorX += x1; + sectorY += x2; + if (sectorX < 1 || sectorX >= 9 || sectorY < 1 || sectorY >= 9) { + // exceeded quadrant limits + x = 8 * quadrantX + x + n * x1; + y = 8 * quadrantY + y + n * x2; + quadrantX = toInt(x / 8); + quadrantY = toInt(y / 8); + sectorX = toInt(x - quadrantX * 8); + sectorY = toInt(y - quadrantY * 8); + if (sectorX == 0) { + quadrantX = quadrantX - 1; + sectorX = 8; + } + if (sectorY == 0) { + quadrantY = quadrantY - 1; + sectorY = 8; + } + boolean hitEdge = false; + if (quadrantX < 1) { + hitEdge = true; + quadrantX = 1; + sectorX = 1; + } + if (quadrantX > 8) { + hitEdge = true; + quadrantX = 8; + sectorX = 8; + } + if (quadrantY < 1) { + hitEdge = true; + quadrantY = 8; + sectorY = 8; + } + if (quadrantY > 8) { + hitEdge = true; + quadrantY = 8; + sectorY = 8; + } + if (hitEdge) { + println("LT. UHURA REPORTS MESSAGE FROM STARFLEET COMMAND:"); + println(" 'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER"); + println(" IS HEREBY *DENIED*. SHUT DOWN YOUR ENGINES.'"); + println("CHIEF ENGINEER SCOTT REPORTS 'WARP ENGINES SHUT DOWN"); + println(" AT SECTOR " + sectorX + "," + sectorY + " OF QUADRANT " + quadrantX + "," + quadrantY + ".'"); + if (stardate > initialStardate + missionDuration) endGameFail(false); + } + if (8 * quadrantX + quadrantY == 8 * initialQuadrantX + initialQuadrantY) { + break; + } + stardate += 1; + maneuverEnergySR(n); + enterNewQuadrant(); + return; + } else { + int S8 = toInt(sectorX) * 24 + toInt(sectorY) * 3 - 26; // S8 = pos + if (!(" ".equals(midStr(quadrantMap, S8, 2)))) { + sectorX = toInt(sectorX - x1); + sectorY = toInt(sectorY - x2); + println("WARP ENGINES SHUT DOWN AT "); + println("SECTOR " + sectorX + "," + sectorY + " DUE TO BAD NAVIGATION"); + break; + } + } + } + sectorX = toInt(sectorX); + sectorY = toInt(sectorY); + insertMarker(MARKER_ENTERPRISE, toInt(sectorX), toInt(sectorY)); + maneuverEnergySR(n); + double stardateDelta = 1; + if (warp < 1) stardateDelta = .1 * toInt(10 * warp); + stardate = stardate + stardateDelta; + if (stardate > initialStardate + missionDuration) endGameFail(false); + shortRangeSensorScan(); + } + + void maneuverEnergySR(final int N) { // 3910 + energy = energy - N - 10; + if (energy >= 0) return; + println("SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER."); + shields = shields + energy; + energy = 0; + if (shields <= 0) shields = 0; + } + + void longRangeSensorScan() { // 3390 + // LONG RANGE SENSOR SCAN CODE + if (deviceStatus[DEVICE_LONG_RANGE_SENSORS] < 0) { + println("LONG RANGE SENSORS ARE INOPERABLE"); + return; + } + println("LONG RANGE SCAN FOR QUADRANT " + quadrantX + "," + quadrantY); + final String rowStr = "-------------------"; + println(rowStr); + final int n[] = new int[4]; + for (int i = quadrantX - 1; i <= quadrantX + 1; i++) { + n[1] = -1; + n[2] = -2; + n[3] = -3; + for (int j = quadrantY - 1; j <= quadrantY + 1; j++) { + if (i > 0 && i < 9 && j > 0 && j < 9) { + n[j - quadrantY + 2] = galaxy[i][j]; + chartedGalaxy[i][j] = galaxy[i][j]; + } + } + for (int l = 1; l <= 3; l++) { + print(": "); + if (n[l] < 0) { + print("*** "); + continue; + } + print(": " + rightStr(Integer.toString(n[l] + 1000), 3) + " "); + } + println(": \n" + rowStr); + } + } + + void firePhasers() { // 4260 + if (deviceStatus[DEVICE_PHASER_CONTROL] < 0) { + println("PHASERS INOPERATIVE"); + return; + } + if (klingons <= 0) { + printNoEnemyShipsMessage(); + return; + } + if (deviceStatus[DEVICE_LIBRARY_COMPUTER] < 0) println("COMPUTER FAILURE HAMPERS ACCURACY"); + println("PHASERS LOCKED ON TARGET; "); + int nrUnitsToFire; + while (true) { + println("ENERGY AVAILABLE = " + energy + " UNITS"); + nrUnitsToFire = toInt(inputFloat("NUMBER OF UNITS TO FIRE")); + if (nrUnitsToFire <= 0) return; + if (energy - nrUnitsToFire >= 0) break; + } + energy = energy - nrUnitsToFire; + if (deviceStatus[DEVICE_SHIELD_CONTROL] < 0) nrUnitsToFire = toInt(nrUnitsToFire * random()); + int h1 = toInt(nrUnitsToFire / klingons); + for (int i = 1; i <= 3; i++) { + if (klingonQuadrants[i][3] <= 0) break; + int hitPoints = toInt((h1 / fnd(0)) * (random() + 2)); + if (hitPoints <= .15 * klingonQuadrants[i][3]) { + println("SENSORS SHOW NO DAMAGE TO ENEMY AT " + klingonQuadrants[i][1] + "," + klingonQuadrants[i][2]); + continue; + } + klingonQuadrants[i][3] = klingonQuadrants[i][3] - hitPoints; + println(hitPoints + " UNIT HIT ON KLINGON AT SECTOR " + klingonQuadrants[i][1] + "," + klingonQuadrants[i][2]); + if (klingonQuadrants[i][3] <= 0) { + println("*** KLINGON DESTROYED ***"); + klingons -= 1; + klingonsInGalaxy -= 1; + insertMarker(MARKER_EMPTY, klingonQuadrants[i][1], klingonQuadrants[i][2]); + klingonQuadrants[i][3] = 0; + galaxy[quadrantX][quadrantY] -= 100; + chartedGalaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY]; + if (klingonsInGalaxy <= 0) endGameSuccess(); + } else { + println(" (SENSORS SHOW" + klingonQuadrants[i][3] + "UNITS REMAINING)"); + } + } + klingonsShoot(); + } + + void printNoEnemyShipsMessage() { // 4270 + println("SCIENCE OFFICER SPOCK REPORTS 'SENSORS SHOW NO ENEMY SHIPS"); + println(" IN THIS QUADRANT'"); + } + + void firePhotonTorpedo() { // 4700 + // PHOTON TORPEDO CODE BEGINS HERE + if (torpedoes <= 0) { + println("ALL PHOTON TORPEDOES EXPENDED"); + return; + } + if (deviceStatus[DEVICE_PHOTON_TUBES] < 0) { + println("PHOTON TUBES ARE NOT OPERATIONAL"); + } + float c1 = inputFloat("PHOTON TORPEDO COURSE (1-9)"); + if (c1 == 9) c1 = 1; + if (c1 < 1 && c1 >= 9) { + println("ENSIGN CHEKOV REPORTS, 'INCORRECT COURSE DATA, SIR!'"); + return; + } + int ic1 = toInt(c1); + float x1 = cardinalDirections[ic1][1] + (cardinalDirections[ic1 + 1][1] - cardinalDirections[ic1][1]) * (c1 - ic1); + energy = energy - 2; + torpedoes = torpedoes - 1; + float x2 = cardinalDirections[ic1][2] + (cardinalDirections[ic1 + 1][2] - cardinalDirections[ic1][2]) * (c1 - ic1); + float x = sectorX; + float y = sectorY; + println("TORPEDO TRACK:"); + while (true) { + x = x + x1; + y = y + x2; + int x3 = Math.round(x); + int y3 = Math.round(y); + if (x3 < 1 || x3 > 8 || y3 < 1 || y3 > 8) { + println("TORPEDO MISSED"); // 5490 + klingonsShoot(); + return; + } + println(" " + x3 + "," + y3); + if (compareMarker(quadrantMap, MARKER_EMPTY, toInt(x), toInt(y))) { + continue; + } else if (compareMarker(quadrantMap, MARKER_KLINGON, toInt(x), toInt(y))) { + println("*** KLINGON DESTROYED ***"); + klingons = klingons - 1; + klingonsInGalaxy = klingonsInGalaxy - 1; + if (klingonsInGalaxy <= 0) endGameSuccess(); + for (int i = 1; i <= 3; i++) { + if (x3 == klingonQuadrants[i][1] && y3 == klingonQuadrants[i][2]) break; + } + int i = 3; + klingonQuadrants[i][3] = 0; + } else if (compareMarker(quadrantMap, MARKER_STAR, toInt(x), toInt(y))) { + println("STAR AT " + x3 + "," + y3 + " ABSORBED TORPEDO ENERGY."); + klingonsShoot(); + return; + } else if (compareMarker(quadrantMap, MARKER_STARBASE, toInt(x), toInt(y))) { + println("*** STARBASE DESTROYED ***"); + starbases = starbases - 1; + basesInGalaxy = basesInGalaxy - 1; + if (basesInGalaxy == 0 && klingonsInGalaxy <= stardate - initialStardate - missionDuration) { + println("THAT DOES IT, CAPTAIN!! YOU ARE HEREBY RELIEVED OF COMMAND"); + println("AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!"); + endGameFail(false); + } else { + println("STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER"); + println("COURT MARTIAL!"); + shipDocked = false; + } + } + insertMarker(MARKER_EMPTY, toInt(x), toInt(y)); + galaxy[quadrantX][quadrantY] = klingons * 100 + starbases * 10 + stars; + chartedGalaxy[quadrantX][quadrantY] = galaxy[quadrantX][quadrantY]; + klingonsShoot(); + } + } + + void shieldControl() { + if (deviceStatus[DEVICE_SHIELD_CONTROL] < 0) { + println("SHIELD CONTROL INOPERABLE"); + return; + } + println("ENERGY AVAILABLE = " + (energy + shields)); + int energyToShields = toInt(inputFloat("NUMBER OF UNITS TO SHIELDS")); + if (energyToShields < 0 || shields == energyToShields) { + println(""); + return; + } + if (energyToShields > energy + energyToShields) { + println("SHIELD CONTROL REPORTS 'THIS IS NOT THE FEDERATION TREASURY.'"); + println(""); + return; + } + energy = energy + shields - energyToShields; + shields = energyToShields; + println("DEFLECTOR CONTROL ROOM REPORT:"); + println(" 'SHIELDS NOW AT " + toInt(shields) + " UNITS PER YOUR COMMAND.'"); + } + + void shortRangeSensorScan() { // 6430 + // SHORT RANGE SENSOR SCAN & STARTUP SUBROUTINE + boolean docked = false; + String shipCondition; // ship condition (docked, red, yellow, green) + for (int i = sectorX - 1; i <= sectorX + 1; i++) { + for (int j = sectorY - 1; j <= sectorY + 1; j++) { + if ((toInt(i) >= 1) && (toInt(i) <= 8) && (toInt(j) >= 1) && (toInt(j) <= 8)) { + if (compareMarker(quadrantMap, MARKER_STARBASE, i, j)) { + docked = true; + } + } + } + } + if (!docked) { + shipDocked = false; + if (klingons > 0) { + shipCondition = "*RED*"; + } else { + shipCondition = "GREEN"; + if (energy < initialEnergy * .1) { + shipCondition = "YELLOW"; + } + } + } else { + shipDocked = true; + shipCondition = "DOCKED"; + energy = initialEnergy; + torpedoes = initialTorpedoes; + println("SHIELDS DROPPED FOR DOCKING PURPOSES"); + shields = 0; + } + if (deviceStatus[DEVICE_SHORT_RANGE_SENSORS] < 0) { // are short range sensors out? + println("\n*** SHORT RANGE SENSORS ARE OUT ***\n"); + return; + } + final String row = "---------------------------------"; + println(row); + for (int i = 1; i <= 8; i++) { + String sectorMapRow = ""; + for (int j = (i - 1) * 24 + 1; j <= (i - 1) * 24 + 22; j += 3) { + sectorMapRow += " " + midStr(quadrantMap, j, 3); + } + switch (i) { + case 1: + println(sectorMapRow + " STARDATE " + toInt(stardate * 10) * .1); + break; + case 2: + println(sectorMapRow + " CONDITION " + shipCondition); + break; + case 3: + println(sectorMapRow + " QUADRANT " + quadrantX + "," + quadrantY); + break; + case 4: + println(sectorMapRow + " SECTOR " + sectorX + "," + sectorY); + break; + case 5: + println(sectorMapRow + " PHOTON TORPEDOES " + toInt(torpedoes)); + break; + case 6: + println(sectorMapRow + " TOTAL ENERGY " + toInt((energy + shields))); + break; + case 7: + println(sectorMapRow + " SHIELDS " + toInt(shields)); + break; + case 8: + println(sectorMapRow + " KLINGONS REMAINING " + toInt(klingonsInGalaxy)); + } + ; + } + println(row); // 7260 + } + + void libraryComputer() { // 7290 + // REM LIBRARY COMPUTER CODE + if (deviceStatus[DEVICE_LIBRARY_COMPUTER] < 0) { + println("COMPUTER DISABLED"); + return; + } + while (true) { + final float commandInput = inputFloat("COMPUTER ACTIVE AND AWAITING COMMAND"); + if (commandInput < 0) return; + println(""); + int command = toInt(commandInput) + 1; + if (command >= COMPUTER_COMMAND_CUMULATIVE_GALACTIC_RECORD && command <= COMPUTER_COMMAND_GALAXY_MAP) { + switch (command) { + case COMPUTER_COMMAND_CUMULATIVE_GALACTIC_RECORD: + //GOTO 7540 + cumulativeGalacticRecord(true); + return; + case COMPUTER_COMMAND_STATUS_REPORT: + //GOTO 7900 + statusReport(); + return; + case COMPUTER_COMMAND_PHOTON_TORPEDO_DATA: + //GOTO 8070 + photonTorpedoData(); + return; + case COMPUTER_COMMAND_STARBASE_NAV_DATA: + //GOTO 8500 + starbaseNavData(); + return; + case COMPUTER_COMMAND_DIR_DIST_CALC: + //GOTO 8150 + directionDistanceCalculator(); + return; + case COMPUTER_COMMAND_GALAXY_MAP: + //GOTO 7400 + cumulativeGalacticRecord(false); + return; + } + } else { + // invalid command + println("FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:"); + println(" 0 = CUMULATIVE GALACTIC RECORD"); + println(" 1 = STATUS REPORT"); + println(" 2 = PHOTON TORPEDO DATA"); + println(" 3 = STARBASE NAV DATA"); + println(" 4 = DIRECTION/DISTANCE CALCULATOR"); + println(" 5 = GALAXY 'REGION NAME' MAP"); + println(""); + } + } + } + + void cumulativeGalacticRecord(final boolean cumulativeReport) { // 7540 + if (cumulativeReport) { + println(""); + println(" "); + println("COMPUTER RECORD OF GALAXY FOR QUADRANT " + quadrantX + "," + quadrantY); + println(""); + } else { + println(" THE GALAXY"); + } + println(" 1 2 3 4 5 6 7 8"); + final String rowDivider = " ----- ----- ----- ----- ----- ----- ----- -----"; + println(rowDivider); + for (int i = 1; i <= 8; i++) { + print(i + " "); + if (cumulativeReport) { + int y = 1; + String quadrantName = getQuadrantName(false, i, y); + int tabLen = toInt(15 - .5 * strlen(quadrantName)); + println(tab(tabLen) + quadrantName); + y = 5; + quadrantName = getQuadrantName(false, i, y); + tabLen = toInt(39 - .5 * strlen(quadrantName)); + println(tab(tabLen) + quadrantName); + } else { + for (int j = 1; j <= 8; j++) { + print(" "); + if (chartedGalaxy[i][j] == 0) { + print("***"); + } else { + print(rightStr(Integer.toString(chartedGalaxy[i][j] + 1000), 3)); + } + } + } + println(""); + println(rowDivider); + } + println(""); + } + + void statusReport() { // 7900 + println(" STATUS REPORT:"); + println("KLINGON" + ((klingonsInGalaxy > 1)? "S" : "") + " LEFT: " + klingonsInGalaxy); + println("MISSION MUST BE COMPLETED IN " + .1 * toInt((initialStardate + missionDuration - stardate) * 10) + "STARDATES"); + if (basesInGalaxy >= 1) { + println("THE FEDERATION IS MAINTAINING " + basesInGalaxy + " STARBASE" + ((basesInGalaxy > 1)? "S" : "") + " IN THE GALAXY"); + } else { + println("YOUR STUPIDITY HAS LEFT YOU ON YOUR OWN IN"); + println(" THE GALAXY -- YOU HAVE NO STARBASES LEFT!"); + } + damageControl(); + } + + void photonTorpedoData() { // 8070 + // TORPEDO, BASE NAV, D/D CALCULATOR + if (klingons <= 0) { + printNoEnemyShipsMessage(); + return; + } + println("FROM ENTERPRISE TO KLINGON BATTLE CRUISER" + ((klingons > 1)? "S" : "")); + for (int i = 1; i <= 3; i++) { + if (klingonQuadrants[i][3] > 0) { + printDirection(sectorX, sectorY, klingonQuadrants[i][1], klingonQuadrants[i][2]); + } + } + } + + void directionDistanceCalculator() { // 8150 + println("DIRECTION/DISTANCE CALCULATOR:"); + println("YOU ARE AT QUADRANT " + quadrantX + "," + quadrantY + " SECTOR " + sectorX + "," + sectorY); + print("PLEASE ENTER "); + int[] initialCoords = inputCoords(" INITIAL COORDINATES (X,Y)"); + int[] finalCoords = inputCoords(" FINAL COORDINATES (X,Y)"); + printDirection(initialCoords[0], initialCoords[1], finalCoords[0], finalCoords[1]); + } + + void printDirection(int from_x, int from_y, int to_x, int to_y) { // 8220 + to_y = to_y - from_y; // delta 2 + from_y = from_x - to_x; // delta 1 + if (to_y > 0) { + if (from_y < 0) { + from_x = 7; + } else { + from_x = 1; + int tempA = from_y; + from_y = to_y; + to_y = tempA; + } + } else { + if (from_y > 0) { + from_x = 3; + } else { + from_x = 5; + int tempA = from_y; + from_y = to_y; + to_y = tempA; + } + } + + from_y = Math.abs(from_y); + to_y = Math.abs(to_y); + + if (from_y > 0 || to_y > 0) { + if (from_y >= to_y) { + println("DIRECTION = " + (from_x + to_y / from_y)); + } else { + println("DIRECTION = " + (from_x + 2 - to_y / from_y)); + } + } + println("DISTANCE = " + round(Math.sqrt(to_y ^ 2 + from_y ^ 2), 6)); + } + + void starbaseNavData() { // 8500 + if (starbases != 0) { + println("FROM ENTERPRISE TO STARBASE:"); + printDirection(sectorX, sectorY, starbaseX, starbaseY); + } else { + println("MR. SPOCK REPORTS, 'SENSORS SHOW NO STARBASES IN THIS"); + println(" QUADRANT.'"); + } + } + + /** + * Finds random empty coordinates in a quadrant. + * + * @param quadrantString + * @return an array with a pair of coordinates x, y + */ + int[] findEmptyPlaceInQuadrant(String quadrantString) { // 8590 + final int x = fnr(); + final int y = fnr(); + if (!compareMarker(quadrantString, MARKER_EMPTY, x, y)) { + return findEmptyPlaceInQuadrant(quadrantString); + } + return new int[]{x, y}; + } + + + void insertMarker(final String marker, final int x, final int y) { // 8670 + final int pos = toInt(y) * 3 + toInt(x) * 24 + 1; + if (marker.length() != 3) { + System.err.println("ERROR"); + System.exit(-1); + } + if (pos == 1) { + quadrantMap = marker + rightStr(quadrantMap, 189); + } + if (pos == 190) { + quadrantMap = leftStr(quadrantMap, 189) + marker; + } + quadrantMap = leftStr(quadrantMap, (pos - 1)) + marker + rightStr(quadrantMap, (190 - pos)); + } + + String printDeviceName(final int deviceNumber) { // 8790 + // PRINTS DEVICE NAME + switch (deviceNumber) { + case DEVICE_WARP_ENGINES: + return "WARP ENGINES"; + case DEVICE_SHORT_RANGE_SENSORS: + return "SHORT RANGE SENSORS"; + case DEVICE_LONG_RANGE_SENSORS: + return "LONG RANGE SENSORS"; + case DEVICE_PHASER_CONTROL: + return "PHASER CONTROL"; + case DEVICE_PHOTON_TUBES: + return "PHOTON TUBES"; + case DEVICE_DAMAGE_CONTROL: + return "DAMAGE CONTROL"; + case DEVICE_SHIELD_CONTROL: + return "SHIELD CONTROL"; + case DEVICE_LIBRARY_COMPUTER: + return "LIBRARY-COMPUTER"; + } + return ""; + } + + boolean compareMarker(final String quadrantString, final String marker, int x, int y) { // 8830 + final int markerRegion = (y - 1) * 3 + (x - 1) * 24 + 1; + if (midStr(quadrantString, markerRegion, 3).equals(marker)) { + return true; + } + return false; + } + + String getRegionName(final boolean regionNameOnly, final int y) { + if (!regionNameOnly) { + switch (y % 4) { + case 1: + return " I"; + case 2: + return " II"; + case 3: + return " III"; + case 4: + return " IV"; + } + } + return ""; + } + + String getQuadrantName(final boolean regionNameOnly, final int x, final int y) { // 9030 + if (y <= 4) { + switch (x) { + case 1: + return "ANTARES" + getRegionName(regionNameOnly, y); + case 2: + return "RIGEL" + getRegionName(regionNameOnly, y); + case 3: + return "PROCYON" + getRegionName(regionNameOnly, y); + case 4: + return "VEGA" + getRegionName(regionNameOnly, y); + case 5: + return "CANOPUS" + getRegionName(regionNameOnly, y); + case 6: + return "ALTAIR" + getRegionName(regionNameOnly, y); + case 7: + return "SAGITTARIUS" + getRegionName(regionNameOnly, y); + case 8: + return "POLLUX" + getRegionName(regionNameOnly, y); + } + } else { + switch (x) { + case 1: + return "SIRIUS" + getRegionName(regionNameOnly, y); + case 2: + return "DENEB" + getRegionName(regionNameOnly, y); + case 3: + return "CAPELLA" + getRegionName(regionNameOnly, y); + case 4: + return "BETELGEUSE" + getRegionName(regionNameOnly, y); + case 5: + return "ALDEBARAN" + getRegionName(regionNameOnly, y); + case 6: + return "REGULUS" + getRegionName(regionNameOnly, y); + case 7: + return "ARCTURUS" + getRegionName(regionNameOnly, y); + case 8: + return "SPICA" + getRegionName(regionNameOnly, y); + } + } + return "UNKNOWN - ERROR"; + } + + void damageControl() { // 5690 + if (deviceStatus[DEVICE_DAMAGE_CONTROL] < 0) { + println("DAMAGE CONTROL REPORT NOT AVAILABLE"); + } else { + println("\nDEVICE STATE OF REPAIR"); + for (int deviceNr = 1; deviceNr <= 8; deviceNr++) { + print(printDeviceName(deviceNr) + leftStr(QUADRANT_ROW, 25 - strlen(printDeviceName(deviceNr))) + " " + toInt(deviceStatus[deviceNr] * 100) * .01 + "\n"); + } + } + if (!shipDocked) return; + + double deltaToRepair = 0; + for (int i = 1; i <= 8; i++) { + if (deviceStatus[i] < 0) deltaToRepair += .1; + } + if (deltaToRepair > 0) { + deltaToRepair += repairCost; + if (deltaToRepair >= 1) deltaToRepair = .9; + println("TECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;"); + println("ESTIMATED TIME TO REPAIR:'" + .01 * toInt(100 * deltaToRepair) + " STARDATES"); + final String reply = inputStr("WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)"); + if ("Y".equals(reply)) { + for (int deviceNr = 1; deviceNr <= 8; deviceNr++) { + if (deviceStatus[deviceNr] < 0) deviceStatus[deviceNr] = 0; + } + stardate = stardate + deltaToRepair + .1; + } + } + } + + void klingonsShoot() { // 6000 + if (klingons <= 0) return; // no klingons + if (shipDocked) { // enterprise is docked + println("STARBASE SHIELDS PROTECT THE ENTERPRISE"); + return; + } + for (int i = 1; i <= 3; i++) { + if (klingonQuadrants[i][3] <= 0) continue; + int hits = toInt((klingonQuadrants[i][3] / fnd(1)) * (2 + random())); // hit points + shields = shields - hits; + klingonQuadrants[i][3] = toInt(klingonQuadrants[i][3] / (3 + random())); // FIXME: RND(0) + println(hits + " UNIT HIT ON ENTERPRISE FROM SECTOR " + klingonQuadrants[i][1] + "," + klingonQuadrants[i][2]); + if (shields <= 0) endGameFail(true); + println(" "); + if (hits < 20) continue; + if ((random() > .6) || (hits / shields <= .02)) continue; + int randomDevice = fnr(); + deviceStatus[randomDevice] = deviceStatus[randomDevice] - hits / shields - .5 * random(); + println("DAMAGE CONTROL REPORTS " + printDeviceName(randomDevice) + " DAMAGED BY THE HIT'"); + } + } + + void endGameFail(final boolean enterpriseDestroyed) { // 6220 + if (enterpriseDestroyed) { + println("\nTHE ENTERPRISE HAS BEEN DESTROYED. THEN FEDERATION "); + println("WILL BE CONQUERED"); + } + println("\nIT IS STARDATE " + stardate); + println("THERE WERE " + klingonsInGalaxy + " KLINGON BATTLE CRUISERS LEFT AT"); + println("THE END OF YOUR MISSION."); + repeatGame(); + } + + void endGameSuccess() { // 6370 + println("CONGRATULATION, CAPTAIN! THE LAST KLINGON BATTLE CRUISER"); + println("MENACING THE FEDERATION HAS BEEN DESTROYED.\n"); + println("YOUR EFFICIENCY RATING IS " + (Math.sqrt(1000 * (remainingKlingons / (stardate - initialStardate))))); + repeatGame(); + } + + void repeatGame() {// 6290 + println("\n"); + if (basesInGalaxy != 0) { + println("THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER"); + println("FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER,"); + final String reply = inputStr("LET HIM STEP FORWARD AND ENTER 'AYE'"); + if ("AYE".equals(reply)) { + this.restart = true; + } else { + System.exit(0); + } + } + } + + static int toInt(final double num) { + int x = (int) Math.floor(num); + if (x < 0) x *= -1; + return x; + } + + static void println(final String s) { + System.out.println(s); + } + + static void print(final String s) { + System.out.print(s); + } + + static String tab(final int n) { + return IntStream.range(1, n).mapToObj(num -> " ").collect(Collectors.joining()); + } + + static int strlen(final String s) { + return s.length(); + } + + static String inputStr(final String message) { + System.out.print(message + "? "); + final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + try { + return reader.readLine(); + } catch (IOException ioe) { + ioe.printStackTrace(); + return ""; + } + } + + static int[] inputCoords(final String message) { + while (true) { + final String input = inputStr(message); + try { + final String[] splitInput = input.split(","); + if (splitInput.length == 2) { + int x = Integer.parseInt(splitInput[0]); + int y = Integer.parseInt(splitInput[0]); + return new int[]{x, y}; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + static float inputFloat(final String message) { + while (true) { + System.out.print(message + "? "); + final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + try { + final String input = reader.readLine(); + if (input.length() > 0) { + return Float.parseFloat(input); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + static String leftStr(final String input, final int len) { + if (input == null || input.length() < len) return input; + return input.substring(0, len); + } + + static String midStr(final String input, final int start, final int len) { + if (input == null || input.length() < ((start - 1) + len)) return input; + return input.substring(start - 1, (start - 1) + len); + } + + static String rightStr(final String input, final int len) { + if (input == null || input.length() < len) return ""; + return input.substring(input.length() - len); + } + + static float random() { + return random.nextFloat(); + } + + private static double round(double value, int places) { + if (places < 0) throw new IllegalArgumentException(); + BigDecimal bd = new BigDecimal(Double.toString(value)); + bd = bd.setScale(places, RoundingMode.HALF_UP); + return bd.doubleValue(); + } +} diff --git a/84_Super_Star_Trek/java/SuperStarTrekInstructions.java b/84_Super_Star_Trek/java/SuperStarTrekInstructions.java new file mode 100644 index 00000000..16f730da --- /dev/null +++ b/84_Super_Star_Trek/java/SuperStarTrekInstructions.java @@ -0,0 +1,162 @@ +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +/** + * SUPER STARTREK INSTRUCTIONS + * MAR 5, 1978 + * Just the instructions for SUPERSTARTREK + * + * Ported to Java in Jan-Feb 2022 by + * Taciano Dreckmann Perez (taciano.perez@gmail.com) + */ +public class SuperStarTrekInstructions { + + public static void main(String[] args) { + printBanner(); + final String reply = inputStr("DO YOU NEED INSTRUCTIONS (Y/N)? "); + if ("Y".equals(reply)) { + printInstructions(); + } + } + + static void printBanner() { + print(tab(10)+"*************************************"); + print(tab(10)+"* *"); + print(tab(10)+"* *"); + print(tab(10)+"* * * SUPER STAR TREK * * *"); + print(tab(10)+"* *"); + print(tab(10)+"* *"); + print(tab(10)+"*************************************"); + } + + static void printInstructions() { + print(" INSTRUCTIONS FOR 'SUPER STAR TREK'"); + print(""); + print("1. WHEN YOU SEE \\COMMAND ?\\ PRINTED, ENTER ONE OF THE LEGAL"); + print(" COMMANDS (NAV,SRS,LRS,PHA,TOR,SHE,DAM,COM, OR XXX)."); + print("2. IF YOU SHOULD TYPE IN AN ILLEGAL COMMAND, YOU'LL GET A SHORT"); + print(" LIST OF THE LEGAL COMMANDS PRINTED OUT."); + print("3. SOME COMMANDS REQUIRE YOU TO ENTER DATA (FOR EXAMPLE, THE"); + print(" 'NAV' COMMAND COMES BACK WITH 'COURSE (1-9) ?'.) IF YOU"); + print(" TYPE IN ILLEGAL DATA (LIKE NEGATIVE NUMBERS), THAN COMMAND"); + print(" WILL BE ABORTED"); + print(""); + print(" THE GALAXY IS DIVIDED INTO AN 8 X 8 QUADRANT GRID,"); + print("AND EACH QUADRANT IS FURTHER DIVIDED INTO AN 8 X 8 SECTOR GRID."); + print(""); + print(" YOU WILL BE ASSIGNED A STARTING POINT SOMEWHERE IN THE"); + print("GALAXY TO BEGIN A TOUR OF DUTY AS COMANDER OF THE STARSHIP"); + print("\\ENTERPRISE\\; YOUR MISSION: TO SEEK AND DESTROY THE FLEET OF"); + print("KLINGON WARWHIPS WHICH ARE MENACING THE UNITED FEDERATION OF"); + print("PLANETS."); + print(""); + print(" YOU HAVE THE FOLLOWING COMMANDS AVAILABLE TO YOU AS CAPTAIN"); + print("OF THE STARSHIP ENTERPRISE:"); + print(""); + print("\\NAV\\ COMMAND = WARP ENGINE CONTROL --"); + print(" COURSE IS IN A CIRCULAR NUMERICAL 4 3 2"); + print(" VECTOR ARRANGEMENT AS SHOWN . . ."); + print(" INTEGER AND REAL VALUES MAY BE ..."); + print(" USED. (THUS COURSE 1.5 IS HALF- 5 ---*--- 1"); + print(" WAY BETWEEN 1 AND 2 ..."); + print(" . . ."); + print(" VALUES MAY APPROACH 9.0, WHICH 6 7 8"); + print(" ITSELF IS EQUIVALENT TO 1.0"); + print(" COURSE"); + print(" ONE WARP FACTOR IS THE SIZE OF "); + print(" ONE QUADTANT. THEREFORE, TO GET"); + print(" FROM QUADRANT 6,5 TO 5,5, YOU WOULD"); + print(" USE COURSE 3, WARP FACTOR 1."); + print(""); + print("\\SRS\\ COMMAND = SHORT RANGE SENSOR SCAN"); + print(" SHOWS YOU A SCAN OF YOUR PRESENT QUADRANT."); + print(""); + print(" SYMBOLOGY ON YOUR SENSOR SCREEN IS AS FOLLOWS:"); + print(" <*> = YOUR STARSHIP'S POSITION"); + print(" +K+ = KLINGON BATTLE CRUISER"); + print(" >!< = FEDERATION STARBASE (REFUEL/REPAIR/RE-ARM HERE!)"); + print(" * = STAR"); + print(""); + print(" A CONDENSED 'STATUS REPORT' WILL ALSO BE PRESENTED."); + print(""); + print("\\LRS\\ COMMAND = LONG RANGE SENSOR SCAN"); + print(" SHOWS CONDITIONS IN SPACE FOR ONE QUADRANT ON EACH SIDE"); + print(" OF THE ENTERPRISE (WHICH IS IN THE MIDDLE OF THE SCAN)"); + print(" THE SCAN IS CODED IN THE FORM \\###\\, WHERE TH UNITS DIGIT"); + print(" IS THE NUMBER OF STARS, THE TENS DIGIT IS THE NUMBER OF"); + print(" STARBASES, AND THE HUNDRESDS DIGIT IS THE NUMBER OF"); + print(" KLINGONS."); + print(""); + print(" EXAMPLE - 207 = 2 KLINGONS, NO STARBASES, & 7 STARS."); + print(""); + print("\\PHA\\ COMMAND = PHASER CONTROL."); + print(" ALLOWS YOU TO DESTROY THE KLINGON BATTLE CRUISERS BY "); + print(" ZAPPING THEM WITH SUITABLY LARGE UNITS OF ENERGY TO"); + print(" DEPLETE THEIR SHIELD POWER. (REMEMBER, KLINGONS HAVE"); + print(" PHASERS TOO!)"); + print(""); + print("\\TOR\\ COMMAND = PHOTON TORPEDO CONTROL"); + print(" TORPEDO COURSE IS THE SAME AS USED IN WARP ENGINE CONTROL"); + print(" IF YOU HIT THE KLINGON VESSEL, HE IS DESTROYED AND"); + print(" CANNOT FIRE BACK AT YOU. IF YOU MISS, YOU ARE SUBJECT TO"); + print(" HIS PHASER FIRE. IN EITHER CASE, YOU ARE ALSO SUBJECT TO "); + print(" THE PHASER FIRE OF ALL OTHER KLINGONS IN THE QUADRANT."); + print(""); + print(" THE LIBRARY-COMPUTER (\\COM\\ COMMAND) HAS AN OPTION TO "); + print(" COMPUTE TORPEDO TRAJECTORY FOR YOU (OPTION 2)"); + print(""); + print("\\SHE\\ COMMAND = SHIELD CONTROL"); + print(" DEFINES THE NUMBER OF ENERGY UNITS TO BE ASSIGNED TO THE"); + print(" SHIELDS. ENERGY IS TAKEN FROM TOTAL SHIP'S ENERGY. NOTE"); + print(" THAN THE STATUS DISPLAY TOTAL ENERGY INCLUDES SHIELD ENERGY"); + print(""); + print("\\DAM\\ COMMAND = DAMMAGE CONTROL REPORT"); + print(" GIVES THE STATE OF REPAIR OF ALL DEVICES. WHERE A NEGATIVE"); + print(" 'STATE OF REPAIR' SHOWS THAT THE DEVICE IS TEMPORARILY"); + print(" DAMAGED."); + print(""); + print("\\COM\\ COMMAND = LIBRARY-COMPUTER"); + print(" THE LIBRARY-COMPUTER CONTAINS SIX OPTIONS:"); + print(" OPTION 0 = CUMULATIVE GALACTIC RECORD"); + print(" THIS OPTION SHOWES COMPUTER MEMORY OF THE RESULTS OF ALL"); + print(" PREVIOUS SHORT AND LONG RANGE SENSOR SCANS"); + print(" OPTION 1 = STATUS REPORT"); + print(" THIS OPTION SHOWS THE NUMBER OF KLINGONS, STARDATES,"); + print(" AND STARBASES REMAINING IN THE GAME."); + print(" OPTION 2 = PHOTON TORPEDO DATA"); + print(" WHICH GIVES DIRECTIONS AND DISTANCE FROM THE ENTERPRISE"); + print(" TO ALL KLINGONS IN YOUR QUADRANT"); + print(" OPTION 3 = STARBASE NAV DATA"); + print(" THIS OPTION GIVES DIRECTION AND DISTANCE TO ANY "); + print(" STARBASE WITHIN YOUR QUADRANT"); + print(" OPTION 4 = DIRECTION/DISTANCE CALCULATOR"); + print(" THIS OPTION ALLOWS YOU TO ENTER COORDINATES FOR"); + print(" DIRECTION/DISTANCE CALCULATIONS"); + print(" OPTION 5 = GALACTIC /REGION NAME/ MAP"); + print(" THIS OPTION PRINTS THE NAMES OF THE SIXTEEN MAJOR "); + print(" GALACTIC REGIONS REFERRED TO IN THE GAME."); + } + + static void print(final String s) { + System.out.println(s); + } + + static String tab(final int n) { + return IntStream.range(1, n).mapToObj(num -> " ").collect(Collectors.joining()); + } + + static String inputStr(final String message) { + System.out.print(message + "? "); + final BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); + try { + return reader.readLine(); + } catch (IOException ioe) { + ioe.printStackTrace(); + return ""; + } + } + +}