This commit is contained in:
rbamforth
2021-03-26 23:05:14 +00:00
80 changed files with 4256 additions and 179 deletions

View File

@@ -0,0 +1,174 @@
#!/usr/bin/perl
use strict;
use warnings;
# The List::Util module is part of the core Perl distribution. Using this
# means we don't need to re-invent the wheel and create a way to shuffle
# a list.
use List::Util qw(shuffle);
# Rather than put in a number of print (or say) statements here, we use a
# "here document". This is very useful for long strings of text. In this
# case, everything between the end of the "print" line and the line with
# "END_INSTRUCTIONS" on it will be printed verbatim.
print << 'END_INSTRUCTIONS';
Acey-Ducey
Adapted from Creative Computing, Morristown, New Jersey
Acey-Ducey is played as follows. The dealer (computer) deals two cards face up.
You have an option to bet or not bet, depending on whether or not you feel that
the next card drawn will have a value between the first two. Aces are low.
Bets must be in whole-dollar amounts only.
If you do not want to bet, input a 0. If you want to quit, input a -1.
END_INSTRUCTIONS
my @cards = (1 .. 13); # That is, Ace through King.
my $keepPlaying = 1;
GAME:
while ($keepPlaying)
{
my $playerBalance = 100; # The player starts with $100
HAND:
while (1)
{
print "\nYou now have $playerBalance dollars.\n\n";
# We'll create a new array that is a shuffled version of the deck.
my @shuffledDeck = shuffle(@cards);
# Then, by taking the two "top cards" off the deck, we're guaranteed
# that those will be unique. This way we don't have to keep drawing
# if we get, say, two queens. We sort them as we pull them to make
# sure that the first card is lower than the second one.
my ($firstCard, $secondCard) = sort { $a <=> $b } @shuffledDeck[ 0 .. 1 ];
print "I drew ", nameOfCard($firstCard), " and ", nameOfCard($secondCard), ".\n";
my $bet = getValidBet($playerBalance);
if ($bet == 0)
{
print "Chicken!\n\n";
next HAND;
}
if ($bet < 0)
{
last GAME;
}
# Now we re-shuffle the whole deck again and choose a third card.
# (Note: This is how the odds get stacked in favor of the dealer since
# the third card can be exactly the same as the first or second.)
@shuffledDeck = shuffle(@cards);
my $thirdCard = $shuffledDeck[0];
print "I drew ", nameOfCard($thirdCard), "!\n";
if (($firstCard < $thirdCard) && ($thirdCard < $secondCard))
{
print "You win!\n\n";
$playerBalance += $bet;
}
else
{
print "You lose!\n\n";
$playerBalance -= $bet;
}
if ($playerBalance <= 0)
{
print "Sorry, buddy, you blew your wad!\n\n";
last HAND;
}
}
$keepPlaying = promptUserToKeepPlaying();
}
print "Thanks for playing!\n";
###############
sub getValidBet
{
my $maxBet = shift;
print "\nWhat's your bet? ";
my $input = <STDIN>;
chomp $input;
# This regular expression will validate that the player entered an integer.
# The !~ match operate *negates* the match, so if the player did NOT enter
# an integer, they'll be given an error and prompted again.
if ($input !~ /^ # Match the beginning of the string
[+-]? # Optional plus or minus...
\d+ # followed by one more more digits...
$ # and then the end of the string
/x # The x modifier ignores whitespace in this regex...
)
{
print "Sorry, numbers only!\n";
$input = getValidBet($maxBet);
}
if ($input > $maxBet)
{
print "Sorry, my friend, you can't bet more money than you have.\n";
print "You only have $maxBet dollars to spend!\n";
$input = getValidBet($maxBet);
}
if ($input != int($input))
{
print "Sorry, you must bet in whole dollars. No change!\n";
$input = getValidBet($maxBet);
}
return $input;
}
# Since arrays in Perl are 0-based, we need to convert the value that we drew from
# the array to its proper position in the deck.
sub nameOfCard
{
my $value = shift;
# Note that the Joker isn't used in this game, but since arrays in Perl are
# 0-based, it's useful to have something there to represent the "0th"
# position. This way the rest of the elements match their expected values
# (e.g., element 1 is Ace, element 7 is 7, and element 12 is Queen).
my @cardlist = qw(Joker Ace 2 3 4 5 6 7 8 9 10 Jack Queen King);
return $cardlist[$value];
}
sub promptUserToKeepPlaying
{
print "Try again (Y/N)? ";
my $input = <STDIN>;
chomp $input;
my $keepGoing;
if (uc($input) eq 'Y')
{
$keepGoing = 1;
}
elsif (uc($input) eq 'N')
{
$keepGoing = 0;
}
else
{
$keepGoing = promptUserToKeepPlaying();
}
return $keepGoing;
}

45
15 Boxing/java/Basic.java Normal file
View File

@@ -0,0 +1,45 @@
import java.util.Scanner;
/**
* It provide some kind of BASIC language behaviour simulations.
*/
final class Basic {
public static int randomOf(int base) {
return (int)Math.round(Math.floor(base* Math.random() + 1));
}
/**
* The Console "simulate" the message error when input does not match with the expected type.
* Specifically for this game if you enter an String when and int was expected.
*/
public static class Console {
private final Scanner input = new Scanner(System.in);
public String readLine() {
return input.nextLine();
}
public int readInt() {
int ret = -1;
boolean failedInput = true;
do {
boolean b = input.hasNextInt();
if (b) {
ret = input.nextInt();
failedInput = false;
} else {
input.next(); // discard read
System.out.print("!NUMBER EXPECTED - RETRY INPUT LINE\n? ");
}
} while (failedInput);
return ret;
}
public void print(String message, Object... args) {
System.out.printf(message, args);
}
}
}

227
15 Boxing/java/Boxing.java Normal file
View File

@@ -0,0 +1,227 @@
/**
* Boxing
*
* <p>
* Based on the Basic game of BatNum here
* https://github.com/coding-horror/basic-computer-games/tree/main/15%20Boxing
* <p>
*/
public class Boxing {
private static final Basic.Console console = new Basic.Console();
private GameSession session;
public void play() {
showIntro();
loadPlayers();
console.print("%s'S ADVANTAGE IS %d AND VULNERABILITY IS SECRET.\n", session.getOpponent().getName(), session.getOpponent().getBestPunch().getCode());
for (int roundNro = 1; roundNro <= 3; roundNro++) {
if (session.isOver())
break;
session.resetPoints();
console.print("\nROUND %d BEGINS...%n", roundNro);
for (int majorPunches = 1; majorPunches <= 7; majorPunches++) {
long i = Basic.randomOf(10);
if (i > 5) {
boolean stopPunches = opponentPunch();
if (stopPunches ) break;
} else {
playerPunch();
}
}
showRoundWinner(roundNro);
}
showWinner();
}
private boolean opponentPunch() {
final Punch punch = Punch.random();
if (punch == session.getOpponent().getBestPunch()) session.addOpponentPoints(2);
if (punch == Punch.FULL_SWING) {
console.print("%s TAKES A FULL SWING AND", session.getOpponent().getName());
long r6 = Basic.randomOf(60);
if (session.getPlayer().hitVulnerability(Punch.FULL_SWING) || r6 < 30) {
console.print(" POW!!!!! HE HITS HIM RIGHT IN THE FACE!\n");
if (session.getPoints(session.getOpponent()) > 35) {
session.setKnocked();
return true;
}
session.addOpponentPoints(15);
} else {
console.print(" IT'S BLOCKED!\n");
}
}
if (punch == Punch.HOOK || punch == Punch.UPPERCUT) {
if (punch == Punch.HOOK) {
console.print("%s GETS %s IN THE JAW (OUCH!)\n", session.getOpponent().getName(), session.getPlayer().getName());
session.addOpponentPoints(7);
console.print("....AND AGAIN!\n");
session.addOpponentPoints(5);
if (session.getPoints(session.getOpponent()) > 35) {
session.setKnocked();
return true;
}
console.print("\n");
}
console.print("%s IS ATTACKED BY AN UPPERCUT (OH,OH)...\n", session.getPlayer().getName());
long q4 = Basic.randomOf(200);
if (session.getPlayer().hitVulnerability(Punch.UPPERCUT) || q4 <= 75) {
console.print("AND %s CONNECTS...\n", session.getOpponent().getName());
session.addOpponentPoints(8);
} else {
console.print(" BLOCKS AND HITS %s WITH A HOOK.\n", session.getOpponent().getName());
session.addPlayerPoints(5);
}
}
else {
console.print("%s JABS AND ", session.getOpponent().getName());
long z4 = Basic.randomOf(7);
if (session.getPlayer().hitVulnerability(Punch.JAB))
session.addOpponentPoints(5);
else if (z4 > 4) {
console.print(" BLOOD SPILLS !!!\n");
session.addOpponentPoints(5);
} else {
console.print("IT'S BLOCKED!\n");
}
}
return true;
}
private void playerPunch() {
console.print("%s'S PUNCH? ", session.getPlayer().getName());
final Punch punch = Punch.fromCode(console.readInt());
if (punch == session.getPlayer().getBestPunch()) session.addPlayerPoints(2);
switch (punch) {
case FULL_SWING -> {
console.print("%s SWINGS AND ", session.getPlayer().getName());
if (session.getOpponent().getBestPunch() == Punch.JAB) {
console.print("HE CONNECTS!\n");
if (session.getPoints(session.getPlayer()) <= 35) session.addPlayerPoints(15);
} else {
long x3 = Basic.randomOf(30);
if (x3 < 10) {
console.print("HE CONNECTS!\n");
if (session.getPoints(session.getPlayer()) <= 35) session.addPlayerPoints(15);
} else {
console.print("HE MISSES \n");
if (session.getPoints(session.getPlayer()) != 1) console.print("\n\n");
}
}
}
case HOOK -> {
console.print("\n%s GIVES THE HOOK... ", session.getPlayer().getName());
long h1 = Basic.randomOf(2);
if (session.getOpponent().getBestPunch() == Punch.HOOK) {
session.addPlayerPoints(7);
} else if (h1 == 1) {
console.print("BUT IT'S BLOCKED!!!!!!!!!!!!!\n");
} else {
console.print("CONNECTS...\n");
session.addPlayerPoints(7);
}
}
case UPPERCUT -> {
console.print("\n%s TRIES AN UPPERCUT ", session.getPlayer().getName());
long d5 = Basic.randomOf(100);
if (session.getOpponent().getBestPunch() == Punch.UPPERCUT || d5 < 51) {
console.print("AND HE CONNECTS!\n");
session.addPlayerPoints(4);
} else {
console.print("AND IT'S BLOCKED (LUCKY BLOCK!)\n");
}
}
default -> {
console.print("%s JABS AT %s'S HEAD \n", session.getPlayer().getName(), session.getOpponent().getName());
if (session.getOpponent().getBestPunch() == Punch.JAB) {
session.addPlayerPoints(3);
} else {
long c = Basic.randomOf(8);
if (c < 4) {
console.print("IT'S BLOCKED.\n");
} else {
session.addPlayerPoints(3);
}
}
}
}
}
private void showRoundWinner(int roundNro) {
if (session.isRoundWinner(session.getPlayer())) {
console.print("\n %s WINS ROUND %d\n", session.getPlayer().getName(), roundNro);
session.addRoundWind(session.getPlayer());
} else {
console.print("\n %s WINS ROUND %d\n", session.getOpponent().getName(), roundNro);
session.addRoundWind(session.getOpponent());
}
}
private void showWinner() {
if (session.isGameWinner(session.getOpponent())) {
console.print("%s WINS (NICE GOING, " + session.getOpponent().getName() + ").", session.getOpponent().getName());
} else if (session.isGameWinner(session.getPlayer())) {
console.print("%s AMAZINGLY WINS!!", session.getPlayer().getName());
} else if (session.isPlayerKnocked()) {
console.print("%s IS KNOCKED COLD AND %s IS THE WINNER AND CHAMP!", session.getPlayer().getName(), session.getOpponent().getName());
} else {
console.print("%s IS KNOCKED COLD AND %s IS THE WINNER AND CHAMP!", session.getOpponent().getName(), session.getPlayer().getName());
}
console.print("\n\nAND NOW GOODBYE FROM THE OLYMPIC ARENA.\n");
}
private void loadPlayers() {
console.print("WHAT IS YOUR OPPONENT'S NAME? ");
final String opponentName = console.readLine();
console.print("INPUT YOUR MAN'S NAME? ");
final String playerName = console.readLine();
console.print("DIFFERENT PUNCHES ARE: (1) FULL SWING; (2) HOOK; (3) UPPERCUT; (4) JAB.\n");
console.print("WHAT IS YOUR MANS BEST? ");
final int b = console.readInt();
console.print("WHAT IS HIS VULNERABILITY? ");
final int d = console.readInt();
final Player player = new Player(playerName, Punch.fromCode(b), Punch.fromCode(d));
final Player opponent = new Player(opponentName);
session = new GameSession(player, opponent);
}
private void showIntro () {
console.print(" BOXING\n");
console.print(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n");
console.print("BOXING OLYMPIC STYLE (3 ROUNDS -- 2 OUT OF 3 WINS)\n\n");
}
}

View File

@@ -0,0 +1,6 @@
public class BoxingGame {
public static void main(String[] args) {
new Boxing().play();
}
}

View File

@@ -0,0 +1,67 @@
/**
* Game Session
* The session store the state of the game
*/
public class GameSession {
private final Player player;
private final Player opponent;
private int opponentRoundWins = 0;
private int playerRoundWins = 0;
int playerPoints = 0;
int opponentPoints = 0;
boolean knocked = false;
GameSession(Player player, Player opponent) {
this.player = player;
this.opponent = opponent;
}
public Player getPlayer() { return player;}
public Player getOpponent() { return opponent;}
public void setKnocked() {
knocked = true;
}
public void resetPoints() {
playerPoints = 0;
opponentPoints = 0;
}
public void addPlayerPoints(int ptos) { playerPoints+=ptos;}
public void addOpponentPoints(int ptos) { opponentPoints+=ptos;}
public int getPoints(Player player) {
if(player.isPlayer())
return playerPoints;
else
return opponentPoints;
}
public void addRoundWind(Player player) {
if(player.isPlayer()) playerRoundWins++; else opponentRoundWins++;
}
public boolean isOver() {
return (opponentRoundWins >= 2 || playerRoundWins >= 2);
}
public boolean isRoundWinner(Player player) {
if (player.isPlayer())
return playerPoints > opponentPoints;
else
return opponentPoints > playerPoints;
}
public boolean isGameWinner(Player player) {
if (player.isPlayer())
return playerRoundWins > 2;
else
return opponentRoundWins > 2;
}
public boolean isPlayerKnocked() {
return knocked;
}
}

View File

@@ -0,0 +1,42 @@
/**
* The Player class model the user and compuer player
*/
public class Player {
private final String name;
private final Punch bestPunch;
private final Punch vulnerability;
private boolean isPlayer = false;
public Player(String name, Punch bestPunch, Punch vulnerability) {
this.name = name;
this.bestPunch = bestPunch;
this.vulnerability = vulnerability;
this.isPlayer = true;
}
/**
* Player with random Best Punch and Vulnerability
*/
public Player(String name) {
this.name = name;
int b1;
int d1;
do {
b1 = Basic.randomOf(4);
d1 = Basic.randomOf(4);
} while (b1 == d1);
this.bestPunch = Punch.fromCode(b1);
this.vulnerability = Punch.fromCode(d1);
}
public boolean isPlayer() { return isPlayer; }
public String getName() { return name; }
public Punch getBestPunch() { return bestPunch; }
public boolean hitVulnerability(Punch punch) {
return vulnerability == punch;
}
}

27
15 Boxing/java/Punch.java Normal file
View File

@@ -0,0 +1,27 @@
import java.util.Arrays;
/**
* Types of Punches
*/
public enum Punch {
FULL_SWING(1),
HOOK(2),
UPPERCUT(3),
JAB(4);
private final int code;
Punch(int code) {
this.code = code;
}
int getCode() { return code;}
public static Punch fromCode(int code) {
return Arrays.stream(Punch.values()).filter(p->p.code == code).findAny().orElse(null);
}
public static Punch random() {
return Punch.fromCode(Basic.randomOf(4));
}
}

View File

@@ -0,0 +1,163 @@
import java.util.Scanner;
/**
* Game of Diamond
* <p>
* Based on the BASIC game of Diamond here
* https://github.com/coding-horror/basic-computer-games/blob/main/32%20Diamond/diamond.bas
* <p>
* Note: The idea was to create a version of the 1970's BASIC game in Java, without introducing
* new features - no additional text, error checking, etc has been added.
*
* Converted from BASIC to Java by Darren Cardenas.
*/
public class Diamond {
private static final int LINE_WIDTH = 60;
private static final String PREFIX = "CC";
private static final char SYMBOL = '!';
private final Scanner scan; // For user input
public Diamond() {
scan = new Scanner(System.in);
} // End of constructor Diamond
public void play() {
showIntro();
startGame();
} // End of method play
private void showIntro() {
System.out.println(" ".repeat(32) + "DIAMOND");
System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
System.out.println("\n\n");
} // End of method showIntro
private void startGame() {
int body = 0;
int column = 0;
int end = 0;
int fill = 0;
int increment = 2;
int numPerSide = 0;
int prefixIndex = 0;
int row = 0;
int start = 1;
int userNum = 0;
String lineContent = "";
// Get user input
System.out.println("FOR A PRETTY DIAMOND PATTERN,");
System.out.print("TYPE IN AN ODD NUMBER BETWEEN 5 AND 21? ");
userNum = scan.nextInt();
System.out.println("");
// Calcuate number of diamonds to be drawn on each side of screen
numPerSide = (int) (LINE_WIDTH / userNum);
end = userNum;
// Begin loop through each row of diamonds
for (row = 1; row <= numPerSide; row++) {
// Begin loop through top and bottom halves of each diamond
for (body = start; increment < 0 ? body >= end : body <= end; body += increment) {
lineContent = "";
// Add whitespace
while (lineContent.length() < ((userNum - body) / 2)) {
lineContent += " ";
}
// Begin loop through each column of diamonds
for (column = 1; column <= numPerSide; column++) {
prefixIndex = 1;
// Begin loop that fills each diamond with characters
for (fill = 1; fill <= body; fill++) {
// Right side of diamond
if (prefixIndex > PREFIX.length()) {
lineContent += SYMBOL;
}
// Left side of diamond
else {
lineContent += PREFIX.charAt(prefixIndex - 1);
prefixIndex++;
}
} // End loop that fills each diamond with characters
// Column finished
if (column == numPerSide) {
break;
}
// Column not finishd
else {
// Add whitespace
while (lineContent.length() < (userNum * column + (userNum - body) / 2)) {
lineContent += " ";
}
}
} // End loop through each column of diamonds
System.out.println(lineContent);
} // End loop through top and bottom half of each diamond
if (start != 1) {
start = 1;
end = userNum;
increment = 2;
}
else {
start = userNum - 2;
end = 1;
increment = -2;
row--;
}
} // End loop through each row of diamonds
} // End of method startGame
public static void main(String[] args) {
Diamond diamond = new Diamond();
diamond.play();
} // End of method main
} // End of class Diamond

42
33 Dice/perl/dice.pl Normal file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/perl
use strict;
print ' 'x 34 . "DICE\n";
print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
print "\n\n\n";
my @F;
#REM DANNY FREIDUS;
print "THIS PROGRAM SIMULATES THE ROLLING OF A\n";
print "PAIR OF DICE.\n";
print "YOU ENTER THE NUMBER OF TIMES YOU WANT THE COMPUTER TO\n";
print "'ROLL' THE DICE. WATCH OUT, VERY LARGE NUMBERS TAKE\n";
print "A LONG TIME. IN PARTICULAR, NUMBERS OVER 5000.\n";
my $X;
my $Z;
do {
for (my $Q=1; $Q<=12; $Q++) {
$F[$Q]=0;
}
print "\n"; print "HOW MANY ROLLS";
print "? "; chomp($X = <STDIN>);
for (my $S=1; $S<=$X; $S++) {
my $A=int(6*rand(1)+1);
my $B=int(6*rand(1)+1);
my $R=$A+$B;
$F[$R]=$F[$R]+1;
}
print "\n";
print "TOTAL SPOTS\tNUMBER OF TIMES\n";
for (my $V=2; $V<=12; $V++) {
print "$V\t\t$F[$V]\n";
}
print "\n";
print "\n"; print "TRY AGAIN";
print "? "; chomp($Z = <STDIN>);
} until (uc($Z) ne "YES");
exit;

BIN
37 Football/javascript/.DS_Store vendored Normal file

Binary file not shown.

View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>GOLF</title>
</head>
<body>
<pre id="output" style="font-size: 12pt;"></pre>
<script src="golf.js"></script>
</body>
</html>

369
39 Golf/javascript/golf.js Normal file
View File

@@ -0,0 +1,369 @@
// GOLF
//
// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
//
function print(str)
{
document.getElementById("output").appendChild(document.createTextNode(str));
}
function input()
{
var input_element;
var input_str;
return new Promise(function (resolve) {
input_element = document.createElement("INPUT");
print("? ");
input_element.setAttribute("type", "text");
input_element.setAttribute("length", "50");
document.getElementById("output").appendChild(input_element);
input_element.focus();
input_str = undefined;
input_element.addEventListener("keydown", function (event) {
if (event.keyCode == 13) {
input_str = input_element.value;
document.getElementById("output").removeChild(input_element);
print(input_str);
print("\n");
resolve(input_str);
}
});
});
}
function tab(space)
{
var str = "";
while (space-- > 0)
str += " ";
return str;
}
var la = [];
var f;
var s1;
var g2;
var g3;
var x;
var hole_data = [
361,4,4,2,389,4,3,3,206,3,4,2,500,5,7,2,
408,4,2,4,359,4,6,4,424,4,4,2,388,4,4,4,
196,3,7,2,400,4,7,2,560,5,7,2,132,3,2,2,
357,4,4,4,294,4,2,4,475,5,2,3,375,4,4,2,
180,3,6,2,550,5,6,6,
];
function show_obstacle()
{
switch (la[x]) {
case 1:
print("FAIRWAY.\n");
break;
case 2:
print("ROUGH.\n");
break;
case 3:
print("TREES.\n");
break;
case 4:
print("ADJACENT FAIRWAY.\n");
break;
case 5:
print("TRAP.\n");
break;
case 6:
print("WATER.\n");
break;
}
}
function show_score()
{
g2 += s1;
print("TOTAL PAR FOR " + (f - 1) + " HOLES IS " + g3 + " YOUR TOTAL IS " + g2 + "\n");
}
// Main program
async function main()
{
print(tab(34) + "GOLF\n");
print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
print("\n");
print("\n");
print("\n");
print("WELCOME TO THE CREATIVE COMPUTING COUNTRY CLUB,\n");
print("AN EIGHTEEN HOLE CHAMPIONSHIP LAYOUT LOCATED A SHORT\n");
print("DISTANCE FROM SCENIC DOWNTOWN MORRISTOWN. THE\n");
print("COMMENTATOR WILL EXPLAIN THE GAME AS YOU PLAY.\n");
print("ENJOY YOUR GAME; SEE YOU AT THE 19TH HOLE...\n");
print("\n");
print("\n");
next_hole = 0;
g1 = 18;
g2 = 0;
g3 = 0;
a = 0;
n = 0.8;
s2 = 0;
f = 1;
while (1) {
print("WHAT IS YOUR HANDICAP");
h = parseInt(await input());
print("\n");
if (h < 0 || h > 30) {
print("PGA HANDICAPS RANGE FROM 0 TO 30.\n");
} else {
break;
}
}
do {
print("DIFFICULTIES AT GOLF INCLUDE:\n");
print("0=HOOK, 1=SLICE, 2=POOR DISTANCE, 4=TRAP SHOTS, 5=PUTTING\n");
print("WHICH ONE (ONLY ONE) IS YOUR WORST");
t = parseInt(await input());
print("\n");
} while (t > 5) ;
s1 = 0;
first_routine = true;
while (1) {
if (first_routine) {
la[0] = 0;
j = 0;
q = 0;
s2++;
k = 0;
if (f != 1) {
print("YOUR SCORE ON HOLE " + (f - 1) + " WAS " + s1 + "\n");
show_score();
if (g1 == f - 1) // Completed all holes?
return; // Exit game
if (s1 > p + 2) {
print("KEEP YOUR HEAD DOWN.\n");
} else if (s1 == p) {
print("A PAR. NICE GOING.\n");
} else if (s1 == p - 1) {
print("A BIRDIE.\n");
} else if (s1 == p - 2) {
if (p != 3)
print("A GREAT BIG EAGLE.\n");
else
print("A HOLE IN ONE.\n");
}
}
if (f == 19) {
print("\n");
show_score();
if (g1 == f - 1)
return;
}
s1 = 0;
print("\n");
if (s1 != 0 && la[0] < 1)
la[0] = 1;
}
if (s1 == 0) {
d = hole_data[next_hole++];
p = hole_data[next_hole++];
la[1] = hole_data[next_hole++];
la[2] = hole_data[next_hole++];
print("\n");
print("YOU ARE AT THE TEE OFF HOLE " + f + " DISTANCE " + d + " YARDS, PAR " + p + "\n");
g3 += p;
print("ON YOUR RIGHT IS ");
x = 1;
show_obstacle();
print("ON YOUR LEFT IS ");
x = 2
show_obstacle();
} else {
x = 0;
if (la[0] > 5) {
if (la[0] > 6) {
print("YOUR SHOT WENT OUT OF BOUNDS.\n");
} else {
print("YOUR SHOT WENT INTO THE WATER.\n");
}
s1++;
print("PENALTY STROKE ASSESSED. HIT FROM PREVIOUS LOCATION.\n");
j++;
la[0] = 1;
d = b;
} else {
print("SHOT WENT " + d1 + " YARDS. IT'S " + d2 + " YARDS FROM THE CUP.\n");
print("BALL IS " + Math.floor(o) + " YARDS OFF LINE... IN ");
show_obstacle();
}
}
while (1) {
if (a != 1) {
print("SELECTION OF CLUBS\n");
print("YARDAGE DESIRED SUGGESTED CLUBS\n");
print("200 TO 280 YARDS 1 TO 4\n");
print("100 TO 200 YARDS 19 TO 13\n");
print(" 0 TO 100 YARDS 29 TO 23\n");
a = 1;
}
print("WHAT CLUB DO YOU CHOOSE");
c = parseInt(await input());
print("\n");
if (c >= 1 && c <= 29 && (c < 5 || c >= 12)) {
if (c > 4)
c -= 6;
if (la[0] <= 5 || c == 14 || c == 23) {
s1++;
w = 1;
if (c <= 13) {
if (f % 3 == 0 && s2 + q + (10 * (f - 1) / 18) < (f - 1) * (72 + ((h + 1) / 0.85)) / 18) {
q++;
if (s1 % 2 != 0 && d >= 95) {
print("BALL HIT TREE - BOUNCED INTO ROUGH " + (d - 75) + " YARDS FROM HOLE.\n");
d -= 75;
continue;
}
print("YOU DUBBED IT.\n");
d1 = 35;
second_routine = 1;
break;
} else if (c < 4 && la[0] == 2) {
print("YOU DUBBED IT.\n");
d1 = 35;
second_routine = 1;
break;
} else {
second_routine = 0;
break;
}
} else {
print("NOW GAUGE YOUR DISTANCE BY A PERCENTAGE (1 TO 100)\n");
print("OF A FULL SWING");
w = parseInt(await input());
w /= 100;
print("\n");
if (w <= 1) {
if (la[0] == 5) {
if (t == 3) {
if (Math.random() <= n) {
n *= 0.2;
print("SHOT DUBBED, STILL IN TRAP.\n");
continue;
}
n = 0.8;
}
d2 = 1 + (3 * Math.floor((80 / (40 - h)) * Math.random()));
second_routine = 2;
break;
}
if (c != 14)
c -= 10;
second_routine = 0;
break;
}
s1--;
// Fall through to THAT CLUB IS NOT IN THE BAG.
}
}
}
print("THAT CLUB IS NOT IN THE BAG.\n");
print("\n");
}
if (second_routine == 0) {
if (s1 > 7 && d < 200) {
d2 = 1 + (3 * Math.floor((80 / (40 - h)) * Math.random()));
second_routine = 2;
} else {
d1 = Math.floor(((30 - h) * 2.5 + 187 - ((30 - h) * 0.25 + 15) * c / 2) + 25 * Math.random());
d1 = Math.floor(d1 * w);
if (t == 2)
d1 = Math.floor(d1 * 0.85);
}
}
if (second_routine <= 1) {
o = (Math.random() / 0.8) * (2 * h + 16) * Math.abs(Math.tan(d1 * 0.0035));
d2 = Math.floor(Math.sqrt(Math.pow(o, 2) + Math.pow(Math.abs(d - d1), 2)));
if (d - d1 < 0) {
if (d2 >= 20)
print("TOO MUCH CLUB, YOU'RE PAST THE HOLE.\n");
}
b = d;
d = d2;
if (d2 > 27) {
if (o < 30 || j > 0) {
la[0] = 1;
} else {
if (t <= 0) {
s9 = (s2 + 1) / 15;
if (Math.floor(s9) == s9) {
print("YOU SLICED- ");
la[0] = la[1];
} else {
print("YOU HOOKED- ");
la[0] = la[2];
}
} else {
s9 = (s2 + 1) / 15;
if (Math.floor(s9) == s9) {
print("YOU HOOKED- ");
la[0] = la[2];
} else {
print("YOU SLICED- ");
la[0] = la[1];
}
}
if (o > 45)
print("BADLY.\n");
}
first_routine = false;
} else if (d2 > 20) {
la[0] = 5;
first_routine = false;
} else if (d2 > 0.5) {
la[0] = 8;
d2 = Math.floor(d2 * 3);
second_routine = 2;
} else {
la[0] = 9;
print("YOU HOLED IT.\n");
print("\n");
f++;
first_routine = true;
}
}
if (second_routine == 2) {
while (1) {
print("ON GREEN, " + d2 + " FEET FROM THE PIN.\n");
print("CHOOSE YOUR PUTT POTENCY (1 TO 13):");
i = parseInt(await input());
s1++;
if (s1 + 1 - p <= (h * 0.072) + 2 && k <= 2) {
k++;
if (t == 4)
d2 -= i * (4 + 1 * Math.random()) + 1;
else
d2 -= i * (4 + 2 * Math.random()) + 1.5;
if (d2 < -2) {
print("PASSED BY CUP.\n");
d2 = Math.floor(-d2);
continue;
}
if (d2 > 2) {
print("PUTT SHORT.\n");
d2 = Math.floor(d2);
continue;
}
}
print("YOU HOLED IT.\n");
print("\n");
f++;
break;
}
first_routine = true;
}
}
}
main();

216
45 Hello/java/Hello.java Normal file
View File

@@ -0,0 +1,216 @@
import java.util.Scanner;
/**
* Game of Hello
* <p>
* Based on the BASIC game of Hello here
* https://github.com/coding-horror/basic-computer-games/blob/main/45%20Hello/hello.bas
* <p>
* Note: The idea was to create a version of the 1970's BASIC game in Java, without introducing
* new features - no additional text, error checking, etc has been added.
*
* Converted from BASIC to Java by Darren Cardenas.
*/
public class Hello {
private static final int MONEY_WAIT_MS = 3000;
private final boolean goodEnding = false;
private final Scanner scan; // For user input
public Hello() {
scan = new Scanner(System.in);
} // End of constructor Hello
public void play() {
showIntro();
startGame();
} // End of method play
private static void showIntro() {
System.out.println(" ".repeat(32) + "HELLO");
System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
System.out.println("\n\n");
} // End of method showIntro
private void startGame() {
boolean moreProblems = true;
String userCategory = "";
String userName = "";
String userResponse = "";
// Name question
System.out.println("HELLO. MY NAME IS CREATIVE COMPUTER.\n\n");
System.out.print("WHAT'S YOUR NAME? ");
userName = scan.nextLine();
System.out.println("");
// Enjoyment question
System.out.print("HI THERE, " + userName + ", ARE YOU ENJOYING YOURSELF HERE? ");
while (true) {
userResponse = scan.nextLine();
System.out.println("");
if (userResponse.toUpperCase().equals("YES")) {
System.out.println("I'M GLAD TO HEAR THAT, " + userName + ".\n");
break;
}
else if (userResponse.toUpperCase().equals("NO")) {
System.out.println("OH, I'M SORRY TO HEAR THAT, " + userName + ". MAYBE WE CAN");
System.out.println("BRIGHTEN UP YOUR VISIT A BIT.");
break;
}
else {
System.out.println(userName + ", I DON'T UNDERSTAND YOUR ANSWER OF '" + userResponse + "'.");
System.out.print("PLEASE ANSWER 'YES' OR 'NO'. DO YOU LIKE IT HERE? ");
}
}
// Category question
System.out.println("");
System.out.println("SAY, " + userName + ", I CAN SOLVE ALL KINDS OF PROBLEMS EXCEPT");
System.out.println("THOSE DEALING WITH GREECE. WHAT KIND OF PROBLEMS DO");
System.out.print("YOU HAVE (ANSWER SEX, HEALTH, MONEY, OR JOB)? ");
while (moreProblems) {
userCategory = scan.nextLine();
System.out.println("");
// Sex advice
if (userCategory.toUpperCase().equals("SEX")) {
System.out.print("IS YOUR PROBLEM TOO MUCH OR TOO LITTLE? ");
userResponse = scan.nextLine();
System.out.println("");
while (true) {
if (userResponse.toUpperCase().equals("TOO MUCH")) {
System.out.println("YOU CALL THAT A PROBLEM?!! I SHOULD HAVE SUCH PROBLEMS!");
System.out.println("IF IT BOTHERS YOU, " + userName + ", TAKE A COLD SHOWER.");
break;
}
else if (userResponse.toUpperCase().equals("TOO LITTLE")) {
System.out.println("WHY ARE YOU HERE IN SUFFERN, " + userName + "? YOU SHOULD BE");
System.out.println("IN TOKYO OR NEW YORK OR AMSTERDAM OR SOMEPLACE WITH SOME");
System.out.println("REAL ACTION.");
break;
}
else {
System.out.println("DON'T GET ALL SHOOK, " + userName + ", JUST ANSWER THE QUESTION");
System.out.print("WITH 'TOO MUCH' OR 'TOO LITTLE'. WHICH IS IT? ");
userResponse = scan.nextLine();
}
}
}
// Health advice
else if (userCategory.toUpperCase().equals("HEALTH")) {
System.out.println("MY ADVICE TO YOU " + userName + " IS:");
System.out.println(" 1. TAKE TWO ASPRIN");
System.out.println(" 2. DRINK PLENTY OF FLUIDS (ORANGE JUICE, NOT BEER!)");
System.out.println(" 3. GO TO BED (ALONE)");
}
// Money advice
else if (userCategory.toUpperCase().equals("MONEY")) {
System.out.println("SORRY, " + userName + ", I'M BROKE TOO. WHY DON'T YOU SELL");
System.out.println("ENCYCLOPEADIAS OR MARRY SOMEONE RICH OR STOP EATING");
System.out.println("SO YOU WON'T NEED SO MUCH MONEY?");
}
// Job advice
else if (userCategory.toUpperCase().equals("JOB")) {
System.out.println("I CAN SYMPATHIZE WITH YOU " + userName + ". I HAVE TO WORK");
System.out.println("VERY LONG HOURS FOR NO PAY -- AND SOME OF MY BOSSES");
System.out.println("REALLY BEAT ON MY KEYBOARD. MY ADVICE TO YOU, " + userName + ",");
System.out.println("IS TO OPEN A RETAIL COMPUTER STORE. IT'S GREAT FUN.");
}
else {
System.out.println("OH, " + userName + ", YOUR ANSWER OF " + userCategory + " IS GREEK TO ME.");
}
// More problems question
while (true) {
System.out.println("");
System.out.print("ANY MORE PROBLEMS YOU WANT SOLVED, " + userName + "? ");
userResponse = scan.nextLine();
System.out.println("");
if (userResponse.toUpperCase().equals("YES")) {
System.out.print("WHAT KIND (SEX, MONEY, HEALTH, JOB)? ");
break;
}
else if (userResponse.toUpperCase().equals("NO")) {
moreProblems = false;
break;
}
else {
System.out.println("JUST A SIMPLE 'YES' OR 'NO' PLEASE, " + userName + ".");
}
}
}
// Payment question
System.out.println("");
System.out.println("THAT WILL BE $5.00 FOR THE ADVICE, " + userName + ".");
System.out.println("PLEASE LEAVE THE MONEY ON THE TERMINAL.");
// Pause
try {
Thread.sleep(MONEY_WAIT_MS);
} catch (Exception e) {
System.out.println("Caught Exception: " + e.getMessage());
}
System.out.println("\n\n");
while (true) {
System.out.print("DID YOU LEAVE THE MONEY? ");
userResponse = scan.nextLine();
System.out.println("");
if (userResponse.toUpperCase().equals("YES")) {
System.out.println("HEY, " + userName + "??? YOU LEFT NO MONEY AT ALL!");
System.out.println("YOU ARE CHEATING ME OUT OF MY HARD-EARNED LIVING.");
System.out.println("");
System.out.println("WHAT A RIP OFF, " + userName + "!!!\n");
break;
}
else if (userResponse.toUpperCase().equals("NO")) {
System.out.println("THAT'S HONEST, " + userName + ", BUT HOW DO YOU EXPECT");
System.out.println("ME TO GO ON WITH MY PSYCHOLOGY STUDIES IF MY PATIENTS");
System.out.println("DON'T PAY THEIR BILLS?");
break;
}
else {
System.out.println("YOUR ANSWER OF '" + userResponse + "' CONFUSES ME, " + userName + ".");
System.out.println("PLEASE RESPOND WITH 'YES' OR 'NO'.");
}
}
// Legacy included unreachable code
if (goodEnding) {
System.out.println("NICE MEETING YOU, " + userName + ", HAVE A NICE DAY.");
}
else {
System.out.println("");
System.out.println("TAKE A WALK, " + userName + ".\n");
}
} // End of method startGame
public static void main(String[] args) {
Hello hello = new Hello();
hello.play();
} // End of method main
} // End of class Hello

45
47 Hi-Lo/perl/hi-lo.pl Normal file
View File

@@ -0,0 +1,45 @@
#!/usr/bin/perl
use strict;
print ' 'x 34 . "HI LO\n";
print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
print "\n"; print "\n"; print "\n";
print "THIS IS THE GAME OF HI LO.\n"; print "\n";
print "YOU WILL HAVE 6 TRIES TO GUESS THE AMOUNT OF MONEY IN THE\n";
print "HI LO JACKPOT, WHICH IS BETWEEN 1 AND 100 DOLLARS. IF YOU\n";
print "GUESS THE AMOUNT, YOU WIN ALL THE MONEY IN THE JACKPOT!\n";
print "THEN YOU GET ANOTHER CHANCE TO WIN MORE MONEY. HOWEVER,\n";
print "IF YOU DO NOT GUESS THE AMOUNT, THE GAME ENDS.\n"; print "\n";
my $R=0;
my $A;
do {
print "\n";
my $Y=int(100*rand(1));
foreach (1..6) {
print "YOUR GUESS $Y";
print "? "; chomp($A = <STDIN>);
if ($A eq $Y) { last; }
if ($A>$Y) {
print "YOUR GUESS IS TOO HIGH.\n";
} else {
print "YOUR GUESS IS TOO LOW.\n";
}
print "\n";
}
if ($A==$Y) {
$R=$R+$Y;
print "GOT IT!!!!!!!!!! YOU WIN $Y DOLLARS.\n";
print "YOUR TOTAL WINNINGS ARE NOW $R DOLLARS.\n";
} else {
$R=0;
print "YOU BLEW IT...TOO BAD...THE NUMBER WAS $Y"
}
print "\n"; print "PLAY AGAIN (YES OR NO)";
print "? "; chomp($A = <STDIN>);
} until (uc($A) ne "YES");
print "\n"; print "SO LONG. HOPE YOU ENJOYED YOURSELF!!!\n";
exit;

53
52 Kinema/perl/kinema.pl Normal file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/perl
use strict;
print ' 'x 33 . "KINEMA\n";
print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
print "\n\n\n";
while (1) {
print "\n";
print "\n";
my $Q=0;
my $V=5+int(35*rand(1));
print "A BALL IS THROWN UPWARDS AT $V METERS PER SECOND.\n";
print "\n";
my $A=.05*$V^2;
print "HOW HIGH WILL IT GO (IN METERS)";
$Q+= &Input($A);
$A=$V/5;
print "HOW LONG UNTIL IT RETURNS (IN SECONDS)";
$Q+= &Input($A);
my $T=1+int(2*$V*rand(1))/10;
$A=$V-10*$T;
print "WHAT WILL ITS VELOCITY BE AFTER $T SECONDS";
$Q+= &Input($A);
print "\n";
print "$Q RIGHT OUT OF 3.";
if ($Q<2) { next; }
print " NOT BAD.\n";
}
exit;
#Line500:
sub Input {
my ($A)= @_;
my $Point=0;
print "? "; chomp(my $G = <STDIN>);
if (abs(($G-$A)/$A)<.15) {
print "CLOSE ENOUGH.\n";
$Point=1;
} else {
print "NOT EVEN CLOSE....\n";
}
print "CORRECT ANSWER IS $A\n";
print "\n";
return $Point;
}

View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>LIFE FOR TWO</title>
</head>
<body>
<pre id="output" style="font-size: 12pt;"></pre>
<script src="lifefortwo.js"></script>
</body>
</html>

View File

@@ -0,0 +1,209 @@
// LIFE FOR TWO
//
// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
//
function print(str)
{
document.getElementById("output").appendChild(document.createTextNode(str));
}
function input()
{
var input_element;
var input_str;
return new Promise(function (resolve) {
input_element = document.createElement("INPUT");
print("? ");
input_element.setAttribute("type", "text");
input_element.setAttribute("length", "50");
document.getElementById("output").appendChild(input_element);
input_element.focus();
input_str = undefined;
input_element.addEventListener("keydown", function (event) {
if (event.keyCode == 13) {
input_str = input_element.value;
document.getElementById("output").removeChild(input_element);
print(input_str);
print("\n");
resolve(input_str);
}
});
});
}
function tab(space)
{
var str = "";
while (space-- > 0)
str += " ";
return str;
}
var na = [];
var ka = [, 3,102,103,120,130,121,112,111,12,
21,30,1020,1030,1011,1021,1003,1002,1012];
var aa = [,-1,0,1,0,0,-1,0,1,-1,-1,1,-1,-1,1,1,1];
var xa = [];
var ya = [];
var j;
var k;
var m2;
var m3;
function show_data()
{
k = 0;
m2 = 0;
m3 = 0;
for (j = 0; j <= 6; j++) {
print("\n");
for (k = 0; k <= 6; k++) {
if (j == 0 || j == 6) {
if (k == 6)
print(" 0 ");
else
print(" " + k + " ");
} else if (k == 0 || k == 6) {
if (j == 6)
print(" 0\n");
else
print(" " + j + " ");
} else {
if (na[j][k] >= 3) {
for (o1 = 1; o1 <= 18; o1++) {
if (na[j][k] == ka[o1])
break;
}
if (o1 <= 18) {
if (o1 <= 9) {
na[j][k] = 100;
m2++;
print(" * ");
} else {
na[j][k] = 1000;
m3++;
print(" # ");
}
} else {
na[j][k] = 0;
print(" ");
}
} else {
na[j][k] = 0;
print(" ");
}
}
}
}
}
function process_board()
{
for (j = 1; j <= 5; j++) {
for (k = 1; k <= 5; k++) {
if (na[j][k] > 99) {
b = 1;
if (na[j][k] > 999)
b = 10;
for (o1 = 1; o1 <= 15; o1 += 2) {
na[j + aa[o1]][k + aa[o1 + 1]] = na[j + aa[o1]][k + aa[o1 + 1]] + b;
}
}
}
}
show_data();
}
// Main program
async function main()
{
print(tab(33) + "LIFE2\n");
print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
print("\n");
print("\n");
print("\n");
print(tab(10) + "U.B. LIFE GAME\n");
m2 = 0;
m3 = 0;
for (j = 0; j <= 6; j++) {
na[j] = [];
for (k = 0; k <= 6; k++)
na[j][k] = 0;
}
for (b = 1; b <= 2; b++) {
p1 = (b == 2) ? 30 : 3;
print("\n");
print("PLAYER " + b + " - 3 LIVE PIECES.\n");
for (k1 = 1; k1 <= 3; k1++) {
while (1) {
print("X,Y\n");
str = await input();
ya[b] = parseInt(str);
xa[b] = parseInt(str.substr(str.indexOf(",") + 1));
if (xa[b] > 0 && xa[b] < 6 && ya[b] > 0 && ya[b] < 5 && na[xa[b]][ya[b]] == 0)
break;
print("ILLEGAL COORDS. RETYPE\n");
}
if (b != 1) {
if (xa[1] == xa[2] && ya[1] == ya[2]) {
print("SAME COORD. SET TO 0\n");
na[xa[b] + 1][ya[b] + 1] = 0;
b = 99;
}
}
na[xa[b]][ya[b]] = p1;
}
}
show_data();
while (1) {
print("\n");
process_board();
if (m2 == 0 && m3 == 0) {
print("\n");
print("A DRAW\n");
break;
}
if (m3 == 0) {
print("\n");
print("PLAYER 1 IS THE WINNER\n");
break;
}
if (m2 == 0) {
print("\n");
print("PLAYER 2 IS THE WINNER\n");
break;
}
for (b = 1; b <= 2; b++) {
print("\n");
print("\n");
print("PLAYER " + b + " ");
while (1) {
print("X,Y\n");
str = await input();
ya[b] = parseInt(str);
xa[b] = parseInt(str.substr(str.indexOf(",") + 1));
if (xa[b] > 0 && xa[b] < 6 && ya[b] > 0 && ya[b] < 5 && na[xa[b]][ya[b]] == 0)
break;
print("ILLEGAL COORDS. RETYPE\n");
}
if (b != 1) {
if (xa[1] == xa[2] && ya[1] == ya[2]) {
print("SAME COORD. SET TO 0\n");
na[xa[b] + 1][ya[b] + 1] = 0;
b = 99;
}
}
if (b == 99)
break;
}
if (b <= 2) {
na[x[1]][y[1]] = 100;
na[x[2]][y[2]] = 1000;
}
}
}
main();

54
58 Love/perl/love.pl Normal file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/perl
use strict;
print ' 'x 33 . "LOVE\n";
print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
print "\n\n\n";
print "A TRIBUTE TO THE GREAT AMERICAN ARTIST, ROBERT INDIANA.\n";
print "HIS GREATEST WORK WILL BE REPRODUCED WITH A MESSAGE OF\n";
print "YOUR CHOICE UP TO 60 CHARACTERS. IF YOU CAN'T THINK OF\n";
print "A MESSAGE, SIMPLE TYPE THE WORD 'LOVE'\n"; print "\n";
print "YOUR MESSAGE, PLEASE? "; chomp(my $A = <STDIN>);
my $L= length($A);
#Original logic too fuzzy, remaked.
my $Width= 60;
my $Text= substr($A x ($Width/$L+1), 0, $Width);
for (my $I=1; $I<10; $I++) { print "\n"; }
my @Data= (
60,1,12,26,9,12,3,8,24,17,8,4,6,23,21,6,4,6,22,12,5,6,5,
4,6,21,11,8,6,4,4,6,21,10,10,5,4,4,6,21,9,11,5,4,
4,6,21,8,11,6,4,4,6,21,7,11,7,4,4,6,21,6,11,8,4,
4,6,19,1,1,5,11,9,4,4,6,19,1,1,5,10,10,4,4,6,18,2,1,6,8,11,4,
4,6,17,3,1,7,5,13,4,4,6,15,5,2,23,5,1,29,5,17,8,
1,29,9,9,12,1,13,5,40,1,1,13,5,40,1,4,6,13,3,10,6,12,5,1,
5,6,11,3,11,6,14,3,1,5,6,11,3,11,6,15,2,1,
6,6,9,3,12,6,16,1,1,6,6,9,3,12,6,7,1,10,
7,6,7,3,13,6,6,2,10,7,6,7,3,13,14,10,8,6,5,3,14,6,6,2,10,
8,6,5,3,14,6,7,1,10,9,6,3,3,15,6,16,1,1,
9,6,3,3,15,6,15,2,1,10,6,1,3,16,6,14,3,1,10,10,16,6,12,5,1,
11,8,13,27,1,11,8,13,27,1,60
);
my $Pos=0;
my $Toggle=1;
foreach my $Size (@Data) {
my $Chunk= $Toggle ? substr($Text, $Pos, $Size) : " " x $Size;
print $Chunk;
$Pos+= $Size;
$Toggle= !$Toggle;
if ($Pos>= $Width) {
print "\n";
$Toggle=1;
$Pos=0;
}
}
for (my $I=1; $I<10; $I++) { print "\n"; }
exit;

View File

@@ -0,0 +1,9 @@
<html>
<head>
<title>MASTERMIND</title>
</head>
<body>
<pre id="output" style="font-size: 12pt;"></pre>
<script src="mastermind.js"></script>
</body>
</html>

View File

@@ -0,0 +1,361 @@
// MASTERMIND
//
// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
//
function print(str)
{
document.getElementById("output").appendChild(document.createTextNode(str));
}
function input()
{
var input_element;
var input_str;
return new Promise(function (resolve) {
input_element = document.createElement("INPUT");
print("? ");
input_element.setAttribute("type", "text");
input_element.setAttribute("length", "50");
document.getElementById("output").appendChild(input_element);
input_element.focus();
input_str = undefined;
input_element.addEventListener("keydown", function (event) {
if (event.keyCode == 13) {
input_str = input_element.value;
document.getElementById("output").removeChild(input_element);
print(input_str);
print("\n");
resolve(input_str);
}
});
});
}
function tab(space)
{
var str = "";
while (space-- > 0)
str += " ";
return str;
}
var p9;
var c9;
var b;
var w;
var f;
var m;
var qa;
var sa;
var ss;
var as;
var gs;
var hs;
function initialize_qa()
{
for (s = 1; s <= p9; s++)
qa[s] = 0;
}
function increment_qa()
{
if (qa[1] <= 0) {
// If zero, this is our firt increment: make all ones
for (s = 1; s <= p9; s++)
qa[s] = 1;
} else {
q = 1;
while (1) {
qa[q] = qa[q] + 1;
if (qa[q] <= c9)
return;
qa[q] = 1;
q++;
}
}
}
function convert_qa()
{
for (s = 1; s <= p9; s++) {
as[s] = ls.substr(qa[s] - 1, 1);
}
}
function get_number()
{
b = 0;
w = 0;
f = 0;
for (s = 1; s <= p9; s++) {
if (gs[s] == as[s]) {
b++;
gs[s] = String.fromCharCode(f);
as[s] = String.fromCharCode(f + 1);
f += 2;
} else {
for (t = 1; t <= p9; t++) {
if (gs[s] == as[t] && gs[t] != as[t]) {
w++;
as[t] = String.fromCharCode(f);
gs[s] = String.fromCharCode(f + 1);
f += 2;
break;
}
}
}
}
}
function convert_qa_hs()
{
for (s = 1; s <= p9; s++) {
hs[s] = ls.substr(qa[s] - 1, 1);
}
}
function copy_hs()
{
for (s = 1; s <= p9; s++) {
gs[s] = hs[s];
}
}
function board_printout()
{
print("\n");
print("BOARD\n");
print("MOVE GUESS BLACK WHITE\n");
for (z = 1; z <= m - 1; z++) {
str = " " + z + " ";
while (str.length < 9)
str += " ";
str += ss[z];
while (str.length < 25)
str += " ";
str += sa[z][1];
while (str.length < 35)
str += " ";
str += sa[z][2];
print(str + "\n");
}
print("\n");
}
function quit()
{
print("QUITTER! MY COMBINATION WAS: ");
convert_qa();
for (x = 1; x <= p9; x++) {
print(as[x]);
}
print("\n");
print("GOOD BYE\n");
}
function show_score()
{
print("SCORE:\n");
show_points();
}
function show_points()
{
print(" COMPUTER " + c + "\n");
print(" HUMAN " + h + "\n");
print("\n");
}
var color = ["BLACK", "WHITE", "RED", "GREEN",
"ORANGE", "YELLOW", "PURPLE", "TAN"];
// Main program
async function main()
{
print(tab(30) + "MASTERMIND\n");
print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
print("\n");
print("\n");
print("\n");
//
// MASTERMIND II
// STEVE NORTH
// CREATIVE COMPUTING
// PO BOX 789-M MORRISTOWN NEW JERSEY 07960
//
//
while (1) {
print("NUMBER OF COLORS");
c9 = parseInt(await input());
if (c9 <= 8)
break;
print("NO MORE THAN 8, PLEASE!\n");
}
print("NUMBER OF POSITIONS");
p9 = parseInt(await input());
print("NUMBER OF ROUNDS");
r9 = parseInt(await input());
p = Math.pow(c9, p9);
print("TOTAL POSSIBILITIES = " + p + "\n");
h = 0;
c = 0;
qa = [];
sa = [];
ss = [];
as = [];
gs = [];
ia = [];
hs = [];
ls = "BWRGOYPT";
print("\n");
print("\n");
print("COLOR LETTER\n");
print("===== ======\n");
for (x = 1; x <= c9; x++) {
str = color[x - 1];
while (str.length < 13)
str += " ";
str += ls.substr(x - 1, 1);
print(str + "\n");
}
print("\n");
for (r = 1; r <= r9; r++) {
print("\n");
print("ROUND NUMBER " + r + " ----\n");
print("\n");
print("GUESS MY COMBINATION.\n");
print("\n");
// Get a combination
a = Math.floor(p * Math.random() + 1);
initialize_qa();
for (x = 1; x <= a; x++) {
increment_qa();
}
for (m = 1; m <= 10; m++) {
while (1) {
print("MOVE # " + m + " GUESS ");
str = await input();
if (str == "BOARD") {
board_printout();
} else if (str == "QUIT") {
quit();
return;
} else if (str.length != p9) {
print("BAD NUMBER OF POSITIONS.\n");
} else {
// Unpack str into gs(1-p9)
for (x = 1; x <= p9; x++) {
y = ls.indexOf(str.substr(x - 1, 1));
if (y < 0) {
print("'" + str.substr(x - 1, 1) + "' IS UNRECOGNIZED.\n");
break;
}
gs[x] = str.substr(x - 1, 1);
}
if (x > p9)
break;
}
}
// Now we convert qa(1-p9) into as(1-p9) [ACTUAL GUESS]
convert_qa();
// And get number of blacks and white
get_number();
if (b == p9) {
print("YOU GUESSED IT IN " + m + " MOVES!\n");
break;
}
// Save all this stuff for board printout later
ss[m] = str;
sa[m] = [];
sa[m][1] = b;
sa[m][2] = w;
}
if (m > 10) {
print("YOU RAN OUT OF MOVES! THAT'S ALL YOU GET!\n");
}
h += m;
show_score();
//
// Now computer guesses
//
for (x = 1; x <= p; x++)
ia[x] = 1;
print("NOW I GUESS. THINK OF A COMBINATION.\n");
print("HIT RETURN WHEN READY:");
str = await input();
for (m = 1; m <= 10; m++) {
initialize_qa();
// Find a guess
g = Math.floor(p * Math.random() + 1);
if (ia[g] != 1) {
for (x = g; x <= p; x++) {
if (ia[x] == 1)
break;
}
if (x > p) {
for (x = 1; x <= g; x++) {
if (ia[x] == 1)
break;
}
if (x > g) {
print("YOU HAVE GIVEN ME INCONSISTENT INFORMATION.\n");
print("TRY AGAIN, AND THIS TIME PLEASE BE MORE CAREFUL.\n");
for (x = 1; x <= p; x++)
ia[x] = 1;
print("NOW I GUESS. THINK OF A COMBINATION.\n");
print("HIT RETURN WHEN READY:");
str = await input();
m = 0;
continue;
}
}
g = x;
}
// Now we convert guess #g into gs
for (x = 1; x <= g; x++) {
increment_qa();
}
convert_qa_hs();
print("MY GUESS IS: ");
for (x = 1; x <= p9; x++) {
print(hs[x]);
}
print(" BLACKS, WHITES ");
str = await input();
b1 = parseInt(str);
w1 = parseInt(str.substr(str.indexOf(",") + 1));
if (b1 == p9) {
print("I GOT IT IN " + m + " MOVES!\n");
break;
}
initialize_qa();
for (x = 1; x <= p; x++) {
increment_qa();
if (ia[x] != 0) {
copy_hs();
convert_qa();
get_number();
if (b1 != b || w1 != w)
ia[x] = 0;
}
}
}
if (m > 10) {
print("I USED UP ALL MY MOVES!\n");
print("I GUESS MY CPU I JUST HAVING AN OFF DAY.\n");
}
c += m;
show_score();
}
print("GAME OVER\n");
print("FINAL SCORE:\n");
show_points();
}
main();

69
66 Number/java/main.class Normal file
View File

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

View File

@@ -0,0 +1,56 @@
#!/usr/bin/perl
use strict;
print ' 'x 21 . "GAME OF ROCK, SCISSORS, PAPER\n";
print ' 'x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
print "\n\n\n";
my $Q=0;
my $C=0;
my $H=0;
do {
print "HOW MANY GAMES? "; chomp($Q = <STDIN>);
if ($Q>10) { print "SORRY, BUT WE AREN'T ALLOWED TO PLAY THAT MANY.\n"; }
} until ($Q<11);
for (my $G=1; $G<=$Q; $G++) {
print "\n"; print "GAME NUMBER $G\n";
my $X=int(rand(1)*3+1);
my $K=0;
do {
print "3=ROCK...2=SCISSORS...1=PAPER\n";
print "1...2...3...WHAT'S YOUR CHOICE? "; chomp($K = <STDIN>);
if (($K-1)*($K-2)*($K-3)!=0) { print "INVALID.\n"; $K=0; }
} until ($K!=0);
print "THIS IS MY CHOICE...\n";
if ($X==1) { print "...PAPER\n"; }
if ($X==2) { print "...SCISSORS\n"; }
if ($X==3) { print "...ROCK\n"; }
#Original logic too complex...
if ($X==$K) { print "TIE GAME. NO WINNER.\n"; next; }
my $Who=0;
if ($X==1 && $K==3) { $Who=1; } #Paper wins over rock.
if ($X==2 && $K==1) { $Who=1; } #Scissors wins over paper.
if ($X==3 && $K==2) { $Who=1; } #Rock wins over scissors.
if ($Who==1) {
print "WOW! I WIN!!!\n"; $C=$C+1;
} else {
print "YOU WIN!!!\n"; $H=$H+1;
}
}
print "\n"; print "HERE IS THE FINAL GAME SCORE:\n";
print "I HAVE WON $C GAME(S).\n";
print "YOU HAVE WON $H GAME(S).\n";
print "AND ".($Q-($C+$H))." GAME(S) ENDED IN A TIE.\n";
print "\n"; print "THANKS FOR PLAYING!!\n";
exit;

View File

@@ -1,6 +1,6 @@
using System.ComponentModel;
namespace SuperStarTrek
namespace SuperStarTrek.Commands
{
internal enum Command
{

View File

@@ -1,7 +1,7 @@
using System.Reflection;
using System.ComponentModel;
namespace SuperStarTrek
namespace SuperStarTrek.Commands
{
internal static class CommandExtensions
{

View File

@@ -0,0 +1,23 @@
namespace SuperStarTrek.Commands
{
internal class CommandResult
{
public static readonly CommandResult Ok = new(false);
public static readonly CommandResult GameOver = new(true);
private CommandResult(bool isGameOver)
{
IsGameOver = isGameOver;
}
private CommandResult(float timeElapsed)
{
TimeElapsed = timeElapsed;
}
public bool IsGameOver { get; }
public float TimeElapsed { get; }
public static CommandResult Elapsed(float timeElapsed) => new(timeElapsed);
}
}

View File

@@ -3,6 +3,7 @@ using SuperStarTrek.Objects;
using SuperStarTrek.Resources;
using SuperStarTrek.Space;
using SuperStarTrek.Systems;
using SuperStarTrek.Systems.ComputerFunctions;
using static System.StringComparison;
namespace SuperStarTrek
@@ -11,12 +12,12 @@ namespace SuperStarTrek
{
private readonly Output _output;
private readonly Input _input;
private readonly Random _random;
private int _initialStardate;
private int _finalStarDate;
private double _currentStardate;
private float _currentStardate;
private Coordinates _currentQuadrant;
private Coordinates _currentSector;
private Galaxy _galaxy;
private int _initialKlingonCount;
private Enterprise _enterprise;
@@ -25,19 +26,17 @@ namespace SuperStarTrek
{
_output = new Output();
_input = new Input(_output);
_random = new Random();
}
public double Stardate => _currentStardate;
public float Stardate => _currentStardate;
public float StardatesRemaining => _finalStarDate - _currentStardate;
public void DoIntroduction()
{
_output.Write(Strings.Title);
_output.Write("Do you need instructions (Y/N)? ");
var response = Console.ReadLine();
_output.WriteLine();
if (!response.Equals("N", InvariantCultureIgnoreCase))
if (_input.GetYesNo("Do you need instructions", Input.YesNoMode.FalseOnN))
{
_output.Write(Strings.Instructions);
@@ -47,8 +46,61 @@ namespace SuperStarTrek
public void Play()
{
var quadrant = Initialise();
Initialise();
var gameOver = false;
var newQuadrantText = Strings.StartText;
while (!gameOver)
{
_enterprise.Quadrant.Display(Strings.NowEntering);
var command = _input.GetCommand();
var result = _enterprise.Execute(command);
gameOver = result.IsGameOver || CheckIfStranded();
_currentStardate += result.TimeElapsed;
gameOver |= _currentStardate > _finalStarDate;
}
if (_galaxy.KlingonCount > 0)
{
_output.Write(Strings.EndOfMission, _currentStardate, _galaxy.KlingonCount);
}
else
{
_output.Write(Strings.Congratulations, GetEfficiency());
}
}
private void Initialise()
{
_currentStardate = _initialStardate = _random.GetInt(20, 40) * 100;
_finalStarDate = _initialStardate + _random.GetInt(25, 35);
_currentQuadrant = _random.GetCoordinate();
_galaxy = new Galaxy(_random);
_initialKlingonCount = _galaxy.KlingonCount;
_enterprise = new Enterprise(3000, _random.GetCoordinate(), _output, _random, _input);
_enterprise
.Add(new WarpEngines(_enterprise, _output, _input))
.Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output))
.Add(new LongRangeSensors(_galaxy, _output))
.Add(new PhaserControl(_enterprise, _output, _input, _random))
.Add(new PhotonTubes(10, _enterprise, _output, _input))
.Add(new ShieldControl(_enterprise, _output, _input))
.Add(new DamageControl(_enterprise, _output))
.Add(new LibraryComputer(
_output,
_input,
new CumulativeGalacticRecord(_output, _galaxy),
new StatusReport(this, _galaxy, _enterprise, _output),
new TorpedoDataCalculator(_enterprise, _output),
new StarbaseDataCalculator(_enterprise, _output),
new DirectionDistanceCalculator(_enterprise, _output, _input),
new GalaxyRegionMap(_output, _galaxy)));
_output.Write(Strings.Enterprise);
_output.Write(
@@ -62,36 +114,21 @@ namespace SuperStarTrek
_input.WaitForAnyKeyButEnter("when ready to accept command");
_enterprise.Enter(quadrant, Strings.StartText);
while (!gameOver)
{
var command = _input.GetCommand();
gameOver = command == Command.XXX || _enterprise.Execute(command);
}
_enterprise.StartIn(BuildCurrentQuadrant());
}
private Quadrant Initialise()
{
var random = new Random();
_currentStardate = _initialStardate = random.GetInt(20, 40) * 100;
_finalStarDate = _initialStardate + random.GetInt(25, 35);
_currentQuadrant = random.GetCoordinate();
_currentSector = random.GetCoordinate();
_galaxy = new Galaxy();
_initialKlingonCount = _galaxy.KlingonCount;
_enterprise = new Enterprise(3000, random.GetCoordinate());
_enterprise.Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output))
.Add(new ShieldControl(_enterprise, _output, _input));
return new Quadrant(_galaxy[_currentQuadrant], _enterprise);
}
private Quadrant BuildCurrentQuadrant() =>
new Quadrant(_galaxy[_currentQuadrant], _enterprise, _random, _galaxy, _input, _output);
public bool Replay() => _galaxy.StarbaseCount > 0 && _input.GetString(Strings.ReplayPrompt, "Aye");
private bool CheckIfStranded()
{
if (_enterprise.IsStranded) { _output.Write(Strings.Stranded); }
return _enterprise.IsStranded;
}
private float GetEfficiency() =>
1000 * (float)Math.Pow(_initialKlingonCount / (_currentStardate - _initialStardate), 2);
}
}

View File

@@ -1,5 +1,7 @@
using System;
using System.Linq;
using SuperStarTrek.Commands;
using SuperStarTrek.Space;
using static System.StringComparison;
namespace SuperStarTrek
@@ -25,14 +27,14 @@ namespace SuperStarTrek
return Console.ReadLine();
}
public double GetNumber(string prompt)
public float GetNumber(string prompt)
{
_output.Prompt(prompt);
while (true)
{
var response = Console.ReadLine();
if (double.TryParse(response, out var value))
if (float.TryParse(response, out var value))
{
return value;
}
@@ -42,7 +44,14 @@ namespace SuperStarTrek
}
}
public bool TryGetNumber(string prompt, double minValue, double maxValue, out double value)
public (float X, float Y) GetCoordinates(string prompt)
{
_output.Prompt($"{prompt} (X,Y)");
var responses = ReadNumbers(2);
return (responses[0], responses[1]);
}
public bool TryGetNumber(string prompt, float minValue, float maxValue, out float value)
{
value = GetNumber($"{prompt} ({minValue}-{maxValue})");
@@ -58,7 +67,7 @@ namespace SuperStarTrek
{
var response = GetString("Command");
if (response != "" &&
if (response.Length >= 3 &&
Enum.TryParse(response.Substring(0, 3), ignoreCase: true, out Command parsedCommand))
{
return parsedCommand;
@@ -72,5 +81,79 @@ namespace SuperStarTrek
_output.WriteLine();
}
}
public bool TryGetCourse(string prompt, string officer, out Course course)
{
if (!TryGetNumber(prompt, 1, 9, out var direction))
{
_output.WriteLine($"{officer} reports, 'Incorrect course data, sir!'");
course = default;
return false;
}
course = new Course(direction);
return true;
}
public bool GetYesNo(string prompt, YesNoMode mode)
{
_output.Prompt($"{prompt} (Y/N)");
var response = Console.ReadLine().ToUpperInvariant();
return (mode, response) switch
{
(YesNoMode.FalseOnN, "N") => false,
(YesNoMode.FalseOnN, _) => true,
(YesNoMode.TrueOnY, "Y") => true,
(YesNoMode.TrueOnY, _) => false,
_ => throw new ArgumentOutOfRangeException(nameof(mode), mode, "Invalid value")
};
}
private float[] ReadNumbers(int quantity)
{
var numbers = new float[quantity];
var index = 0;
bool tryAgain;
do
{
tryAgain = false;
var responses = Console.ReadLine().Split(',');
if (responses.Length > quantity)
{
_output.WriteLine("!Extra input ingored");
}
for (; index < responses.Length; index++)
{
if (!float.TryParse(responses[index], out numbers[index]))
{
_output.WriteLine("!Number expected - retry input line");
_output.Prompt();
tryAgain = true;
break;
}
}
} while (tryAgain);
if (index < quantity)
{
_output.Prompt("?");
var responses = ReadNumbers(quantity - index);
for (int i = 0; i < responses.Length; i++, index++)
{
numbers[index] = responses[i];
}
}
return numbers;
}
public enum YesNoMode
{
TrueOnY,
FalseOnN
}
}
}

View File

@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SuperStarTrek.Commands;
using SuperStarTrek.Resources;
using SuperStarTrek.Space;
using SuperStarTrek.Systems;
@@ -10,84 +12,71 @@ namespace SuperStarTrek.Objects
internal class Enterprise
{
private readonly int _maxEnergy;
private readonly Output _output;
private readonly List<Subsystem> _systems;
private readonly Dictionary<Command, Subsystem> _commandExecutors;
private readonly Random _random;
private readonly Input _input;
private Quadrant _quadrant;
private ShieldControl _shieldControl;
public Enterprise(int maxEnergy, Coordinates sector)
public Enterprise(int maxEnergy, Coordinates sector, Output output, Random random, Input input)
{
Sector = sector;
SectorCoordinates = sector;
TotalEnergy = _maxEnergy = maxEnergy;
_systems = new List<Subsystem>();
_commandExecutors = new Dictionary<Command, Subsystem>();
_output = output;
_random = random;
_input = input;
}
public Coordinates Quadrant => _quadrant.Coordinates;
public Coordinates Sector { get; }
public string Condition => GetCondition();
public double Shields => _shieldControl.Energy;
public double Energy => TotalEnergy - Shields;
public double TotalEnergy { get; private set; }
public int TorpedoCount { get; }
public Quadrant Quadrant => _quadrant;
public Coordinates QuadrantCoordinates => _quadrant.Coordinates;
public Coordinates SectorCoordinates { get; private set; }
public bool IsDocked { get; private set; }
public string Condition => GetCondition();
public LibraryComputer Computer => (LibraryComputer)_commandExecutors[Command.COM];
public ShieldControl ShieldControl => (ShieldControl)_commandExecutors[Command.SHE];
public float Energy => TotalEnergy - ShieldControl.ShieldEnergy;
public float TotalEnergy { get; private set; }
public int DamagedSystemCount => _systems.Count(s => s.IsDamaged);
public IEnumerable<Subsystem> Systems => _systems;
public PhotonTubes PhotonTubes => (PhotonTubes)_commandExecutors[Command.TOR];
public bool IsDocked => _quadrant.EnterpriseIsNextToStarbase;
public bool IsStranded => TotalEnergy < 10 || Energy < 10 && ShieldControl.IsDamaged;
public Enterprise Add(Subsystem system)
{
_systems.Add(system);
_commandExecutors[system.Command] = system;
if (system is ShieldControl shieldControl) { _shieldControl = shieldControl; }
return this;
}
public string GetDamageReport()
{
var report = new StringBuilder();
report.AppendLine().AppendLine().AppendLine("Device State of Repair");
foreach (var system in _systems)
{
report.Append(system.Name.PadRight(25)).AppendLine(system.Condition.ToString(" 0.00;-0.00"));
}
report.AppendLine();
return report.ToString();
}
public void Enter(Quadrant quadrant, string entryTextFormat)
public void StartIn(Quadrant quadrant)
{
_quadrant = quadrant;
var _output = new Output();
_output.Write(entryTextFormat, quadrant);
if (quadrant.HasKlingons)
{
_output.Write(Strings.CombatArea);
if (Shields <= 200) { _output.Write(Strings.LowShields); }
}
IsDocked = quadrant.EnterpriseIsNextToStarbase;
Execute(Command.SRS);
quadrant.Display(Strings.StartText);
}
private string GetCondition() =>
(_quadrant.HasKlingons, Energy / _maxEnergy) switch
{
(true, _) => "*Red*",
(_, < 0.1) => "Yellow",
(_, < 0.1f) => "Yellow",
_ => "Green"
};
public bool Execute(Command command)
public CommandResult Execute(Command command)
{
_commandExecutors[command].ExecuteCommand(_quadrant);
return false;
if (command == Command.XXX) { return CommandResult.GameOver; }
return _commandExecutors[command].ExecuteCommand(_quadrant);
}
public void Refuel() => TotalEnergy = _maxEnergy;
internal bool Recognises(string command)
{
throw new NotImplementedException();
@@ -99,5 +88,143 @@ namespace SuperStarTrek.Objects
}
public override string ToString() => "<*>";
internal void UseEnergy(float amountUsed)
{
TotalEnergy -= amountUsed;
}
internal CommandResult TakeHit(Coordinates sector, int hitStrength)
{
_output.WriteLine($"{hitStrength} unit hit on Enterprise from sector {sector}");
ShieldControl.AbsorbHit(hitStrength);
if (ShieldControl.ShieldEnergy <= 0)
{
_output.WriteLine(Strings.Destroyed);
return CommandResult.GameOver;
}
_output.WriteLine($" <Shields down to {ShieldControl.ShieldEnergy} units>");
if (hitStrength >= 20)
{
TakeDamage(hitStrength);
}
return CommandResult.Ok;
}
private void TakeDamage(float hitStrength)
{
var hitShieldRatio = hitStrength / ShieldControl.ShieldEnergy;
if (_random.GetFloat() > 0.6 || hitShieldRatio <= 0.02f)
{
return;
}
var system = _systems[_random.Get1To8Inclusive() - 1];
system.TakeDamage(hitShieldRatio + 0.5f * _random.GetFloat());
_output.WriteLine($"Damage Control reports, '{system.Name} damaged by the hit.'");
}
internal void RepairSystems(float repairWorkDone)
{
var repairedSystems = new List<string>();
foreach (var system in _systems.Where(s => s.IsDamaged))
{
if (system.Repair(repairWorkDone))
{
repairedSystems.Add(system.Name);
}
}
if (repairedSystems.Any())
{
_output.WriteLine("Damage Control report:");
foreach (var systemName in repairedSystems)
{
_output.WriteLine($" {systemName} repair completed.");
}
}
}
internal void VaryConditionOfRandomSystem()
{
if (_random.GetFloat() > 0.2f) { return; }
var system = _systems[_random.Get1To8Inclusive() - 1];
_output.Write($"Damage Control report: {system.Name} ");
if (_random.GetFloat() >= 0.6)
{
system.Repair(_random.GetFloat() * 3 + 1);
_output.WriteLine("state of repair improved");
}
else
{
system.TakeDamage(_random.GetFloat() * 5 + 1);
_output.WriteLine("damaged");
}
}
internal float Move(Course course, float warpFactor, int distance)
{
var (quadrant, sector) = MoveWithinQuadrant(course, distance) ?? MoveBeyondQuadrant(course, distance);
if (quadrant != _quadrant.Coordinates)
{
_quadrant = new Quadrant(_quadrant.Galaxy[quadrant], this, _random, _quadrant.Galaxy, _input, _output);
}
_quadrant.SetEnterpriseSector(sector);
SectorCoordinates = sector;
TotalEnergy -= distance + 10;
if (Energy < 0)
{
_output.WriteLine("Shield Control supplies energy to complete the maneuver.");
ShieldControl.ShieldEnergy = Math.Max(0, TotalEnergy);
}
return GetTimeElapsed(quadrant, warpFactor);
}
private (Coordinates, Coordinates)? MoveWithinQuadrant(Course course, int distance)
{
var currentSector = SectorCoordinates;
foreach (var (sector, index) in course.GetSectorsFrom(SectorCoordinates).Select((s, i) => (s, i)))
{
if (distance == 0) { break; }
if (_quadrant.HasObjectAt(sector))
{
_output.WriteLine($"Warp engines shut down at sector {currentSector} dues to bad navigation");
distance = 0;
break;
}
currentSector = sector;
distance -= 1;
}
return distance == 0 ? (_quadrant.Coordinates, currentSector) : null;
}
private (Coordinates, Coordinates) MoveBeyondQuadrant(Course course, int distance)
{
var (complete, quadrant, sector) = course.GetDestination(QuadrantCoordinates, SectorCoordinates, distance);
if (!complete)
{
_output.Write(Strings.PermissionDenied, sector, quadrant);
}
return (quadrant, sector);
}
private float GetTimeElapsed(Coordinates finalQuadrant, float warpFactor) =>
finalQuadrant == _quadrant.Coordinates
? Math.Min(1, (float)Math.Round(warpFactor, 1, MidpointRounding.ToZero))
: 1;
}
}

View File

@@ -1,14 +1,42 @@
using SuperStarTrek.Commands;
using SuperStarTrek.Space;
namespace SuperStarTrek.Objects
{
internal class Klingon
{
private double _energy;
private readonly Random _random;
public Klingon()
public Klingon(Coordinates sector, Random random)
{
_energy = new Random().GetDouble(100, 300);
Sector = sector;
_random = random;
Energy = _random.GetFloat(100, 300);
}
public float Energy { get; private set; }
public Coordinates Sector { get; private set; }
public override string ToString() => "+K+";
public CommandResult FireOn(Enterprise enterprise)
{
var attackStrength = _random.GetFloat();
var distanceToEnterprise = Sector.GetDistanceTo(enterprise.SectorCoordinates);
var hitStrength = (int)(Energy * (2 + attackStrength) / distanceToEnterprise);
Energy /= 3 + attackStrength;
return enterprise.TakeHit(Sector, hitStrength);
}
internal bool TakeHit(int hitStrength)
{
if (hitStrength < 0.15 * Energy) { return false; }
Energy -= hitStrength;
return true;
}
internal void MoveTo(Coordinates newSector) => Sector = newSector;
}
}

View File

@@ -1,7 +1,44 @@
using SuperStarTrek.Resources;
using SuperStarTrek.Space;
namespace SuperStarTrek.Objects
{
internal class Starbase
{
private readonly Input _input;
private readonly Output _output;
private readonly float _repairDelay;
public Starbase(Coordinates sector, Random random, Input input, Output output)
{
Sector = sector;
_repairDelay = random.GetFloat() * 0.5f;
_input = input;
_output = output;
}
internal Coordinates Sector { get; }
public override string ToString() => ">!<";
internal bool TryRepair(Enterprise enterprise, out float repairTime)
{
repairTime = enterprise.DamagedSystemCount * 0.1f + _repairDelay;
if (repairTime >= 1) { repairTime = 0.9f; }
_output.Write(Strings.RepairEstimate, repairTime);
if (_input.GetYesNo(Strings.RepairPrompt, Input.YesNoMode.TrueOnY))
{
foreach (var system in enterprise.Systems)
{
system.Repair();
}
return true;
}
repairTime = 0;
return false;
}
internal void ProtectEnterprise() => _output.WriteLine(Strings.Protected);
}
}

View File

@@ -4,12 +4,37 @@ namespace SuperStarTrek
{
internal class Output
{
public void Write(string text) => Console.Write(text);
public void Write(string format, params object[] args) => Console.Write(format, args);
public void WriteLine(string text = "") => Console.WriteLine(text);
public Output Write(string text)
{
Console.Write(text);
return this;
}
public void NextLine() => Console.WriteLine();
public Output Write(string format, params object[] args)
{
Console.Write(format, args);
return this;
}
public Output WriteLine(string text = "")
{
Console.WriteLine(text);
return this;
}
public Output NextLine()
{
Console.WriteLine();
return this;
}
public Output Prompt(string text = "")
{
Console.Write($"{text}? ");
return this;
}
public void Prompt(string text = "") => Console.Write($"{text}? ");
}
}

View File

@@ -29,6 +29,7 @@ namespace SuperStarTrek
{
static void Main()
{
var foo = Utils.DirectionAndDistance.From(1,1).To(4,5);
var game = new Game();
game.DoIntroduction();

View File

@@ -6,20 +6,20 @@ namespace SuperStarTrek
{
private static readonly System.Random _random = new();
public Coordinates GetCoordinate() => new Coordinates(Get1To8Inclusive(), Get1To8Inclusive());
public Coordinates GetCoordinate() => new Coordinates(Get1To8Inclusive() - 1, Get1To8Inclusive() - 1);
// Duplicates the algorithm used in the original code to get an integer value from 1 to 8, inclusive:
// 475 DEF FNR(R)=INT(RND(R)*7.98+1.01)
// Returns a value from 1 to 8, inclusive.
// Note there's a slight bias away from the extreme values, 1 and 8.
public int Get1To8Inclusive() => (int)(_random.NextDouble() * 7.98 + 1.01);
public int Get1To8Inclusive() => (int)(GetFloat() * 7.98 + 1.01);
public int GetInt(int inclusiveMinValue, int exclusiveMaxValue) =>
_random.Next(inclusiveMinValue, exclusiveMaxValue);
public double GetDouble() => _random.NextDouble();
public float GetFloat() => (float)_random.NextDouble();
public double GetDouble(double inclusiveMinValue, double exclusiveMaxValue)
=> _random.NextDouble() * (exclusiveMaxValue - inclusiveMinValue) + inclusiveMinValue;
public float GetFloat(float inclusiveMinValue, float exclusiveMaxValue)
=> GetFloat() * (exclusiveMaxValue - inclusiveMinValue) + inclusiveMinValue;
}
}

View File

@@ -0,0 +1,9 @@
Functions available from Library-Computer:
0 = Cumulative galactic record
1 = Status report
2 = Photon torpedo data
3 = Starbase nav data
4 = Direction/distance calculator
5 = Galaxy 'region name' map

View File

@@ -0,0 +1,4 @@
Congratulations, Captain! The last Klingon battle cruiser
menacing the Federation has been destroyed.
Your efficiency rating is {0}.

View File

@@ -0,0 +1,3 @@
Starfleet Command reviewing your record to consider
court martial!

View File

@@ -0,0 +1 @@
The Enterprise has been destroyed. The Federation will be conquered.

View File

@@ -0,0 +1,3 @@
Is is stardate {0}.
There were {1} Klingon battle cruisers left at
the end of your mission.

View File

@@ -1,3 +1,4 @@
INSTRUCTIONS FOR 'SUPER STAR TREK'
1. When you see "Command ?" printed, enter one of the legal

View File

@@ -0,0 +1,2 @@
Science Officer Spock reports, 'Sensors show no enemy ships
in this quadrant'

View File

@@ -0,0 +1 @@
Mr. Spock reports, 'Sensors show no starbases in this quadrant.'

View File

@@ -0,0 +1,2 @@
Now entering {0} quadrant . . .

View File

@@ -0,0 +1,5 @@
Lt. Uhura report message from Starfleet Command:
'Permission to attempt crossing of galactic perimeter
is hereby *Denied*. Shut down your engines.'
Chief Engineer Scott reports, 'Warp engines shut down
at sector {0} of quadrant {1}.'

View File

@@ -0,0 +1 @@
Starbase shields protect the Enterprise

View File

@@ -0,0 +1,8 @@
Antares Sirius
Rigel Deneb
Procyon Capella
Vega Betelgeuse
Canopus Aldebaran
Altair Regulus
Sagittarius Arcturus
Pollux Spica

View File

@@ -0,0 +1,3 @@
That does it, Captain!! You are hereby relieved of command
and sentenced to 99 stardates at hard labor on Cygnus 12!!

View File

@@ -0,0 +1,2 @@
Technicians standing by to effect repairs to your ship;
Estimated time to repair: {0} stardates.

View File

@@ -0,0 +1 @@
Will you authorize the repair order (Y/N)

View File

@@ -1,3 +1,5 @@
The Federation is in need of a new starship commander
for a similar mission -- if there is a volunteer
let him step forward and enter 'Aye'

View File

@@ -0,0 +1,3 @@
** FATAL ERROR ** You've just stranded your ship in space
You have insufficient maneuvering energy, and shield control
is presently incapable of cross-circuiting to engine room!!

View File

@@ -7,14 +7,29 @@ namespace SuperStarTrek.Resources
internal static class Strings
{
public static string CombatArea => GetResource();
public static string ComputerFunctions => GetResource();
public static string Congratulations => GetResource();
public static string CourtMartial => GetResource();
public static string Destroyed => GetResource();
public static string EndOfMission => GetResource();
public static string Enterprise => GetResource();
public static string Instructions => GetResource();
public static string LowShields => GetResource();
public static string NoEnemyShips => GetResource();
public static string NoStarbase => GetResource();
public static string NowEntering => GetResource();
public static string Orders => GetResource();
public static string PermissionDenied => GetResource();
public static string Protected => GetResource();
public static string RegionNames => GetResource();
public static string RelievedOfCommand => GetResource();
public static string RepairEstimate => GetResource();
public static string RepairPrompt => GetResource();
public static string ReplayPrompt => GetResource();
public static string ShieldsDropped => GetResource();
public static string ShortRangeSensorsOut => GetResource();
public static string StartText => GetResource();
public static string Stranded => GetResource();
public static string Title => GetResource();
private static string GetResource([CallerMemberName] string name = "")

View File

@@ -1,27 +0,0 @@
using System;
namespace SuperStarTrek.Space
{
// Represents the corrdintate of a quadrant in the galaxy, or a sector in a quadrant.
// Note that the origin is top-left, x increase downwards, and y increases to the right.
internal record Coordinates
{
public Coordinates(int x, int y)
{
X = Validated(x, nameof(x));
Y = Validated(y, nameof(y));
}
public int X { get; }
public int Y { get; }
private int Validated(int value, string argumentName)
{
if (value >= 1 && value <= 8) { return value; }
throw new ArgumentOutOfRangeException(argumentName, value, "Must be 1 to 8 inclusive");
}
public override string ToString() => $"{X} , {Y}";
}
}

View File

@@ -0,0 +1,67 @@
using System;
using SuperStarTrek.Utils;
namespace SuperStarTrek.Space
{
// Represents the corrdintate of a quadrant in the galaxy, or a sector in a quadrant.
// Note that the origin is top-left, x increase downwards, and y increases to the right.
internal record Coordinates
{
public Coordinates(int x, int y)
{
X = Validated(x, nameof(x));
Y = Validated(y, nameof(y));
RegionIndex = (X << 1) + (Y >> 2);
SubRegionIndex = Y % 4;
}
public int X { get; }
public int Y { get; }
public int RegionIndex { get; }
public int SubRegionIndex { get; }
private int Validated(int value, string argumentName)
{
if (value >= 0 && value <= 7) { return value; }
throw new ArgumentOutOfRangeException(argumentName, value, "Must be 0 to 7 inclusive");
}
private static bool IsValid(int value) => value >= 0 && value <= 7;
public override string ToString() => $"{X+1} , {Y+1}";
internal void Deconstruct(out int x, out int y)
{
x = X;
y = Y;
}
internal static bool TryCreate(float x, float y, out Coordinates coordinates)
{
var roundedX = Round(x);
var roundedY = Round(y);
if (IsValid(roundedX) && IsValid(roundedY))
{
coordinates = new Coordinates(roundedX, roundedY);
return true;
}
coordinates = default;
return false;
static int Round(float value) => (int)Math.Round(value, MidpointRounding.AwayFromZero);
}
internal (float Direction, float Distance) GetDirectionAndDistanceTo(Coordinates destination) =>
DirectionAndDistance.From(this).To(destination);
internal float GetDistanceTo(Coordinates destination)
{
var (_, distance) = GetDirectionAndDistanceTo(destination);
return distance;
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
namespace SuperStarTrek.Space
{
@@ -24,7 +25,7 @@ namespace SuperStarTrek.Space
(0, 1)
};
public Course(double direction)
internal Course(float direction)
{
if (direction < 1 || direction > 9)
{
@@ -44,7 +45,53 @@ namespace SuperStarTrek.Space
DeltaY = baseCardinal.DeltaY + (nextCardinal.DeltaY - baseCardinal.DeltaY) * fractionalDirection;
}
public double DeltaX { get; }
public double DeltaY { get; }
internal float DeltaX { get; }
internal float DeltaY { get; }
internal IEnumerable<Coordinates> GetSectorsFrom(Coordinates start)
{
(float x, float y) = start;
while(true)
{
x += DeltaX;
y += DeltaY;
if (!Coordinates.TryCreate(x, y, out var coordinates))
{
yield break;
}
yield return coordinates;
}
}
internal (bool, Coordinates, Coordinates) GetDestination(Coordinates quadrant, Coordinates sector, int distance)
{
var (xComplete, quadrantX, sectorX) = GetNewCoordinate(quadrant.X, sector.X, DeltaX * distance);
var (yComplete, quadrantY, sectorY) = GetNewCoordinate(quadrant.Y, sector.Y, DeltaY * distance);
return (xComplete && yComplete, new Coordinates(quadrantX, quadrantY), new Coordinates(sectorX, sectorY));
}
private (bool, int, int) GetNewCoordinate(int quadrant, int sector, float sectorsTravelled)
{
var galacticCoordinate = quadrant * 8 + sector + sectorsTravelled;
var newQuadrant = (int)(galacticCoordinate / 8);
var newSector = (int)(galacticCoordinate - newQuadrant * 8);
if (newSector == -1)
{
newQuadrant -= 1;
newSector = 7;
}
return newQuadrant switch
{
< 0 => (false, 0, 0),
> 7 => (false, 7, 7),
_ => (true, newQuadrant, newSector)
};
}
}
}

View File

@@ -1,17 +1,37 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using SuperStarTrek.Objects;
using SuperStarTrek.Resources;
using static System.StringSplitOptions;
namespace SuperStarTrek.Space
{
internal class Galaxy
{
private static readonly string[] _regionNames;
private static readonly string[] _subRegionIdentifiers;
private readonly QuadrantInfo[][] _quadrants;
private readonly Random _random;
public Galaxy()
static Galaxy()
{
var random = new Random();
_regionNames = Strings.RegionNames.Split(new[] { ' ', '\n' }, RemoveEmptyEntries | TrimEntries);
_subRegionIdentifiers = new[] { "I", "II", "III", "IV" };
}
_quadrants = Enumerable.Range(1, 8).Select(x =>
Enumerable.Range(1, 8).Select(y => QuadrantInfo.Create(new Coordinates(x, y), "")).ToArray())
public Galaxy(Random random)
{
_random = random;
_quadrants = Enumerable
.Range(0, 8)
.Select(x => Enumerable
.Range(0, 8)
.Select(y => new Coordinates(x, y))
.Select(c => QuadrantInfo.Create(c, GetQuadrantName(c)))
.ToArray())
.ToArray();
if (StarbaseCount == 0)
@@ -26,9 +46,22 @@ namespace SuperStarTrek.Space
}
}
public QuadrantInfo this[Coordinates coordinate] => _quadrants[coordinate.X - 1][coordinate.Y - 1];
public QuadrantInfo this[Coordinates coordinate] => _quadrants[coordinate.X][coordinate.Y];
public int KlingonCount => _quadrants.SelectMany(q => q).Sum(q => q.KlingonCount);
public int StarbaseCount => _quadrants.SelectMany(q => q).Count(q => q.HasStarbase);
public IEnumerable<IEnumerable<QuadrantInfo>> Quadrants => _quadrants;
private static string GetQuadrantName(Coordinates coordinates) =>
$"{_regionNames[coordinates.RegionIndex]} {_subRegionIdentifiers[coordinates.SubRegionIndex]}";
public IEnumerable<IEnumerable<QuadrantInfo>> GetNeighborhood(Quadrant quadrant) =>
Enumerable.Range(-1, 3)
.Select(dx => dx + quadrant.Coordinates.X)
.Select(x => GetNeighborhoodRow(quadrant, x));
private IEnumerable<QuadrantInfo> GetNeighborhoodRow(Quadrant quadrant, int x) =>
Enumerable.Range(-1, 3)
.Select(dy => dy + quadrant.Coordinates.Y)
.Select(y => y < 0 || y > 7 || x < 0 || x > 7 ? null : _quadrants[x][y]);
}
}

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SuperStarTrek.Commands;
using SuperStarTrek.Objects;
using SuperStarTrek.Resources;
namespace SuperStarTrek.Space
{
@@ -10,42 +12,56 @@ namespace SuperStarTrek.Space
private readonly QuadrantInfo _info;
private readonly Random _random;
private readonly Dictionary<Coordinates, object> _sectors;
private readonly Coordinates _enterpriseSector;
private readonly Coordinates _starbaseSector;
private readonly Enterprise _enterprise;
private readonly Output _output;
private bool _displayed = false;
public Quadrant(QuadrantInfo info, Enterprise enterprise)
public Quadrant(
QuadrantInfo info,
Enterprise enterprise,
Random random,
Galaxy galaxy,
Input input,
Output output)
{
_info = info;
_random = new Random();
_random = random;
_output = output;
Galaxy = galaxy;
_enterpriseSector = enterprise.Sector;
_sectors = new Dictionary<Coordinates, object> { [enterprise.Sector] = enterprise };
PositionObject(() => new Klingon(), _info.KlingonCount);
info.MarkAsKnown();
_sectors = new() { [enterprise.SectorCoordinates] = _enterprise = enterprise };
PositionObject(sector => new Klingon(sector, _random), _info.KlingonCount);
if (_info.HasStarbase)
{
_starbaseSector = PositionObject(() => new Starbase());
Starbase = PositionObject(sector => new Starbase(sector, _random, input, output));
}
PositionObject(() => new Star(), _info.StarCount);
PositionObject(_ => new Star(), _info.StarCount);
}
public Coordinates Coordinates => _info.Coordinates;
public bool HasKlingons => _info.KlingonCount > 0;
public int KlingonCount => _info.KlingonCount;
public bool HasStarbase => _info.HasStarbase;
public Starbase Starbase { get; }
internal Galaxy Galaxy { get; }
public bool EnterpriseIsNextToStarbase =>
_info.HasStarbase &&
Math.Abs(_enterpriseSector.X - _starbaseSector.X) <= 1 &&
Math.Abs(_enterpriseSector.Y - _starbaseSector.Y) <= 1;
Math.Abs(_enterprise.SectorCoordinates.X - Starbase.Sector.X) <= 1 &&
Math.Abs(_enterprise.SectorCoordinates.Y - Starbase.Sector.Y) <= 1;
internal IEnumerable<Klingon> Klingons => _sectors.Values.OfType<Klingon>();
public override string ToString() => _info.Name;
private Coordinates PositionObject(Func<object> objectFactory)
private T PositionObject<T>(Func<Coordinates, T> objectFactory)
{
var sector = GetRandomEmptySector();
_sectors[sector] = objectFactory.Invoke();
return sector;
_sectors[sector] = objectFactory.Invoke(sector);
return (T)_sectors[sector];
}
private void PositionObject(Func<object> objectFactory, int count)
private void PositionObject(Func<Coordinates, object> objectFactory, int count)
{
for (int i = 0; i < count; i++)
{
@@ -53,6 +69,91 @@ namespace SuperStarTrek.Space
}
}
internal void Display(string textFormat)
{
if (_displayed) { return; }
_output.Write(textFormat, this);
if (_info.KlingonCount > 0)
{
_output.Write(Strings.CombatArea);
if (_enterprise.ShieldControl.ShieldEnergy <= 200) { _output.Write(Strings.LowShields); }
}
_enterprise.Execute(Command.SRS);
_displayed = true;
}
internal bool HasObjectAt(Coordinates coordinates) => _sectors.ContainsKey(coordinates);
internal bool TorpedoCollisionAt(Coordinates coordinates, out string message, out bool gameOver)
{
gameOver = false;
message = default;
switch (_sectors.GetValueOrDefault(coordinates))
{
case Klingon klingon:
message = Remove(klingon);
gameOver = Galaxy.KlingonCount == 0;
return true;
case Star _:
message = $"Star at {coordinates} absorbed torpedo energy.";
return true;
case Starbase _:
_sectors.Remove(coordinates);
_info.RemoveStarbase();
message = "*** Starbase destroyed ***" +
(Galaxy.StarbaseCount > 0 ? Strings.CourtMartial : Strings.RelievedOfCommand);
gameOver = Galaxy.StarbaseCount == 0;
return true;
default:
return false;
}
}
internal string Remove(Klingon klingon)
{
_sectors.Remove(klingon.Sector);
_info.RemoveKlingon();
return "*** Klingon destroyed ***";
}
internal CommandResult KlingonsMoveAndFire()
{
foreach (var klingon in Klingons.ToList())
{
var newSector = GetRandomEmptySector();
_sectors.Remove(klingon.Sector);
_sectors[newSector] = klingon;
klingon.MoveTo(newSector);
}
return KlingonsFireOnEnterprise();
}
internal CommandResult KlingonsFireOnEnterprise()
{
if (EnterpriseIsNextToStarbase && Klingons.Any())
{
Starbase.ProtectEnterprise();
return CommandResult.Ok;
}
foreach (var klingon in Klingons)
{
var result = klingon.FireOn(_enterprise);
if (result.IsGameOver) { return result; }
}
return CommandResult.Ok;
}
private Coordinates GetRandomEmptySector()
{
while (true)
@@ -65,15 +166,21 @@ namespace SuperStarTrek.Space
}
}
public IEnumerable<string> GetDisplayLines() => Enumerable.Range(1, 8).Select(x => GetDisplayLine(x));
public IEnumerable<string> GetDisplayLines() => Enumerable.Range(0, 8).Select(x => GetDisplayLine(x));
private string GetDisplayLine(int x)
=> string.Join(
" ",
Enumerable
.Range(1, 8)
.Range(0, 8)
.Select(y => new Coordinates(x, y))
.Select(c => _sectors.GetValueOrDefault(c))
.Select(o => o?.ToString() ?? " "));
internal void SetEnterpriseSector(Coordinates sector)
{
_sectors.Remove(_enterprise.SectorCoordinates);
_sectors[sector] = _enterprise;
}
}
}

View File

@@ -1,7 +1,11 @@
using SuperStarTrek.Objects;
namespace SuperStarTrek.Space
{
internal class QuadrantInfo
{
private bool _isKnown;
private QuadrantInfo(Coordinates coordinates, string name, int klingonCount, int starCount, bool hasStarbase)
{
Coordinates = coordinates;
@@ -20,14 +24,14 @@ namespace SuperStarTrek.Space
public static QuadrantInfo Create(Coordinates coordinates, string name)
{
var random = new Random();
var klingonCount = random.GetDouble() switch
var klingonCount = random.GetFloat() switch
{
> 0.98 => 3,
> 0.95 => 2,
> 0.80 => 1,
> 0.98f => 3,
> 0.95f => 2,
> 0.80f => 1,
_ => 0
};
var hasStarbase = random.GetDouble() > 0.96;
var hasStarbase = random.GetFloat() > 0.96f;
var starCount = random.Get1To8Inclusive();
return new QuadrantInfo(coordinates, name, klingonCount, starCount, hasStarbase);
@@ -36,5 +40,25 @@ namespace SuperStarTrek.Space
internal void AddKlingon() => KlingonCount += 1;
internal void AddStarbase() => HasStarbase = true;
internal void MarkAsKnown() => _isKnown = true;
internal string Scan()
{
_isKnown = true;
return ToString();
}
public override string ToString() => _isKnown ? $"{KlingonCount}{(HasStarbase ? 1 : 0)}{StarCount}" : "***";
internal void RemoveKlingon()
{
if (KlingonCount > 0)
{
KlingonCount -= 1;
}
}
internal void RemoveStarbase() => HasStarbase = false;
}
}

View File

@@ -0,0 +1,7 @@
namespace SuperStarTrek
{
internal static class StringExtensions
{
internal static string Pluralize(this string singular, int quantity) => singular + (quantity > 1 ? "s" : "");
}
}

View File

@@ -0,0 +1,18 @@
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems.ComputerFunctions
{
internal abstract class ComputerFunction
{
protected ComputerFunction(string description, Output output)
{
Description = description;
Output = output;
}
internal string Description { get; }
protected Output Output { get; }
internal abstract void Execute(Quadrant quadrant);
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems.ComputerFunctions
{
internal class CumulativeGalacticRecord : GalacticReport
{
internal CumulativeGalacticRecord(Output output, Galaxy galaxy)
: base("Cumulative galactic record", output, galaxy)
{
}
protected override void WriteHeader(Quadrant quadrant) =>
Output.NextLine().WriteLine($"Computer record of galaxy for quadrant {quadrant.Coordinates}").NextLine();
protected override IEnumerable<string> GetRowData() =>
Galaxy.Quadrants.Select(row => " " + string.Join(" ", row));
}
}

View File

@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SuperStarTrek.Objects;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems.ComputerFunctions
{
internal class DirectionDistanceCalculator : NavigationCalculator
{
private readonly Enterprise _enterprise;
private readonly Input _input;
public DirectionDistanceCalculator(Enterprise enterprise, Output output, Input input)
: base("Starbase nav data", output)
{
_enterprise = enterprise;
_input = input;
}
internal override void Execute(Quadrant quadrant)
{
Output.WriteLine("Direction/distance calculator:")
.Write($"You are at quadrant {_enterprise.QuadrantCoordinates}")
.WriteLine($" sector {_enterprise.SectorCoordinates}")
.WriteLine("Please enter");
WriteDirectionAndDistance(
_input.GetCoordinates(" Initial coordinates"),
_input.GetCoordinates(" Final coordinates"));
}
}
}

View File

@@ -0,0 +1,34 @@
using System.Collections.Generic;
using System.Linq;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems.ComputerFunctions
{
internal abstract class GalacticReport : ComputerFunction
{
public GalacticReport(string description, Output output, Galaxy galaxy)
: base(description, output)
{
Galaxy = galaxy;
}
protected Galaxy Galaxy { get; }
protected abstract void WriteHeader(Quadrant quadrant);
protected abstract IEnumerable<string> GetRowData();
internal sealed override void Execute(Quadrant quadrant)
{
WriteHeader(quadrant);
Output.WriteLine(" 1 2 3 4 5 6 7 8")
.WriteLine(" ----- ----- ----- ----- ----- ----- ----- -----");
foreach (var (row, index) in GetRowData().Select((r, i) => (r, i)))
{
Output.WriteLine($" {index+1} {row}")
.WriteLine(" ----- ----- ----- ----- ----- ----- ----- -----");
}
}
}
}

View File

@@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Linq;
using SuperStarTrek.Resources;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems.ComputerFunctions
{
internal class GalaxyRegionMap : GalacticReport
{
internal GalaxyRegionMap(Output output, Galaxy galaxy)
: base("Galaxy 'region name' map", output, galaxy)
{
}
protected override void WriteHeader(Quadrant quadrant) =>
Output.WriteLine(" The Galaxy");
protected override IEnumerable<string> GetRowData() =>
Strings.RegionNames.Split('\n').Select(n => n.TrimEnd('\r'));
}
}

View File

@@ -0,0 +1,29 @@
using SuperStarTrek.Space;
using SuperStarTrek.Utils;
namespace SuperStarTrek.Systems.ComputerFunctions
{
internal abstract class NavigationCalculator : ComputerFunction
{
protected NavigationCalculator(string description, Output output)
: base(description, output)
{
}
protected void WriteDirectionAndDistance(Coordinates from, Coordinates to)
{
var (direction, distance) = from.GetDirectionAndDistanceTo(to);
Write(direction, distance);
}
protected void WriteDirectionAndDistance((float X, float Y) from, (float X, float Y) to)
{
var (direction, distance) = DirectionAndDistance.From(from.X, from.Y).To(to.X, to.Y);
Write(direction, distance);
}
private void Write(float direction, float distance) =>
Output.WriteLine($"Direction = {direction}")
.WriteLine($"Distance = {distance}");
}
}

View File

@@ -0,0 +1,30 @@
using SuperStarTrek.Objects;
using SuperStarTrek.Resources;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems.ComputerFunctions
{
internal class StarbaseDataCalculator : NavigationCalculator
{
private readonly Enterprise _enterprise;
public StarbaseDataCalculator(Enterprise enterprise, Output output)
: base("Starbase nav data", output)
{
_enterprise = enterprise;
}
internal override void Execute(Quadrant quadrant)
{
if (!quadrant.HasStarbase)
{
Output.WriteLine(Strings.NoStarbase);
return;
}
Output.WriteLine("From Enterprise to Starbase:");
WriteDirectionAndDistance(_enterprise.SectorCoordinates, quadrant.Starbase.Sector);
}
}
}

View File

@@ -0,0 +1,41 @@
using SuperStarTrek.Commands;
using SuperStarTrek.Objects;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems.ComputerFunctions
{
internal class StatusReport : ComputerFunction
{
private readonly Game _game;
private readonly Galaxy _galaxy;
private readonly Enterprise _enterprise;
public StatusReport(Game game, Galaxy galaxy, Enterprise enterprise, Output output)
: base("Status report", output)
{
_game = game;
_galaxy = galaxy;
_enterprise = enterprise;
}
internal override void Execute(Quadrant quadrant)
{
Output.WriteLine(" Status report:")
.Write("Klingon".Pluralize(_galaxy.KlingonCount)).WriteLine($" left: {_galaxy.KlingonCount}")
.WriteLine($"Mission must be completed in {_game.StardatesRemaining:0.#} stardates.");
if (_galaxy.StarbaseCount > 0)
{
Output.Write($"The Federation is maintaining {_galaxy.StarbaseCount} ")
.Write("starbase".Pluralize(_galaxy.StarbaseCount)).WriteLine(" in the galaxy.");
}
else
{
Output.WriteLine("Your stupidity has left you on your own in")
.WriteLine(" the galaxy -- you have no starbases left!");
}
_enterprise.Execute(Command.DAM);
}
}
}

View File

@@ -0,0 +1,33 @@
using SuperStarTrek.Objects;
using SuperStarTrek.Resources;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems.ComputerFunctions
{
internal class TorpedoDataCalculator : NavigationCalculator
{
private readonly Enterprise _enterprise;
public TorpedoDataCalculator(Enterprise enterprise, Output output)
: base("Photon torpedo data", output)
{
_enterprise = enterprise;
}
internal override void Execute(Quadrant quadrant)
{
if (!quadrant.HasKlingons)
{
Output.WriteLine(Strings.NoEnemyShips);
return;
}
Output.WriteLine("From Enterprise to Klingon battle cruiser".Pluralize(quadrant.KlingonCount));
foreach (var klingon in quadrant.Klingons)
{
WriteDirectionAndDistance(_enterprise.SectorCoordinates, klingon.Sector);
}
}
}
}

View File

@@ -0,0 +1,54 @@
using SuperStarTrek.Commands;
using SuperStarTrek.Objects;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems
{
internal class DamageControl : Subsystem
{
private readonly Enterprise _enterprise;
private readonly Output _output;
public DamageControl(Enterprise enterprise, Output output)
: base("Damage Control", Command.DAM, output)
{
_enterprise = enterprise;
_output = output;
}
protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
{
if (IsDamaged)
{
_output.WriteLine("Damage Control report not available");
}
else
{
_output.NextLine();
WriteDamageReport();
}
if (_enterprise.DamagedSystemCount > 0 && _enterprise.IsDocked)
{
if (quadrant.Starbase.TryRepair(_enterprise, out var repairTime))
{
WriteDamageReport();
return CommandResult.Elapsed(repairTime);
}
}
return CommandResult.Ok;
}
public void WriteDamageReport()
{
_output.NextLine().WriteLine("Device State of Repair");
foreach (var system in _enterprise.Systems)
{
_output.Write(system.Name.PadRight(25))
.WriteLine(((int)(system.Condition * 100) * 0.01).ToString(" 0.##;-0.##"));
}
_output.NextLine();
}
}
}

View File

@@ -0,0 +1,47 @@
using SuperStarTrek.Commands;
using SuperStarTrek.Space;
using SuperStarTrek.Systems.ComputerFunctions;
namespace SuperStarTrek.Systems
{
internal class LibraryComputer : Subsystem
{
private readonly Output _output;
private readonly Input _input;
private readonly ComputerFunction[] _functions;
public LibraryComputer(Output output, Input input, params ComputerFunction[] functions)
: base("Library-Computer", Command.COM, output)
{
_output = output;
_input = input;
_functions = functions;
}
protected override bool CanExecuteCommand() => IsOperational("Computer disabled");
protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
{
var index = GetFunctionIndex();
_output.NextLine();
_functions[index].Execute(quadrant);
return CommandResult.Ok;
}
private int GetFunctionIndex()
{
while (true)
{
var index = (int)_input.GetNumber("Computer active and waiting command");
if (index >= 0 && index <= 5) { return index; }
for (int i = 0; i < _functions.Length; i++)
{
_output.WriteLine($" {i} = {_functions[i].Description}");
}
}
}
}
}

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SuperStarTrek.Commands;
using SuperStarTrek.Objects;
using SuperStarTrek.Resources;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems
{
internal class LongRangeSensors : Subsystem
{
private readonly Galaxy _galaxy;
private readonly Output _output;
public LongRangeSensors(Galaxy galaxy, Output output)
: base("Long Range Sensors", Command.LRS, output)
{
_galaxy = galaxy;
_output = output;
}
protected override bool CanExecuteCommand() => IsOperational("{name} are inoperable");
protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
{
_output.WriteLine($"Long range scan for quadrant {quadrant.Coordinates}");
_output.WriteLine("-------------------");
foreach (var quadrants in _galaxy.GetNeighborhood(quadrant))
{
_output.WriteLine(": " + string.Join(" : ", quadrants.Select(q => q?.Scan() ?? "***")) + " :");
_output.WriteLine("-------------------");
}
return CommandResult.Ok;
}
}
}

View File

@@ -0,0 +1,97 @@
using System.Linq;
using SuperStarTrek.Commands;
using SuperStarTrek.Objects;
using SuperStarTrek.Resources;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems
{
internal class PhaserControl : Subsystem
{
private readonly Enterprise _enterprise;
private readonly Output _output;
private readonly Input _input;
private readonly Random _random;
public PhaserControl(Enterprise enterprise, Output output, Input input, Random random)
: base("Phaser Control", Command.PHA, output)
{
_enterprise = enterprise;
_output = output;
_input = input;
_random = random;
}
protected override bool CanExecuteCommand() => IsOperational("Phasers inoperative");
protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
{
if (!quadrant.HasKlingons)
{
_output.WriteLine(Strings.NoEnemyShips);
return CommandResult.Ok;
}
if (_enterprise.Computer.IsDamaged)
{
_output.WriteLine("Computer failure hampers accuracy");
}
_output.Write($"Phasers locked on target; ");
var phaserStrength = GetPhaserStrength();
if (phaserStrength < 0) { return CommandResult.Ok; }
_enterprise.UseEnergy(phaserStrength);
var perEnemyStrength = GetPerTargetPhaserStrength(phaserStrength, quadrant.KlingonCount);
foreach (var klingon in quadrant.Klingons.ToList())
{
ResolveHitOn(klingon, perEnemyStrength, quadrant);
}
return quadrant.KlingonsFireOnEnterprise();
}
private float GetPhaserStrength()
{
while (true)
{
_output.WriteLine($"Energy available = {_enterprise.Energy} units");
var phaserStrength = _input.GetNumber("Number of units to fire");
if (phaserStrength <= _enterprise.Energy) { return phaserStrength; }
}
}
private float GetPerTargetPhaserStrength(float phaserStrength, int targetCount)
{
if (_enterprise.Computer.IsDamaged)
{
phaserStrength *= _random.GetFloat();
}
return phaserStrength / targetCount;
}
private void ResolveHitOn(Klingon klingon, float perEnemyStrength, Quadrant quadrant)
{
var distance = _enterprise.SectorCoordinates.GetDistanceTo(klingon.Sector);
var hitStrength = (int)(perEnemyStrength / distance * (2 + _random.GetFloat()));
if (klingon.TakeHit(hitStrength))
{
_output.WriteLine($"{hitStrength} unit hit on Klingon at sector {klingon.Sector}");
_output.WriteLine(
klingon.Energy <= 0
? quadrant.Remove(klingon)
: $" (sensors show {klingon.Energy} units remaining)");
}
else
{
_output.WriteLine($"Sensors show no damage to enemy at {klingon.Sector}");
}
}
}
}

View File

@@ -0,0 +1,66 @@
using SuperStarTrek.Commands;
using SuperStarTrek.Objects;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems
{
internal class PhotonTubes : Subsystem
{
private readonly int _tubeCount;
private readonly Enterprise _enterprise;
private readonly Output _output;
private readonly Input _input;
public PhotonTubes(int tubeCount, Enterprise enterprise, Output output, Input input)
: base("Photon Tubes", Command.TOR, output)
{
TorpedoCount = _tubeCount = tubeCount;
_enterprise = enterprise;
_output = output;
_input = input;
}
public int TorpedoCount { get; private set; }
protected override bool CanExecuteCommand() => HasTorpedoes() && IsOperational("{name} are not operational");
private bool HasTorpedoes()
{
if (TorpedoCount > 0) { return true; }
_output.WriteLine("All photon torpedoes expended");
return false;
}
protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
{
if (!_input.TryGetCourse("Photon torpedo course", "Ensign Chekov", out var course))
{
return CommandResult.Ok;
}
TorpedoCount -= 1;
var isHit = false;
_output.WriteLine("Torpedo track:");
foreach (var sector in course.GetSectorsFrom(_enterprise.SectorCoordinates))
{
_output.WriteLine($" {sector}");
if (quadrant.TorpedoCollisionAt(sector, out var message, out var gameOver))
{
_output.WriteLine(message);
isHit = true;
if (gameOver) { return CommandResult.GameOver; }
break;
}
}
if (!isHit) { _output.WriteLine("Torpedo missed!"); }
return quadrant.KlingonsFireOnEnterprise();
}
internal void ReplenishTorpedoes() => TorpedoCount = _tubeCount;
}
}

View File

@@ -1,3 +1,4 @@
using SuperStarTrek.Commands;
using SuperStarTrek.Objects;
using SuperStarTrek.Space;
@@ -10,36 +11,35 @@ namespace SuperStarTrek.Systems
private readonly Input _input;
public ShieldControl(Enterprise enterprise, Output output, Input input)
: base("Shield Control", Command.SHE)
: base("Shield Control", Command.SHE, output)
{
_enterprise = enterprise;
_output = output;
_input = input;
}
public double Energy { get; private set; }
public float ShieldEnergy { get; set; }
public override void ExecuteCommand(Quadrant quadrant)
protected override bool CanExecuteCommand() => IsOperational("{name} inoperable");
protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
{
if (Condition < 0)
{
_output.WriteLine("Shield Control inoperable");
return;
}
_output.WriteLine($"Energy available = {_enterprise.TotalEnergy}");
var requested = _input.GetNumber($"Number of units to shields");
if (Validate(requested))
{
Energy = requested;
return;
ShieldEnergy = requested;
}
else
{
_output.WriteLine("<SHIELDS UNCHANGED>");
}
_output.WriteLine("<SHIELDS UNCHANGED>");
return CommandResult.Ok;
}
private bool Validate(double requested)
private bool Validate(float requested)
{
if (requested > _enterprise.TotalEnergy)
{
@@ -47,7 +47,11 @@ namespace SuperStarTrek.Systems
return false;
}
return requested >= 0 && requested != Energy;
return requested >= 0 && requested != ShieldEnergy;
}
internal void AbsorbHit(int hitStrength) => ShieldEnergy -= hitStrength;
internal void DropShields() => ShieldEnergy = 0;
}
}

View File

@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using SuperStarTrek.Commands;
using SuperStarTrek.Objects;
using SuperStarTrek.Resources;
using SuperStarTrek.Space;
@@ -16,7 +17,7 @@ namespace SuperStarTrek.Systems
private readonly Output _output;
public ShortRangeSensors(Enterprise enterprise, Galaxy galaxy, Game game, Output output)
: base("Short Range Sensors", Command.SRS)
: base("Short Range Sensors", Command.SRS, output)
{
_enterprise = enterprise;
_galaxy = galaxy;
@@ -24,7 +25,7 @@ namespace SuperStarTrek.Systems
_output = output;
}
public override void ExecuteCommand(Quadrant quadrant)
protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
{
if (_enterprise.IsDocked)
{
@@ -42,17 +43,19 @@ namespace SuperStarTrek.Systems
.ToList()
.ForEach(l => _output.WriteLine(l));
_output.WriteLine("---------------------------------");
return CommandResult.Ok;
}
public IEnumerable<string> GetStatusLines()
{
yield return $"Stardate {_game.Stardate}";
yield return $"Condition {_enterprise.Condition}";
yield return $"Quadrant {_enterprise.Quadrant}";
yield return $"Sector {_enterprise.Sector}";
yield return $"Photon torpedoes {_enterprise.TorpedoCount}";
yield return $"Total energy {Math.Ceiling(_enterprise.Energy)}";
yield return $"Shields {(int)_enterprise.Shields}";
yield return $"Quadrant {_enterprise.QuadrantCoordinates}";
yield return $"Sector {_enterprise.SectorCoordinates}";
yield return $"Photon torpedoes {_enterprise.PhotonTubes.TorpedoCount}";
yield return $"Total energy {Math.Ceiling(_enterprise.TotalEnergy)}";
yield return $"Shields {(int)_enterprise.ShieldControl.ShieldEnergy}";
yield return $"Klingons remaining {_galaxy.KlingonCount}";
}
}

View File

@@ -1,20 +1,66 @@
using System;
using SuperStarTrek.Commands;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems
{
internal abstract class Subsystem
{
protected Subsystem(string name, Command command)
private readonly Output _output;
protected Subsystem(string name, Command command, Output output)
{
Name = name;
Command = command;
Condition = 0;
_output = output;
}
public string Name { get; }
public double Condition { get; }
public float Condition { get; private set; }
public bool IsDamaged => Condition < 0;
public Command Command { get; }
public abstract void ExecuteCommand(Quadrant quadrant);
protected virtual bool CanExecuteCommand() => true;
protected bool IsOperational(string notOperationalMessage)
{
if (IsDamaged)
{
_output.WriteLine(notOperationalMessage.Replace("{name}", Name));
return false;
}
return true;
}
public CommandResult ExecuteCommand(Quadrant quadrant)
=> CanExecuteCommand() ? ExecuteCommandCore(quadrant) : CommandResult.Ok;
protected abstract CommandResult ExecuteCommandCore(Quadrant quadrant);
public virtual void Repair()
{
if (IsDamaged)
{
Condition = 0;
}
}
public virtual bool Repair(float repairWorkDone)
{
if (IsDamaged)
{
Condition += repairWorkDone;
if (Condition > -0.1f && Condition < 0)
{
Condition = -0.1f;
}
}
return !IsDamaged;
}
internal void TakeDamage(float damage) => Condition -= damage;
}
}

View File

@@ -0,0 +1,82 @@
using System;
using SuperStarTrek.Commands;
using SuperStarTrek.Objects;
using SuperStarTrek.Space;
namespace SuperStarTrek.Systems
{
internal class WarpEngines : Subsystem
{
private readonly Enterprise _enterprise;
private readonly Output _output;
private readonly Input _input;
public WarpEngines(Enterprise enterprise, Output output, Input input)
: base("Warp Engines", Command.NAV, output)
{
_enterprise = enterprise;
_output = output;
_input = input;
}
protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
{
if (_input.TryGetCourse("Course", " Lt. Sulu", out var course) &&
TryGetWarpFactor(out var warpFactor) &&
TryGetDistanceToMove(warpFactor, out var distanceToMove))
{
var result = quadrant.KlingonsMoveAndFire();
if (result.IsGameOver) { return result; }
_enterprise.RepairSystems(warpFactor);
_enterprise.VaryConditionOfRandomSystem();
var timeElapsed = _enterprise.Move(course, warpFactor, distanceToMove);
if (_enterprise.IsDocked)
{
_enterprise.ShieldControl.DropShields();
_enterprise.Refuel();
_enterprise.PhotonTubes.ReplenishTorpedoes();
}
return CommandResult.Elapsed(timeElapsed);
}
return CommandResult.Ok;
}
private bool TryGetWarpFactor(out float warpFactor)
{
var maximumWarp = IsDamaged ? 0.2f : 8;
if (_input.TryGetNumber("Warp Factor", 0, maximumWarp, out warpFactor))
{
return warpFactor > 0;
}
_output.WriteLine(
IsDamaged && warpFactor > maximumWarp
? "Warp engines are damaged. Maximum speed = warp 0.2"
: $" Chief Engineer Scott reports, 'The engines won't take warp {warpFactor} !'");
return false;
}
private bool TryGetDistanceToMove(float warpFactor, out int distanceToTravel)
{
distanceToTravel = (int)Math.Round(warpFactor * 8, MidpointRounding.AwayFromZero);
if (distanceToTravel <= _enterprise.Energy) { return true; }
_output.WriteLine("Engineering reports, 'Insufficient energy available")
.WriteLine($" for maneuvering at warp {warpFactor} !'");
if (distanceToTravel <= _enterprise.TotalEnergy && !_enterprise.ShieldControl.IsDamaged)
{
_output.Write($"Deflector control room acknowledges {_enterprise.ShieldControl.ShieldEnergy} ")
.WriteLine("units of energy")
.WriteLine(" presently deployed to shields.");
}
return false;
}
}
}

View File

@@ -0,0 +1,65 @@
using System;
using SuperStarTrek.Space;
namespace SuperStarTrek.Utils
{
internal class DirectionAndDistance
{
private readonly float _fromX;
private readonly float _fromY;
private DirectionAndDistance(float fromX, float fromY)
{
_fromX = fromX;
_fromY = fromY;
}
public static DirectionAndDistance From(Coordinates coordinates) => From(coordinates.X, coordinates.Y);
public static DirectionAndDistance From(float x, float y) => new DirectionAndDistance(x, y);
public (float Direction, float Distance) To(Coordinates coordinates) => To(coordinates.X, coordinates.Y);
public (float Direction, float Distance) To(float x, float y)
{
var deltaX = x - _fromX;
var deltaY = y - _fromY;
return (GetDirection(deltaX, deltaY), GetDistance(deltaX, deltaY));
}
// The algorithm here is mathematically equivalent to the following code in the original,
// where X is deltaY and A is deltaX
// 8220 X=X-A:A=C1-W1:IFX<0THEN8350
// 8250 IFA<0THEN8410
// 8260 IFX>0THEN8280
// 8270 IFA=0THENC1=5:GOTO8290
// 8280 C1=1
// 8290 IFABS(A)<=ABS(X)THEN8330
// 8310 PRINT"DIRECTION =";C1+(((ABS(A)-ABS(X))+ABS(A))/ABS(A)):GOTO8460
// 8330 PRINT"DIRECTION =";C1+(ABS(A)/ABS(X)):GOTO8460
// 8350 IFA>0THENC1=3:GOTO8420
// 8360 IFX<>0THENC1=5:GOTO8290
// 8410 C1=7
// 8420 IFABS(A)>=ABS(X)THEN8450
// 8430 PRINT"DIRECTION =";C1+(((ABS(X)-ABS(A))+ABS(X))/ABS(X)):GOTO8460
// 8450 PRINT"DIRECTION =";C1+(ABS(X)/ABS(A))
// 8460 PRINT"DISTANCE =";SQR(X^2+A^2):IFH8=1THEN1990
private float GetDirection(float deltaX, float deltaY)
{
var deltaXDominant = Math.Abs(deltaX) > Math.Abs(deltaY);
var fractionalPart = deltaXDominant ? deltaY / deltaX : -deltaX / deltaY;
var nearestCardinal = deltaXDominant switch
{
true => deltaX > 0 ? 7 : 3,
false => deltaY > 0 ? 1 : 5
};
var direction = nearestCardinal + fractionalPart;
return direction < 1 ? direction + 8 : direction;
}
private float GetDistance(float deltaX, float deltaY) =>
(float)Math.Sqrt(Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2));
}
}

View File

@@ -0,0 +1,97 @@
import java.lang.Math;
/**
* Game of 3-D Plot
* <p>
* Based on the BASIC game of 3-D Plot here
* https://github.com/coding-horror/basic-computer-games/blob/main/87%203-D%20Plot/3dplot.bas
* <p>
* Note: The idea was to create a version of the 1970's BASIC game in Java, without introducing
* new features - no additional text, error checking, etc has been added.
*
* Converted from BASIC to Java by Darren Cardenas.
*/
// Java class names cannot begin with a letter, so class name 3dplot cannot be used
public class Plot3D {
public void play() {
showIntro();
startGame();
} // End of method play
private void showIntro() {
System.out.println(" ".repeat(31) + "3D PLOT");
System.out.println(" ".repeat(14) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
System.out.println("\n\n\n");
} // End of method showIntro
private void startGame() {
float row = 0;
int column = 0;
int limit = 0;
int plotVal = 0;
int root = 0;
String lineContent = "";
// Begin loop through all rows
for (row = -30; row <= 30; row += 1.5) {
limit = 0;
root = 5 * (int) Math.floor((Math.sqrt(900 - row * row) / 5));
// Begin loop through all columns
for (column = root; column >= -root; column += -5) {
plotVal = 25 + (int) Math.floor(func(Math.sqrt(row * row + column * column)) - 0.7 * column);
if (plotVal > limit) {
limit = plotVal;
// Add whitespace
while (lineContent.length() < (plotVal-1)) {
lineContent += " ";
}
lineContent += "*";
}
} // End loop through all columns
System.out.println(lineContent);
lineContent = "";
} // End loop through all rows
} // End of method startGame
// Function to be plotted
public double func(double inputVal) {
return (30 * Math.exp(-inputVal * inputVal / 100));
}
public static void main(String[] args) {
Plot3D plot = new Plot3D();
plot.play();
} // End of method main
} // End of class Plot3D

View File

@@ -0,0 +1,280 @@
import java.util.Scanner;
/**
* WEEKDAY
*
* Converted from BASIC to Java by Aldrin Misquitta (@aldrinm)
*
*/
public class Weekday {
//TABLE OF VALUES FOR THE MONTHS TO BE USED IN CALCULATIONS.
//Dummy value added at index 0, so we can reference directly by the month number value
private final static int[] t = new int[]{-1, 0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
public static void main(String[] args) {
printIntro();
Scanner scanner = new Scanner(System.in);
System.out.print("ENTER TODAY'S DATE IN THE FORM: 3,24,1979 ");
DateStruct todaysDate = readDate(scanner);
System.out.print("ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST) ");
DateStruct dateOfInterest = readDate(scanner);
int I1 = (dateOfInterest.year - 1500) / 100;
//TEST FOR DATE BEFORE CURRENT CALENDAR.
if ((dateOfInterest.year - 1582) >= 0) {
int A = I1 * 5 + (I1 + 3) / 4;
int I2 = (A - b(A) * 7);
int Y2 = (dateOfInterest.year / 100);
int Y3 = (dateOfInterest.year - Y2 * 100);
A = Y3 / 4 + Y3 + dateOfInterest.day + t[dateOfInterest.month] + I2;
calculateAndPrintDayOfWeek(I1, A, todaysDate, dateOfInterest, Y3);
if ((todaysDate.year * 12 + todaysDate.month) * 31 + todaysDate.day
== (dateOfInterest.year * 12 + dateOfInterest.month) * 31 + dateOfInterest.day) {
return; //stop the program
}
int I5 = todaysDate.year - dateOfInterest.year;
System.out.print("\n");
int I6 = todaysDate.month - dateOfInterest.month;
int I7 = todaysDate.day - dateOfInterest.day;
if (I7 < 0) {
I6 = I6 - 1;
I7 = I7 + 30;
}
if (I6 < 0) {
I5 = I5 - 1;
I6 = I6 + 12;
}
if (I5 < 0) {
return; //do nothing. end the program
} else {
if (I7 != 0) {
printHeadersAndAge(I5, I6, I7);
} else {
if (I6 != 0) {
printHeadersAndAge(I5, I6, I7);
} else {
System.out.println("***HAPPY BIRTHDAY***");
printHeadersAndAge(I5, I6, I7);
}
}
}
int A8 = (I5 * 365) + (I6 * 30) + I7 + (I6 / 2);
int K5 = I5;
int K6 = I6;
int K7 = I7;
//CALCULATE RETIREMENT DATE.
int E = dateOfInterest.year + 65;
// CALCULATE TIME SPENT IN THE FOLLOWING FUNCTIONS.
float F = 0.35f;
System.out.printf("%-28s", "YOU HAVE SLEPT");
DateStruct scratchDate = new DateStruct(K6, K7, K5); //K5 is a temp year, K6 is month, K7 is day
printStatisticRow(F, A8, scratchDate);
K5 = scratchDate.year;
K6 = scratchDate.month;
K7 = scratchDate.day;
F = 0.17f;
System.out.printf("%-28s", "YOU HAVE EATEN");
scratchDate = new DateStruct(K6, K7, K5);
printStatisticRow(F, A8, scratchDate);
K5 = scratchDate.year;
K6 = scratchDate.month;
K7 = scratchDate.day;
F = 0.23f;
if (K5 > 3) {
if (K5 > 9) {
System.out.printf("%-28s", "YOU HAVE WORKED/PLAYED");
} else {
System.out.printf("%-28s", "YOU HAVE PLAYED/STUDIED");
}
} else {
System.out.printf("%-28s", "YOU HAVE PLAYED");
}
scratchDate = new DateStruct(K6, K7, K5);
printStatisticRow(F, A8, scratchDate);
K5 = scratchDate.year;
K6 = scratchDate.month;
K7 = scratchDate.day;
if (K6 == 12) {
K5 = K5 + 1;
K6 = 0;
}
System.out.printf("%-28s%14s%14s%14s%n", "YOU HAVE RELAXED", K5, K6, K7);
System.out.printf("%16s*** YOU MAY RETIRE IN %s ***%n", " ", E);
System.out.printf("%n%n%n%n%n");
} else {
System.out.println("NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII.");
}
}
private static void printStatisticRow(float F, int A8, DateStruct scratchDate) {
int K1 = (int) (F * A8);
int I5 = K1 / 365;
K1 = K1 - (I5 * 365);
int I6 = K1 / 30;
int I7 = K1 - (I6 * 30);
int K5 = scratchDate.year - I5;
int K6 = scratchDate.month - I6;
int K7 = scratchDate.day - I7;
if (K7 < 0) {
K7 = K7 + 30;
K6 = K6 - 1;
}
if (K6 <= 0) {
K6 = K6 + 12;
K5 = K5 - 1;
}
//to return the updated values of K5, K6, K7 we send them through the scratchDate
scratchDate.year = K5;
scratchDate.month = K6;
scratchDate.day = K7;
System.out.printf("%14s%14s%14s%n", I5, I6, I7);
}
private static void printHeadersAndAge(int I5, int I6, int I7) {
System.out.printf("%14s%14s%14s%14s%14s%n", " ", " ", "YEARS", "MONTHS", "DAYS");
System.out.printf("%14s%14s%14s%14s%14s%n", " ", " ", "-----", "------", "----");
System.out.printf("%-28s%14s%14s%14s%n", "YOUR AGE (IF BIRTHDATE)", I5, I6, I7);
}
private static void calculateAndPrintDayOfWeek(int i1, int a, DateStruct dateStruct, DateStruct dateOfInterest, int y3) {
int b = (a - b(a) * 7) + 1;
if (dateOfInterest.month > 2) {
printDayOfWeek(dateStruct, dateOfInterest, b);
} else {
if (y3 == 0) {
int aa = i1 - 1;
int t1 = aa - a(aa) * 4;
if (t1 == 0) {
if (b != 0) {
b = b - 1;
printDayOfWeek(dateStruct, dateOfInterest, b);
} else {
b = 6;
b = b - 1;
printDayOfWeek(dateStruct, dateOfInterest, b);
}
}
}
}
}
/**
* PRINT THE DAY OF THE WEEK THE DATE FALLS ON.
*/
private static void printDayOfWeek(DateStruct dateStruct, DateStruct dateOfInterest, int b) {
if (b == 0) {
b = 7;
}
if ((dateStruct.year * 12 + dateStruct.month) * 31
+ dateStruct.day
<
(dateOfInterest.year * 12
+ dateOfInterest.month) * 31 + dateOfInterest.day) {
System.out.printf("%s / %s / %s WILL BE A ", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year);
} else if ((dateStruct.year * 12 + dateStruct.month) * 31
+ dateStruct.day == (dateOfInterest.year * 12 + dateOfInterest.month)
* 31 + dateOfInterest.day) {
System.out.printf("%s / %s / %s IS A ", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year);
} else {
System.out.printf("%s / %s / %s WAS A ", dateOfInterest.month, dateOfInterest.day, dateOfInterest.year);
}
switch (b) {
case 1:
System.out.println("SUNDAY.");
break;
case 2:
System.out.println("MONDAY.");
break;
case 3:
System.out.println("TUESDAY.");
break;
case 4:
System.out.println("WEDNESDAY.");
break;
case 5:
System.out.println("THURSDAY.");
break;
case 6:
if (dateOfInterest.day == 13) {
System.out.println("FRIDAY THE THIRTEENTH---BEWARE!");
} else {
System.out.println("FRIDAY.");
}
break;
case 7:
System.out.println("SATURDAY.");
break;
}
}
private static int a(int a) {
return a / 4;
}
private static int b(int a) {
return a / 7;
}
private static void printIntro() {
System.out.println(" WEEKDAY");
System.out.println(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
System.out.println("\n\n\n");
System.out.println("WEEKDAY IS A COMPUTER DEMONSTRATION THAT");
System.out.println("GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.");
System.out.println("\n");
}
/**
* Read user input for a date, do some validation and return a simple date structure
*/
private static DateStruct readDate(Scanner scanner) {
boolean done = false;
int mm = 0, dd = 0, yyyy = 0;
while (!done) {
String input = scanner.next();
String[] tokens = input.split(",");
if (tokens.length < 3) {
System.out.println("DATE EXPECTED IN FORM: 3,24,1979 - RETRY INPUT LINE");
} else {
try {
mm = Integer.parseInt(tokens[0]);
dd = Integer.parseInt(tokens[1]);
yyyy = Integer.parseInt(tokens[2]);
done = true;
} catch (NumberFormatException nfe) {
System.out.println("NUMBER EXPECTED - RETRY INPUT LINE");
}
}
}
return new DateStruct(mm, dd, yyyy);
}
/**
* Convenience date structure to hold user date input
*/
private static class DateStruct {
int month;
int day;
int year;
public DateStruct(int month, int day, int year) {
this.month = month;
this.day = day;
this.year = year;
}
}
}