Merge remote-tracking branch 'origin/main'

This commit is contained in:
Zev Spitz
2022-01-17 02:58:50 +02:00
8 changed files with 1023 additions and 443 deletions

View File

@@ -2,159 +2,244 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Scanner;
import java.util.stream.Collectors;
/**
* ANIMAL
* <p>
* Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)
* The original BASIC program uses an array to maintain the questions and answers and to decide which question to
* ask next. Updated this Java implementation to use a tree instead of the earlier faulty one based on a list (thanks @patimen).
*/
public class Animal {
public static void main(String[] args) {
printIntro();
Scanner scan = new Scanner(System.in);
public static void main(String[] args) {
printIntro();
Scanner scan = new Scanner(System.in);
List<Question> questions = new ArrayList<>();
questions.add(new Question("DOES IT SWIM", "FISH", "BIRD"));
Node root = new QuestionNode("DOES IT SWIM",
new AnimalNode("FISH"), new AnimalNode("BIRD"));
boolean stopGame = false;
while (!stopGame) {
String choice = readMainChoice(scan);
switch (choice) {
case "LIST":
printKnownAnimals(questions);
break;
case "Q":
case "QUIT":
stopGame = true;
break;
default:
if (choice.toUpperCase(Locale.ROOT).startsWith("Y")) {
int k = 0;
boolean correctGuess = false;
while (questions.size() > k && !correctGuess) {
Question question = questions.get(k);
correctGuess = askQuestion(question, scan);
if (correctGuess) {
System.out.println("WHY NOT TRY ANOTHER ANIMAL?");
} else {
k++;
}
}
boolean stopGame = false;
while (!stopGame) {
String choice = readMainChoice(scan);
switch (choice) {
case "TREE":
printTree(root);
break;
case "LIST":
printKnownAnimals(root);
break;
case "Q":
case "QUIT":
stopGame = true;
break;
default:
if (choice.toUpperCase(Locale.ROOT).startsWith("Y")) {
Node current = root; //where we are in the question tree
Node previous; //keep track of parent of current in order to place new questions later on.
if (!correctGuess) {
askForInformationAndSave(scan, questions);
}
}
}
}
while (current instanceof QuestionNode) {
var currentQuestion = (QuestionNode) current;
var reply = askQuestionAndGetReply(currentQuestion, scan);
}
previous = current;
current = reply ? currentQuestion.getTrueAnswer() : currentQuestion.getFalseAnswer();
if (current instanceof AnimalNode) {
//We have reached a animal node, so offer it as the guess
var currentAnimal = (AnimalNode) current;
System.out.printf("IS IT A %s ? ", currentAnimal.getAnimal());
var animalGuessResponse = readYesOrNo(scan);
if (animalGuessResponse) {
//we guessed right! end this round
System.out.println("WHY NOT TRY ANOTHER ANIMAL?");
} else {
//we guessed wrong :(, ask for feedback
//cast previous to QuestionNode since we know at this point that it is not a leaf node
askForInformationAndSave(scan, currentAnimal, (QuestionNode) previous, reply);
}
}
}
}
}
}
}
private static void askForInformationAndSave(Scanner scan, List<Question> questions) {
//Failed to get it right and ran out of questions
//Let's ask the user for the new information
System.out.print("THE ANIMAL YOU WERE THINKING OF WAS A ");
String animal = scan.nextLine();
System.out.printf("PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A %s FROM A %s ", animal, questions.get(
questions.size() - 1).falseAnswer);
String newQuestion = scan.nextLine();
System.out.printf("FOR A %s THE ANSWER WOULD BE ", animal);
boolean newAnswer = readYesOrNo(scan);
//Add it to our list
addNewAnimal(questions, animal, newQuestion, newAnswer);
}
/**
* Prompt for information about the animal we got wrong
* @param current The animal that we guessed wrong
* @param previous The root of current
* @param previousToCurrentDecisionChoice Whether it was a Y or N answer that got us here. true = Y, false = N
*/
private static void askForInformationAndSave(Scanner scan, AnimalNode current, QuestionNode previous, boolean previousToCurrentDecisionChoice) {
//Failed to get it right and ran out of questions
//Let's ask the user for the new information
System.out.print("THE ANIMAL YOU WERE THINKING OF WAS A ");
String animal = scan.nextLine();
System.out.printf("PLEASE TYPE IN A QUESTION THAT WOULD DISTINGUISH A %s FROM A %s ", animal, current.getAnimal());
String newQuestion = scan.nextLine();
System.out.printf("FOR A %s THE ANSWER WOULD BE ", animal);
boolean newAnswer = readYesOrNo(scan);
//Add it to our question store
addNewAnimal(current, previous, animal, newQuestion, newAnswer, previousToCurrentDecisionChoice);
}
private static void addNewAnimal(List<Question> questions, String animal, String newQuestion, boolean newAnswer) {
Question lastQuestion = questions.get(questions.size() - 1);
String lastAnimal = lastQuestion.falseAnswer;
lastQuestion.falseAnswer = null; //remove the false option to indicate that there is a next question
private static void addNewAnimal(Node current,
QuestionNode previous,
String animal,
String newQuestion,
boolean newAnswer,
boolean previousToCurrentDecisionChoice) {
var animalNode = new AnimalNode(animal);
var questionNode = new QuestionNode(newQuestion,
newAnswer ? animalNode : current,
!newAnswer ? animalNode : current);
Question newOption;
if (newAnswer) {
newOption = new Question(newQuestion, animal, lastAnimal);
} else {
newOption = new Question(newQuestion, lastAnimal, animal);
}
questions.add(newOption);
}
if (previous != null) {
if (previousToCurrentDecisionChoice) {
previous.setTrueAnswer(questionNode);
} else {
previous.setFalseAnswer(questionNode);
}
}
}
private static boolean askQuestion(Question question, Scanner scanner) {
System.out.printf("%s ? ", question.question);
private static boolean askQuestionAndGetReply(QuestionNode questionNode, Scanner scanner) {
System.out.printf("%s ? ", questionNode.question);
return readYesOrNo(scanner);
}
boolean chosenAnswer = readYesOrNo(scanner);
if (chosenAnswer) {
if (question.trueAnswer != null) {
System.out.printf("IS IT A %s ? ", question.trueAnswer);
return readYesOrNo(scanner);
}
//else go to the next question
} else {
if (question.falseAnswer != null) {
System.out.printf("IS IT A %s ? ", question.falseAnswer);
return readYesOrNo(scanner);
}
//else go to the next question
}
return false;
}
private static boolean readYesOrNo(Scanner scanner) {
boolean validAnswer = false;
Boolean choseAnswer = null;
while (!validAnswer) {
String answer = scanner.nextLine();
if (answer.toUpperCase(Locale.ROOT).startsWith("Y")) {
validAnswer = true;
choseAnswer = true;
} else if (answer.toUpperCase(Locale.ROOT).startsWith("N")) {
validAnswer = true;
choseAnswer = false;
}
}
return choseAnswer;
}
private static boolean readYesOrNo(Scanner scanner) {
boolean validAnswer = false;
Boolean choseAnswer = null;
while (!validAnswer) {
String answer = scanner.nextLine();
if (answer.toUpperCase(Locale.ROOT).startsWith("Y")) {
validAnswer = true;
choseAnswer = true;
} else if (answer.toUpperCase(Locale.ROOT).startsWith("N")) {
validAnswer = true;
choseAnswer = false;
}
}
return choseAnswer;
}
private static void printKnownAnimals(Node root) {
System.out.println("\nANIMALS I ALREADY KNOW ARE:");
private static void printKnownAnimals(List<Question> questions) {
System.out.println("\nANIMALS I ALREADY KNOW ARE:");
List<String> animals = new ArrayList<>();
questions.forEach(q -> {
if (q.trueAnswer != null) {
animals.add(q.trueAnswer);
}
if (q.falseAnswer != null) {
animals.add(q.falseAnswer);
}
});
System.out.println(String.join("\t\t", animals));
}
List<AnimalNode> leafNodes = collectLeafNodes(root);
String allAnimalsString = leafNodes.stream().map(AnimalNode::getAnimal).collect(Collectors.joining("\t\t"));
private static String readMainChoice(Scanner scan) {
System.out.print("ARE YOU THINKING OF AN ANIMAL ? ");
return scan.nextLine();
}
System.out.println(allAnimalsString);
}
private static void printIntro() {
System.out.println(" ANIMAL");
System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
System.out.println("\n\n");
System.out.println("PLAY 'GUESS THE ANIMAL'");
System.out.println("\n");
System.out.println("THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.");
}
//Traverse the tree and collect all the leaf nodes, which basically have all the animals.
private static List<AnimalNode> collectLeafNodes(Node root) {
List<AnimalNode> collectedNodes = new ArrayList<>();
if (root instanceof AnimalNode) {
collectedNodes.add((AnimalNode) root);
} else {
var q = (QuestionNode) root;
collectedNodes.addAll(collectLeafNodes(q.getTrueAnswer()));
collectedNodes.addAll(collectLeafNodes(q.getFalseAnswer()));
}
return collectedNodes;
}
private static String readMainChoice(Scanner scan) {
System.out.print("ARE YOU THINKING OF AN ANIMAL ? ");
return scan.nextLine();
}
private static void printIntro() {
System.out.println(" ANIMAL");
System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
System.out.println("\n\n");
System.out.println("PLAY 'GUESS THE ANIMAL'");
System.out.println("\n");
System.out.println("THINK OF AN ANIMAL AND THE COMPUTER WILL TRY TO GUESS IT.");
}
//Based on https://stackoverflow.com/a/8948691/74057
private static void printTree(Node root) {
StringBuilder buffer = new StringBuilder(50);
print(root, buffer, "", "");
System.out.println(buffer);
}
private static void print(Node root, StringBuilder buffer, String prefix, String childrenPrefix) {
buffer.append(prefix);
buffer.append(root.toString());
buffer.append('\n');
if (root instanceof QuestionNode) {
var questionNode = (QuestionNode) root;
print(questionNode.getTrueAnswer(), buffer, childrenPrefix + "├─Y─ ", childrenPrefix + "");
print(questionNode.getFalseAnswer(), buffer, childrenPrefix + "└─N─ ", childrenPrefix + " ");
}
}
public static class Question {
String question;
String trueAnswer;
String falseAnswer;
/**
* Base interface for all nodes in our question tree
*/
private interface Node {
}
public Question(String question, String trueAnswer, String falseAnswer) {
this.question = question;
this.trueAnswer = trueAnswer;
this.falseAnswer = falseAnswer;
}
}
private static class QuestionNode implements Node {
private final String question;
private Node trueAnswer;
private Node falseAnswer;
public QuestionNode(String question, Node trueAnswer, Node falseAnswer) {
this.question = question;
this.trueAnswer = trueAnswer;
this.falseAnswer = falseAnswer;
}
public String getQuestion() {
return question;
}
public Node getTrueAnswer() {
return trueAnswer;
}
public void setTrueAnswer(Node trueAnswer) {
this.trueAnswer = trueAnswer;
}
public Node getFalseAnswer() {
return falseAnswer;
}
public void setFalseAnswer(Node falseAnswer) {
this.falseAnswer = falseAnswer;
}
@Override
public String toString() {
return "Question{'" + question + "'}";
}
}
private static class AnimalNode implements Node {
private final String animal;
public AnimalNode(String animal) {
this.animal = animal;
}
public String getAnimal() {
return animal;
}
@Override
public String toString() {
return "Animal{'" + animal + "'}";
}
}
}

125
29_Craps/ruby/craps.rb Normal file
View File

@@ -0,0 +1,125 @@
class CRAPSGAME
# class variables start with a double "@"
@@standings = 0
def displayHeading
puts "CRAPS".center(80)
puts "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY".center(80)
puts "\n\n\n"
puts "2,3,12 are losers"
puts "4,5,6,8,9,10 are points"
puts "7,11 are natural winners.\n\n"
end
def displayStanding
if @@standings < 0
print "you are in the hole by "
elsif @@standings == 0
print "you currently have "
else
# show how much money we currently have
print "you now have won "
end
# print the absolute value of the amount in the standings
puts @@standings.abs.to_s + " dollars"
end
# dice can come up 2 through 12
# so return a minimum of 2 and add 0 through 10 to that
def rollDice
puts "I will now throw the dice"
return rand(5) + rand(5) + 2
end
def placeBet
print "How much do you want to wager? "
wager = gets.strip.to_i
return wager
end
def loseBetBy amount
@@standings -= amount
end
def winBetBy amount
@@standings += amount
end
def askQuit?
print "\nDo you want to play again? "
# just the first character, make it uppercase
again = gets.strip.upcase[0]
return again != "Y"
end
def pointRoll point, wager
while true do
puts " is the point."
puts " I will roll again when you press Enter."
waitForIt = gets
roll = rollDice
print roll.to_s
# the only critical rolls here are 7 and the previous roll
# if anything else comes up we roll again.
case roll.to_i
when 7
puts " craps - you lose"
loseBetBy wager
break
when point
puts " is a winner! congrats!"
puts "at 2 to 1 odds pays you " + (2 * wager).to_s + " dollars"
winBetBy 2 * wager
break
else
print " no point - " + point.to_s
end
end
end
def play
displayHeading
while true do
wagerAmount = placeBet
roll = rollDice
print roll.to_s
case roll
when 2
puts " snake eyes - you lose"
loseBetBy wagerAmount
when 3, 12
puts " craps - you lose"
loseBetBy wagerAmount
when 4, 5, 6, 8, 9, 10
pointRoll roll, wagerAmount
when 7, 11
puts " a natural - a winner"
puts "pays even money: " + wagerAmount.to_s + " dollars"
winBetBy wagerAmount
end
displayStanding
if askQuit?
endPlay
end
end
end
def endPlay
case
when @@standings < 0
puts "Too bad. You are in the hole " + @@standings.abs.to_s + " dollars. Come again."
when @@standings > 0
puts "Congratulations --- You came out a winner of " + @@standings.to_s + " dollars. Come again!"
when @@standings == 0
puts "Congratulations --- You came out even, not bad for an amateur"
end
exit
end
end
craps = CRAPSGAME.new
craps.play

48
41_Guess/ruby/guess.rb Normal file
View File

@@ -0,0 +1,48 @@
def print_intro
print " " * 31 + "GUESS\n"
print " " * 15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n"
print "THIS IS A NUMBER GUESSING GAME. I'LL THINK\nOF A NUMBER BETWEEN 1 AND ANY LIMIT YOU WANT.\nTHEN YOU HAVE TO GUESS WHAT IT IS.\n"
end
def game_play(limit,choice_limit)
random = rand(limit.to_i)+1
puts "I'M THINKING OF A NUMBER BETWEEN 1 and #{limit}"
puts "NOW YOU TRY TO GUESS WHAT IT IS."
print "? "
ans=0
guesses=0
until ans.to_i == random.to_i
ans = gets.chomp
guesses += 1
if ans.to_i > random.to_i
puts "TOO HIGH. TRY A SMALLER ANSWER."
print "? "
elsif ans.to_i < random.to_i
puts "TOO LOW. TRY A BIGGER ANSWER."
print "? "
elsif ans.to_i == random.to_i
puts "THAT'S IT! YOU GOT IT IN #{guesses} TRIES."
if guesses.to_i < choice_limit.to_i
puts "VERY GOOD."
elsif guesses.to_i == choice_limit.to_i
puts "GOOD."
else
puts "YOU SHOULD HAVE BEEN ABLE TO GET IT IN ONLY #{choice_limit}"
end
print "\n\n\n\n\n"
end
end
end
def main
print_intro
puts "WHAT LIMIT DO YOU WANT"
limit = gets.chomp
choice_limit = (Math.log(limit.to_i)/Math.log(2)+1).to_i
while 1
game_play(limit,choice_limit)
end
end
main

View File

@@ -0,0 +1,115 @@
def intro
puts " MATH DICE
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
THIS PROGRAM GENERATES SUCCESSIVE PICTURES OF TWO DICE.
WHEN TWO DICE AND AN EQUAL SIGN FOLLOWED BY A QUESTION
MARK HAVE BEEN PRINTED, TYPE YOUR ANSWER AND THE RETURN KEY.
TO CONCLUDE THE LESSON, TYPE '0' AS YOUR ANSWER.
"
end
def game_play
num = 0
sum = 0
tries = 0
until num == 2 do
num+=1
roll = rand(6) + 1
print_dice(roll)
sum = sum + roll
if num == 1
print "\n +\n\n"
end
if num == 2
print "\n =? "
ans = gets.chomp
if ans.to_i == 0
#END GAME
exit(0)
elsif ans.to_i == sum
puts "RIGHT!"
puts "THE DICE ROLL AGAIN"
else
puts "NO, COUNT THE SPOTS AND GIVE ANOTHER ANSWER"
print "\n =? "
ans = gets.chomp
if ans.to_i == sum
puts "RIGHT!"
puts "THE DICE ROLL AGAIN"
elsif ans.to_i == 0
exit(0)
else
puts "NO, THE ANSWER IS #{sum}"
end
end
end
end
end
def print_dice(roll)
puts " -----"
if roll == 1
print_blank
print_one_mid
print_blank
elsif roll == 2
print_one_left
print_blank
print_one_right
elsif roll == 3
print_one_left
print_one_mid
print_one_right
elsif roll == 4
print_two
print_blank
print_two
elsif roll == 5
print_two
print_one_mid
print_two
elsif roll == 6
print_two
print_two
print_two
else
puts "not a legit dice roll"
end
puts " -----"
end
def print_one_left
puts "I * I"
end
def print_one_mid
puts "I * I"
end
def print_one_right
puts "I * I"
end
def print_two
puts "I * * I"
end
def print_blank
puts "I I"
end
def main
intro
#Continue playing forever until it terminates with exit in game_play
while 1 == 1 do
game_play
end
end
main

View File

@@ -21,12 +21,12 @@
210 REM *** BY USING "?" INSTEAD OF "PRINT" WHEN ENTERING LINES
215 REM ***
220 PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT:PRINT
221 PRINT" ,------*------,"
222 PRINT" ,------------- '--- ------'"
223 PRINT" '-------- --' / /"
224 PRINT" ,---' '-------/ /--,"
225 PRINT" '----------------'":PRINT
226 PRINT" THE USS ENTERPRISE --- NCC-1701"
221 PRINT " ,------*------,"
222 PRINT " ,------------- '--- ------'"
223 PRINT " '-------- --' / /"
224 PRINT " ,---' '-------/ /--,"
225 PRINT " '----------------'":PRINT
226 PRINT " THE USS ENTERPRISE --- NCC-1701"
227 PRINT:PRINT:PRINT:PRINT:PRINT
260 REM CLEAR 600
270 Z$=" "
@@ -37,353 +37,353 @@
475 DEF FNR(R)=INT(RND(R)*7.98+1.01)
480 REM INITIALIZE ENTERPRIZE'S POSITION
490 Q1=FNR(1):Q2=FNR(1):S1=FNR(1):S2=FNR(1)
530 FORI=1TO9:C(I,1)=0:C(I,2)=0:NEXTI
530 FOR I=1 TO 9:C(I,1)=0:C(I,2)=0:NEXT I
540 C(3,1)=-1:C(2,1)=-1:C(4,1)=-1:C(4,2)=-1:C(5,2)=-1:C(6,2)=-1
600 C(1,2)=1:C(2,2)=1:C(6,1)=1:C(7,1)=1:C(8,1)=1:C(8,2)=1:C(9,2)=1
670 FORI=1TO8:D(I)=0:NEXTI
670 FOR I=1 TO 8:D(I)=0:NEXT I
710 A1$="NAVSRSLRSPHATORSHEDAMCOMXXX"
810 REM SETUP WHAT EXHISTS IN GALAXY . . .
815 REM K3= # KLINGONS B3= # STARBASES S3 = # STARS
820 FORI=1TO8:FORJ=1TO8:K3=0:Z(I,J)=0:R1=RND(1)
850 IFR1>.98THENK3=3:K9=K9+3:GOTO980
860 IFR1>.95THENK3=2:K9=K9+2:GOTO980
870 IFR1>.80THENK3=1:K9=K9+1
980 B3=0:IFRND(1)>.96THENB3=1:B9=B9+1
1040 G(I,J)=K3*100+B3*10+FNR(1):NEXTJ:NEXTI:IFK9>T9THENT9=K9+1
1100 IFB9<>0THEN1200
1150 IFG(Q1,Q2)<200THENG(Q1,Q2)=G(Q1,Q2)+120:K9=K9+1
820 FOR I=1 TO 8:FOR J=1 TO 8:K3=0:Z(I,J)=0:R1=RND(1)
850 IF R1>.98 THEN K3=3:K9=K9+3:GOTO 980
860 IF R1>.95 THEN K3=2:K9=K9+2:GOTO 980
870 IF R1>.80 THEN K3=1:K9=K9+1
980 B3=0:IF RND(1)>.96 THEN B3=1:B9=B9+1
1040 G(I,J)=K3*100+B3*10+FNR(1):NEXT J:NEXT I:IF K9>T9 THEN T9=K9+1
1100 IF B9<>0 THEN 1200
1150 IF G(Q1,Q2)<200 THEN G(Q1,Q2)=G(Q1,Q2)+120:K9=K9+1
1160 B9=1:G(Q1,Q2)=G(Q1,Q2)+10:Q1=FNR(1):Q2=FNR(1)
1200 K7=K9:IFB9<>1THENX$="S":X0$=" ARE "
1230 PRINT"YOUR ORDERS ARE AS FOLLOWS:"
1240 PRINT" DESTROY THE";K9;"KLINGON WARSHIPS WHICH HAVE INVADED"
1252 PRINT" THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS"
1260 PRINT" ON STARDATE";T0+T9;" THIS GIVES YOU";T9;"DAYS. THERE";X0$
1272 PRINT" ";B9;"STARBASE";X$;" IN THE GALAXY FOR RESUPPLYING YOUR SHIP"
1280 PRINT:REM PRINT"HIT ANY KEY EXCEPT RETURN WHEN READY TO ACCEPT COMMAND"
1200 K7=K9:IF B9<>1 THEN X$="S":X0$=" ARE "
1230 PRINT "YOUR ORDERS ARE AS FOLLOWS:"
1240 PRINT " DESTROY THE";K9;"KLINGON WARSHIPS WHICH HAVE INVADED"
1252 PRINT " THE GALAXY BEFORE THEY CAN ATTACK FEDERATION HEADQUARTERS"
1260 PRINT " ON STARDATE";T0+T9;" THIS GIVES YOU";T9;"DAYS. THERE";X0$
1272 PRINT " ";B9;"STARBASE";X$;" IN THE GALAXY FOR RESUPPLYING YOUR SHIP"
1280 PRINT:REM PRINT "HIT ANY KEY EXCEPT RETURN WHEN READY TO ACCEPT COMMAND"
1300 I=RND(1):REM IF INP(1)=13 THEN 1300
1310 REM HERE ANY TIME NEW QUADRANT ENTERED
1320 Z4=Q1:Z5=Q2:K3=0:B3=0:S3=0:G5=0:D4=.5*RND(1):Z(Q1,Q2)=G(Q1,Q2)
1390 IFQ1<1ORQ1>8ORQ2<1ORQ2>8THEN1600
1390 IF Q1<1 OR Q1>8 OR Q2<1 OR Q2>8 THEN 1600
1430 GOSUB 9030:PRINT:IF T0<>T THEN 1490
1460 PRINT"YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED"
1470 PRINT"IN THE GALACTIC QUADRANT, '";G2$;"'.":GOTO 1500
1490 PRINT"NOW ENTERING ";G2$;" QUADRANT . . ."
1460 PRINT "YOUR MISSION BEGINS WITH YOUR STARSHIP LOCATED"
1470 PRINT "IN THE GALACTIC QUADRANT, '";G2$;"'.":GOTO 1500
1490 PRINT "NOW ENTERING ";G2$;" QUADRANT . . ."
1500 PRINT:K3=INT(G(Q1,Q2)*.01):B3=INT(G(Q1,Q2)*.1)-10*K3
1540 S3=G(Q1,Q2)-100*K3-10*B3:IFK3=0THEN1590
1560 PRINT"COMBAT AREA CONDITION RED":IFS>200THEN1590
1580 PRINT" SHIELDS DANGEROUSLY LOW"
1590 FORI=1TO3:K(I,1)=0:K(I,2)=0:NEXTI
1600 FORI=1TO3:K(I,3)=0:NEXTI:Q$=Z$+Z$+Z$+Z$+Z$+Z$+Z$+LEFT$(Z$,17)
1540 S3=G(Q1,Q2)-100*K3-10*B3:IF K3=0 THEN 1590
1560 PRINT "COMBAT AREA CONDITION RED":IF S>200 THEN 1590
1580 PRINT " SHIELDS DANGEROUSLY LOW"
1590 FOR I=1 TO 3:K(I,1)=0:K(I,2)=0:NEXT I
1600 FOR I=1 TO 3:K(I,3)=0:NEXT I:Q$=Z$+Z$+Z$+Z$+Z$+Z$+Z$+LEFT$(Z$,17)
1660 REM POSITION ENTERPRISE IN QUADRANT, THEN PLACE "K3" KLINGONS, &
1670 REM "B3" STARBASES, & "S3" STARS ELSEWHERE.
1680 A$="<*>":Z1=S1:Z2=S2:GOSUB8670:IFK3<1THEN1820
1720 FORI=1TOK3:GOSUB8590:A$="+K+":Z1=R1:Z2=R2
1780 GOSUB8670:K(I,1)=R1:K(I,2)=R2:K(I,3)=S9*(0.5+RND(1)):NEXTI
1820 IFB3<1THEN1910
1880 GOSUB8590:A$=">!<":Z1=R1:B4=R1:Z2=R2:B5=R2:GOSUB8670
1910 FORI=1TOS3:GOSUB8590:A$=" * ":Z1=R1:Z2=R2:GOSUB8670:NEXTI
1980 GOSUB6430
1990 IFS+E>10THENIFE>10ORD(7)=0THEN2060
2020 PRINT:PRINT"** FATAL ERROR ** YOU'VE JUST STRANDED YOUR SHIP IN "
2030 PRINT"SPACE":PRINT"YOU HAVE INSUFFICIENT MANEUVERING ENERGY,";
2040 PRINT" AND SHIELD CONTROL":PRINT"IS PRESENTLY INCAPABLE OF CROSS";
2050 PRINT"-CIRCUITING TO ENGINE ROOM!!":GOTO6220
1680 A$="<*>":Z1=S1:Z2=S2:GOSUB 8670:IF K3<1 THEN 1820
1720 FOR I=1 TO K3:GOSUB 8590:A$="+K+":Z1=R1:Z2=R2
1780 GOSUB 8670:K(I,1)=R1:K(I,2)=R2:K(I,3)=S9*(0.5+RND(1)):NEXT I
1820 IF B3<1 THEN 1910
1880 GOSUB 8590:A$=">!<":Z1=R1:B4=R1:Z2=R2:B5=R2:GOSUB 8670
1910 FOR I=1 TO S3:GOSUB 8590:A$=" * ":Z1=R1:Z2=R2:GOSUB 8670:NEXT I
1980 GOSUB 6430
1990 IF S+E>10 THEN IF E>10 OR D(7)=0 THEN 2060
2020 PRINT:PRINT "** FATAL ERROR ** YOU'VE JUST STRANDED YOUR SHIP IN "
2030 PRINT "SPACE":PRINT "YOU HAVE INSUFFICIENT MANEUVERING ENERGY,";
2040 PRINT " AND SHIELD CONTROL":PRINT "IS PRESENTLY INCAPABLE OF CROSS";
2050 PRINT "-CIRCUITING TO ENGINE ROOM!!":GOTO 6220
2060 INPUT"COMMAND";A$
2080 FORI=1TO9:IFLEFT$(A$,3)<>MID$(A1$,3*I-2,3)THEN2160
2140 ONIGOTO2300,1980,4000,4260,4700,5530,5690,7290,6270
2160 NEXTI:PRINT"ENTER ONE OF THE FOLLOWING:"
2180 PRINT" NAV (TO SET COURSE)"
2190 PRINT" SRS (FOR SHORT RANGE SENSOR SCAN)"
2200 PRINT" LRS (FOR LONG RANGE SENSOR SCAN)"
2210 PRINT" PHA (TO FIRE PHASERS)"
2220 PRINT" TOR (TO FIRE PHOTON TORPEDOES)"
2230 PRINT" SHE (TO RAISE OR LOWER SHIELDS)"
2240 PRINT" DAM (FOR DAMAGE CONTROL REPORTS)"
2250 PRINT" COM (TO CALL ON LIBRARY-COMPUTER)"
2260 PRINT" XXX (TO RESIGN YOUR COMMAND)":PRINT:GOTO 1990
2080 FOR I=1 TO 9:IF LEFT$(A$,3)<>MID$(A1$,3*I-2,3) THEN 2160
2140 ON I GOTO 2300,1980,4000,4260,4700,5530,5690,7290,6270
2160 NEXT I:PRINT "ENTER ONE OF THE FOLLOWING:"
2180 PRINT " NAV (TO SET COURSE)"
2190 PRINT " SRS (FOR SHORT RANGE SENSOR SCAN)"
2200 PRINT " LRS (FOR LONG RANGE SENSOR SCAN)"
2210 PRINT " PHA (TO FIRE PHASERS)"
2220 PRINT " TOR (TO FIRE PHOTON TORPEDOES)"
2230 PRINT " SHE (TO RAISE OR LOWER SHIELDS)"
2240 PRINT " DAM (FOR DAMAGE CONTROL REPORTS)"
2250 PRINT " COM (TO CALL ON LIBRARY-COMPUTER)"
2260 PRINT " XXX (TO RESIGN YOUR COMMAND)":PRINT:GOTO 1990
2290 REM COURSE CONTROL BEGINS HERE
2300 INPUT"COURSE (0-9)";C1:IFC1=9THENC1=1
2310 IFC1>=1ANDC1<9THEN2350
2330 PRINT" LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'":GOTO1990
2350 X$="8":IFD(1)<0THENX$="0.2"
2360 PRINT"WARP FACTOR (0-";X$;")";:INPUTW1:IFD(1)<0ANDW1>.2THEN2470
2380 IFW1>0ANDW1<=8THEN2490
2390 IFW1=0THEN1990
2420 PRINT" CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE";
2430 PRINT" WARP ";W1;"!'":GOTO1990
2470 PRINT"WARP ENGINES ARE DAMAGED. MAXIUM SPEED = WARP 0.2":GOTO1990
2490 N=INT(W1*8+.5):IFE-N>=0THEN2590
2500 PRINT"ENGINEERING REPORTS 'INSUFFICIENT ENERGY AVAILABLE"
2510 PRINT" FOR MANEUVERING AT WARP";W1;"!'"
2530 IFS<N-EORD(7)<0THEN1990
2550 PRINT"DEFLECTOR CONTROL ROOM ACKNOWLEDGES";S;"UNITS OF ENERGY"
2560 PRINT" PRESENTLY DEPLOYED TO SHIELDS."
2570 GOTO1990
2300 INPUT"COURSE (0-9)";C1:IF C1=9 THEN C1=1
2310 IF C1>=1 AND C1<9 THEN 2350
2330 PRINT " LT. SULU REPORTS, 'INCORRECT COURSE DATA, SIR!'":GOTO 1990
2350 X$="8":IF D(1)<0 THEN X$="0.2"
2360 PRINT "WARP FACTOR (0-";X$;")";:INPUT W1:IF D(1)<0 AND W1>.2 THEN 2470
2380 IF W1>0 AND W1<=8 THEN 2490
2390 IF W1=0 THEN 1990
2420 PRINT " CHIEF ENGINEER SCOTT REPORTS 'THE ENGINES WON'T TAKE";
2430 PRINT " WARP ";W1;"!'":GOTO 1990
2470 PRINT "WARP ENGINES ARE DAMAGED. MAXIUM SPEED = WARP 0.2":GOTO 1990
2490 N=INT(W1*8+.5):IF E-N>=0 THEN 2590
2500 PRINT "ENGINEERING REPORTS 'INSUFFICIENT ENERGY AVAILABLE"
2510 PRINT " FOR MANEUVERING AT WARP";W1;"!'"
2530 IF S<N-E OR D(7)<0 THEN 1990
2550 PRINT "DEFLECTOR CONTROL ROOM ACKNOWLEDGES";S;"UNITS OF ENERGY"
2560 PRINT " PRESENTLY DEPLOYED TO SHIELDS."
2570 GOTO 1990
2580 REM KLINGONS MOVE/FIRE ON MOVING STARSHIP . . .
2590 FORI=1TOK3:IFK(I,3)=0THEN2700
2610 A$=" ":Z1=K(I,1):Z2=K(I,2):GOSUB8670:GOSUB8590
2660 K(I,1)=Z1:K(I,2)=Z2:A$="+K+":GOSUB8670
2700 NEXTI:GOSUB6000:D1=0:D6=W1:IFW1>=1THEND6=1
2770 FORI=1TO8:IFD(I)>=0THEN2880
2790 D(I)=D(I)+D6:IFD(I)>-.1ANDD(I)<0THEND(I)=-.1:GOTO2880
2800 IFD(I)<0THEN2880
2810 IFD1<>1THEND1=1:PRINT"DAMAGE CONTROL REPORT: ";
2840 PRINTTAB(8);:R1=I:GOSUB8790:PRINTG2$;" REPAIR COMPLETED."
2880 NEXTI:IFRND(1)>.2THEN3070
2910 R1=FNR(1):IFRND(1)>=.6THEN3000
2930 D(R1)=D(R1)-(RND(1)*5+1):PRINT"DAMAGE CONTROL REPORT: ";
2960 GOSUB8790:PRINTG2$;" DAMAGED":PRINT:GOTO3070
3000 D(R1)=D(R1)+RND(1)*3+1:PRINT"DAMAGE CONTROL REPORT: ";
3030 GOSUB8790:PRINTG2$;" STATE OF REPAIR IMPROVED":PRINT
2590 FOR I=1 TO K3:IF K(I,3)=0 THEN 2700
2610 A$=" ":Z1=K(I,1):Z2=K(I,2):GOSUB 8670:GOSUB 8590
2660 K(I,1)=Z1:K(I,2)=Z2:A$="+K+":GOSUB 8670
2700 NEXT I:GOSUB 6000:D1=0:D6=W1:IF W1>=1 THEN D6=1
2770 FOR I=1 TO 8:IF D(I)>=0 THEN 2880
2790 D(I)=D(I)+D6:IF D(I)>-.1 AND D(I)<0 THEN D(I)=-.1:GOTO 2880
2800 IF D(I)<0 THEN 2880
2810 IF D1<>1 THEN D1=1:PRINT "DAMAGE CONTROL REPORT: ";
2840 PRINT TAB(8);:R1=I:GOSUB 8790:PRINT G2$;" REPAIR COMPLETED."
2880 NEXT I:IF RND(1)>.2 THEN 3070
2910 R1=FNR(1):IF RND(1)>=.6 THEN 3000
2930 D(R1)=D(R1)-(RND(1)*5+1):PRINT "DAMAGE CONTROL REPORT: ";
2960 GOSUB 8790:PRINT G2$;" DAMAGED":PRINT:GOTO 3070
3000 D(R1)=D(R1)+RND(1)*3+1:PRINT "DAMAGE CONTROL REPORT: ";
3030 GOSUB 8790:PRINT G2$;" STATE OF REPAIR IMPROVED":PRINT
3060 REM BEGIN MOVING STARSHIP
3070 A$=" ":Z1=INT(S1):Z2=INT(S2):GOSUB8670
3070 A$=" ":Z1=INT(S1):Z2=INT(S2):GOSUB 8670
3110 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1)):X=S1:Y=S2
3140 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1)):Q4=Q1:Q5=Q2
3170 FORI=1TON:S1=S1+X1:S2=S2+X2:IFS1<1ORS1>=9ORS2<1ORS2>=9THEN3500
3240 S8=INT(S1)*24+INT(S2)*3-26:IFMID$(Q$,S8,2)=" "THEN3360
3320 S1=INT(S1-X1):S2=INT(S2-X2):PRINT"WARP ENGINES SHUT DOWN AT ";
3350 PRINT"SECTOR";S1;",";S2;"DUE TO BAD NAVAGATION":GOTO3370
3360 NEXTI:S1=INT(S1):S2=INT(S2)
3370 A$="<*>":Z1=INT(S1):Z2=INT(S2):GOSUB8670:GOSUB3910:T8=1
3430 IFW1<1THENT8=.1*INT(10*W1)
3450 T=T+T8:IFT>T0+T9THEN6220
3170 FOR I=1 TO N:S1=S1+X1:S2=S2+X2:IF S1<1 OR S1>=9 OR S2<1 OR S2>=9 THEN 3500
3240 S8=INT(S1)*24+INT(S2)*3-26:IF MID$(Q$,S8,2)=" " THEN 3360
3320 S1=INT(S1-X1):S2=INT(S2-X2):PRINT "WARP ENGINES SHUT DOWN AT ";
3350 PRINT "SECTOR";S1;",";S2;"DUE TO BAD NAVAGATION":GOTO 3370
3360 NEXT I:S1=INT(S1):S2=INT(S2)
3370 A$="<*>":Z1=INT(S1):Z2=INT(S2):GOSUB 8670:GOSUB 3910:T8=1
3430 IF W1<1 THEN T8=.1*INT(10*W1)
3450 T=T+T8:IF T>T0+T9 THEN 6220
3470 REM SEE IF DOCKED, THEN GET COMMAND
3480 GOTO1980
3480 GOTO 1980
3490 REM EXCEEDED QUADRANT LIMITS
3500 X=8*Q1+X+N*X1:Y=8*Q2+Y+N*X2:Q1=INT(X/8):Q2=INT(Y/8):S1=INT(X-Q1*8)
3550 S2=INT(Y-Q2*8):IFS1=0THENQ1=Q1-1:S1=8
3590 IFS2=0THENQ2=Q2-1:S2=8
3620 X5=0:IFQ1<1THENX5=1:Q1=1:S1=1
3670 IFQ1>8THENX5=1:Q1=8:S1=8
3710 IFQ2<1THENX5=1:Q2=1:S2=1
3750 IFQ2>8THENX5=1:Q2=8:S2=8
3790 IFX5=0THEN3860
3800 PRINT"LT. UHURA REPORTS MESSAGE FROM STARFLEET COMMAND:"
3810 PRINT" 'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER"
3820 PRINT" IS HEREBY *DENIED*. SHUT DOWN YOUR ENGINES.'"
3830 PRINT"CHIEF ENGINEER SCOTT REPORTS 'WARP ENGINES SHUT DOWN"
3840 PRINT" AT SECTOR";S1;",";S2;"OF QUADRANT";Q1;",";Q2;".'"
3850 IFT>T0+T9THEN6220
3860 IF8*Q1+Q2=8*Q4+Q5THEN3370
3870 T=T+1:GOSUB3910:GOTO1320
3550 S2=INT(Y-Q2*8):IF S1=0 THEN Q1=Q1-1:S1=8
3590 IF S2=0 THEN Q2=Q2-1:S2=8
3620 X5=0:IF Q1<1 THEN X5=1:Q1=1:S1=1
3670 IF Q1>8 THEN X5=1:Q1=8:S1=8
3710 IF Q2<1 THEN X5=1:Q2=1:S2=1
3750 IF Q2>8 THEN X5=1:Q2=8:S2=8
3790 IF X5=0 THEN 3860
3800 PRINT "LT. UHURA REPORTS MESSAGE FROM STARFLEET COMMAND:"
3810 PRINT " 'PERMISSION TO ATTEMPT CROSSING OF GALACTIC PERIMETER"
3820 PRINT " IS HEREBY *DENIED*. SHUT DOWN YOUR ENGINES.'"
3830 PRINT "CHIEF ENGINEER SCOTT REPORTS 'WARP ENGINES SHUT DOWN"
3840 PRINT " AT SECTOR";S1;",";S2;"OF QUADRANT";Q1;",";Q2;".'"
3850 IF T>T0+T9 THEN 6220
3860 IF 8*Q1+Q2=8*Q4+Q5 THEN 3370
3870 T=T+1:GOSUB 3910:GOTO 1320
3900 REM MANEUVER ENERGY S/R **
3910 E=E-N-10:IFE>=0THENRETURN
3930 PRINT"SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER."
3940 S=S+E:E=0:IFS<=0THENS=0
3910 E=E-N-10:IF E>=0 THEN RETURN
3930 PRINT "SHIELD CONTROL SUPPLIES ENERGY TO COMPLETE THE MANEUVER."
3940 S=S+E:E=0:IF S<=0 THEN S=0
3980 RETURN
3990 REM LONG RANGE SENSOR SCAN CODE
4000 IFD(3)<0THENPRINT"LONG RANGE SENSORS ARE INOPERABLE":GOTO1990
4030 PRINT"LONG RANGE SCAN FOR QUADRANT";Q1;",";Q2
4040 O1$="-------------------":PRINTO1$
4060 FORI=Q1-1TOQ1+1:N(1)=-1:N(2)=-2:N(3)=-3:FORJ=Q2-1TOQ2+1
4120 IFI>0ANDI<9ANDJ>0ANDJ<9THENN(J-Q2+2)=G(I,J):Z(I,J)=G(I,J)
4180 NEXTJ:FORL=1TO3:PRINT": ";:IFN(L)<0THENPRINT"*** ";:GOTO4230
4210 PRINTRIGHT$(STR$(N(L)+1000),3);" ";
4230 NEXTL:PRINT":":PRINTO1$:NEXTI:GOTO1990
4000 IF D(3)<0 THEN PRINT "LONG RANGE SENSORS ARE INOPERABLE":GOTO 1990
4030 PRINT "LONG RANGE SCAN FOR QUADRANT";Q1;",";Q2
4040 O1$="-------------------":PRINT O1$
4060 FOR I=Q1-1TOQ1+1:N(1)=-1:N(2)=-2:N(3)=-3:FOR J=Q2-1TOQ2+1
4120 IF I>0 AND I<9 AND J>0 AND J<9 THEN N(J-Q2+2)=G(I,J):Z(I,J)=G(I,J)
4180 NEXT J:FOR L=1 TO 3:PRINT ": ";:IF N(L)<0 THEN PRINT "*** ";:GOTO 4230
4210 PRINT RIGHT$(STR$(N(L)+1000),3);" ";
4230 NEXT L:PRINT ":":PRINT O1$:NEXT I:GOTO 1990
4250 REM PHASER CONTROL CODE BEGINS HERE
4260 IFD(4)<0THENPRINT"PHASERS INOPERATIVE":GOTO1990
4265 IFK3>0THEN4330
4270 PRINT"SCIENCE OFFICER SPOCK REPORTS 'SENSORS SHOW NO ENEMY SHIPS"
4280 PRINT" IN THIS QUADRANT'":GOTO1990
4330 IFD(8)<0THENPRINT"COMPUTER FAILURE HAMPERS ACCURACY"
4350 PRINT"PHASERS LOCKED ON TARGET; ";
4360 PRINT"ENERGY AVAILABLE =";E;"UNITS"
4370 INPUT"NUMBER OF UNITS TO FIRE";X:IFX<=0THEN1990
4400 IFE-X<0THEN4360
4410 E=E-X:IFD(7)<0THENX=X*RND(1)
4450 H1=INT(X/K3):FORI=1TO3:IFK(I,3)<=0THEN4670
4480 H=INT((H1/FND(0))*(RND(1)+2)):IFH>.15*K(I,3)THEN4530
4500 PRINT"SENSORS SHOW NO DAMAGE TO ENEMY AT ";K(I,1);",";K(I,2):GOTO4670
4530 K(I,3)=K(I,3)-H:PRINTH;"UNIT HIT ON KLINGON AT SECTOR";K(I,1);",";
4550 PRINTK(I,2):IFK(I,3)<=0THENPRINT"*** KLINGON DESTROYED ***":GOTO4580
4560 PRINT" (SENSORS SHOW";K(I,3);"UNITS REMAINING)":GOTO4670
4580 K3=K3-1:K9=K9-1:Z1=K(I,1):Z2=K(I,2):A$=" ":GOSUB8670
4650 K(I,3)=0:G(Q1,Q2)=G(Q1,Q2)-100:Z(Q1,Q2)=G(Q1,Q2):IFK9<=0THEN6370
4670 NEXTI:GOSUB6000:GOTO1990
4260 IF D(4)<0 THEN PRINT "PHASERS INOPERATIVE":GOTO 1990
4265 IF K3>0 THEN 4330
4270 PRINT "SCIENCE OFFICER SPOCK REPORTS 'SENSORS SHOW NO ENEMY SHIPS"
4280 PRINT " IN THIS QUADRANT'":GOTO 1990
4330 IF D(8)<0 THEN PRINT "COMPUTER FAILURE HAMPERS ACCURACY"
4350 PRINT "PHASERS LOCKED ON TARGET; ";
4360 PRINT "ENERGY AVAILABLE =";E;"UNITS"
4370 INPUT"NUMBER OF UNITS TO FIRE";X:IF X<=0 THEN 1990
4400 IF E-X<0 THEN 4360
4410 E=E-X:IF D(7)<0 THEN X=X*RND(1)
4450 H1=INT(X/K3):FOR I=1TO3:IF K(I,3)<=0 THEN 4670
4480 H=INT((H1/FND(0))*(RND(1)+2)):IF H>.15*K(I,3) THEN 4530
4500 PRINT "SENSORS SHOW NO DAMAGE TO ENEMY AT ";K(I,1);",";K(I,2):GOTO 4670
4530 K(I,3)=K(I,3)-H:PRINT H;"UNIT HIT ON KLINGON AT SECTOR";K(I,1);",";
4550 PRINT K(I,2):IF K(I,3)<=0 THEN PRINT "*** KLINGON DESTROYED ***":GOTO 4580
4560 PRINT " (SENSORS SHOW";K(I,3);"UNITS REMAINING)":GOTO 4670
4580 K3=K3-1:K9=K9-1:Z1=K(I,1):Z2=K(I,2):A$=" ":GOSUB 8670
4650 K(I,3)=0:G(Q1,Q2)=G(Q1,Q2)-100:Z(Q1,Q2)=G(Q1,Q2):IF K9<=0 THEN 6370
4670 NEXT I:GOSUB 6000:GOTO 1990
4690 REM PHOTON TORPEDO CODE BEGINS HERE
4700 IFP<=0THENPRINT"ALL PHOTON TORPEDOES EXPENDED":GOTO 1990
4730 IFD(5)<0THENPRINT"PHOTON TUBES ARE NOT OPERATIONAL":GOTO1990
4760 INPUT"PHOTON TORPEDO COURSE (1-9)";C1:IFC1=9THENC1=1
4780 IFC1>=1ANDC1<9THEN4850
4790 PRINT"ENSIGN CHEKOV REPORTS, 'INCORRECT COURSE DATA, SIR!'"
4800 GOTO1990
4700 IF P<=0 THEN PRINT "ALL PHOTON TORPEDOES EXPENDED":GOTO 1990
4730 IF D(5)<0 THEN PRINT "PHOTON TUBES ARE NOT OPERATIONAL":GOTO 1990
4760 INPUT"PHOTON TORPEDO COURSE (1-9)";C1:IF C1=9 THEN C1=1
4780 IF C1>=1ANDC1<9 THEN 4850
4790 PRINT "ENSIGN CHEKOV REPORTS, 'INCORRECT COURSE DATA, SIR!'"
4800 GOTO 1990
4850 X1=C(C1,1)+(C(C1+1,1)-C(C1,1))*(C1-INT(C1)):E=E-2:P=P-1
4860 X2=C(C1,2)+(C(C1+1,2)-C(C1,2))*(C1-INT(C1)):X=S1:Y=S2
4910 PRINT"TORPEDO TRACK:"
4910 PRINT "TORPEDO TRACK:"
4920 X=X+X1:Y=Y+X2:X3=INT(X+.5):Y3=INT(Y+.5)
4960 IFX3<1ORX3>8ORY3<1ORY3>8THEN5490
5000 PRINT" ";X3;",";Y3:A$=" ":Z1=X:Z2=Y:GOSUB8830
5050 IFZ3<>0THEN4920
5060 A$="+K+":Z1=X:Z2=Y:GOSUB8830:IFZ3=0THEN5210
5110 PRINT"*** KLINGON DESTROYED ***":K3=K3-1:K9=K9-1:IFK9<=0THEN6370
5150 FORI=1TO3:IFX3=K(I,1)ANDY3=K(I,2)THEN5190
5180 NEXTI:I=3
5190 K(I,3)=0:GOTO5430
5210 A$=" * ":Z1=X:Z2=Y:GOSUB8830:IFZ3=0THEN5280
5260 PRINT"STAR AT";X3;",";Y3;"ABSORBED TORPEDO ENERGY.":GOSUB6000:GOTO1990
5280 A$=">!<":Z1=X:Z2=Y:GOSUB8830:IFZ3=0THEN4760
5330 PRINT"*** STARBASE DESTROYED ***":B3=B3-1:B9=B9-1
5360 IFB9>0ORK9>T-T0-T9THEN5400
5370 PRINT"THAT DOES IT, CAPTAIN!! YOU ARE HEREBY RELIEVED OF COMMAND"
5380 PRINT"AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!"
4960 IF X3<1 OR X3>8 OR Y3<1 OR Y3>8 THEN 5490
5000 PRINT " ";X3;",";Y3:A$=" ":Z1=X:Z2=Y:GOSUB 8830
5050 IF Z3<>0 THEN 4920
5060 A$="+K+":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 5210
5110 PRINT "*** KLINGON DESTROYED ***":K3=K3-1:K9=K9-1:IF K9<=0 THEN 6370
5150 FOR I=1TO3:IF X3=K(I,1) AND Y3=K(I,2) THEN 5190
5180 NEXT I:I=3
5190 K(I,3)=0:GOTO 5430
5210 A$=" * ":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 5280
5260 PRINT "STAR AT";X3;",";Y3;"ABSORBED TORPEDO ENERGY.":GOSUB 6000:GOTO 1990
5280 A$=">!<":Z1=X:Z2=Y:GOSUB 8830:IF Z3=0 THEN 4760
5330 PRINT "*** STARBASE DESTROYED ***":B3=B3-1:B9=B9-1
5360 IF B9>0 OR K9>T-T0-T9 THEN 5400
5370 PRINT "THAT DOES IT, CAPTAIN!! YOU ARE HEREBY RELIEVED OF COMMAND"
5380 PRINT "AND SENTENCED TO 99 STARDATES AT HARD LABOR ON CYGNUS 12!!"
5390 GOTO 6270
5400 PRINT"STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER"
5410 PRINT"COURT MARTIAL!":D0=0
5430 Z1=X:Z2=Y:A$=" ":GOSUB8670
5470 G(Q1,Q2)=K3*100+B3*10+S3:Z(Q1,Q2)=G(Q1,Q2):GOSUB6000:GOTO1990
5490 PRINT"TORPEDO MISSED":GOSUB6000:GOTO1990
5400 PRINT "STARFLEET COMMAND REVIEWING YOUR RECORD TO CONSIDER"
5410 PRINT "COURT MARTIAL!":D0=0
5430 Z1=X:Z2=Y:A$=" ":GOSUB 8670
5470 G(Q1,Q2)=K3*100+B3*10+S3:Z(Q1,Q2)=G(Q1,Q2):GOSUB 6000:GOTO 1990
5490 PRINT "TORPEDO MISSED":GOSUB 6000:GOTO 1990
5520 REM SHIELD CONTROL
5530 IFD(7)<0THENPRINT"SHIELD CONTROL INOPERABLE":GOTO1990
5560 PRINT"ENERGY AVAILABLE =";E+S;:INPUT"NUMBER OF UNITS TO SHIELDS";X
5580 IFX<0ORS=XTHENPRINT"<SHIELDS UNCHANGED>":GOTO1990
5590 IFX<=E+STHEN5630
5600 PRINT"SHIELD CONTROL REPORTS 'THIS IS NOT THE FEDERATION TREASURY.'"
5610 PRINT"<SHIELDS UNCHANGED>":GOTO1990
5630 E=E+S-X:S=X:PRINT"DEFLECTOR CONTROL ROOM REPORT:"
5660 PRINT" 'SHIELDS NOW AT";INT(S);"UNITS PER YOUR COMMAND.'":GOTO1990
5530 IF D(7)<0 THEN PRINT "SHIELD CONTROL INOPERABLE":GOTO 1990
5560 PRINT "ENERGY AVAILABLE =";E+S;:INPUT"NUMBER OF UNITS TO SHIELDS";X
5580 IF X<0 OR S=X THEN PRINT "<SHIELDS UNCHANGED>":GOTO 1990
5590 IF X<=E+S THEN 5630
5600 PRINT "SHIELD CONTROL REPORTS 'THIS IS NOT THE FEDERATION TREASURY.'"
5610 PRINT "<SHIELDS UNCHANGED>":GOTO 1990
5630 E=E+S-X:S=X:PRINT "DEFLECTOR CONTROL ROOM REPORT:"
5660 PRINT " 'SHIELDS NOW AT";INT(S);"UNITS PER YOUR COMMAND.'":GOTO 1990
5680 REM DAMAGE CONTROL
5690 IFD(6)>=0THEN5910
5700 PRINT"DAMAGE CONTROL REPORT NOT AVAILABLE":IFD0=0THEN1990
5720 D3=0:FORI=1TO8:IFD(I)<0THEND3=D3+.1
5760 NEXTI:IFD3=0THEN1990
5780 PRINT:D3=D3+D4:IFD3>=1THEND3=.9
5810 PRINT"TECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;"
5820 PRINT"ESTIMATED TIME TO REPAIR:";.01*INT(100*D3);"STARDATES"
5690 IF D(6)>=0 THEN 5910
5700 PRINT "DAMAGE CONTROL REPORT NOT AVAILABLE":IF D0=0 THEN 1990
5720 D3=0:FOR I=1TO8:IF D(I)<0 THEN D3=D3+.1
5760 NEXT I:IF D3=0 THEN 1990
5780 PRINT:D3=D3+D4:IF D3>=1 THEN D3=.9
5810 PRINT "TECHNICIANS STANDING BY TO EFFECT REPAIRS TO YOUR SHIP;"
5820 PRINT "ESTIMATED TIME TO REPAIR:";.01*INT(100*D3);"STARDATES"
5840 INPUT "WILL YOU AUTHORIZE THE REPAIR ORDER (Y/N)";A$
5860 IFA$<>"Y"THEN 1990
5870 FORI=1TO8:IFD(I)<0THEND(I)=0
5890 NEXTI:T=T+D3+.1
5910 PRINT:PRINT"DEVICE STATE OF REPAIR":FORR1=1TO8
5920 GOSUB8790:PRINTG2$;LEFT$(Z$,25-LEN(G2$));INT(D(R1)*100)*.01
5950 NEXTR1:PRINT:IFD0<>0THEN5720
5860 IF A$<>"Y" THEN 1990
5870 FOR I=1TO8:IF D(I)<0 THEN D(I)=0
5890 NEXT I:T=T+D3+.1
5910 PRINT:PRINT "DEVICE STATE OF REPAIR":FOR R1=1TO8
5920 GOSUB 8790:PRINT G2$;LEFT$(Z$,25-LEN(G2$));INT(D(R1)*100)*.01
5950 NEXT R1:PRINT:IF D0<>0 THEN 5720
5980 GOTO 1990
5990 REM KLINGONS SHOOTING
6000 IFK3<=0THENRETURN
6010 IFD0<>0THENPRINT"STARBASE SHIELDS PROTECT THE ENTERPRISE":RETURN
6040 FORI=1TO3:IFK(I,3)<=0THEN6200
6000 IF K3<=0 THEN RETURN
6010 IF D0<>0 THEN PRINT "STARBASE SHIELDS PROTECT THE ENTERPRISE":RETURN
6040 FOR I=1TO3:IF K(I,3)<=0 THEN 6200
6060 H=INT((K(I,3)/FND(1))*(2+RND(1))):S=S-H:K(I,3)=K(I,3)/(3+RND(0))
6080 PRINTH;"UNIT HIT ON ENTERPRISE FROM SECTOR";K(I,1);",";K(I,2)
6090 IFS<=0THEN6240
6100 PRINT" <SHIELDS DOWN TO";S;"UNITS>":IFH<20THEN6200
6120 IFRND(1)>.6ORH/S<=.02THEN6200
6140 R1=FNR(1):D(R1)=D(R1)-H/S-.5*RND(1):GOSUB8790
6170 PRINT"DAMAGE CONTROL REPORTS ";G2$;" DAMAGED BY THE HIT'"
6200 NEXTI:RETURN
6080 PRINT H;"UNIT HIT ON ENTERPRISE FROM SECTOR";K(I,1);",";K(I,2)
6090 IF S<=0 THEN 6240
6100 PRINT " <SHIELDS DOWN TO";S;"UNITS>":IF H<20 THEN 6200
6120 IF RND(1)>.6 OR H/S<=.02 THEN 6200
6140 R1=FNR(1):D(R1)=D(R1)-H/S-.5*RND(1):GOSUB 8790
6170 PRINT "DAMAGE CONTROL REPORTS ";G2$;" DAMAGED BY THE HIT'"
6200 NEXT I:RETURN
6210 REM END OF GAME
6220 PRINT"IT IS STARDATE";T:GOTO 6270
6240 PRINT:PRINT"THE ENTERPRISE HAS BEEN DESTROYED. THEN FEDERATION ";
6250 PRINT"WILL BE CONQUERED":GOTO 6220
6270 PRINT"THERE WERE";K9;"KLINGON BATTLE CRUISERS LEFT AT"
6280 PRINT"THE END OF YOUR MISSION."
6290 PRINT:PRINT:IFB9=0THEN6360
6310 PRINT"THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER"
6320 PRINT"FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER,"
6330 INPUT"LET HIM STEP FORWARD AND ENTER 'AYE'";A$:IFA$="AYE"THEN10
6220 PRINT "IT IS STARDATE";T:GOTO 6270
6240 PRINT:PRINT "THE ENTERPRISE HAS BEEN DESTROYED. THEN FEDERATION ";
6250 PRINT "WILL BE CONQUERED":GOTO 6220
6270 PRINT "THERE WERE";K9;"KLINGON BATTLE CRUISERS LEFT AT"
6280 PRINT "THE END OF YOUR MISSION."
6290 PRINT:PRINT:IF B9=0 THEN 6360
6310 PRINT "THE FEDERATION IS IN NEED OF A NEW STARSHIP COMMANDER"
6320 PRINT "FOR A SIMILAR MISSION -- IF THERE IS A VOLUNTEER,"
6330 INPUT"LET HIM STEP FORWARD AND ENTER 'AYE'";A$:IF A$="AYE" THEN 10
6360 END
6370 PRINT"CONGRULATION, CAPTAIN! THEN LAST KLINGON BATTLE CRUISER"
6380 PRINT"MENACING THE FDERATION HAS BEEN DESTROYED.":PRINT
6400 PRINT"YOUR EFFICIENCY RATING IS";1000*(K7/(T-T0))^2:GOTO6290
6370 PRINT "CONGRULATION, CAPTAIN! THEN LAST KLINGON BATTLE CRUISER"
6380 PRINT "MENACING THE FDERATION HAS BEEN DESTROYED.":PRINT
6400 PRINT "YOUR EFFICIENCY RATING IS";1000*(K7/(T-T0))^2:GOTO 6290
6420 REM SHORT RANGE SENSOR SCAN & STARTUP SUBROUTINE
6430 FORI=S1-1TOS1+1:FORJ=S2-1TOS2+1
6450 IFINT(I+.5)<1ORINT(I+.5)>8ORINT(J+.5)<1ORINT(J+.5)>8THEN6540
6490 A$=">!<":Z1=I:Z2=J:GOSUB8830:IFZ3=1THEN6580
6540 NEXTJ:NEXTI:D0=0:GOTO6650
6430 FOR I=S1-1TOS1+1:FOR J=S2-1 TO S2+1
6450 IF INT(I+.5)<1 OR INT(I+.5)>8 OR INT(J+.5)<1 OR INT(J+.5)>8 THEN 6540
6490 A$=">!<":Z1=I:Z2=J:GOSUB 8830:IF Z3=1 THEN 6580
6540 NEXT J:NEXT I:D0=0:GOTO 6650
6580 D0=1:C$="DOCKED":E=E0:P=P0
6620 PRINT"SHIELDS DROPPED FOR DOCKING PURPOSES":S=0:GOTO6720
6650 IFK3>0THENC$="*RED*":GOTO6720
6660 C$="GREEN":IFE<E0*.1THENC$="YELLOW"
6720 IFD(2)>=0THEN6770
6730 PRINT:PRINT"*** SHORT RANGE SENSORS ARE OUT ***":PRINT:RETURN
6770 O1$="---------------------------------":PRINTO1$:FORI=1TO8
6820 FORJ=(I-1)*24+1TO(I-1)*24+22STEP3:PRINT" ";MID$(Q$,J,3);:NEXTJ
6830 ONIGOTO6850,6900,6960,7020,7070,7120,7180,7240
6850 PRINT" STARDATE ";INT(T*10)*.1:GOTO7260
6900 PRINT" CONDITION ";C$:GOTO7260
6960 PRINT" QUADRANT ";Q1;",";Q2:GOTO7260
7020 PRINT" SECTOR ";S1;",";S2:GOTO7260
7070 PRINT" PHOTON TORPEDOES ";INT(P):GOTO7260
7120 PRINT" TOTAL ENERGY ";INT(E+S):GOTO7260
7180 PRINT" SHIELDS ";INT(S):GOTO7260
7240 PRINT" KLINGONS REMAINING";INT(K9)
7260 NEXTI:PRINTO1$:RETURN
6620 PRINT "SHIELDS DROPPED FOR DOCKING PURPOSES":S=0:GOTO 6720
6650 IF K3>0 THEN C$="*RED*":GOTO 6720
6660 C$="GREEN":IF E<E0*.1 THEN C$="YELLOW"
6720 IF D(2)>=0 THEN 6770
6730 PRINT:PRINT "*** SHORT RANGE SENSORS ARE OUT ***":PRINT:RETURN
6770 O1$="---------------------------------":PRINT O1$:FOR I=1 TO 8
6820 FOR J=(I-1)*24+1 TO (I-1)*24+22STEP3:PRINT " ";MID$(Q$,J,3);:NEXT J
6830 ON I GOTO 6850,6900,6960,7020,7070,7120,7180,7240
6850 PRINT " STARDATE ";INT(T*10)*.1:GOTO 7260
6900 PRINT " CONDITION ";C$:GOTO 7260
6960 PRINT " QUADRANT ";Q1;",";Q2:GOTO 7260
7020 PRINT " SECTOR ";S1;",";S2:GOTO 7260
7070 PRINT " PHOTON TORPEDOES ";INT(P):GOTO 7260
7120 PRINT " TOTAL ENERGY ";INT(E+S):GOTO 7260
7180 PRINT " SHIELDS ";INT(S):GOTO 7260
7240 PRINT " KLINGONS REMAINING";INT(K9)
7260 NEXT I:PRINT O1$:RETURN
7280 REM LIBRARY COMPUTER CODE
7290 IFD(8)<0THENPRINT"COMPUTER DISABLED":GOTO1990
7320 INPUT"COMPUTER ACTIVE AND AWAITING COMMAND";A:IFA<0THEN1990
7350 PRINT:H8=1:ONA+1GOTO7540,7900,8070,8500,8150,7400
7360 PRINT"FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:"
7370 PRINT" 0 = CUMULATIVE GALACTIC RECORD"
7372 PRINT" 1 = STATUS REPORT"
7374 PRINT" 2 = PHOTON TORPEDO DATA"
7376 PRINT" 3 = STARBASE NAV DATA"
7378 PRINT" 4 = DIRECTION/DISTANCE CALCULATOR"
7380 PRINT" 5 = GALAXY 'REGION NAME' MAP":PRINT:GOTO7320
7290 IF D(8)<0 THEN PRINT "COMPUTER DISABLED":GOTO 1990
7320 INPUT"COMPUTER ACTIVE AND AWAITING COMMAND";A:IF A<0 THEN 1990
7350 PRINT:H8=1:ON A+1 GOTO 7540,7900,8070,8500,8150,7400
7360 PRINT "FUNCTIONS AVAILABLE FROM LIBRARY-COMPUTER:"
7370 PRINT " 0 = CUMULATIVE GALACTIC RECORD"
7372 PRINT " 1 = STATUS REPORT"
7374 PRINT " 2 = PHOTON TORPEDO DATA"
7376 PRINT " 3 = STARBASE NAV DATA"
7378 PRINT " 4 = DIRECTION/DISTANCE CALCULATOR"
7380 PRINT " 5 = GALAXY 'REGION NAME' MAP":PRINT:GOTO 7320
7390 REM SETUP TO CHANGE CUM GAL RECORD TO GALAXY MAP
7400 H8=0:G5=1:PRINT" THE GALAXY":GOTO7550
7400 H8=0:G5=1:PRINT " THE GALAXY":GOTO 7550
7530 REM CUM GALACTIC RECORD
7540 REM INPUT"DO YOU WANT A HARDCOPY? IS THE TTY ON (Y/N)";A$
7542 REM IFA$="Y"THENPOKE1229,2:POKE1237,3:NULL1
7543 PRINT:PRINT" ";
7544 PRINT"COMPUTER RECORD OF GALAXY FOR QUADRANT";Q1;",";Q2
7542 REM IF A$="Y" THEN POKE1229,2:POKE1237,3:NULL1
7543 PRINT:PRINT " ";
7544 PRINT "COMPUTER RECORD OF GALAXY FOR QUADRANT";Q1;",";Q2
7546 PRINT
7550 PRINT" 1 2 3 4 5 6 7 8"
7550 PRINT " 1 2 3 4 5 6 7 8"
7560 O1$=" ----- ----- ----- ----- ----- ----- ----- -----"
7570 PRINTO1$:FORI=1TO8:PRINTI;:IFH8=0THEN7740
7630 FORJ=1TO8:PRINT" ";:IFZ(I,J)=0THENPRINT"***";:GOTO7720
7700 PRINTRIGHT$(STR$(Z(I,J)+1000),3);
7720 NEXTJ:GOTO7850
7740 Z4=I:Z5=1:GOSUB9030:J0=INT(15-.5*LEN(G2$)):PRINTTAB(J0);G2$;
7800 Z5=5:GOSUB 9030:J0=INT(39-.5*LEN(G2$)):PRINTTAB(J0);G2$;
7850 PRINT:PRINTO1$:NEXTI:PRINT:GOTO1990
7570 PRINT O1$:FOR I=1 TO 8:PRINT I;:IF H8=0 THEN 7740
7630 FOR J=1 TO 8:PRINT " ";:IF Z(I,J)=0 THEN PRINT "***";:GOTO 7720
7700 PRINT RIGHT$(STR$(Z(I,J)+1000),3);
7720 NEXT J:GOTO 7850
7740 Z4=I:Z5=1:GOSUB 9030:J0=INT(15-.5*LEN(G2$)):PRINT TAB(J0);G2$;
7800 Z5=5:GOSUB 9030:J0=INT(39-.5*LEN(G2$)):PRINT TAB(J0);G2$;
7850 PRINT:PRINT O1$:NEXT I:PRINT:GOTO 1990
7890 REM STATUS REPORT
7900 PRINT " STATUS REPORT:":X$="":IFK9>1THENX$="S"
7940 PRINT"KLINGON";X$;" LEFT: ";K9
7960 PRINT"MISSION MUST BE COMPLETED IN";.1*INT((T0+T9-T)*10);"STARDATES"
7970 X$="S":IFB9<2THENX$="":IFB9<1THEN8010
7980 PRINT"THE FEDERATION IS MAINTAINING";B9;"STARBASE";X$;" IN THE GALAXY"
7990 GOTO5690
8010 PRINT"YOUR STUPIDITY HAS LEFT YOU ON YOUR ON IN"
8020 PRINT" THE GALAXY -- YOU HAVE NO STARBASES LEFT!":GOTO5690
7900 PRINT " STATUS REPORT:":X$="":IF K9>1 THEN X$="S"
7940 PRINT "KLINGON";X$;" LEFT: ";K9
7960 PRINT "MISSION MUST BE COMPLETED IN";.1*INT((T0+T9-T)*10);"STARDATES"
7970 X$="S":IF B9<2 THEN X$="":IF B9<1 THEN 8010
7980 PRINT "THE FEDERATION IS MAINTAINING";B9;"STARBASE";X$;" IN THE GALAXY"
7990 GOTO 5690
8010 PRINT "YOUR STUPIDITY HAS LEFT YOU ON YOUR ON IN"
8020 PRINT " THE GALAXY -- YOU HAVE NO STARBASES LEFT!":GOTO 5690
8060 REM TORPEDO, BASE NAV, D/D CALCULATOR
8070 IFK3<=0THEN4270
8080 X$="":IFK3>1THENX$="S"
8090 PRINT"FROM ENTERPRISE TO KLINGON BATTLE CRUSER";X$
8100 H8=0:FORI=1TO3:IFK(I,3)<=0THEN8480
8070 IF K3<=0 THEN 4270
8080 X$="":IF K3>1 THEN X$="S"
8090 PRINT "FROM ENTERPRISE TO KLINGON BATTLE CRUSER";X$
8100 H8=0:FOR I=1 TO 3:IF K(I,3)<=0 THEN 8480
8110 W1=K(I,1):X=K(I,2)
8120 C1=S1:A=S2:GOTO8220
8150 PRINT"DIRECTION/DISTANCE CALCULATOR:"
8160 PRINT"YOU ARE AT QUADRANT ";Q1;",";Q2;" SECTOR ";S1;",";S2
8170 PRINT"PLEASE ENTER":INPUT" INITIAL COORDINATES (X,Y)";C1,A
8120 C1=S1:A=S2:GOTO 8220
8150 PRINT "DIRECTION/DISTANCE CALCULATOR:"
8160 PRINT "YOU ARE AT QUADRANT ";Q1;",";Q2;" SECTOR ";S1;",";S2
8170 PRINT "PLEASE ENTER":INPUT" INITIAL COORDINATES (X,Y)";C1,A
8200 INPUT" FINAL COORDINATES (X,Y)";W1,X
8220 X=X-A:A=C1-W1:IFX<0THEN8350
8250 IFA<0THEN8410
8260 IFX>0THEN8280
8270 IFA=0THENC1=5:GOTO8290
8220 X=X-A:A=C1-W1:IF X<0 THEN 8350
8250 IF A<0 THEN 8410
8260 IF X>0 THEN 8280
8270 IF A=0 THEN C1=5:GOTO 8290
8280 C1=1
8290 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
8290 IF ABS(A)<=ABS(X) THEN 8330
8310 PRINT "DIRECTION =";C1+(((ABS(A)-ABS(X))+ABS(A))/ABS(A)):GOTO 8460
8330 PRINT "DIRECTION =";C1+(ABS(A)/ABS(X)):GOTO 8460
8350 IF A>0 THEN C1=3:GOTO 8420
8360 IF X<>0 THEN C1=5:GOTO 8290
8410 C1=7
8420 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
8480 NEXTI:GOTO1990
8500 IFB3<>0THENPRINT"FROM ENTERPRISE TO STARBASE:":W1=B4:X=B5:GOTO8120
8510 PRINT"MR. SPOCK REPORTS, 'SENSORS SHOW NO STARBASES IN THIS";
8520 PRINT" QUADRANT.'":GOTO1990
8420 IF ABS(A)>=ABS(X) THEN 8450
8430 PRINT "DIRECTION =";C1+(((ABS(X)-ABS(A))+ABS(X))/ABS(X)):GOTO 8460
8450 PRINT "DIRECTION =";C1+(ABS(X)/ABS(A))
8460 PRINT "DISTANCE =";SQR(X^2+A^2):IF H8=1 THEN 1990
8480 NEXT I:GOTO 1990
8500 IF B3<>0 THEN PRINT "FROM ENTERPRISE TO STARBASE:":W1=B4:X=B5:GOTO 8120
8510 PRINT "MR. SPOCK REPORTS, 'SENSORS SHOW NO STARBASES IN THIS";
8520 PRINT " QUADRANT.'":GOTO 1990
8580 REM FIND EMPTY PLACE IN QUADRANT (FOR THINGS)
8590 R1=FNR(1):R2=FNR(1):A$=" ":Z1=R1:Z2=R2:GOSUB8830:IFZ3=0THEN8590
8590 R1=FNR(1):R2=FNR(1):A$=" ":Z1=R1:Z2=R2:GOSUB 8830:IF Z3=0 THEN 8590
8600 RETURN
8660 REM INSERT IN STRING ARRAY FOR QUADRANT
8670 S8=INT(Z2-.5)*3+INT(Z1-.5)*24+1
8675 IF LEN(A$)<>3THEN PRINT"ERROR":STOP
8680 IFS8=1THENQ$=A$+RIGHT$(Q$,189):RETURN
8690 IFS8=190THENQ$=LEFT$(Q$,189)+A$:RETURN
8675 IF LEN(A$)<>3 THEN PRINT "ERROR":STOP
8680 IF S8=1 THEN Q$=A$+RIGHT$(Q$,189):RETURN
8690 IF S8=190 THEN Q$=LEFT$(Q$,189)+A$:RETURN
8700 Q$=LEFT$(Q$,S8-1)+A$+RIGHT$(Q$,190-S8):RETURN
8780 REM PRINTS DEVICE NAME
8790 ONR1GOTO8792,8794,8796,8798,8800,8802,8804,8806
8790 ON R1 GOTO 8792,8794,8796,8798,8800,8802,8804,8806
8792 G2$="WARP ENGINES":RETURN
8794 G2$="SHORT RANGE SENSORS":RETURN
8796 G2$="LONG RANGE SENSORS":RETURN
@@ -394,30 +394,30 @@
8806 G2$="LIBRARY-COMPUTER":RETURN
8820 REM STRING COMPARISON IN QUADRANT ARRAY
8830 Z1=INT(Z1+.5):Z2=INT(Z2+.5):S8=(Z2-1)*3+(Z1-1)*24+1:Z3=0
8890 IFMID$(Q$,S8,3)<>A$THENRETURN
8890 IF MID$(Q$,S8,3)<>A$ THEN RETURN
8900 Z3=1:RETURN
9010 REM QUADRANT NAME IN G2$ FROM Z4,Z5 (=Q1,Q2)
9020 REM CALL WITH G5=1 TO GET REGION NAME ONLY
9030 IFZ5<=4THENONZ4GOTO9040,9050,9060,9070,9080,9090,9100,9110
9035 GOTO9120
9040 G2$="ANTARES":GOTO9210
9050 G2$="RIGEL":GOTO9210
9060 G2$="PROCYON":GOTO9210
9070 G2$="VEGA":GOTO9210
9080 G2$="CANOPUS":GOTO9210
9090 G2$="ALTAIR":GOTO9210
9100 G2$="SAGITTARIUS":GOTO9210
9110 G2$="POLLUX":GOTO9210
9120 ONZ4GOTO9130,9140,9150,9160,9170,9180,9190,9200
9130 G2$="SIRIUS":GOTO9210
9140 G2$="DENEB":GOTO9210
9150 G2$="CAPELLA":GOTO9210
9160 G2$="BETELGEUSE":GOTO9210
9170 G2$="ALDEBARAN":GOTO9210
9180 G2$="REGULUS":GOTO9210
9190 G2$="ARCTURUS":GOTO9210
9030 IF Z5<=4 THEN ON Z4 GOTO 9040,9050,9060,9070,9080,9090,9100,9110
9035 GOTO 9120
9040 G2$="ANTARES":GOTO 9210
9050 G2$="RIGEL":GOTO 9210
9060 G2$="PROCYON":GOTO 9210
9070 G2$="VEGA":GOTO 9210
9080 G2$="CANOPUS":GOTO 9210
9090 G2$="ALTAIR":GOTO 9210
9100 G2$="SAGITTARIUS":GOTO 9210
9110 G2$="POLLUX":GOTO 9210
9120 ON Z4 GOTO 9130,9140,9150,9160,9170,9180,9190,9200
9130 G2$="SIRIUS":GOTO 9210
9140 G2$="DENEB":GOTO 9210
9150 G2$="CAPELLA":GOTO 9210
9160 G2$="BETELGEUSE":GOTO 9210
9170 G2$="ALDEBARAN":GOTO 9210
9180 G2$="REGULUS":GOTO 9210
9190 G2$="ARCTURUS":GOTO 9210
9200 G2$="SPICA"
9210 IFG5<>1THENONZ5GOTO9230,9240,9250,9260,9230,9240,9250,9260
9210 IF G5<>1 THEN ON Z5 GOTO 9230,9240,9250,9260,9230,9240,9250,9260
9220 RETURN
9230 G2$=G2$+" I":RETURN
9240 G2$=G2$+" II":RETURN

2
94_War/d/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.exe
*.obj

125
94_War/d/README.md Normal file
View File

@@ -0,0 +1,125 @@
Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)
Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).
## Running the code
Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:
```shell
dmd -preview=dip1000 -run war.d
```
[Other compilers](https://dlang.org/download.html) also exist.
## Specialties explained
This game code contains some specialties that you might want to know more about. Here goes.
### Suits
Most modern consoles are capable of displaying more than just ASCII, and so I have chosen to display the actual ♠, ♥, ♦
and ♣ instead of substituting them by letters like the BASIC original did. Only the Windows console needs a nudge in
the right direction with these instructions:
```d
SetConsoleOutputCP(CP_UTF8); // Set code page
SetConsoleOutputCP(GetACP); // Restore the default
```
Instead of cluttering the `main()` function with these lesser important details, we can move them into a
[module constructor and module destructor](https://dlang.org/spec/module.html#staticorder), which run before and after
`main()` respectively. And because order of declaration is irrelevant in a D module, we can push those all the way
down to the bottom of the file. This is of course only necessary on Windows (and won't even work anywhere else) so
we'll need to wrap this in a `version (Windows)` conditional code block:
```d
version (Windows)
{
import core.sys.windows.windows;
shared static this() @trusted
{
SetConsoleOutputCP(CP_UTF8);
}
shared static ~this() @trusted
{
SetConsoleOutputCP(GetACP);
}
}
```
Although it doesn't matter much in this single-threaded program, the `shared` attribute makes that these
constructors/destructors are run once per program invocation; non-shared module constructors and module destructors are
run for every thread. The `@trusted` annotation is necessary because these are system API calls; The compiler cannot
check these for memory-safety, and so we must indicate that we have reviewed the safety manually.
### Uniform Function Call Syntax
In case you wonder why this line works:
```d
if ("Do you want instructions?".yes)
// ...
```
then it is because this is equivalent to
```d
if (yes("Do you want instructions?"))
// ...
```
where `yes()` is a Boolean function that is defined below `main()`. This is made possible by the language feature that
is called [uniform function call syntax (UFCS)](https://dlang.org/spec/function.html#pseudo-member). UFCS works by
passing what is in front of the dot as the first parameter to the function, and it was invented to make it possible to
call free functions on objects as if they were member functions. UFCS can also be used to obtain a more natural order
of function calls, such as this line inside `yes()`:
```d
return trustedReadln.strip.toLower.startsWith("y");
```
which reads easier than the equivalent
```d
return startsWith(toLower(strip(trustedReadln())), "y");
```
### Type a lot or not?
It would have been straight forward to define the `cards` array explicitly like so:
```d
const cards = ["2♠", "2♥", "2♦", "2♣", "3♠", "3♥", "3♦", "3♣",
"4♠", "4♥", "4♦", "4♣", "5♠", "5♥", "5♦", "5♣",
"6♠", "6♥", "6♦", "6♣", "7♠", "7♥", "7♦", "7♣",
"8♠", "8♥", "8♦", "8♣", "9♠", "9♥", "9♦", "9♣",
"10♠", "10♥", "10♦", "10♣", "J♥", "J♦", "J♣", "J♣",
"Q♠", "Q♥", "Q♦", "Q♣", "K♠", "K♥", "K♦", "K♣",
"A♠", "A♥", "A♦", "A♣"];
```
but that's tedious, difficult to spot errors in (*can you?*) and looks like something a computer can automate. Indeed
it can:
```d
static const cards = cartesianProduct(["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"],
["♠", "♥", "♦", "♣"]).map!(a => a.expand.only.join).array;
```
The function [`cartesianProduct`](https://dlang.org/phobos/std_algorithm_setops.html#cartesianProduct) takes two
ranges, like the horizontal and vertical headers of a spreadsheet, and fills the table with the combinations that form
the coordinates of the cells. But the output of that function is in the form of an array of
[`Tuple`](https://dlang.org/phobos/std_typecons.html#Tuple)s, which looks like `[Tuple!(string, string)("2", "♠"),
Tuple!(string, string)("2", "♥"), ... etc]`. [`map`](https://dlang.org/phobos/std_algorithm_iteration.html#map)
comes to the rescue, converting each Tuple to a string, by calling
[`expand`](https://dlang.org/phobos/std_typecons.html#.Tuple.expand), then
[`only`](https://dlang.org/phobos/std_range.html#only) and then [`join`](https://dlang.org/phobos/std_array.html#join)
on them. The result is a lazily evaluated range of strings. Finally,
[`array`](https://dlang.org/phobos/std_array.html#array) turns the range into a random access array. The `static`
attribute makes that all this is performed at compile-time, so the result is exactly the same as the manually entered
data, but without the typo's.
### Shuffle the cards or not?
The original BASIC code works with a constant array of cards, ordered by increasing numerical value, and indexing it
with indices that have been shuffled. This is efficient because in comparing who wins, the indices can be compared
directly, since a higher index correlates to a card with a higher numerical value (when divided by the number of suits,
4). Some of the other reimplementations in other languages have been written in a lesser efficient way by shuffling the
array of cards itself. This then requires the use of a lookup table or searching for equality in an auxiliary array
when comparing cards.
I find the original more elegant, so that's what you see here:
```d
const indices = iota(0, cards.length).array.randomShuffle;
```
[`iota`](https://dlang.org/phobos/std_range.html#iota) produces a range of integers, in this case starting at 0 and
increasing up to the number of cards in the deck (exclusive). [`array`](https://dlang.org/phobos/std_array.html#array)
turns the range into an array, so that [`randomShuffle`](https://dlang.org/phobos/std_random.html#randomShuffle) can
do its work.

80
94_War/d/war.d Normal file
View File

@@ -0,0 +1,80 @@
@safe: // Make @safe the default for this file, enforcing memory-safety.
import std;
void main()
{
enum width = 50;
writeln(center("War", width));
writeln(center("(After Creative Computing Morristown, New Jersey)\n\n", width));
writeln(wrap("This is the card game of war. Each card is given by suit-# " ~
"as 7♠ for seven of spades. ", width));
if ("Do you want instructions?".yes)
writeln("\n", wrap("The computer gives you and it a 'card'. The higher card " ~
"(numerically) wins. The game ends when you choose not to " ~
"continue or when you have finished the pack.\n", width));
static const cards = cartesianProduct(["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"],
["♠", "♥", "♦", "♣"]).map!(a => a.expand.only.join).array;
const indices = iota(0, cards.length).array.randomShuffle;
int yourScore = 0, compScore = 0, i = 0;
while (i < indices.length)
{
size_t your = indices[i++], comp = indices[i++];
writeln("\nYou: ", cards[your].leftJustify(9), "Computer: ", cards[comp]);
your /= 4; comp /= 4;
if (your == comp)
writeln("Tie. No score change.");
else if (your < comp)
writeln("The computer wins!!! You have ", yourScore,
" and the computer has ", ++compScore, ".");
else
writeln("You win. You have ", ++yourScore,
" and the computer has ", compScore, ".");
if (i == indices.length)
writeln("\nWe have run out of cards. Final score: You: ", yourScore,
", the computer: ", compScore, ".");
else if (!"Do you want to continue?".yes)
break;
}
writeln("\nThanks for playing. It was fun.");
}
/// Returns whether question was answered positively.
bool yes(string question)
{
writef!"%s "(question);
try
return trustedReadln.strip.toLower.startsWith("y");
catch (Exception) // readln throws on I/O and Unicode errors, which we handle here.
return false;
}
/** An @trusted wrapper around readln.
*
* This is the only function that formally requires manual review for memory-safety.
* [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com)
* which would remove the need to have any @trusted code in this program.
*/
string trustedReadln() @trusted
{
return readln;
}
version (Windows)
{
// Make the Windows console do a better job at printing UTF-8 strings,
// and restore the default upon termination.
import core.sys.windows.windows;
shared static this() @trusted
{
SetConsoleOutputCP(CP_UTF8);
}
shared static ~this() @trusted
{
SetConsoleOutputCP(GetACP);
}
}