mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 07:10:42 -08:00
Merge branch 'coding-horror:main' into main
This commit is contained in:
50
00_Utilities/markdown_todo.py
Normal file
50
00_Utilities/markdown_todo.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import os
|
||||
|
||||
|
||||
lang_pos = {
|
||||
"csharp": 1, "java": 2, "javascript": 3,
|
||||
"pascal": 4, "perl": 5, "python": 6, "ruby": 7, "vbnet": 8
|
||||
}
|
||||
|
||||
write_string = "# TODO list \n game | csharp | java | javascript | pascal | perl | python | ruby | vbnet \n --- | --- | --- | --- | --- | --- | --- | --- | --- \n"
|
||||
# Set the directory you want to start from
|
||||
rootDir = '..'
|
||||
|
||||
strings_done = []
|
||||
|
||||
checklist = ["game", "csharp", "java", "javascript",
|
||||
"pascal", "perl", "python", "ruby", "vbnet"]
|
||||
|
||||
prev_game = ""
|
||||
|
||||
for dirName, subdirList, fileList in os.walk(rootDir):
|
||||
split_dir = dirName.split("/")
|
||||
|
||||
if len(split_dir) == 2 and not split_dir[1] in ['.git', '00_Utilities']:
|
||||
if prev_game == "":
|
||||
prev_game = split_dir[1]
|
||||
checklist[0] = split_dir[1]
|
||||
|
||||
if prev_game != split_dir[1]:
|
||||
# it's a new dir
|
||||
strings_done.append(checklist)
|
||||
checklist = [split_dir[1], "csharp", "java", "javascript",
|
||||
"pascal", "perl", "python", "ruby", "vbnet"]
|
||||
prev_game = split_dir[1]
|
||||
|
||||
elif len(split_dir) == 3 and split_dir[1] != '.git':
|
||||
if split_dir[2] in lang_pos.keys():
|
||||
if len(fileList) > 1 or len(subdirList) > 0:
|
||||
# there is more files than the readme
|
||||
checklist[lang_pos[split_dir[2]]] = "✅"
|
||||
else:
|
||||
checklist[lang_pos[split_dir[2]]] = "⬜️"
|
||||
|
||||
|
||||
sorted_strings = list(map(lambda l: " | ".join(l) + "\n",
|
||||
sorted(strings_done, key=lambda x: x[0])))
|
||||
write_string += ''.join(sorted_strings)
|
||||
|
||||
|
||||
with open("README.md", "w") as f:
|
||||
f.write(write_string)
|
||||
@@ -15,4 +15,5 @@ As published in Basic Computer Games (1978):
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
A Common Lisp port is [here](https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp).
|
||||
#### External Links
|
||||
- Common Lisp: https://github.com/koalahedron/lisp-computer-games/blob/master/01%20Acey%20Ducey/common-lisp/acey-deucy.lisp
|
||||
|
||||
2
01_Acey_Ducey/d/.gitignore
vendored
Normal file
2
01_Acey_Ducey/d/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.exe
|
||||
*.obj
|
||||
29
01_Acey_Ducey/d/README.md
Normal file
29
01_Acey_Ducey/d/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).
|
||||
|
||||
Two versions are supplied that are functionally equivalent, but differ in source layout:
|
||||
|
||||
<dl>
|
||||
<dt><tt>aceyducey_literal.d</tt></dt>
|
||||
<dd>A largely literal transcription of the original Basic source. All unnecessary uglyness is preserved.</dd>
|
||||
<dt><tt>aceyducey.d</tt></dt>
|
||||
<dd>An idiomatic D refactoring of the original, with a focus on increasing the readability and robustness.
|
||||
Memory-safety <A href="https://dlang.org/spec/memory-safe-d.html">is ensured by the language</a>, thanks to the
|
||||
<tt>@safe</tt> annotation.</dd>
|
||||
</dl>
|
||||
|
||||
## Running the code
|
||||
|
||||
Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:
|
||||
```shell
|
||||
dmd -run aceyducey.d
|
||||
```
|
||||
|
||||
[Other compilers](https://dlang.org/download.html) also exist.
|
||||
|
||||
Note that there are compiler switches related to memory-safety (`-preview=dip25` and `-preview=dip1000`) that are not
|
||||
used here because they are unnecessary in this case. What these do is to make the analysis more thorough, so that with
|
||||
them some code that needed to be `@system` can then be inferred to be in fact `@safe`. [Code that compiles without
|
||||
these switches is just as safe as when compiled with them]
|
||||
(https://forum.dlang.org/post/dftgjalswvwfjpyushgn@forum.dlang.org).
|
||||
131
01_Acey_Ducey/d/aceyducey.d
Normal file
131
01_Acey_Ducey/d/aceyducey.d
Normal file
@@ -0,0 +1,131 @@
|
||||
@safe: // Make @safe the default for this file, enforcing memory-safety.
|
||||
|
||||
void main()
|
||||
{
|
||||
import std.stdio : write, writeln;
|
||||
import std.string : center, toUpper, wrap;
|
||||
import std.exception : ifThrown;
|
||||
|
||||
enum width = 80;
|
||||
writeln(center("Acey Ducey Card Game", width));
|
||||
writeln(center("(After Creative Computing Morristown, New Jersey)\n", width));
|
||||
writeln(wrap("Acey-Ducey is played in the following manner: The dealer (computer) deals two cards face up. " ~
|
||||
"You have an option to bet or not bet depending on whether or not you feel the third card will " ~
|
||||
"have a value between the first two. If you do not want to bet, input a 0.", width));
|
||||
|
||||
enum Hand {low, middle, high}
|
||||
Card[Hand.max + 1] cards; // Three cards.
|
||||
bool play = true;
|
||||
|
||||
while (play)
|
||||
{
|
||||
int cash = 100;
|
||||
while (cash > 0)
|
||||
{
|
||||
writeln("\nYou now have ", cash, " dollars.");
|
||||
int bet = 0;
|
||||
while (bet <= 0)
|
||||
{
|
||||
do // Draw new cards, until the first card has a smaller value than the last card.
|
||||
{
|
||||
foreach (ref card; cards)
|
||||
card.drawNew;
|
||||
} while (cards[Hand.low] >= cards[Hand.high]);
|
||||
writeln("Here are your next two cards:\n", cards[Hand.low], "\n", cards[Hand.high]);
|
||||
|
||||
int askBet() // A nested function.
|
||||
{
|
||||
import std.conv : to;
|
||||
|
||||
write("\nWhat is your bet? ");
|
||||
int answer = readString.to!int.
|
||||
ifThrown!Exception(askBet); // Try again when answer does not convert to int.
|
||||
if (answer <= cash)
|
||||
return answer;
|
||||
writeln("Sorry, my friend, but you bet too much.\nYou have only ", cash, " dollars to bet.");
|
||||
return askBet; // Recurse: Ask again.
|
||||
}
|
||||
bet = askBet;
|
||||
if (bet <= 0) // Negative bets are interpreted as 0.
|
||||
writeln("CHICKEN!!");
|
||||
} // bet is now > 0.
|
||||
|
||||
writeln(cards[Hand.middle]);
|
||||
if (cards[Hand.low] < cards[Hand.middle] && cards[Hand.middle] < cards[Hand.high])
|
||||
{
|
||||
writeln("YOU WIN!!!");
|
||||
cash += bet;
|
||||
}
|
||||
else
|
||||
{
|
||||
writeln("Sorry, you lose.");
|
||||
cash -= bet;
|
||||
if (cash <= 0)
|
||||
{
|
||||
writeln("\n\nSorry, friend, but you blew your wad.");
|
||||
write("\n\nTry again (Yes or No)? ");
|
||||
play = readString.toUpper == "YES";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
writeln("O.K., hope you had fun!");
|
||||
}
|
||||
|
||||
struct Card
|
||||
{
|
||||
int value = 2;
|
||||
alias value this; // Enables Card to stand in as an int, so that cards can be compared as ints.
|
||||
|
||||
invariant
|
||||
{
|
||||
assert(2 <= value && value <= 14); // Ensure cards always have a valid value.
|
||||
}
|
||||
|
||||
/// Adopt a new value.
|
||||
void drawNew()
|
||||
{
|
||||
import std.random : uniform;
|
||||
|
||||
value = uniform!("[]", int, int)(2, 14); // A random int between inclusive bounds.
|
||||
}
|
||||
|
||||
/// Called for implicit conversion to string.
|
||||
string toString() const pure
|
||||
{
|
||||
import std.conv : text;
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case 11: return "Jack";
|
||||
case 12: return "Queen";
|
||||
case 13: return "King";
|
||||
case 14: return "Ace";
|
||||
default: return text(" ", value); // Basic prepends a space.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a string from standard input, stripping newline and other enclosing whitespace.
|
||||
string readString() nothrow
|
||||
{
|
||||
import std.string : strip;
|
||||
|
||||
try
|
||||
return trustedReadln.strip;
|
||||
catch (Exception) // readln throws on I/O and Unicode errors, which we handle here.
|
||||
return "";
|
||||
}
|
||||
|
||||
/** An @trusted wrapper around readln.
|
||||
*
|
||||
* This is the only function that formally requires manual review for memory-safety.
|
||||
* [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com)
|
||||
* which would remove the need to have any @trusted code in this program.
|
||||
*/
|
||||
string trustedReadln() @trusted
|
||||
{
|
||||
import std.stdio : readln;
|
||||
|
||||
return readln;
|
||||
}
|
||||
104
01_Acey_Ducey/d/aceyducey_literal.d
Normal file
104
01_Acey_Ducey/d/aceyducey_literal.d
Normal file
@@ -0,0 +1,104 @@
|
||||
void main()
|
||||
{
|
||||
import std;
|
||||
|
||||
L10: writef("%26s", ' '); writeln("ACEY DUCEY CARD GAME");
|
||||
L20: writef("%15s", ' '); writeln("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
L21: writeln;
|
||||
L22: writeln;
|
||||
L30: writeln("ACEY-DUCEY IS PLAYED IN THE FOLLOWING MANNER ");
|
||||
L40: writeln("THE DEALER (COMPUTER) DEALS TWO CARDS FACE UP");
|
||||
L50: writeln("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING");
|
||||
L60: writeln("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE");
|
||||
L70: writeln("A VALUE BETWEEN THE FIRST TWO.");
|
||||
L80: writeln("IF YOU DO NOT WANT TO BET, INPUT A 0");
|
||||
L100: int N=100;
|
||||
L110: int Q=100, M;
|
||||
L120: writeln("YOU NOW HAVE ",Q," DOLLARS.");
|
||||
L130: writeln;
|
||||
L140: goto L260;
|
||||
L210: Q=Q+M;
|
||||
L220: goto L120;
|
||||
L240: Q=Q-M;
|
||||
L250: goto L120;
|
||||
L260: writeln("HERE ARE YOUR NEXT TWO CARDS: ");
|
||||
L270: auto A=to!int(14*uniform01)+2;
|
||||
L280: if (A<2) goto L270;
|
||||
L290: if (A>14) goto L270;
|
||||
L300: auto B=to!int(14*uniform01)+2;
|
||||
L310: if (B<2) goto L300;
|
||||
L320: if (B>14) goto L300;
|
||||
L330: if (A>=B) goto L270;
|
||||
L350: if (A<11) goto L400;
|
||||
L360: if (A==11) goto L420;
|
||||
L370: if (A==12) goto L440;
|
||||
L380: if (A==13) goto L460;
|
||||
L390: if (A==14) goto L480;
|
||||
L400: writefln("%2d", A);
|
||||
L410: goto L500;
|
||||
L420: writeln("JACK");
|
||||
L430: goto L500;
|
||||
L440: writeln("QUEEN");
|
||||
L450: goto L500;
|
||||
L460: writeln("KING");
|
||||
L470: goto L500;
|
||||
L480: writeln("ACE");
|
||||
L500: if (B<11) goto L550;
|
||||
L510: if (B==11) goto L570;
|
||||
L520: if (B==12) goto L590;
|
||||
L530: if (B==13) goto L610;
|
||||
L540: if (B==14) goto L630;
|
||||
L550: writefln("%2d", B);
|
||||
L560: goto L650;
|
||||
L570: writeln("JACK");
|
||||
L580: goto L650;
|
||||
L590: writeln("QUEEN");
|
||||
L600: goto L650;
|
||||
L610: writeln("KING");
|
||||
L620: goto L650;
|
||||
L630: writeln("ACE");
|
||||
L640: writeln;
|
||||
L650: writeln;
|
||||
L660: write("WHAT IS YOUR BET? "); M = stdin.readln.strip.to!int;
|
||||
L670: if (M!=0) goto L680;
|
||||
L675: writeln("CHICKEN!!");
|
||||
L676: writeln;
|
||||
L677: goto L260;
|
||||
L680: if (M<=Q) goto L730;
|
||||
L690: writeln("SORRY, MY FRIEND, BUT YOU BET TOO MUCH.");
|
||||
L700: writeln("YOU HAVE ONLY ",Q," DOLLARS TO BET.");
|
||||
L710: goto L650;
|
||||
L730: auto C=to!int(14*uniform01)+2;
|
||||
L740: if (C<2) goto L730;
|
||||
L750: if (C>14) goto L730;
|
||||
L760: if (C<11) goto L810;
|
||||
L770: if (C==11) goto L830;
|
||||
L780: if (C==12) goto L850;
|
||||
L790: if (C==13) goto L870;
|
||||
L800: if (C==14) goto L890;
|
||||
L810: writeln(C);
|
||||
L820: goto L910;
|
||||
L830: writeln("JACK");
|
||||
L840: goto L910;
|
||||
L850: writeln("QUEEN");
|
||||
L860: goto L910;
|
||||
L870: writeln("KING");
|
||||
L880: goto L910;
|
||||
L890: writeln( "ACE");
|
||||
L900: writeln;
|
||||
L910: if (C>A) goto L930;
|
||||
L920: goto L970;
|
||||
L930: if (C>=B) goto L970;
|
||||
L950: writeln("YOU WIN!!!");
|
||||
L960: goto L210;
|
||||
L970: writeln("SORRY, YOU LOSE");
|
||||
L980: if (M<Q) goto L240;
|
||||
L990: writeln;
|
||||
L1000: writeln;
|
||||
L1010: writeln("SORRY, FRIEND, BUT YOU BLEW YOUR WAD.");
|
||||
L1015: writeln;writeln;
|
||||
L1020: write("TRY AGAIN (YES OR NO)? "); auto AS=stdin.readln;
|
||||
L1025: writeln;writeln;
|
||||
L1030: if (AS.strip.toUpper=="YES") goto L110;
|
||||
L1040: writeln("O.K., HOPE YOU HAD FUN!");
|
||||
}
|
||||
@@ -167,6 +167,6 @@ public class AceyDucey {
|
||||
System.out.println("YOU HAVE AN OPTION TO BET OR NOT BET DEPENDING");
|
||||
System.out.println("ON WHETHER OR NOT YOU FEEL THE CARD WILL HAVE");
|
||||
System.out.println("A VALUE BETWEEN THE FIRST TWO.");
|
||||
System.out.println("IF YOU DO NOT WANT TO BET, INPUT A 0");
|
||||
System.out.println("IF YOU DO NOT WANT TO BET, INPUT: 0");
|
||||
}
|
||||
}
|
||||
@@ -28,17 +28,15 @@ 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 @cards = ( 1 .. 13 ); # That is, Ace through King.
|
||||
my $keepPlaying = 1;
|
||||
|
||||
GAME:
|
||||
while ($keepPlaying)
|
||||
{
|
||||
my $playerBalance = 100; # The player starts with $100
|
||||
while ($keepPlaying) {
|
||||
my $playerBalance = 100; # The player starts with $100
|
||||
|
||||
HAND:
|
||||
while (1)
|
||||
{
|
||||
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.
|
||||
@@ -48,19 +46,17 @@ while ($keepPlaying)
|
||||
# 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 ];
|
||||
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)
|
||||
{
|
||||
if ( $bet == 0 ) {
|
||||
print "Chicken!\n\n";
|
||||
next HAND;
|
||||
}
|
||||
|
||||
if ($bet < 0)
|
||||
{
|
||||
if ( $bet < 0 ) {
|
||||
last GAME;
|
||||
}
|
||||
|
||||
@@ -72,19 +68,16 @@ while ($keepPlaying)
|
||||
|
||||
print "I drew ", nameOfCard($thirdCard), "!\n";
|
||||
|
||||
if (($firstCard < $thirdCard) && ($thirdCard < $secondCard))
|
||||
{
|
||||
if ( ( $firstCard < $thirdCard ) && ( $thirdCard < $secondCard ) ) {
|
||||
print "You win!\n\n";
|
||||
$playerBalance += $bet;
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
print "You lose!\n\n";
|
||||
$playerBalance -= $bet;
|
||||
}
|
||||
|
||||
if ($playerBalance <= 0)
|
||||
{
|
||||
if ( $playerBalance <= 0 ) {
|
||||
print "Sorry, buddy, you blew your wad!\n\n";
|
||||
last HAND;
|
||||
}
|
||||
@@ -96,49 +89,43 @@ while ($keepPlaying)
|
||||
print "Thanks for playing!\n";
|
||||
|
||||
###############
|
||||
sub getValidBet
|
||||
{
|
||||
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...
|
||||
)
|
||||
INPUT:
|
||||
{
|
||||
print "Sorry, numbers only!\n";
|
||||
$input = getValidBet($maxBet);
|
||||
}
|
||||
print "\nWhat's your bet? ";
|
||||
|
||||
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);
|
||||
}
|
||||
chomp( my $input = <STDIN> );
|
||||
|
||||
if ($input != int($input))
|
||||
{
|
||||
print "Sorry, you must bet in whole dollars. No change!\n";
|
||||
$input = getValidBet($maxBet);
|
||||
}
|
||||
# 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";
|
||||
redo INPUT;
|
||||
}
|
||||
|
||||
return $input;
|
||||
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";
|
||||
redo INPUT;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
sub nameOfCard {
|
||||
my $value = shift;
|
||||
|
||||
# Note that the Joker isn't used in this game, but since arrays in Perl are
|
||||
@@ -150,25 +137,21 @@ sub nameOfCard
|
||||
return $cardlist[$value];
|
||||
}
|
||||
|
||||
sub promptUserToKeepPlaying
|
||||
{
|
||||
print "Try again (Y/N)? ";
|
||||
my $input = <STDIN>;
|
||||
chomp $input;
|
||||
sub promptUserToKeepPlaying {
|
||||
YESNO:
|
||||
{
|
||||
print "Try again (Y/N)? ";
|
||||
|
||||
my $keepGoing;
|
||||
if (uc($input) eq 'Y')
|
||||
{
|
||||
$keepGoing = 1;
|
||||
}
|
||||
elsif (uc($input) eq 'N')
|
||||
{
|
||||
$keepGoing = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
$keepGoing = promptUserToKeepPlaying();
|
||||
}
|
||||
chomp( my $input = uc <STDIN> );
|
||||
|
||||
return $keepGoing;
|
||||
if ( $input eq 'Y' ) {
|
||||
return 1;
|
||||
}
|
||||
elsif ( $input eq 'N' ) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
redo YESNO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,3 +12,7 @@ As published in Basic Computer Games (1978):
|
||||
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
---
|
||||
|
||||
**2022-01-04:** patched original source in [#400](https://github.com/coding-horror/basic-computer-games/pull/400) to fix a minor bug where a generated maze may be missing an exit, particularly at small maze sizes.
|
||||
|
||||
@@ -117,10 +117,15 @@
|
||||
975 V(R,S)=3:Q=0:GOTO 1000
|
||||
980 V(R,S)=1:Q=0:R=1:S=1:GOTO 250
|
||||
1000 GOTO 210
|
||||
1010 FOR J=1 TO V
|
||||
1011 PRINT "I";
|
||||
1012 FOR I=1 TO H
|
||||
1013 IF V(I,J)<2 THEN 1030
|
||||
1010 IF Z=1 THEN 1015
|
||||
1011 X=INT(RND(1)*H+1)
|
||||
1012 IF V(X,V)=0 THEN 1014
|
||||
1013 V(X,V)=3: GOTO 1015
|
||||
1014 V(X,V)=1
|
||||
1015 FOR J=1 TO V
|
||||
1016 PRINT "I";
|
||||
1017 FOR I=1 TO H
|
||||
1018 IF V(I,J)<2 THEN 1030
|
||||
1020 PRINT " ";
|
||||
1021 GOTO 1040
|
||||
1030 PRINT " I";
|
||||
|
||||
159
02_Amazing/perl/amazing.pl
Executable file
159
02_Amazing/perl/amazing.pl
Executable file
@@ -0,0 +1,159 @@
|
||||
#! /usr/bin/perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# Translated from BASIC by Alex Kapranoff
|
||||
|
||||
use feature qw/say/;
|
||||
|
||||
# width and height of the maze
|
||||
my ($width, $height) = input_dimensions();
|
||||
|
||||
# wall masks for all cells
|
||||
my @walls;
|
||||
|
||||
# flags of previous visitation for all cells
|
||||
my %is_visited;
|
||||
|
||||
# was the path out of the maze found?
|
||||
my $path_found = 0;
|
||||
|
||||
# column of entry to the maze in the top line
|
||||
my $entry_col = int(rand($width));
|
||||
|
||||
# cell coordinates for traversal
|
||||
my $col = $entry_col;
|
||||
my $row = 0;
|
||||
|
||||
$is_visited{$row, $col} = 1;
|
||||
|
||||
# looping until we visit every cell
|
||||
while (keys %is_visited < $width * $height) {
|
||||
if (my @dirs = get_possible_directions()) {
|
||||
my $dir = $dirs[rand @dirs];
|
||||
|
||||
# modify current cell wall if needed
|
||||
$walls[$row]->[$col] |= $dir->[2];
|
||||
|
||||
# move the position
|
||||
$row += $dir->[0];
|
||||
$col += $dir->[1];
|
||||
|
||||
# we found the exit!
|
||||
if ($row == $height) {
|
||||
$path_found = 1;
|
||||
--$row;
|
||||
|
||||
if ($walls[$row]->[$col] == 1) {
|
||||
($row, $col) = get_next_branch(0, 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
# modify the new cell wall if needed
|
||||
$walls[$row]->[$col] |= $dir->[3];
|
||||
|
||||
$is_visited{$row, $col} = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
($row, $col) = get_next_branch($row, $col);
|
||||
}
|
||||
}
|
||||
|
||||
unless ($path_found) {
|
||||
$walls[-1]->[rand $width] |= 1;
|
||||
}
|
||||
|
||||
print_maze();
|
||||
|
||||
sub input_dimensions {
|
||||
# Print the banner and returns the dimensions as two integers > 1.
|
||||
# The integers are parsed from the first line of standard input.
|
||||
say ' ' x 28, 'AMAZING PROGRAM';
|
||||
say ' ' x 15, 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY';
|
||||
print "\n" x 4;
|
||||
|
||||
my ($w, $h) = (0, 0);
|
||||
|
||||
while ($w <= 1 || $h <= 1) {
|
||||
print 'WHAT ARE YOUR WIDTH AND LENGTH? ';
|
||||
|
||||
($w, $h) = <STDIN> =~ / \d+ /xg;
|
||||
|
||||
if ($w < 1 || $h < 1) {
|
||||
say "MEANINGLESS DIMENSIONS. TRY AGAIN."
|
||||
}
|
||||
}
|
||||
|
||||
print "\n" x 4;
|
||||
|
||||
return ($w, $h);
|
||||
}
|
||||
|
||||
sub get_possible_directions {
|
||||
# Returns a list of all directions that are available to go to
|
||||
# from the current coordinates. "Down" is available on the last line
|
||||
# until we go there once and mark it as the path through the maze.
|
||||
#
|
||||
# Each returned direction element contains changes to the coordindates and to
|
||||
# the wall masks of the previous and next cell after the move.
|
||||
|
||||
my @rv;
|
||||
# up
|
||||
if ($row > 0 && !$is_visited{$row - 1, $col}) {
|
||||
push @rv, [-1, 0, 0, 1];
|
||||
}
|
||||
# left
|
||||
if ($col > 0 && !$is_visited{$row, $col - 1}) {
|
||||
push @rv, [0, -1, 0, 2];
|
||||
}
|
||||
# right
|
||||
if ($col < $width - 1 && !$is_visited{$row, $col + 1}) {
|
||||
push @rv, [0, 1, 2, 0];
|
||||
}
|
||||
# down
|
||||
if ($row < $height - 1 && !$is_visited{$row + 1, $col}
|
||||
|| $row == $height - 1 && !$path_found
|
||||
) {
|
||||
push @rv, [1, 0, 1, 0];
|
||||
}
|
||||
|
||||
return @rv;
|
||||
}
|
||||
|
||||
sub get_next_branch {
|
||||
# Returns the cell coordinates to start a new maze branch from.
|
||||
# It looks for a visited cell starting from passed position and
|
||||
# going down in the natural traversal order incrementing column and
|
||||
# rows with a rollover to start at the bottom right corner.
|
||||
my ($y, $x) = @_;
|
||||
do {
|
||||
if ($x < $width - 1) {
|
||||
++$x;
|
||||
} elsif ($y < $height - 1) {
|
||||
($y, $x) = ($y + 1, 0);
|
||||
} else {
|
||||
($y, $x) = (0, 0);
|
||||
}
|
||||
} while (!$is_visited{$y, $x});
|
||||
|
||||
return ($y, $x);
|
||||
}
|
||||
|
||||
sub print_maze {
|
||||
# Print the full maze based on wall masks.
|
||||
# For each cell, we mark the absense of the wall to the right with
|
||||
# bit 2 and the absense of the wall down with bit 1. Full table:
|
||||
# 0 -> both walls are present
|
||||
# 1 -> wall down is absent
|
||||
# 2 -> wall to the right is absent
|
||||
# 3 -> both walls are absent
|
||||
say join('.', '', map { $_ == $entry_col ? ' ' : '--' } 0 .. $width - 1), '.';
|
||||
|
||||
for my $row (@walls) {
|
||||
say join(' ', map { $_ & 2 ? ' ' : 'I' } 0, @$row);
|
||||
say join(':', '', map { $_ & 1 ? ' ' : '--' } @$row), '.';
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -37,14 +37,14 @@ fun main() {
|
||||
// an answer or a blank string
|
||||
fun ask(question: String): String {
|
||||
print("$question? ")
|
||||
return readLine()?.uppercase() ?: ""
|
||||
return readln().uppercase() ?: ""
|
||||
}
|
||||
|
||||
// Special case for a "yes or no" question, returns true of yes
|
||||
fun askYesOrNo(question: String): Boolean {
|
||||
return generateSequence {
|
||||
print("$question? ")
|
||||
readLine()
|
||||
readln()
|
||||
}.firstNotNullOf { yesOrNo(it) }
|
||||
}
|
||||
|
||||
|
||||
267
04_Awari/perl/awari.pl
Normal file
267
04_Awari/perl/awari.pl
Normal file
@@ -0,0 +1,267 @@
|
||||
#!/usr/bin/env perl
|
||||
use v5.24;
|
||||
use warnings;
|
||||
use experimental 'signatures';
|
||||
no warnings 'experimental::signatures';
|
||||
use List::Util 'none';
|
||||
|
||||
# our board will be represented with an array of 14 slots, from 0 to 13.
|
||||
# Positions 6 and 13 represent the "home pit" for the human and the
|
||||
# computer, respectively.
|
||||
use constant PLAYER_HOME => 6;
|
||||
use constant COMPUTER_HOME => 13;
|
||||
|
||||
use constant FIRST => 0;
|
||||
use constant AGAIN => 1;
|
||||
|
||||
exit main(@ARGV);
|
||||
|
||||
sub main {
|
||||
$|++; # disable buffering on standard output, every print will be
|
||||
# done immediately
|
||||
|
||||
welcome(); # startup message
|
||||
|
||||
# this array will keep track of computer-side failures, defined as
|
||||
# "the computer did not win". Whenever the computer loses or draws, the
|
||||
# specific sequence of moves will be saved and then used to drive
|
||||
# the search for a (hopefully) optimal move.
|
||||
my $failures = [];
|
||||
while ('enjoying') {
|
||||
|
||||
# a new game starts, let's reset the board to the initial condition
|
||||
my $board = [ (3) x 6, 0, (3) x 6, 0 ];
|
||||
|
||||
# this string will keep track of all moves performed
|
||||
my $moves = '/';
|
||||
|
||||
# the human player starts
|
||||
my $turn = 'player';
|
||||
|
||||
say "\n";
|
||||
print_board($board);
|
||||
|
||||
while (not is_game_over($board)) {
|
||||
|
||||
my $move; # this will collect the move in this turn
|
||||
|
||||
if ($turn eq 'player') { # "first" move for player
|
||||
|
||||
# player_move(...) does the move selected by the player,
|
||||
# returning both the selected move as well as the pit id
|
||||
# where the last seed landed
|
||||
($move, my $landing) = player_move($board);
|
||||
|
||||
# if we landed on the Player's Home Pit we get another move
|
||||
$turn = $landing == PLAYER_HOME ? 'player-again' : 'computer';
|
||||
}
|
||||
elsif ($turn eq 'player-again') { # "second" move for player
|
||||
|
||||
# here we call player_move making it clear that it's the
|
||||
# second move, to get the right prompt eventually. We only
|
||||
# care for the $move as the result, so we ignore the other.
|
||||
($move) = player_move($board, AGAIN);
|
||||
$turn = 'computer';
|
||||
}
|
||||
else {
|
||||
|
||||
# the computer_move(...) function analyzes the $board as well
|
||||
# as adapting the strategy based on past "failures" (i.e.
|
||||
# matches where the computer did not win). For this it's
|
||||
# important to pass the log of these failures, as well as the
|
||||
# full record of moves in this specific match.
|
||||
($move, my $landing) = computer_move($board, $failures, $moves);
|
||||
print "\nMY MOVE IS ", $move - 6;
|
||||
|
||||
# do the second move in the turn if conditions apply
|
||||
if ($landing == COMPUTER_HOME && ! is_game_over($board)) {
|
||||
|
||||
# save the first move before doing the second one!
|
||||
$moves .= "$move/";
|
||||
|
||||
my ($move) = computer_move($board, $failures, $moves);
|
||||
print ',', $move - 6;
|
||||
}
|
||||
$turn = 'player';
|
||||
}
|
||||
|
||||
# append the last selected move by either party, to track this
|
||||
# specific match (useful for computer's AI and ML)
|
||||
$moves .= "$move/";
|
||||
print_board($board);
|
||||
}
|
||||
|
||||
# assess_victory() returns the difference between player's and
|
||||
# computer's seeds, so a negative value is a win for the computer.
|
||||
my $computer_won = assess_victory($board) < 0;
|
||||
|
||||
# if this last match was a "failure" (read: not a win for the
|
||||
# computer), then record it for future memory.
|
||||
push $failures->@*, $moves unless $computer_won;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
# calculate the difference between the two home pits. Negative values mean
|
||||
# that the computer won, 0 is a draw, positive values is a player's win.
|
||||
# The difference is also returned back, in case of need.
|
||||
sub assess_victory ($board) {
|
||||
say "\nGAME OVER";
|
||||
my $difference = $board->[PLAYER_HOME] - $board->[COMPUTER_HOME];
|
||||
if ($difference < 0) {
|
||||
say 'I WIN BY ', -$difference, ' POINTS';
|
||||
}
|
||||
else {
|
||||
say $difference ? "YOU WIN BY $difference POINTS" : 'DRAWN GAME';
|
||||
}
|
||||
return $difference;
|
||||
}
|
||||
|
||||
# move the seeds from $pit and take into account possible bonuses
|
||||
sub move_seeds ($board, $pit) {
|
||||
|
||||
# get the seeds from the selected pit $pit
|
||||
my $seeds = $board->[$pit];
|
||||
$board->[$pit] = 0;
|
||||
|
||||
# $landing will be our "moving cursor" to place seeds around
|
||||
my $landing = $pit;
|
||||
while ($seeds > 0) {
|
||||
$landing = ($landing + 1) % 14; # 12 --> 13 -[wrap]-> 0 --> 1
|
||||
--$seeds;
|
||||
++$board->[$landing];
|
||||
}
|
||||
|
||||
# check for "stealing seeds" condition. This cannot happen in home pits
|
||||
if ($landing != PLAYER_HOME && $landing != COMPUTER_HOME
|
||||
&& $board->[$landing] == 1 && $board->[12 - $landing] > 0) {
|
||||
my $home = $pit < 7 ? PLAYER_HOME : COMPUTER_HOME;
|
||||
$board->[$home] += 1 + $board->[12 - $landing];
|
||||
$board->@[$landing, 12 - $landing] = (0, 0);
|
||||
}
|
||||
|
||||
return ($pit, $landing);
|
||||
}
|
||||
|
||||
sub get_player_move ($board, $prompt) {
|
||||
print "\n$prompt? ";
|
||||
while (defined(my $move = <STDIN>)) {
|
||||
chomp($move); # remove newline
|
||||
return $move - 1 if $move =~ m{\A[1-6]\z}mxs && $board->[$move - 1];
|
||||
print 'ILLEGAL MOVE\nAGAIN? ';
|
||||
}
|
||||
die "goodbye\n";
|
||||
}
|
||||
|
||||
sub player_move ($board, $stage = FIRST) {
|
||||
my $prompt = $stage == FIRST ? 'YOUR MOVE' : 'AGAIN';
|
||||
my $selected_move = get_player_move($board, $prompt);
|
||||
return move_seeds($board, $selected_move);
|
||||
}
|
||||
|
||||
sub computer_move ($board, $failures, $moves) {
|
||||
|
||||
# we will go through all possible moves for the computer and all
|
||||
# possible responses by the player, collecting the "best" move in terms
|
||||
# of reasonable outcome (assuming that each side wants to maximize their
|
||||
# outcome. $best_move will eventually contain the best move for the
|
||||
# computer, and $best_difference the best difference in scoring (as
|
||||
# seen from the computer).
|
||||
my ($best_move, $best_difference);
|
||||
for my $c_move (7 .. 12) {
|
||||
next unless $board->[$c_move]; # only consider pits with seeds inside
|
||||
|
||||
# we work on a copy of the board to do all our trial-and-errors
|
||||
my $copy = [ $board->@* ];
|
||||
move_seeds($copy, $c_move);
|
||||
|
||||
# it's time to "think like a player" and see what's the "best" move
|
||||
# for the player in this situation. This heuristic is "not perfect"
|
||||
# but it seems OK anyway.
|
||||
my $best_player_score = 0;
|
||||
for my $p_move (0 .. 5) {
|
||||
next unless $copy->[$p_move]; # only pits with seeds inside
|
||||
my $landing = $copy->[$p_move] + $p_move;
|
||||
|
||||
# the player's score for this move, calculated as additional seeds
|
||||
# placed in the player's pit. The original algorithm sets this to
|
||||
# 1 only if the $landing position is greater than 13, which can
|
||||
# be obtained by setting the ORIGINAL environment variable to a
|
||||
# "true" value (in Perl terms). Otherwise it is calculated
|
||||
# according to the real rules for the game.
|
||||
my $p_score = $ENV{ORIGINAL} ? $landing > 13 : int(($landing - 5) / 14);
|
||||
|
||||
# whatever, the landing position must be within the bounds
|
||||
$landing %= 14;
|
||||
|
||||
# if the conditions apply, the player's move might win additional
|
||||
# seeds, which we have to to take into account.
|
||||
$p_score += $copy->[12 - $landing]
|
||||
if $copy->[$landing] == 0
|
||||
&& $landing != PLAYER_HOME && $landing != COMPUTER_HOME;
|
||||
|
||||
# let's compare this move's score against the best collected
|
||||
# so far (as a response to a specific computer's move).
|
||||
$best_player_score = $p_score if $p_score > $best_player_score;
|
||||
}
|
||||
|
||||
# the overall score for the player is the additional seeds we just
|
||||
# calculated into $best_player_score plus the seeds that were already
|
||||
# in the player's pit
|
||||
$best_player_score += $copy->[PLAYER_HOME];
|
||||
|
||||
# the best difference we can aim for with this computer's move must
|
||||
# assume that the player will try its best
|
||||
my $difference = $copy->[COMPUTER_HOME] - $best_player_score;
|
||||
|
||||
# now it's time to check this computer's move against the history
|
||||
# of failed matches. $candidate_moves will be the "candidate" list
|
||||
# of moves if we accept this one.
|
||||
my $candidate_moves = $moves . $c_move . '/';
|
||||
for my $failure ($failures->@*) {
|
||||
|
||||
# index(.) returns 0 if and only if $candidate_moves appears at
|
||||
# the very beginning of $failure, i.e. it matches a previous
|
||||
# behaviour.
|
||||
next if index($failure, $candidate_moves) != 0;
|
||||
|
||||
# same sequence of moves as before... assign a penalty
|
||||
$difference -= 2;
|
||||
}
|
||||
|
||||
# update $best_move and $best_difference if they need to
|
||||
($best_move, $best_difference) = ($c_move, $difference)
|
||||
if (! defined $best_move) || ($best_difference < $difference);
|
||||
}
|
||||
|
||||
# apply the selected move and return
|
||||
return move_seeds($board, $best_move);
|
||||
}
|
||||
|
||||
sub welcome {
|
||||
say ' ' x 34, 'AWARI';
|
||||
say ' ' x 15, 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY';
|
||||
}
|
||||
|
||||
sub print_board ($board) {
|
||||
my $template = '
|
||||
%2d %2d %2d %2d %2d %2d
|
||||
%2d %d
|
||||
%2d %2d %2d %2d %2d %2d
|
||||
';
|
||||
printf $template, $board->@[12, 11, 10, 9, 8 , 7, 13, 6, 0 .. 5];
|
||||
return;
|
||||
}
|
||||
|
||||
sub is_game_over ($board) {
|
||||
|
||||
# game over if the player's side is empty
|
||||
return 1 if none { $_ } $board->@[0 .. 5];
|
||||
|
||||
# game over if the computers' side is empty
|
||||
return 1 if none { $_ } $board->@[7 .. 12];
|
||||
|
||||
# not game over
|
||||
return 0;
|
||||
}
|
||||
183
11_Bombardment/csharp/Bombardment.cs
Normal file
183
11_Bombardment/csharp/Bombardment.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Bombardment
|
||||
{
|
||||
// <summary>
|
||||
// Game of Bombardment
|
||||
// Based on the Basic game of Bombardment here
|
||||
// https://github.com/coding-horror/basic-computer-games/blob/main/11%20Bombardment/bombardment.bas
|
||||
// Note: The idea was to create a version of the 1970's Basic game in C#, without introducing
|
||||
// new features - no additional text, error checking, etc has been added.
|
||||
// </summary>
|
||||
internal class Bombardment
|
||||
{
|
||||
private static int MAX_GRID_SIZE = 25;
|
||||
private static int MAX_PLATOONS = 4;
|
||||
private static Random random = new Random();
|
||||
private List<int> computerPositions = new List<int>();
|
||||
private List<int> playerPositions = new List<int>();
|
||||
private List<int> computerGuesses = new List<int>();
|
||||
|
||||
private void PrintStartingMessage()
|
||||
{
|
||||
Console.WriteLine("{0}BOMBARDMENT", new string(' ', 33));
|
||||
Console.WriteLine("{0}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY", new string(' ', 15));
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
Console.WriteLine();
|
||||
|
||||
Console.WriteLine("YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU");
|
||||
Console.WriteLine("HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.");
|
||||
Console.WriteLine("YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.");
|
||||
Console.WriteLine("THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE");
|
||||
Console.WriteLine("OUTPOSTS OF THE COMPUTER. IT WILL DO THE SAME TO YOU.");
|
||||
Console.WriteLine("THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS");
|
||||
Console.WriteLine("FIRST IS THE WINNER.");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!");
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.");
|
||||
|
||||
// As an alternative to repeating the call to WriteLine(),
|
||||
// we can print the new line character five times.
|
||||
Console.Write(new string('\n', 5));
|
||||
|
||||
// Print a sample board (presumably the game was originally designed to be
|
||||
// physically printed on paper while played).
|
||||
for (var i = 1; i <= 25; i += 5)
|
||||
{
|
||||
// The token replacement can be padded by using the format {tokenPosition, padding}
|
||||
// Negative values for the padding cause the output to be left-aligned.
|
||||
Console.WriteLine("{0,-3}{1,-3}{2,-3}{3,-3}{4,-3}", i, i + 1, i + 2, i + 3, i + 4);
|
||||
}
|
||||
|
||||
Console.WriteLine("\n");
|
||||
}
|
||||
|
||||
// Generate 5 random positions for the computer's platoons.
|
||||
private void PlaceComputerPlatoons()
|
||||
{
|
||||
do
|
||||
{
|
||||
var nextPosition = random.Next(1, MAX_GRID_SIZE);
|
||||
if (!computerPositions.Contains(nextPosition))
|
||||
{
|
||||
computerPositions.Add(nextPosition);
|
||||
}
|
||||
|
||||
} while (computerPositions.Count < MAX_PLATOONS);
|
||||
}
|
||||
|
||||
private void StoreHumanPositions()
|
||||
{
|
||||
Console.WriteLine("WHAT ARE YOUR FOUR POSITIONS");
|
||||
|
||||
// The original game assumed that the input would be five comma-separated values, all on one line.
|
||||
// For example: 12,22,1,4,17
|
||||
var input = Console.ReadLine();
|
||||
var playerPositionsAsStrings = input.Split(",");
|
||||
foreach (var playerPosition in playerPositionsAsStrings) {
|
||||
playerPositions.Add(int.Parse(playerPosition));
|
||||
}
|
||||
}
|
||||
|
||||
private void HumanTurn()
|
||||
{
|
||||
Console.WriteLine("WHERE DO YOU WISH TO FIRE YOUR MISSLE");
|
||||
var input = Console.ReadLine();
|
||||
var humanGuess = int.Parse(input);
|
||||
|
||||
if(computerPositions.Contains(humanGuess))
|
||||
{
|
||||
Console.WriteLine("YOU GOT ONE OF MY OUTPOSTS!");
|
||||
computerPositions.Remove(humanGuess);
|
||||
|
||||
switch(computerPositions.Count)
|
||||
{
|
||||
case 3:
|
||||
Console.WriteLine("ONE DOWN, THREE TO GO.");
|
||||
break;
|
||||
case 2:
|
||||
Console.WriteLine("TWO DOWN, TWO TO GO.");
|
||||
break;
|
||||
case 1:
|
||||
Console.WriteLine("THREE DOWN, ONE TO GO.");
|
||||
break;
|
||||
case 0:
|
||||
Console.WriteLine("YOU GOT ME, I'M GOING FAST.");
|
||||
Console.WriteLine("BUT I'LL GET YOU WHEN MY TRANSISTO&S RECUP%RA*E!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("HA, HA YOU MISSED. MY TURN NOW:");
|
||||
}
|
||||
}
|
||||
|
||||
private int GenerateComputerGuess()
|
||||
{
|
||||
int computerGuess;
|
||||
do
|
||||
{
|
||||
computerGuess = random.Next(1, 25);
|
||||
}
|
||||
while(computerGuesses.Contains(computerGuess));
|
||||
computerGuesses.Add(computerGuess);
|
||||
|
||||
return computerGuess;
|
||||
}
|
||||
|
||||
private void ComputerTurn()
|
||||
{
|
||||
var computerGuess = GenerateComputerGuess();
|
||||
|
||||
if (playerPositions.Contains(computerGuess))
|
||||
{
|
||||
Console.WriteLine("I GOT YOU. IT WON'T BE LONG NOW. POST {0} WAS HIT.", computerGuess);
|
||||
playerPositions.Remove(computerGuess);
|
||||
|
||||
switch(playerPositions.Count)
|
||||
{
|
||||
case 3:
|
||||
Console.WriteLine("YOU HAVE ONLY THREE OUTPOSTS LEFT.");
|
||||
break;
|
||||
case 2:
|
||||
Console.WriteLine("YOU HAVE ONLY TWO OUTPOSTS LEFT.");
|
||||
break;
|
||||
case 1:
|
||||
Console.WriteLine("YOU HAVE ONLY ONE OUTPOST LEFT.");
|
||||
break;
|
||||
case 0:
|
||||
Console.WriteLine("YOU'RE DEAD. YOUR LAST OUTPOST WAS AT {0}. HA, HA, HA.", computerGuess);
|
||||
Console.WriteLine("BETTER LUCK NEXT TIME.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("I MISSED YOU, YOU DIRTY RAT. I PICKED {0}. YOUR TURN:", computerGuess);
|
||||
}
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
PrintStartingMessage();
|
||||
PlaceComputerPlatoons();
|
||||
StoreHumanPositions();
|
||||
|
||||
while (playerPositions.Count > 0 && computerPositions.Count > 0)
|
||||
{
|
||||
HumanTurn();
|
||||
|
||||
if (computerPositions.Count > 0)
|
||||
{
|
||||
ComputerTurn();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
11_Bombardment/csharp/Bombardment.csproj
Normal file
8
11_Bombardment/csharp/Bombardment.csproj
Normal file
@@ -0,0 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
13
11_Bombardment/csharp/Program.cs
Normal file
13
11_Bombardment/csharp/Program.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace Bombardment
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var bombardment = new Bombardment();
|
||||
bombardment.Play();
|
||||
}
|
||||
}
|
||||
}
|
||||
129
11_Bombardment/perl/bombardment.pl
Normal file
129
11_Bombardment/perl/bombardment.pl
Normal file
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
|
||||
#GLOBAL
|
||||
my %player_bases;
|
||||
my %computer_bases;
|
||||
my %player_choices;
|
||||
my %computer_choices;
|
||||
|
||||
&main;
|
||||
|
||||
sub main {
|
||||
&print_intro;
|
||||
&display_field;
|
||||
&populate_computer_bases;
|
||||
&populate_player_bases;
|
||||
&game_play;
|
||||
}
|
||||
|
||||
sub game_play {
|
||||
until (keys %computer_bases == 0 || keys %player_bases == 0) {
|
||||
&player_turn;
|
||||
if (keys %computer_bases == 0) {
|
||||
exit;
|
||||
}
|
||||
&computer_turn;
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
sub computer_turn {
|
||||
# There is logic in here to ensure that the computer doesn't try to pick a target it has already picked
|
||||
my $valid_choice = 0;
|
||||
until ($valid_choice == 1) {
|
||||
my $target = int(rand(25)+1);
|
||||
if (exists $computer_choices{$target}) {
|
||||
$valid_choice = 0;
|
||||
}
|
||||
else {
|
||||
$valid_choice = 1;
|
||||
$computer_choices{$target}=1;
|
||||
if (exists $player_bases{$target}) {
|
||||
delete($player_bases{$target});
|
||||
my $size = keys %player_bases;
|
||||
if ($size > 0) {
|
||||
print "I GOT YOU. IT WON'T BE LONG NOW. POST $target WAS HIT.\n";
|
||||
if ($size == 3) { print "YOU HAVE ONLY THREE OUTPOSTS LEFT.\n"};
|
||||
if ($size == 2) { print "YOU HAVE ONLY TWO OUTPOSTS LEFT.\n"};
|
||||
if ($size == 1) { print "YOU HAVE ONLY ONE OUTPOSTS LEFT.\n"};
|
||||
}
|
||||
else {
|
||||
print "YOU'RE DEAD. YOUR LAST OUTPOST WAS AT $target. HA, HA, HA.\nBETTER LUCK NEXT TIME\n";
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
print "I MISSED YOU, YOU DIRTY RAT. I PICKED $target. YOUR TURN:\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub player_turn {
|
||||
print "WHERE DO YOU WISH TO FIRE YOUR MISSILE\n";
|
||||
chomp(my $target=<STDIN>);
|
||||
if (exists $computer_bases{$target}) {
|
||||
print "YOU GOT ONE OF MY OUTPOSTS!\n";
|
||||
delete($computer_bases{$target});
|
||||
my $size = keys %computer_bases;
|
||||
if ($size == 3) { print "ONE DOWN, THREE TO GO.\n"};
|
||||
if ($size == 2) { print "TWO DOWN, TWO TO GO.\n"};
|
||||
if ($size == 1) { print "THREE DOWN, ONE TO GO.\n"};
|
||||
if ($size == 0) { print "YOU GOT ME, I'M GOING FAST. BUT I'LL GET YOU WHEN\nMY TRANSISTO&S RECUP%RA*E!\n"};
|
||||
}
|
||||
else {
|
||||
print "HA, HA YOU MISSED. MY TURN NOW:\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub populate_player_bases {
|
||||
print "WHAT ARE YOUR FOUR POSITIONS\n";
|
||||
my $positions=<STDIN>;
|
||||
chomp($positions);
|
||||
my @positions = split/ /,$positions;
|
||||
foreach my $base (@positions) {
|
||||
$player_bases{$base}=0;
|
||||
}
|
||||
}
|
||||
|
||||
sub display_field {
|
||||
for my $num (1..25) {
|
||||
if (length($num) < 2) {
|
||||
$num = " $num";
|
||||
}
|
||||
print "$num ";
|
||||
if ($num % 5 == 0) {
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub populate_computer_bases {
|
||||
my $size = 0;
|
||||
until ($size == 4) {
|
||||
my $base = int(rand(25)+1);
|
||||
$computer_bases{$base}=0;
|
||||
$size = keys %computer_bases;
|
||||
}
|
||||
}
|
||||
|
||||
sub print_intro {
|
||||
print " " x 33, "BOMBARDMENT\n";
|
||||
print " " x 15, " CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
|
||||
print "\n\n";
|
||||
print "YOU ARE ON A BATTLEFIELD WITH 4 PLATOONS AND YOU\n";
|
||||
print "HAVE 25 OUTPOSTS AVAILABLE WHERE THEY MAY BE PLACED.\n";
|
||||
print "YOU CAN ONLY PLACE ONE PLATOON AT ANY ONE OUTPOST.\n";
|
||||
print "THE COMPUTER DOES THE SAME WITH ITS FOUR PLATOONS.\n\n";
|
||||
print "THE OBJECT OF THE GAME IS TO FIRE MISSLES AT THE\n";
|
||||
print "OUTPOSTS OF THE COMPUTER. IT WILL DO THE SAME TO YOU.\n";
|
||||
print "THE ONE WHO DESTROYS ALL FOUR OF THE ENEMY'S PLATOONS\n";
|
||||
print "FIRST IS THE WINNER.\n\n";
|
||||
print "GOOD LUCK... AND TELL US WHERE YOU WANT THE BODIES SENT!\n\n";
|
||||
print "TEAR OFF MATRIX AND USE IT TO CHECK OFF THE NUMBERS.\n";
|
||||
print "\n\n\n\n";
|
||||
}
|
||||
140
12_Bombs_Away/perl/bombsaway.pl
Normal file
140
12_Bombs_Away/perl/bombsaway.pl
Normal file
@@ -0,0 +1,140 @@
|
||||
#!/usr/bin/env perl
|
||||
use v5.24;
|
||||
use warnings;
|
||||
use experimental 'signatures';
|
||||
no warnings 'experimental::signatures';
|
||||
|
||||
exit main(@ARGV);
|
||||
|
||||
sub main {
|
||||
$|++;
|
||||
my $mission = 'y';
|
||||
|
||||
my @choices = (
|
||||
{ # 1 - Italy
|
||||
ask => 'YOUR TARGET -- ALBANIA(1), GREECE(2), NORTH AFRICA(3)',
|
||||
comments => [
|
||||
q{SHOULD BE EASY -- YOU'RE FLYING A NAZI-MADE PLANE.},
|
||||
'BE CAREFUL!!!',
|
||||
q{YOU'RE GOING FOR THE OIL, EH?},
|
||||
],
|
||||
},
|
||||
{ # 2 - Allies
|
||||
ask => 'AIRCRAFT -- LIBERATOR(1), B-29(2), B-17(3), LANCASTER(4)',
|
||||
comments => [
|
||||
q{YOU'VE GOT 2 TONS OF BOMBS FLYING FOR PLOESTI.},
|
||||
q{YOU'RE DUMPING THE A-BOMB ON HIROSHIMA.},
|
||||
q{YOU'RE CHASING THE BISMARK IN THE NORTH SEA.},
|
||||
q{YOU'RE BUSTING A GERMAN HEAVY WATER PLANT IN THE RUHR.},
|
||||
],
|
||||
},
|
||||
\&japan,
|
||||
{ # 4 - Germany
|
||||
ask => "A NAZI, EH? OH WELL. ARE YOU GOING FOR RUSSIA(1),\n"
|
||||
. 'ENGLAND(2), OR FRANCE(3)',
|
||||
comments => [
|
||||
q{YOU'RE NEARING STALINGRAD.},
|
||||
q{NEARING LONDON. BE CAREFUL, THEY'VE GOT RADAR.},
|
||||
q{NEARING VERSAILLES. DUCK SOUP. THEY'RE NEARLY DEFENSELESS.},
|
||||
],
|
||||
},
|
||||
);
|
||||
|
||||
while (fc($mission // 'n') eq fc('y')) {
|
||||
say 'YOU ARE A PILOT IN A WORLD WAR II BOMBER.';
|
||||
|
||||
my $side = choose(
|
||||
'WHAT SIDE -- ITALY(1), ALLIES(2), JAPAN(3), GERMANY(4)? ', 4);
|
||||
my $choice = $choices[$side - 1];
|
||||
ref($choice) eq 'HASH' ? multiple($choice) : $choice->();
|
||||
|
||||
print "\n\n\nANOTHER MISSION (Y OR N)? ";
|
||||
chomp($mission = <STDIN>);
|
||||
}
|
||||
say "CHICKEN !!!\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub choose ($prompt, $n_max) {
|
||||
while ('necessary') {
|
||||
print "$prompt? ";
|
||||
chomp(my $side = <STDIN>);
|
||||
return $side if $side =~ m{\A [1-9]\d* \z}mxs && $side <= $n_max;
|
||||
say 'TRY AGAIN...';
|
||||
}
|
||||
}
|
||||
|
||||
sub multiple ($spec) {
|
||||
my $target = choose("$spec->{ask}? ", scalar $spec->{comments}->@*);
|
||||
say $spec->{comments}->[$target - 1];
|
||||
say '';
|
||||
|
||||
my $missions;
|
||||
while ('necessary') {
|
||||
print 'HOW MANY MISSIONS HAVE YOU FLOWN? ';
|
||||
chomp($missions = <STDIN>);
|
||||
last if $missions < 160;
|
||||
print 'MISSIONS, NOT MILES...
|
||||
150 MISSIONS IS HIGH EVEN FOR OLD-TIMERS.
|
||||
NOW THEN, ';
|
||||
}
|
||||
if ($missions < 25) { say 'FRESH OUT OF TRANING, EH?' }
|
||||
elsif ($missions >= 100) { say q{THAT'S PUSHING THE ODDS!} }
|
||||
|
||||
return direct_hit() if $missions >= rand(160);
|
||||
|
||||
my $miss = 2 + int rand(30);
|
||||
say "MISSED TARGET BY $miss MILES!";
|
||||
say "NOW YOU'RE REALLY IN FOR IT !!\n";
|
||||
our $double_fire = 0;
|
||||
my $response = choose(
|
||||
'DOES THE ENEMY HAVE GUNS(1), MISSILES(2), OR BOTH(3)', 3);
|
||||
if ($response != 2) {
|
||||
print q{WHAT'S THE PERCENT HIT RATE OF ENEMY GUNNERS (10 TO 50)? };
|
||||
chomp (our $hit_rate = <STDIN>);
|
||||
if ($hit_rate < 10) {
|
||||
say q{YOU LIE, BUT YOU'LL PAY...};
|
||||
return endgame('fail'); # sure failure
|
||||
}
|
||||
say '';
|
||||
}
|
||||
if ($response > 1) {
|
||||
$double_fire = 35;
|
||||
}
|
||||
return endgame();
|
||||
}
|
||||
|
||||
sub direct_hit {
|
||||
my $killed = int rand(100);
|
||||
say "DIRECT HIT!!!! $killed KILLED.\nMISSION SUCCESSFUL";
|
||||
return;
|
||||
}
|
||||
|
||||
sub endgame ($fail = 0) {
|
||||
our $double_fire //= 0;
|
||||
our $hit_rate //= 0;
|
||||
$fail ||= ($double_fire + $hit_rate) > rand(100);
|
||||
if ($fail) {
|
||||
say '* * * * BOOM * * * *
|
||||
YOU HAVE BEEN SHOT DOWN.....
|
||||
DEARLY BELOVED, WE ARE GATHERED HERE TODAY TO PAY OUR
|
||||
LAST TRIBUTE...';
|
||||
}
|
||||
else {
|
||||
say 'YOU MADE IT THROUGH TREMENDOUS FLAK!!';
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub japan {
|
||||
say q{YOU'RE FLYING A KAMIKAZE MISSION OVER THE USS LEXINGTON.};
|
||||
print q{YOUR FIRST KAMIKAZE MISSION(Y OR N)? };
|
||||
chomp(my $is_first_kamikaze = <STDIN>);
|
||||
if (fc($is_first_kamikaze) eq fc('n')) {
|
||||
our $hit_rate = 0;
|
||||
say '';
|
||||
return endgame();
|
||||
}
|
||||
return direct_hit() if rand(1) > 0.65;
|
||||
return endgame('fail');
|
||||
}
|
||||
184
13_Bounce/ruby/bounce.rb
Normal file
184
13_Bounce/ruby/bounce.rb
Normal file
@@ -0,0 +1,184 @@
|
||||
## Global constants
|
||||
|
||||
# Gravity accelaration (F/S^2) ~= 32
|
||||
G = 32
|
||||
|
||||
# Used to indent the plotting of ball positions
|
||||
# so that the height digits don't affect
|
||||
# where we start plotting ball positions
|
||||
BALL_PLOT_INDENT = "\t"
|
||||
|
||||
# The deviation between current plotted height and the actual
|
||||
# height of the ball that we will accept to plot the ball in
|
||||
# that plotted height
|
||||
BALL_PLOT_DEVIATION = 0.25
|
||||
|
||||
# The step we will take as we move down vertically while
|
||||
# plotting ball positions
|
||||
BALL_PLOT_HEIGHT_STEP = 0.5
|
||||
|
||||
|
||||
## Helper functions
|
||||
|
||||
# Calculates the bounce speed (up) of the ball for a given
|
||||
# bounce number and coefficient
|
||||
def calc_velocity_for_bounce(v0, bounce, coefficient)
|
||||
v = v0 * coefficient**bounce
|
||||
end
|
||||
|
||||
# Check https://physics.stackexchange.com/a/333436 for nice explanation
|
||||
def calc_bounce_total_time(v0, bounce, coefficient)
|
||||
v = calc_velocity_for_bounce(v0, bounce, coefficient)
|
||||
t = 2 * v / G
|
||||
end
|
||||
|
||||
# Check https://physics.stackexchange.com/a/333436 for nice explanation
|
||||
def calc_ball_height(v0, bounce, coefficient, t)
|
||||
v = calc_velocity_for_bounce(v0, bounce, coefficient)
|
||||
h = v * t - 0.5 * G * t**2
|
||||
end
|
||||
|
||||
def heighest_position_in_next_bounce(time_in_bounce, v0, i, c)
|
||||
time_in_next_bounce = time_in_bounce[i+1]
|
||||
return -1 if time_in_next_bounce.nil?
|
||||
return calc_ball_height(v0, i, c, time_in_next_bounce / 2) unless time_in_next_bounce.nil?
|
||||
end
|
||||
|
||||
def intro
|
||||
puts <<~INSTRUCTIONS
|
||||
BOUNCE
|
||||
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||
|
||||
|
||||
THIS SIMULATION LETS YOU SPECIFY THE INITIAL VELOCITY
|
||||
OF A BALL THROWN STRAIGHT UP, AND THE COEFFICIENT OF
|
||||
ELASTICITY OF THE BALL. PLEASE USE A DECIMAL FRACTION
|
||||
COEFFICIENCY (LESS THAN 1).
|
||||
|
||||
YOU ALSO SPECIFY THE TIME INCREMENT TO BE USED IN
|
||||
'STROBING' THE BALL'S FLIGHT (TRY .1 INITIALLY).
|
||||
INSTRUCTIONS
|
||||
end
|
||||
|
||||
|
||||
## Plottin functions
|
||||
|
||||
def plot_header
|
||||
puts
|
||||
puts "FEET"
|
||||
end
|
||||
|
||||
def plot_bouncing_ball(strobbing_time, v0, c)
|
||||
## Initializing helper values
|
||||
|
||||
# How many bounces we want to plot
|
||||
# original BASIC version is 70 / (V / (16 * S2))
|
||||
# 70 is assumed to be an arbitrary number higher than 2G and 16 is 1/2G
|
||||
bounces_to_plot = (G**2 / (v0 / strobbing_time)).to_i
|
||||
|
||||
# Holds the total time the ball spends in the air in every bounce
|
||||
time_in_bounce = bounces_to_plot.times.map { |i| calc_bounce_total_time v0, i, c }
|
||||
|
||||
plot_width = 0
|
||||
|
||||
# Calculate the highest position for the ball after the very first bounce
|
||||
plotted_height = (calc_ball_height(v0, 0, c, v0/G) + 0.5).to_i
|
||||
|
||||
## Plotting bouncing ball
|
||||
while plotted_height >= 0 do
|
||||
# We will print only whole-number heights
|
||||
print plotted_height.to_i if plotted_height.to_i === plotted_height
|
||||
|
||||
print BALL_PLOT_INDENT
|
||||
|
||||
bounces_to_plot.times { |i|
|
||||
(0..time_in_bounce[i]).step(strobbing_time) { |t|
|
||||
ball_pos = calc_ball_height v0, i, c, t
|
||||
|
||||
# If the ball is within the acceptable deviation
|
||||
# from the current height, we will plot it
|
||||
if (plotted_height - ball_pos).abs <= BALL_PLOT_DEVIATION then
|
||||
print "0"
|
||||
else
|
||||
print " "
|
||||
end
|
||||
|
||||
# Increment the plot width when we are plotting height = 0
|
||||
# which will definitely be the longest since it never gets
|
||||
# skipped by line 98
|
||||
plot_width += 1 if plotted_height == 0
|
||||
}
|
||||
|
||||
if heighest_position_in_next_bounce(time_in_bounce, v0, i, c) < plotted_height then
|
||||
# If we got no more ball positions at or above current height in the next bounce,
|
||||
# we can skip the rest of the bounces and move down to the next height to plot
|
||||
puts
|
||||
break
|
||||
end
|
||||
}
|
||||
|
||||
plotted_height -= BALL_PLOT_HEIGHT_STEP
|
||||
end
|
||||
|
||||
# Return plot_width to be used by the plot_footer
|
||||
plot_width
|
||||
end
|
||||
|
||||
def plot_footer (plot_width, strobbing_time)
|
||||
# Dotted separator line
|
||||
puts
|
||||
print BALL_PLOT_INDENT
|
||||
(plot_width).times { |_| print "." }
|
||||
puts
|
||||
|
||||
# Time values line
|
||||
print BALL_PLOT_INDENT
|
||||
points_in_sec = (1 / strobbing_time).to_i
|
||||
plot_width.times { |i|
|
||||
if i % points_in_sec == 0 then
|
||||
print (i / points_in_sec).to_i
|
||||
else
|
||||
print " "
|
||||
end
|
||||
}
|
||||
puts
|
||||
|
||||
# Time unit line
|
||||
print BALL_PLOT_INDENT
|
||||
(plot_width / 2 - 4).to_i.times { |_| print " " }
|
||||
puts "SECONDS"
|
||||
puts
|
||||
end
|
||||
|
||||
def game_loop
|
||||
# Read strobing, velocity and coefficient parameters from user input
|
||||
puts "TIME INCREMENT (SEC)"
|
||||
strobbing_time = gets.to_f
|
||||
|
||||
puts "VELOCITY (FPS)"
|
||||
v0 = gets.to_f
|
||||
|
||||
puts "COEFFICIENT"
|
||||
c = gets.to_f
|
||||
|
||||
# Plotting
|
||||
plot_header
|
||||
|
||||
plot_width = plot_bouncing_ball strobbing_time, v0, c
|
||||
|
||||
plot_footer plot_width, strobbing_time
|
||||
end
|
||||
|
||||
|
||||
## Entry point
|
||||
|
||||
begin
|
||||
intro
|
||||
loop do
|
||||
game_loop
|
||||
end
|
||||
rescue SystemExit, Interrupt
|
||||
exit
|
||||
rescue => exception
|
||||
p exception
|
||||
end
|
||||
156
21_Calendar/python/calendar.py
Normal file
156
21_Calendar/python/calendar.py
Normal file
@@ -0,0 +1,156 @@
|
||||
########################################################
|
||||
# Calendar
|
||||
#
|
||||
# From: BASIC Computer Games (1978)
|
||||
# Edited by David Ahl#
|
||||
#
|
||||
# This program prints out a calendar
|
||||
# for any year. You must specify the
|
||||
# starting day of the week of the year in
|
||||
# statement 130. (Sunday(0), Monday
|
||||
# (-1), Tuesday(-2), etc.) You can determine
|
||||
# this by using the program WEEKDAY.
|
||||
# You must also make two changes
|
||||
# for leap years in statement 360 and 620.
|
||||
# The program listing describes the necessary
|
||||
# changes. Running the program produces a
|
||||
# nice 12-month calendar.
|
||||
# The program was written by Geofrey
|
||||
# Chase of the Abbey, Portsmouth, Rhode Island.
|
||||
#
|
||||
########################################################
|
||||
|
||||
def parse_input():
|
||||
"""
|
||||
function to parse input for weekday and leap year boolean
|
||||
"""
|
||||
|
||||
days_mapping = {
|
||||
"sunday": 0,
|
||||
"monday": -1,
|
||||
"tuesday": -2,
|
||||
"wednesday": -3,
|
||||
"thursday": -4,
|
||||
"friday": -5,
|
||||
"saturday": -6
|
||||
}
|
||||
|
||||
day = 0
|
||||
leap_day = False
|
||||
|
||||
correct_day_input = False
|
||||
while not correct_day_input:
|
||||
weekday = input("INSERT THE STARTING DAY OF THE WEEK OF THE YEAR:")
|
||||
|
||||
for day_k in days_mapping.keys():
|
||||
if weekday.lower() in day_k:
|
||||
day = days_mapping[day_k]
|
||||
correct_day_input = True
|
||||
break
|
||||
|
||||
while True:
|
||||
leap = input("IS IT A LEAP YEAR?:")
|
||||
|
||||
if 'y' in leap.lower():
|
||||
leap_day = True
|
||||
break
|
||||
|
||||
if 'n' in leap.lower():
|
||||
leap_day = False
|
||||
break
|
||||
|
||||
return day, leap_day
|
||||
|
||||
|
||||
def calendar(weekday, leap_year):
|
||||
"""
|
||||
function to print a year's calendar.
|
||||
|
||||
input:
|
||||
_weekday_: int - the initial day of the week (0=SUN, -1=MON, -2=TUES...)
|
||||
_leap_year_: bool - indicates if the year is a leap year
|
||||
"""
|
||||
months_days = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
||||
days = 'S M T W T F S\n'
|
||||
sep = "*" * 59
|
||||
years_day = 365
|
||||
d = weekday
|
||||
|
||||
if leap_year:
|
||||
months_days[2] = 29
|
||||
years_day = 366
|
||||
|
||||
months_names = [" JANUARY ",
|
||||
" FEBRUARY",
|
||||
" MARCH ",
|
||||
" APRIL ",
|
||||
" MAY ",
|
||||
" JUNE ",
|
||||
" JULY ",
|
||||
" AUGUST ",
|
||||
"SEPTEMBER",
|
||||
" OCTOBER ",
|
||||
" NOVEMBER",
|
||||
" DECEMBER"]
|
||||
|
||||
days_count = 0 # S in the original program
|
||||
|
||||
# main loop
|
||||
for n in range(1, 13):
|
||||
days_count += months_days[n-1]
|
||||
print("** {} ****************** {} ****************** {} **\n".format(days_count,
|
||||
months_names[n-1], years_day-days_count))
|
||||
print(days)
|
||||
print(sep)
|
||||
|
||||
for w in range(1, 7):
|
||||
print("\n")
|
||||
for g in range(1, 8):
|
||||
d += 1
|
||||
d2 = d - days_count
|
||||
|
||||
if d2 > months_days[n]:
|
||||
break
|
||||
|
||||
if d2 <= 0:
|
||||
print("{}".format(' '), end=' ')
|
||||
elif d2 < 10:
|
||||
print(" {}".format(d2), end=' ')
|
||||
else:
|
||||
print("{}".format(d2), end=' ')
|
||||
print()
|
||||
|
||||
if d2 >= months_days[n]:
|
||||
break
|
||||
|
||||
if d2 > months_days[n]:
|
||||
d -= g
|
||||
|
||||
print("\n")
|
||||
|
||||
print("\n")
|
||||
|
||||
|
||||
def main():
|
||||
print(" "*32 + "CALENDAR")
|
||||
print(" "*15 + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||
print("\n"*11)
|
||||
|
||||
day, leap_year = parse_input()
|
||||
calendar(day, leap_year)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
########################################################
|
||||
#
|
||||
########################################################
|
||||
#
|
||||
# Porting notes:
|
||||
#
|
||||
# It has been added an input at the beginning of the
|
||||
# program so the user can specify the first day of the
|
||||
# week of the year and if the year is leap or not.
|
||||
#
|
||||
########################################################
|
||||
@@ -13,4 +13,5 @@ As published in Basic Computer Games (1978):
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
[Conversion to C](https://github.com/ericfischer/basic-computer-games/blob/main/24%20Chemist/c/chemist.c)
|
||||
#### External Links
|
||||
- C: https://github.com/ericfischer/basic-computer-games/blob/main/24%20Chemist/c/chemist.c
|
||||
|
||||
69
25_Chief/perl/chief.pl
Normal file
69
25_Chief/perl/chief.pl
Normal file
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
print ' ' x 30 . "CHIEF\n";
|
||||
print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
|
||||
print "\n\n\n";
|
||||
|
||||
print "I AM CHIEF NUMBERS FREEK, THE GREAT INDIAN MATH GOD.\n";
|
||||
print "ARE YOU READY TO TAKE THE TEST YOU CALLED ME OUT FOR?\n";
|
||||
|
||||
chomp( my $A = uc <STDIN> );
|
||||
print "SHUT UP, PALE FACE WITH WISE TONGUE.\n" unless ( $A eq 'YES' );
|
||||
|
||||
print " TAKE A NUMBER AND ADD 3. DIVIDE THIS NUMBER BY 5 AND\n";
|
||||
print "MULTIPLY BY 8. DIVIDE BY 5 AND ADD THE SAME. SUBTRACT 1.\n";
|
||||
print " WHAT DO YOU HAVE?\n";
|
||||
|
||||
chomp( my $B = <STDIN> );
|
||||
my $C = ( $B + 1 - 5 ) * 5 / 8 * 5 - 3;
|
||||
|
||||
print "I BET YOUR NUMBER WAS $C. AM I RIGHT?\n";
|
||||
|
||||
chomp( my $D = uc <STDIN> );
|
||||
if ( $D eq 'YES' ) {
|
||||
print "BYE!!!\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
print "WHAT WAS YOUR ORIGINAL NUMBER?\n";
|
||||
|
||||
chomp( my $K = <STDIN> );
|
||||
my $F = $K + 3;
|
||||
my $G = $F / 5;
|
||||
my $H = $G * 8;
|
||||
my $I = $H / 5 + 5;
|
||||
my $J = $I - 1;
|
||||
|
||||
print "SO YOU THINK YOU'RE SO SMART, EH?\n";
|
||||
print "NOW WATCH.\n";
|
||||
print "$K PLUS 3 EQUALS $F. THIS DIVIDED BY 5 EQUALS $G;\n";
|
||||
print "THIS TIMES 8 EQUALS $H. IF WE DIVIDE BY 5 AND ADD 5,\n";
|
||||
print "WE GET $I , WHICH, MINUS 1, EQUALS $J.\n";
|
||||
print "NOW DO YOU BELIEVE ME?\n";
|
||||
|
||||
chomp( my $Z = uc <STDIN> );
|
||||
if ( $Z eq 'YES' ) {
|
||||
print "BYE!!!\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
print "YOU HAVE MADE ME MAD!!!\n";
|
||||
print "THERE MUST BE A GREAT LIGHTNING BOLT!\n\n\n";
|
||||
|
||||
for my $i ( reverse 22 .. 30 ) {
|
||||
print ' ' x $i . "X X\n";
|
||||
}
|
||||
print ' ' x 21 . "X XXX\n";
|
||||
print ' ' x 20 . "X X\n";
|
||||
print ' ' x 19 . "XX X\n";
|
||||
for my $i ( reverse 13 .. 20 ) {
|
||||
print ' ' x $i . "X X\n";
|
||||
}
|
||||
print ' ' x 12 . "XX\n";
|
||||
print ' ' x 11 . "X\n";
|
||||
print ' ' x 10 . "*\n";
|
||||
print "\n#########################\n\n";
|
||||
print "I HOPE YOU BELIEVE ME NOW, FOR YOUR SAKE!!\n";
|
||||
77
25_Chief/python/Chief.py
Normal file
77
25_Chief/python/Chief.py
Normal file
@@ -0,0 +1,77 @@
|
||||
def print_lightning_bolt():
|
||||
|
||||
print('*'*36)
|
||||
n = 24
|
||||
while n > 16:
|
||||
print(' '*n + 'x x')
|
||||
n -=1
|
||||
print(' '*16 + 'x xxx')
|
||||
print(' '*15 + 'x x')
|
||||
print(' '*14+ 'xxx x')
|
||||
n -=1
|
||||
while n > 8:
|
||||
print(' '*n + 'x x')
|
||||
n -=1
|
||||
print(' '*8 + 'xx')
|
||||
print(' '*7 +'x')
|
||||
print('*'*36)
|
||||
|
||||
|
||||
def print_solution(n):
|
||||
|
||||
print('\n{} plus 3 gives {}. This Divided by 5 equals {}'.format(n, n+3, (n+3)/5))
|
||||
print('This times 8 gives {}. If we divide 5 and add 5.'.format(( (n+3)/5 )*8 ))
|
||||
print('We get {}, which, minus 1 equals {}'.format(( ((n+3)/5)*8)/5+5, ((((n+3)/5)*8)/5+5)-1 ))
|
||||
|
||||
def Game():
|
||||
print('\nTake a Number and ADD 3. Now, Divide this number by 5 and')
|
||||
print('multiply by 8. Now, Divide by 5 and add the same. Subtract 1')
|
||||
|
||||
resp = float(input('\nWhat do you have? '))
|
||||
comp_guess = (((resp - 4)*5)/8)*5 -3
|
||||
resp2 = input('\nI bet your number was {} was i right(Yes or No)? '.format(comp_guess))
|
||||
|
||||
if resp2 == 'Yes' or resp2 == 'YES' or resp2 == 'yes':
|
||||
print('\nHuh, I Knew I was unbeatable')
|
||||
print('And here is how i did it')
|
||||
print_solution(comp_guess)
|
||||
input('')
|
||||
|
||||
else:
|
||||
resp3 = float(input('\nHUH!! what was you original number? '))
|
||||
|
||||
if resp3 == comp_guess:
|
||||
print('\nThat was my guess, AHA i was right')
|
||||
print("Shamed to accept defeat i guess, don't worry you can master mathematics too")
|
||||
print('Here is how i did it')
|
||||
print_solution(comp_guess)
|
||||
input('')
|
||||
|
||||
else:
|
||||
print('\nSo you think you\'re so smart, EH?')
|
||||
print('Now, Watch')
|
||||
print_solution(resp3)
|
||||
|
||||
resp4 = input('\nNow do you believe me? ')
|
||||
|
||||
if resp4 == 'Yes' or resp4 == 'YES' or resp4 == 'yes':
|
||||
print('\nOk, Lets play again sometime bye!!!!')
|
||||
input('')
|
||||
|
||||
else:
|
||||
print('\nYOU HAVE MADE ME VERY MAD!!!!!')
|
||||
print("BY THE WRATH OF THE MATHEMATICS AND THE RAGE OF THE GODS")
|
||||
print("THERE SHALL BE LIGHTNING!!!!!!!")
|
||||
print_lightning_bolt()
|
||||
print('\nI Hope you believe me now, for your own sake')
|
||||
input('')
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
print('I am CHIEF NUMBERS FREEK, The GREAT INDIAN MATH GOD.')
|
||||
play = input('\nAre you ready to take the test you called me out for(Yes or No)? ')
|
||||
if play == 'Yes' or play == 'YES' or play == 'yes':
|
||||
Game()
|
||||
else:
|
||||
print('Ok, Nevermind. Let me go back to my great slumber, Bye')
|
||||
input('')
|
||||
226
30_Cube/java/src/Cube.java
Normal file
226
30_Cube/java/src/Cube.java
Normal file
@@ -0,0 +1,226 @@
|
||||
import java.io.PrintStream;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Game of Cube
|
||||
* <p>
|
||||
* Based on game of Cube at:
|
||||
* https://github.com/coding-horror/basic-computer-games/blob/main/30_Cube/cube.bas
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class Cube {
|
||||
|
||||
//Current player location
|
||||
private Location playerLocation;
|
||||
|
||||
//Current list of mines
|
||||
private Set<Location> mines;
|
||||
|
||||
//System input / output objects
|
||||
private PrintStream out;
|
||||
private Scanner scanner;
|
||||
|
||||
//Player's current money
|
||||
private int money;
|
||||
|
||||
/**
|
||||
* Entry point, creates a new Cube object and calls the play method
|
||||
* @param args Java execution arguments, not used in application
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
new Cube().play();
|
||||
}
|
||||
|
||||
public Cube() {
|
||||
out = System.out;
|
||||
scanner = new Scanner(System.in);
|
||||
money = 500;
|
||||
mines = new HashSet<>(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears mines and places 5 new mines on the board
|
||||
*/
|
||||
private void placeMines() {
|
||||
mines.clear();
|
||||
Random random = new Random();
|
||||
for(int i = 0; i < 5; i++) {
|
||||
int x = random.nextInt(1,4);
|
||||
int y = random.nextInt(1,4);
|
||||
int z = random.nextInt(1,4);
|
||||
mines.add(new Location(x,y,z));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the entire game until the player runs out of money or chooses to stop
|
||||
*/
|
||||
public void play() {
|
||||
out.println("DO YOU WANT TO SEE INSTRUCTIONS? (YES--1,NO--0)");
|
||||
if(readParsedBoolean()) {
|
||||
printInstructions();
|
||||
}
|
||||
do {
|
||||
placeMines();
|
||||
out.println("WANT TO MAKE A WAGER?");
|
||||
int wager = 0 ;
|
||||
|
||||
if(readParsedBoolean()) {
|
||||
out.println("HOW MUCH?");
|
||||
do {
|
||||
wager = Integer.parseInt(scanner.nextLine());
|
||||
if(wager > money) {
|
||||
out.println("TRIED TO FOOL ME; BET AGAIN");
|
||||
}
|
||||
} while(wager > money);
|
||||
}
|
||||
|
||||
playerLocation = new Location(1,1,1);
|
||||
while(playerLocation.x + playerLocation.y + playerLocation.z != 9) {
|
||||
out.println("\nNEXT MOVE");
|
||||
String input = scanner.nextLine();
|
||||
|
||||
String[] stringValues = input.split(",");
|
||||
|
||||
if(stringValues.length < 3) {
|
||||
out.println("ILLEGAL MOVE, YOU LOSE.");
|
||||
return;
|
||||
}
|
||||
|
||||
int x = Integer.parseInt(stringValues[0]);
|
||||
int y = Integer.parseInt(stringValues[1]);
|
||||
int z = Integer.parseInt(stringValues[2]);
|
||||
|
||||
Location location = new Location(x,y,z);
|
||||
|
||||
if(x < 1 || x > 3 || y < 1 || y > 3 || z < 1 || z > 3 || !isMoveValid(playerLocation,location)) {
|
||||
out.println("ILLEGAL MOVE, YOU LOSE.");
|
||||
return;
|
||||
}
|
||||
|
||||
playerLocation = location;
|
||||
|
||||
if(mines.contains(location)) {
|
||||
out.println("******BANG******");
|
||||
out.println("YOU LOSE!\n\n");
|
||||
money -= wager;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(wager > 0) {
|
||||
out.printf("YOU NOW HAVE %d DOLLARS\n",money);
|
||||
}
|
||||
|
||||
} while(money > 0 && doAnotherRound());
|
||||
|
||||
out.println("TOUGH LUCK!");
|
||||
out.println("\nGOODBYE.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries the user whether they want to play another round
|
||||
* @return True if the player decides to play another round,
|
||||
* False if the player would not like to play again
|
||||
*/
|
||||
private boolean doAnotherRound() {
|
||||
if(money > 0) {
|
||||
out.println("DO YOU WANT TO TRY AGAIN?");
|
||||
return readParsedBoolean();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the instructions to the game, copied from the original code.
|
||||
*/
|
||||
public void printInstructions() {
|
||||
out.println("THIS IS A GAME IN WHICH YOU WILL BE PLAYING AGAINST THE");
|
||||
out.println("RANDOM DECISION OF THE COMPUTER. THE FIELD OF PLAY IS A");
|
||||
out.println("CUBE OF SIDE 3. ANY OF THE 27 LOCATIONS CAN BE DESIGNATED");
|
||||
out.println("BY INPUTTING THREE NUMBERS SUCH AS 2,3,1. AT THE START");
|
||||
out.println("YOU ARE AUTOMATICALLY AT LOCATION 1,1,1. THE OBJECT OF");
|
||||
out.println("THE GAME IS TO GET TO LOCATION 3,3,3. ONE MINOR DETAIL:");
|
||||
out.println("THE COMPUTER WILL PICK, AT RANDOM, 5 LOCATIONS AT WHICH");
|
||||
out.println("IT WILL PLANT LAND MINES. IF YOU HIT ONE OF THESE LOCATIONS");
|
||||
out.println("YOU LOSE. ONE OTHER DETAIL: YOU MAY MOVE ONLY ONE SPACE");
|
||||
out.println("IN ONE DIRECTION EACH MOVE. FOR EXAMPLE: FROM 1,1,2 YOU");
|
||||
out.println("MAY MOVE TO 2,1,2 OR 1,1,3. YOU MAY NOT CHANGE");
|
||||
out.println("TWO OF THE NUMBERS ON THE SAME MOVE. IF YOU MAKE AN ILLEGAL");
|
||||
out.println("MOVE, YOU LOSE AND THE COMPUTER TAKES THE MONEY YOU MAY");
|
||||
out.println("\n");
|
||||
out.println("ALL YES OR NO QUESTIONS WILL BE ANSWERED BY A 1 FOR YES");
|
||||
out.println("OR A 0 (ZERO) FOR NO.");
|
||||
out.println();
|
||||
out.println("WHEN STATING THE AMOUNT OF A WAGER, PRINT ONLY THE NUMBER");
|
||||
out.println("OF DOLLARS (EXAMPLE: 250) YOU ARE AUTOMATICALLY STARTED WITH");
|
||||
out.println("500 DOLLARS IN YOUR ACCOUNT.");
|
||||
out.println();
|
||||
out.println("GOOD LUCK!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the user to input a boolean value. This could either be (true,false), (1,0), (y,n), (yes,no), etc.
|
||||
* By default, it will return false
|
||||
* @return Parsed boolean value of the user input
|
||||
*/
|
||||
private boolean readParsedBoolean() {
|
||||
String in = scanner.nextLine();
|
||||
try {
|
||||
return in.toLowerCase().charAt(0) == 'y' || Boolean.parseBoolean(in) || Integer.parseInt(in) == 1;
|
||||
} catch(NumberFormatException exception) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a move is valid
|
||||
* @param from The point that the player is at
|
||||
* @param to The point that the player wishes to move to
|
||||
* @return True if the player is only moving, at most, 1 location in any direction, False if the move is invalid
|
||||
*/
|
||||
private boolean isMoveValid(Location from, Location to) {
|
||||
return Math.abs(from.x - to.x) + Math.abs(from.y - to.y) + Math.abs(from.z - to.z) <= 1;
|
||||
}
|
||||
|
||||
public class Location {
|
||||
int x,y,z;
|
||||
|
||||
public Location(int x, int y, int z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
/*
|
||||
For use in HashSet and checking if two Locations are the same
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
Location location = (Location) o;
|
||||
|
||||
if (x != location.x) return false;
|
||||
if (y != location.y) return false;
|
||||
return z == location.z;
|
||||
}
|
||||
|
||||
/*
|
||||
For use in the HashSet to accordingly index the set
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = x;
|
||||
result = 31 * result + y;
|
||||
result = 31 * result + z;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
57
31_Depth_Charge/ruby/.gitignore
vendored
Normal file
57
31_Depth_Charge/ruby/.gitignore
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
# Package Shell Specific Things
|
||||
|
||||
## Build Process
|
||||
|
||||
/build
|
||||
|
||||
## Transient files
|
||||
|
||||
/src/input
|
||||
/src/output
|
||||
/src/log
|
||||
/drop
|
||||
|
||||
# Programming Languages
|
||||
|
||||
## Java
|
||||
/src/java/**/*.class
|
||||
|
||||
## Rakudo / Perl6
|
||||
/src/**/.precomp
|
||||
|
||||
## PHP
|
||||
/vendor/
|
||||
|
||||
## Python
|
||||
*.swp
|
||||
__pycache__/
|
||||
*.pyc
|
||||
*.egg-info
|
||||
/dist
|
||||
|
||||
## Ruby
|
||||
*.gem
|
||||
.bundle
|
||||
|
||||
# Editors
|
||||
|
||||
## Dia
|
||||
*.dia.autosave
|
||||
|
||||
## Emacs
|
||||
\#*\#
|
||||
.\#*
|
||||
|
||||
|
||||
## Vi / Vim
|
||||
*.swp
|
||||
|
||||
# Filesystem Artifacts
|
||||
|
||||
## Mac
|
||||
|
||||
.DS_Store
|
||||
|
||||
## NFS
|
||||
|
||||
.nfs*
|
||||
@@ -13,7 +13,6 @@ class DepthCharge
|
||||
break if ! get_input_another_game()
|
||||
end
|
||||
|
||||
# 420 PRINT "OK. HOPE YOU ENJOYED YOURSELF." : GOTO 600
|
||||
printf("OK. HOPE YOU ENJOYED YOURSELF.\n")
|
||||
end
|
||||
|
||||
@@ -51,7 +50,7 @@ class DepthCharge
|
||||
|
||||
the_input = Integer(value) rescue nil
|
||||
|
||||
if the_input == nil || the_input < 0
|
||||
if the_input == nil || the_input < 1
|
||||
printf("PLEASE ENTER A POSITIVE NUMBER\n\n")
|
||||
next
|
||||
|
||||
@@ -61,25 +60,7 @@ class DepthCharge
|
||||
end
|
||||
end
|
||||
|
||||
def get_search_area_dimension
|
||||
# 20 INPUT "DIMENSION OF SEARCH AREA";G: PRINT
|
||||
@search_area_dimension = get_input_positive_integer("DIMENSION OF SEARCH AREA: ")
|
||||
# 30 N=INT(LOG(G)/LOG(2))+1
|
||||
|
||||
@num_tries = Integer(
|
||||
Math.log(@search_area_dimension)/Math.log(2)
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def print_instructions
|
||||
# 40 PRINT "YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER"
|
||||
# 50 PRINT "AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR"
|
||||
# 60 PRINT "MISSION IS TO DESTROY IT. YOU HAVE";N;"SHOTS."
|
||||
# 70 PRINT "SPECIFY DEPTH CHARGE EXPLOSION POINT WITH A"
|
||||
# 80 PRINT "TRIO OF NUMBERS -- THE FIRST TWO ARE THE"
|
||||
# 90 PRINT "SURFACE COORDINATES; THE THIRD IS THE DEPTH."
|
||||
# 100 PRINT : PRINT "GOOD LUCK !": PRINT
|
||||
printf( <<~INSTRUCTIONS
|
||||
YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER
|
||||
AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR
|
||||
@@ -110,19 +91,21 @@ GOOD LUCK !
|
||||
end
|
||||
|
||||
def setup_game
|
||||
get_search_area_dimension()
|
||||
@search_area_dimension = get_input_positive_integer("DIMENSION OF SEARCH AREA: ")
|
||||
|
||||
@num_tries = Integer(
|
||||
Math.log(@search_area_dimension)/Math.log(2) + 1
|
||||
)
|
||||
setup_enemy()
|
||||
end
|
||||
|
||||
def setup_enemy
|
||||
# 110 A=INT(G*RND(1)) : B=INT(G*RND(1)) : C=INT(G*RND(1))
|
||||
@enemy_x = rand(1..@search_area_dimension)
|
||||
@enemy_y = rand(1..@search_area_dimension)
|
||||
@enemy_z = rand(1..@search_area_dimension)
|
||||
end
|
||||
end
|
||||
|
||||
def game_loop
|
||||
# 120 FOR D=1 TO N : PRINT : PRINT "TRIAL #";D; : INPUT X,Y,Z
|
||||
for @trial in 1..@num_tries do
|
||||
output_game_status()
|
||||
|
||||
@@ -130,7 +113,6 @@ GOOD LUCK !
|
||||
@shot_y = get_input_positive_integer("Y: ")
|
||||
@shot_z = get_input_positive_integer("Z: ")
|
||||
|
||||
# 130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300
|
||||
if (
|
||||
(@enemy_x - @shot_x).abs \
|
||||
+ (@enemy_y - @shot_y).abs \
|
||||
@@ -140,7 +122,6 @@ GOOD LUCK !
|
||||
you_win()
|
||||
return
|
||||
else
|
||||
# 140 GOSUB 500 : PRINT : NEXT D
|
||||
missed_shot()
|
||||
end
|
||||
end
|
||||
@@ -156,54 +137,41 @@ GOOD LUCK !
|
||||
printf("TRIAL \#%d\n", @trial)
|
||||
end
|
||||
def you_win
|
||||
printf("B O O M ! ! YOU FOUND IT IN %d TRIES!\n\n", @trial )
|
||||
printf("\nB O O M ! ! YOU FOUND IT IN %d TRIES!\n\n", @trial )
|
||||
end
|
||||
def missed_shot
|
||||
missed_directions = []
|
||||
|
||||
# 530 IF X>A THEN PRINT "EAST";
|
||||
# 540 IF X<A THEN PRINT "WEST";
|
||||
if @shot_x > @enemy_x
|
||||
missed_directions.push('TOO FAR EAST')
|
||||
elsif @shot_x < @enemy_x
|
||||
missed_directions.push('TOO FAR WEST')
|
||||
end
|
||||
|
||||
# 510 IF Y>B THEN PRINT "NORTH";
|
||||
# 520 IF Y<B THEN PRINT "SOUTH";
|
||||
if @shot_y > @enemy_y
|
||||
missed_directions.push('TOO FAR NORTH')
|
||||
elsif @shot_y < @enemy_y
|
||||
missed_directions.push('TOO FAR SOUTH')
|
||||
end
|
||||
|
||||
# 560 IF Z>C THEN PRINT " TOO LOW."
|
||||
# 570 IF Z<C THEN PRINT " TOO HIGH."
|
||||
# 580 IF Z=C THEN PRINT " DEPTH OK."
|
||||
if @shot_z > @enemy_z
|
||||
missed_directions.push('TOO DEEP')
|
||||
elsif @shot_z < @enemy_z
|
||||
missed_directions.push('TOO SHALLOW')
|
||||
end
|
||||
|
||||
# 500 PRINT "SONAR REPORTS SHOT WAS ";
|
||||
printf("SONAR REPORTS SHOT WAS: \n")
|
||||
printf("%s\n", "\t" + missed_directions.join("\n\t"))
|
||||
# 550 IF Y<>B OR X<>A THEN PRINT " AND";
|
||||
# 590 RETURN
|
||||
end
|
||||
|
||||
def you_lose
|
||||
# You took too long!
|
||||
printf("YOU HAVE BEEN TORPEDOED! ABANDON SHIP!\n")
|
||||
printf("THE SUBMARINE WAS AT %d %d %d\n", @enemy_x, @enemy_y, @enemy_z)
|
||||
|
||||
end
|
||||
|
||||
def get_input_another_game
|
||||
# 400 PRINT : PRINT: INPUT "ANOTHER GAME (Y OR N)";A$
|
||||
return get_input_y_or_n("ANOTHER GAME (Y OR N): ")
|
||||
# 410 IF A$="Y" THEN 100
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
179
35_Even_Wins/perl/evenwins.pl
Normal file
179
35_Even_Wins/perl/evenwins.pl
Normal file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
&main;
|
||||
|
||||
sub main {
|
||||
&print_intro;
|
||||
&game_play;
|
||||
}
|
||||
|
||||
sub game_play {
|
||||
my $marbles = 27;
|
||||
my $turn = 0;
|
||||
my $player_total = 0;
|
||||
my $computer_total = 0;
|
||||
print "TYPE A '1' IF YOU WANT TO GO FIRST AND TYPE A '0' IF YOU WANT ME TO GO FIRST\n";
|
||||
my $choice = <STDIN>;
|
||||
chomp($choice);
|
||||
if ($choice == 0) {
|
||||
until ($marbles == 0) {
|
||||
|
||||
my $computer_choice = &computer_select($marbles,$turn,$player_total);
|
||||
$marbles = $marbles - $computer_choice;
|
||||
$computer_total = $computer_total + $computer_choice;
|
||||
print "MY TOTAL IS $computer_total\n";
|
||||
|
||||
print "TOTAL= $marbles\n";
|
||||
|
||||
if ($marbles == 0) {&determine_winner($computer_total,$player_total)};
|
||||
|
||||
my $player_choice = &player_select($marbles,$turn);
|
||||
$marbles = $marbles - $player_choice;
|
||||
$player_total = $player_total + $player_choice;
|
||||
print "YOUR TOTAL IS $player_total\n";
|
||||
$turn++;
|
||||
print "TOTAL= $marbles\n";
|
||||
if ($marbles == 0) {&determine_winner($computer_total,$player_total)};
|
||||
}
|
||||
}
|
||||
elsif ($choice == 1) {
|
||||
until ($marbles == 0) {
|
||||
|
||||
my $player_choice = &player_select($marbles,$turn);
|
||||
$marbles = $marbles - $player_choice;
|
||||
$player_total = $player_total + $player_choice;
|
||||
$turn++;
|
||||
print "YOUR TOTAL IS $player_total\n";
|
||||
|
||||
print "TOTAL= $marbles\n";
|
||||
|
||||
if ($marbles == 0) {&determine_winner($computer_total,$player_total)};
|
||||
|
||||
my $computer_choice = &computer_select($marbles,$turn,$player_total);
|
||||
$marbles = $marbles - $computer_choice;
|
||||
$computer_total = $computer_total + $computer_choice;
|
||||
print "MY TOTAL IS $computer_total\n";
|
||||
|
||||
print "TOTAL= $marbles\n";
|
||||
|
||||
if ($marbles == 0) {&determine_winner($computer_total,$player_total)};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub determine_winner {
|
||||
my $computer = shift;
|
||||
my $player = shift;
|
||||
print "THAT IS ALL OF THE MARBLES.\n\n";
|
||||
print "MY TOTAL IS $computer, YOUR TOTAL IS $player\n";
|
||||
if ($player % 2 == 0) {
|
||||
print " YOU WON.\n";
|
||||
}
|
||||
if ($computer % 2 == 0) {
|
||||
print " I WON.\n";
|
||||
}
|
||||
my $answer = -1;
|
||||
until ($answer == 1 || $answer == 0) {
|
||||
print "DO YOU WANT TO PLAY AGAIN? TYPE 1 FOR YES AND 0 FOR NO.\n";
|
||||
$answer=<STDIN>;
|
||||
chomp($answer);
|
||||
}
|
||||
if ($answer == 1) {
|
||||
&game_play;
|
||||
}
|
||||
else {
|
||||
print "OK. SEE YOU LATER.\n";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
sub player_select {
|
||||
my $marbles = shift;
|
||||
my $turn = shift;
|
||||
my $validity="invalid";
|
||||
if ($turn == 0) {
|
||||
print "WHAT IS YOUR FIRST MOVE\n";
|
||||
}
|
||||
else {
|
||||
print "WHAT IS YOUR NEXT MOVE\n";
|
||||
}
|
||||
until ($validity eq "valid") {
|
||||
my $num = <STDIN>;
|
||||
chomp($num);
|
||||
my $validity=&validity_check($marbles,$num);
|
||||
if ($validity eq "valid") {
|
||||
return $num;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub computer_select {
|
||||
my $marbles = shift;
|
||||
my $turn = shift;
|
||||
my $player_total = shift;
|
||||
my $num = 2;
|
||||
my $validity = "invalid";
|
||||
if ($turn == 0) {
|
||||
print "I PICK UP $num MARBLES.\n\n";
|
||||
}
|
||||
else {
|
||||
until ($validity eq "valid") {
|
||||
my $R=$marbles-6*int(($marbles/6));
|
||||
|
||||
if (int($player_total/2) == $player_total/2) {
|
||||
if ($R < 1.5 || $R > 5.3) {
|
||||
$num = 1;
|
||||
}
|
||||
else {
|
||||
$num = $R - 1;
|
||||
}
|
||||
}
|
||||
|
||||
elsif ($marbles < 4.2) {
|
||||
$num = $marbles;
|
||||
}
|
||||
elsif ($R > 3.4) {
|
||||
if ($R < 4.7 || $R > 3.5) {
|
||||
$num = 4;
|
||||
}
|
||||
else {
|
||||
$num = 1;
|
||||
}
|
||||
}
|
||||
$validity=&validity_check($marbles,$num);
|
||||
}
|
||||
print "\nI PICK UP $num MARBLES.\n\n";
|
||||
}
|
||||
return $num;
|
||||
}
|
||||
|
||||
sub validity_check {
|
||||
my $marbles = shift;
|
||||
my $num = shift;
|
||||
if ($num > $marbles) {
|
||||
print "YOU HAVE TRIED TO TAKE MORE MARBLES THAN THERE ARE LEFT. TRY AGAIN. THERE ARE $marbles MARBLES LEFT\n";
|
||||
return "invalid";
|
||||
}
|
||||
if ($num > 0 && $num <= 4) {
|
||||
return "valid";
|
||||
}
|
||||
if ($num < 1 || $num > 4) {
|
||||
print "THE NUMBER OF MARBLES YOU TAKE MUST BE A POSITIVE INTEGER BETWEEN 1 AND 4\nWHAT IS YOUR NEXT MOVE?\n";
|
||||
return "invalid";
|
||||
}
|
||||
else {
|
||||
return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
sub print_intro {
|
||||
print ' ' x 31 . "EVEN WINS\n";
|
||||
print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n\n";
|
||||
print "THIS IS A 2 PERSON GAME CALLED 'EVEN WINS'. TO PLAY THE GAME, THE PLAYERS NEED 27 MARBLES OR OTHER OBJECTS ON THE TABLE\n\n";
|
||||
print "THE 2 PLAYERS ALTERNATE TURNS, WITH EACH PLAYER REMOVING FROM 1 TO 4 MARBLES ON EACH MOVE. THE GAME ENDS WHEN THERE ARE NO MARBLES LEFT, AND THE WINNER IS THE ONE WITH AN EVEN NUMBER OF MARBLES\n";
|
||||
print "THE ONLY RULES ARE THAT (1) YOU MUST ALTERNATE TURNS, (2) YOU MUST TAKE BETWEEN 1 AND 4 MARBLES EACH TURN, AND (3) YOU CANNOT SKIP A TURN.\n\n";
|
||||
}
|
||||
@@ -142,17 +142,32 @@ def game_over():
|
||||
print('')
|
||||
|
||||
def computer_turn():
|
||||
global marbles_in_middle
|
||||
global computer_marbles
|
||||
global marbles_in_middle
|
||||
global computer_marbles
|
||||
global human_marbles
|
||||
|
||||
print("It's the computer's turn ...")
|
||||
max_choice = min(4, marbles_in_middle)
|
||||
marbles_to_take=0
|
||||
|
||||
# choose at random
|
||||
n = random.randint(1, max_choice)
|
||||
print(f'Computer takes {marbles_str(n)} ...')
|
||||
marbles_in_middle -= n
|
||||
computer_marbles += n
|
||||
print("It's the computer's turn ...")
|
||||
r = marbles_in_middle - 6 * int((marbles_in_middle/6)) #line 500
|
||||
|
||||
if int(human_marbles/2) == human_marbles/2: #line 510
|
||||
if r < 1.5 or r > 5.3: #lines 710 and 720
|
||||
marbles_to_take = 1
|
||||
else:
|
||||
marbles_to_take = r - 1
|
||||
|
||||
elif marbles_in_middle < 4.2: #line 580
|
||||
marbles_to_take = marbles_in_middle
|
||||
elif r > 3.4: #line 530
|
||||
if r < 4.7 or r > 3.5:
|
||||
marbles_to_take = 4
|
||||
else:
|
||||
marbles_to_take = r + 1
|
||||
|
||||
print(f'Computer takes {marbles_str(marbles_to_take)} ...')
|
||||
marbles_in_middle -= marbles_to_take
|
||||
computer_marbles += marbles_to_take
|
||||
|
||||
def play_game():
|
||||
global marbles_in_middle
|
||||
|
||||
162
36_Flip_Flop/ruby/flipflop.rb
Normal file
162
36_Flip_Flop/ruby/flipflop.rb
Normal file
@@ -0,0 +1,162 @@
|
||||
#A class representing the internal state of a single game of flip flop
|
||||
# state represents the list of X's (A in the original code)
|
||||
# guesses represents the number of guesses the user has made (C in the original code)
|
||||
# seed represents the random seed for an instance of the game (Q in the original code)
|
||||
Game = Struct.new(:state, :guesses, :seed) do
|
||||
|
||||
#The original BASIC program used 1 indexed arrays while Ruby has 0-indexed arrays.
|
||||
#We can't use 0 indexed arrays for the flip functions or we'll get divide by zero errors.
|
||||
#These convenience functions allow us to modify and access internal game state in a 1-indexed fashion
|
||||
def flip_letter(letter_number)
|
||||
index = letter_number -1
|
||||
if self.state[index] == 'X'
|
||||
self.state[index] = 'O'
|
||||
else
|
||||
self.state[index] = 'X'
|
||||
end
|
||||
end
|
||||
|
||||
def letter_at(letter_number)
|
||||
self.state[letter_number - 1]
|
||||
end
|
||||
end
|
||||
|
||||
def print_welcome
|
||||
puts 'FLIPFLOP'.center(72)
|
||||
puts 'CREATIVE COMPUTING MORRISTOWN, NEW JERSEY'.center(72)
|
||||
puts <<~EOS
|
||||
|
||||
THE OBJECT OF THIS PUZZLE IS TO CHANGE THIS:
|
||||
|
||||
X X X X X X X X X X
|
||||
|
||||
TO THIS:
|
||||
|
||||
O O O O O O O O O O
|
||||
|
||||
BY TYPING THE NUMBER CORRESPONDING TO THE POSITION OF THE
|
||||
LETTER ON SOME NUMBERS, ONE POSITION WILL CHANGE, ON
|
||||
OTHERS, TWO WILL CHANGE. TO RESET LINE TO ALL X'S, TYPE 0
|
||||
(ZERO) AND TO START OVER IN THE MIDDLE OF A GAME, TYPE
|
||||
11 (ELEVEN).
|
||||
EOS
|
||||
end
|
||||
|
||||
def print_starting_message
|
||||
puts <<~EOS
|
||||
|
||||
HERE IS THE STARTING LINE OF X'S.
|
||||
|
||||
1 2 3 4 5 6 7 8 9 10
|
||||
X X X X X X X X X X
|
||||
|
||||
EOS
|
||||
end
|
||||
|
||||
#Create a new game with [X,X,X,X,X,X,X,X,X,X] as the state
|
||||
#0 as the number of guesses and a random seed between 0 and 1
|
||||
def generate_new_game
|
||||
Game.new(Array.new(10, 'X'), 0, rand())
|
||||
end
|
||||
|
||||
#Given a game, an index, and a shuffle function, flip one or more letters
|
||||
def shuffle_board(game, index, shuffle_function)
|
||||
n = method(shuffle_function).call(game, index)
|
||||
|
||||
if game.letter_at(n) == "O"
|
||||
game.flip_letter(n)
|
||||
if index == n
|
||||
n = shuffle_board(game, index, shuffle_function)
|
||||
end
|
||||
else
|
||||
game.flip_letter(n)
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
#Shuffle logic copied from original BASIC code
|
||||
def shuffle_function1(game, index)
|
||||
r = Math.tan(game.seed + index / game.seed - index) - Math.sin(game.seed / index) + 336 * Math.sin(8 * index)
|
||||
n = r - r.floor
|
||||
(10 * n).floor
|
||||
end
|
||||
|
||||
def shuffle_function2(game, index)
|
||||
r = 0.592 * (1/ Math.tan(game.seed / index + game.seed)) / Math.sin(index * 2 + game.seed) - Math.cos(index)
|
||||
n = r - r.floor
|
||||
(10 * n)
|
||||
end
|
||||
|
||||
def play_game
|
||||
print_starting_message
|
||||
game = generate_new_game
|
||||
working_index = nil
|
||||
|
||||
loop do
|
||||
puts "INPUT THE NUMBER"
|
||||
input = gets.chomp.downcase
|
||||
|
||||
#See if the user input a valid integer, fail otherwise
|
||||
if numeric_input = Integer(input, exception: false)
|
||||
|
||||
#If 11 is entered, we're done with this version of the game
|
||||
if numeric_input == 11
|
||||
return :restart
|
||||
end
|
||||
|
||||
if numeric_input > 11
|
||||
puts 'ILLEGAL ENTRY--TRY AGAIN.'
|
||||
next #illegal entries don't count towards your guesses
|
||||
end
|
||||
|
||||
if working_index == numeric_input
|
||||
game.flip_letter(numeric_input)
|
||||
working_index = shuffle_board(game, numeric_input, :shuffle_function2)
|
||||
#If 0 is entered, we want to reset the state, but not the random seed or number of guesses and keep playing
|
||||
elsif numeric_input == 0
|
||||
game.state = Array.new(10, 'X')
|
||||
elsif game.letter_at(numeric_input) == "O"
|
||||
game.flip_letter(numeric_input)
|
||||
if numeric_input == working_index
|
||||
working_index = shuffle_board(game, numeric_input, :shuffle_function1)
|
||||
end
|
||||
else
|
||||
game.flip_letter(numeric_input)
|
||||
working_index = shuffle_board(game, numeric_input, :shuffle_function1)
|
||||
end
|
||||
else
|
||||
puts 'ILLEGAL ENTRY--TRY AGAIN.'
|
||||
next #illegal entries don't count towards your guesses
|
||||
end
|
||||
|
||||
game.guesses += 1
|
||||
puts '1 2 3 4 5 6 7 8 9 10'
|
||||
puts game.state.join(' ')
|
||||
|
||||
if game.state.all? { |x| x == 'O' }
|
||||
if game.guesses > 12
|
||||
puts "TRY HARDER NEXT TIME. IT TOOK YOU #{game.guesses} GUESSES."
|
||||
else
|
||||
puts "VERY GOOD. YOU GUESSED IT IN ONLY #{game.guesses} GUESSES."
|
||||
end
|
||||
#game is complete
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
#Execution starts
|
||||
print_welcome
|
||||
loop do
|
||||
result = play_game
|
||||
if result == :restart
|
||||
next
|
||||
end
|
||||
|
||||
puts 'DO YOU WANT TO TRY ANOTHER PUZZLE'
|
||||
if gets.chomp.downcase[0] == 'n'
|
||||
break
|
||||
end
|
||||
end
|
||||
@@ -21,6 +21,6 @@ As published in Basic Computer Games (1978):
|
||||
Downloaded from Vintage Basic at
|
||||
http://www.vintage-basic.net/games.html
|
||||
|
||||
[Port to C language](https://github.com/beyonddream/hamurabi)
|
||||
|
||||
[Port to Rust language](https://github.com/beyonddream/hamurabi.rs)
|
||||
#### External Links
|
||||
- C: https://github.com/beyonddream/hamurabi
|
||||
- Rust: https://github.com/beyonddream/hamurabi.rs
|
||||
|
||||
223
44_Hangman/perl/hangman.pl
Executable file
223
44_Hangman/perl/hangman.pl
Executable file
@@ -0,0 +1,223 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
|
||||
# global variables defined here
|
||||
|
||||
my(@WORDS) = qw(
|
||||
GUM SIN FOR CRY LUG BYE FLY
|
||||
UGLY EACH FROM WORK TALK WITH SELF
|
||||
PIZZA THING FEIGN FIEND ELBOW FAULT DIRTY
|
||||
BUDGET SPIRIT QUAINT MAIDEN ESCORT PICKAX
|
||||
EXAMPLE TENSION QUININE KIDNEY REPLICA SLEEPER
|
||||
TRIANGLE KANGAROO MAHOGANY SERGEANT SEQUENCE
|
||||
MOUSTACHE DANGEROUS SCIENTIST DIFFERENT QUIESCENT
|
||||
MAGISTRATE ERRONEOUSLY LOUDSPEAKER PHYTOTOXIC
|
||||
MATRIMONIAL PARASYMPATHOMIMETIC THIGMOTROPISM
|
||||
);
|
||||
my(@PIC,$board,@guessedLetters,$guessCount,$hangCount);
|
||||
my(%GUESSED);
|
||||
|
||||
# Subroutines defined here.
|
||||
|
||||
# init_variables: initialize all of the variables needed
|
||||
# (this covers lines 50-90 in the original BASIC program)
|
||||
|
||||
sub init_variables {
|
||||
@guessedLetters = ();
|
||||
@PIC = (
|
||||
'XXXXXXX ',
|
||||
'X X ',
|
||||
'X ',
|
||||
'X ',
|
||||
'X ',
|
||||
'X ',
|
||||
'X ',
|
||||
'X ',
|
||||
'X ',
|
||||
'X ',
|
||||
'X ',
|
||||
'X ',
|
||||
);
|
||||
$guessCount = 0; %GUESSED = ();
|
||||
$hangCount = 0;
|
||||
}
|
||||
|
||||
# addchar: given a row & column, put the specified char in that place in @PIC
|
||||
sub addchar {
|
||||
my($row,$col, $c) = @_;
|
||||
|
||||
substr($PIC[$row],$col,1) = $c;
|
||||
}
|
||||
|
||||
|
||||
# main code starts here
|
||||
|
||||
print ' 'x31; print "Hangman\n";
|
||||
print ' 'x14; print "Creative Computing Morristown, New Jersey\n\n\n\n";
|
||||
|
||||
# an iteration of the PLAY block is one complete game.
|
||||
# There is a continue block that will ask if the user
|
||||
# wants to play another game.
|
||||
|
||||
PLAY: while (1) {
|
||||
|
||||
init_variables();
|
||||
# Any words left?
|
||||
if (@WORDS == 0) {
|
||||
print "You did all the words!\n";
|
||||
last PLAY;
|
||||
}
|
||||
# splice a random word out of the @WORDS array
|
||||
my($thisWord) = splice(@WORDS, int(rand(scalar @WORDS)),1);
|
||||
# $board is the "game board" of the filled-out word
|
||||
# that the user is working on
|
||||
$board = '.'x(length $thisWord);
|
||||
|
||||
# GUESS loop is run for every time the user guesses a letter
|
||||
GUESS: while(1) {
|
||||
print "Here are the letters you used:\n";
|
||||
printf("%s\n", join(',',@guessedLetters));
|
||||
printf("\n\n%s\n", $board);
|
||||
|
||||
print "What is your guess for a letter ? ";
|
||||
chomp(my $guess = <STDIN>);
|
||||
# The %GUESSED hash allows us to quickly identify
|
||||
# letters that have already been guessed
|
||||
if ($GUESSED{lc $guess}) {
|
||||
print "You guessed that letter before!\n\n";
|
||||
redo GUESS;
|
||||
}
|
||||
|
||||
# save the guessed letter
|
||||
push @guessedLetters, $guess;
|
||||
$GUESSED{lc $guess} = 1;
|
||||
++$guessCount;
|
||||
|
||||
# now look for the letter in the $thisWord var
|
||||
# and put it into the $board var wherever it
|
||||
# shows up. $foundLetter is a flag that indicates
|
||||
# whether or not the letter is found.
|
||||
my $foundLetter = 0;
|
||||
for (my $i = 0; $i < length $thisWord; ++$i) {
|
||||
if (lc substr($thisWord,$i,1) eq lc $guess) {
|
||||
$foundLetter = 1;
|
||||
substr($board, $i, 1) = substr($thisWord, $i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
# The user found a letter in the solution!
|
||||
if ($foundLetter) {
|
||||
|
||||
# Are there any '.' chars left in the board?
|
||||
if (index($board, '.') < 0) {
|
||||
print "You found the word!\n\n";
|
||||
} else {
|
||||
printf("%s\n\n", $board);
|
||||
print "What is your guess for the word ? ";
|
||||
chomp(my $guessword = <STDIN>);
|
||||
if (lc $thisWord ne lc $guessword) {
|
||||
print "Wrong. Try another letter.\n";
|
||||
# Go to the next iteration of the GUESS loop
|
||||
next GUESS;
|
||||
}
|
||||
printf("Right! It took you %d %s!\n", $guessCount, ($guessCount == 1 ? 'guess' : 'guesses'));
|
||||
}
|
||||
# At this point the user has discovered the word and won.
|
||||
# This "next" statement takes execution down to the
|
||||
# continue block for the PLAY loop;
|
||||
next PLAY;
|
||||
|
||||
} else { # didn't find a letter
|
||||
|
||||
++$hangCount;
|
||||
print "\n\n\nSorry, that letter isn't in the word.\n";
|
||||
|
||||
# The addchar() calls in the block below piece together the
|
||||
# hangman graphic, depending on how many wrong letters
|
||||
# the user has.
|
||||
if ($hangCount == 1) {
|
||||
print "First, we draw a head\n";
|
||||
addchar(2,5,"-");addchar(2,6,"-");addchar(2,7,"-");
|
||||
addchar(3,4,"("); addchar(3,5,"."); addchar(3,7,"."); addchar(3,8,")");
|
||||
addchar(4,5,"-");addchar(4,6,"-");addchar(4,7,"-");
|
||||
}
|
||||
if ($hangCount == 2) {
|
||||
print "Now we draw a body.\n";
|
||||
for (5 .. 8) {
|
||||
addchar($_, 6, "X");
|
||||
}
|
||||
}
|
||||
if ($hangCount == 3) {
|
||||
print "Next we draw an arm.\n";
|
||||
for (3 .. 6) {
|
||||
addchar($_, $_-1, "\\");
|
||||
}
|
||||
}
|
||||
if ($hangCount == 4) {
|
||||
print "This time it's the other arm.\n";
|
||||
addchar(3,10, "/");
|
||||
addchar(4, 9, "/");
|
||||
addchar(5, 8, "/");
|
||||
addchar(6, 7, "/");
|
||||
}
|
||||
if ($hangCount == 5) {
|
||||
print "Now, let's draw the right leg.\n";
|
||||
addchar( 9,5, "/");
|
||||
addchar(10,4, "/");
|
||||
}
|
||||
if ($hangCount == 6) {
|
||||
print "This time we draw the left leg.\n";
|
||||
addchar(9,7,"\\");
|
||||
addchar(10,8,"\\");
|
||||
}
|
||||
if ($hangCount == 7) {
|
||||
print "Now we put up a hand.\n";
|
||||
addchar(2,10,"\\");
|
||||
}
|
||||
if ($hangCount == 8) {
|
||||
print "Next the other hand.\n";
|
||||
addchar(2,2,"/");
|
||||
}
|
||||
if ($hangCount == 9) {
|
||||
print "Now we draw one foot\n";
|
||||
addchar(11,9,"\\");
|
||||
addchar(11,10, "-");
|
||||
}
|
||||
if ($hangCount == 10) {
|
||||
print "Here's the other foot -- you're hung!!\n";
|
||||
addchar(11,2,"-");
|
||||
addchar(11,3, "/");
|
||||
}
|
||||
|
||||
printf("$_\n") for @PIC;
|
||||
print "\n\n";
|
||||
|
||||
# Next guess if the user has not lost
|
||||
if ($hangCount < 10) {
|
||||
next GUESS;
|
||||
}
|
||||
|
||||
printf("Sorry, you lose. The word was %s\n", $thisWord);
|
||||
next PLAY;
|
||||
|
||||
} # didn't find a letter block
|
||||
} # GUESS block
|
||||
} # PLAY block
|
||||
|
||||
# This block is reached either by the player winning (see the "next PLAY")
|
||||
# statement) or by the user losing (as the PLAY block is complete and
|
||||
# execution naturally comes to this continue block).
|
||||
continue {
|
||||
print "Want another word ? ";
|
||||
chomp(my $in = <STDIN>);
|
||||
if ($in !~ m/^y/i) {
|
||||
# Exit the PLAY loop
|
||||
print "\nIt's been fun! Bye for now.\n\n";
|
||||
last PLAY;
|
||||
}
|
||||
# At this point execution goes to the start of the PLAY block,
|
||||
# meaning a new game
|
||||
}
|
||||
153
48_High_IQ/java/src/HighIQ.java
Normal file
153
48_High_IQ/java/src/HighIQ.java
Normal file
@@ -0,0 +1,153 @@
|
||||
import java.io.PrintStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* Game of HighIQ
|
||||
* <p>
|
||||
* Based on the Basic Game of HighIQ Here:
|
||||
* https://github.com/coding-horror/basic-computer-games/blob/main/48_High_IQ/highiq.bas
|
||||
*
|
||||
* No additional functionality has been added
|
||||
*/
|
||||
public class HighIQ {
|
||||
|
||||
//Game board, as a map of position numbers to their values
|
||||
private final Map<Integer, Boolean> board;
|
||||
|
||||
//Output stream
|
||||
private final PrintStream out;
|
||||
|
||||
//Input scanner to use
|
||||
private final Scanner scanner;
|
||||
|
||||
|
||||
public HighIQ(Scanner scanner) {
|
||||
out = System.out;
|
||||
this.scanner = scanner;
|
||||
board = new HashMap<>();
|
||||
|
||||
//Set of all locations to put initial pegs on
|
||||
int[] locations = new int[]{
|
||||
13, 14, 15, 22, 23, 24, 29, 30, 31, 32, 33, 34, 35, 38, 39, 40, 42, 43, 44, 47, 48, 49, 50, 51, 52, 53, 58, 59, 60, 67, 68, 69
|
||||
};
|
||||
|
||||
for (int i : locations) {
|
||||
board.put(i, true);
|
||||
}
|
||||
|
||||
board.put(41, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays the actual game, from start to finish.
|
||||
*/
|
||||
public void play() {
|
||||
do {
|
||||
printBoard();
|
||||
while (!move()) {
|
||||
out.println("ILLEGAL MOVE, TRY AGAIN...");
|
||||
}
|
||||
} while (!isGameFinished());
|
||||
|
||||
int pegCount = 0;
|
||||
for (Integer key : board.keySet()) {
|
||||
if (board.getOrDefault(key, false)) {
|
||||
pegCount++;
|
||||
}
|
||||
}
|
||||
|
||||
out.println("YOU HAD " + pegCount + " PEGS REMAINING");
|
||||
|
||||
if (pegCount == 1) {
|
||||
out.println("BRAVO! YOU MADE A PERFECT SCORE!");
|
||||
out.println("SAVE THIS PAPER AS A RECORD OF YOUR ACCOMPLISHMENT!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes an individual move
|
||||
* @return True if the move was valid, false if the user made an error and the move is invalid
|
||||
*/
|
||||
public boolean move() {
|
||||
out.println("MOVE WHICH PIECE");
|
||||
int from = scanner.nextInt();
|
||||
|
||||
//using the getOrDefault, which will make the statement false if it is an invalid position
|
||||
if (!board.getOrDefault(from, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out.println("TO WHERE");
|
||||
int to = scanner.nextInt();
|
||||
|
||||
if (board.getOrDefault(to, true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Do nothing if they are the same
|
||||
if (from == to) {
|
||||
return true;
|
||||
}
|
||||
|
||||
//using the difference to check if the relative locations are valid
|
||||
int difference = Math.abs(to - from);
|
||||
if (difference != 2 && difference != 18) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//check if there is a peg between from and to
|
||||
if (!board.getOrDefault((to + from) / 2, false)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Actually move
|
||||
board.put(from,false);
|
||||
board.put(to,true);
|
||||
board.put((from + to) / 2, false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the game is finished
|
||||
* @return True if there are no more moves, False otherwise
|
||||
*/
|
||||
public boolean isGameFinished() {
|
||||
for (Integer key : board.keySet()) {
|
||||
if (board.get(key)) {
|
||||
//Spacing is either 1 or 9
|
||||
//Looking to the right and down from every point, checking for both directions of movement
|
||||
for (int space : new int[]{1, 9}) {
|
||||
Boolean nextToPeg = board.getOrDefault(key + space, false);
|
||||
Boolean hasMovableSpace = !board.getOrDefault(key - space, true) || !board.getOrDefault(key + space * 2, true);
|
||||
if (nextToPeg && hasMovableSpace) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void printBoard() {
|
||||
for (int i = 0; i < 7; i++) {
|
||||
for (int j = 11; j < 18; j++) {
|
||||
out.print(getChar(j + 9 * i));
|
||||
}
|
||||
out.println();
|
||||
}
|
||||
}
|
||||
|
||||
private char getChar(int position) {
|
||||
Boolean value = board.get(position);
|
||||
if (value == null) {
|
||||
return ' ';
|
||||
} else if (value) {
|
||||
return '!';
|
||||
} else {
|
||||
return 'O';
|
||||
}
|
||||
}
|
||||
}
|
||||
37
48_High_IQ/java/src/HighIQGame.java
Normal file
37
48_High_IQ/java/src/HighIQGame.java
Normal file
@@ -0,0 +1,37 @@
|
||||
import java.util.Scanner;
|
||||
|
||||
public class HighIQGame {
|
||||
public static void main(String[] args) {
|
||||
|
||||
printInstructions();
|
||||
|
||||
Scanner scanner = new Scanner(System.in);
|
||||
do {
|
||||
new HighIQ(scanner).play();
|
||||
System.out.println("PLAY AGAIN (YES OR NO)");
|
||||
} while(scanner.nextLine().equalsIgnoreCase("yes"));
|
||||
}
|
||||
|
||||
public static void printInstructions() {
|
||||
System.out.println("\t\t\t H-I-Q");
|
||||
System.out.println("CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
System.out.println("HERE IS THE BOARD:");
|
||||
System.out.println(" ! ! !");
|
||||
System.out.println(" 13 14 15\n");
|
||||
System.out.println(" ! ! !");
|
||||
System.out.println(" 22 23 24\n");
|
||||
System.out.println("! ! ! ! ! ! !");
|
||||
System.out.println("29 30 31 32 33 34 35\n");
|
||||
System.out.println("! ! ! ! ! ! !");
|
||||
System.out.println("38 39 40 41 42 43 44\n");
|
||||
System.out.println("! ! ! ! ! ! !");
|
||||
System.out.println("47 48 49 50 51 52 53\n");
|
||||
System.out.println(" ! ! !");
|
||||
System.out.println(" 58 59 60\n");
|
||||
System.out.println(" ! ! !");
|
||||
System.out.println(" 67 68 69");
|
||||
System.out.println("TO SAVE TYPING TIME, A COMPRESSED VERSION OF THE GAME BOARD");
|
||||
System.out.println("WILL BE USED DURING PLAY. REFER TO THE ABOVE ONE FOR PEG");
|
||||
System.out.println("NUMBERS. OK, LET'S BEGIN.");
|
||||
}
|
||||
}
|
||||
@@ -5,40 +5,37 @@ print ' 'x33 . "LETTER\n";
|
||||
print ' 'x15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n";
|
||||
print "\n\n\n";
|
||||
|
||||
print "LETTER GUESSING GAME\n"; print "\n";
|
||||
print "LETTER GUESSING GAME\n\n";
|
||||
print "I'LL THINK OF A LETTER OF THE ALPHABET, A TO Z.\n";
|
||||
print "TRY TO GUESS MY LETTER AND I'LL GIVE YOU CLUES\n";
|
||||
print "AS TO HOW CLOSE YOU'RE GETTING TO MY LETTER.\n";
|
||||
|
||||
my $A;
|
||||
while (1) {
|
||||
my $L= 65+int(rand(1)*26);
|
||||
my $G= 0;
|
||||
print "\n"; print "O.K., I HAVE A LETTER. START GUESSING.\n";
|
||||
my $letter = 65 + int(rand(26));
|
||||
my $guesses = 0;
|
||||
print "\nO.K., I HAVE A LETTER. START GUESSING.\n";
|
||||
|
||||
my $answer;
|
||||
do {
|
||||
print "\n"; print "WHAT IS YOUR GUESS? ";
|
||||
$G=$G+1;
|
||||
chomp($A= <STDIN>);
|
||||
$A= ord($A);
|
||||
print "\nWHAT IS YOUR GUESS? ";
|
||||
$guesses++;
|
||||
chomp($answer = <STDIN>);
|
||||
$answer = ord($answer);
|
||||
print "\n";
|
||||
if ($A<$L) { print "TOO LOW. TRY A HIGHER LETTER.\n"; }
|
||||
if ($A>$L) { print "TOO HIGH. TRY A LOWER LETTER.\n"; }
|
||||
} until($A eq $L);
|
||||
print "TOO LOW. TRY A HIGHER LETTER.\n" if $answer < $letter;
|
||||
print "TOO HIGH. TRY A LOWER LETTER.\n" if $answer > $letter;
|
||||
} until($answer eq $letter);
|
||||
|
||||
print "\n"; print "YOU GOT IT IN $G GUESSES!!\n";
|
||||
print "\nYOU GOT IT IN $guesses GUESSES!!\n";
|
||||
|
||||
if ($G<=5) {
|
||||
if ($guesses <= 5) {
|
||||
print "GOOD JOB !!!!!\n";
|
||||
for (my $N=1; $N<=15; $N++) { print chr(7); } #ASCII Bell.
|
||||
} else {
|
||||
print chr(7) x 15; # ASCII Bell
|
||||
} else {
|
||||
print "BUT IT SHOULDN'T TAKE MORE THAN 5 GUESSES!\n";
|
||||
}
|
||||
|
||||
print "\n";
|
||||
print "LET'S PLAN AGAIN.....\n";
|
||||
}
|
||||
|
||||
print "\nLET'S PLAY AGAIN.....\n";
|
||||
}
|
||||
|
||||
exit;
|
||||
|
||||
|
||||
|
||||
96
62_Mugwump/perl/mugwump.pl
Executable file
96
62_Mugwump/perl/mugwump.pl
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
# global variables defined here
|
||||
my(@MUGWUMP) = ();
|
||||
|
||||
# subroutines defined here
|
||||
|
||||
# init_mugwump: pick the random places for the Mugwumps
|
||||
sub init_mugwump() {
|
||||
@MUGWUMP = ();
|
||||
for (1 .. 4) {
|
||||
push @MUGWUMP, [ int(rand 10), int(rand 10) ];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# main code starts here
|
||||
|
||||
# print introductory text
|
||||
print <<HERE;
|
||||
Mugwump
|
||||
Creative Computing Morristown, New Jersey
|
||||
|
||||
|
||||
|
||||
The object of this game is to find four Mugwumps
|
||||
hidden on a 10 by 10 grid. Homebase is position 0,0.
|
||||
Any guess you make must be two numbers with each
|
||||
number between 0 and 9, inclusive. First number
|
||||
is distance to right of homebase and second number
|
||||
is distance above homebase.
|
||||
|
||||
You get 10 tries. After each try, I will tell
|
||||
you how far you are from each Mugwump.
|
||||
|
||||
HERE
|
||||
|
||||
|
||||
# PLAY block implements a complete game, and the
|
||||
# continue block prints the "let's play again" msg
|
||||
PLAY: while (1) {
|
||||
|
||||
init_mugwump();
|
||||
TURN: for my $turn (1 .. 10) {
|
||||
|
||||
printf("\nTurn no %d -- what is your guess ? ", $turn);
|
||||
|
||||
# Note that parsing of input is rudimentary, in keeping with the
|
||||
# spirit of the original BASIC program. Increased input checks
|
||||
# would be a good place to start working on this program!
|
||||
chomp(my $in = <STDIN>);
|
||||
my($M,$N) = split(/,/,$in);
|
||||
$M = int($M);
|
||||
$N = int($N);
|
||||
|
||||
for my $i (0 .. $#MUGWUMP) {
|
||||
# -1 indicates a Mugwump that was already found
|
||||
next if $MUGWUMP[$i]->[0] == -1;
|
||||
|
||||
if ($MUGWUMP[$i]->[0] == $M && $MUGWUMP[$i]->[1] == $N) {
|
||||
$MUGWUMP[$i]->[0] = -1;
|
||||
printf("You have found Mugwump %d\n", $i+1);
|
||||
} else {
|
||||
my $d = sqrt(($MUGWUMP[$i]->[0] - $M) ** 2 + ($MUGWUMP[$i]->[1] - $N) ** 2);
|
||||
printf("You are %.1f units away from Mugwump %d\n", $d, $i+1);
|
||||
}
|
||||
}
|
||||
|
||||
# If a Mugwump still has not been found,
|
||||
# go to the next turn
|
||||
for my $j (0 .. $#MUGWUMP) {
|
||||
if ($MUGWUMP[$j]->[0] != -1) {
|
||||
next TURN;
|
||||
}
|
||||
}
|
||||
# You win!
|
||||
printf("You got all of them in %d %s!\n\n", $turn, ($turn == 1 ? 'turn' : 'turns'));
|
||||
# Pass execution down to the continue block
|
||||
next PLAY;
|
||||
|
||||
} # end of TURN loop
|
||||
|
||||
print "\nSorry, that's 10 tries. Here's where they're hiding:\n";
|
||||
for my $i (0 .. $#MUGWUMP) {
|
||||
printf("Mugwump %d is at (%d, %d)\n", $i+1, $MUGWUMP[$i]->[0], $MUGWUMP[$i]->[1])
|
||||
if $MUGWUMP[$i]->[0] != -1;
|
||||
}
|
||||
}
|
||||
continue {
|
||||
print "\nThat was fun! Let's play again.......\n";
|
||||
print "Four more Mugwumps are now in hiding.\n\n";
|
||||
}
|
||||
|
||||
126
65_Nim/python/Traditional_NIM.py
Normal file
126
65_Nim/python/Traditional_NIM.py
Normal file
@@ -0,0 +1,126 @@
|
||||
import random
|
||||
|
||||
#Class of the Game
|
||||
class NIM:
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.Piles = {
|
||||
1 : 7,
|
||||
2 : 5,
|
||||
3 : 3,
|
||||
4 : 1
|
||||
}
|
||||
|
||||
def Remove_pegs(self, command):
|
||||
|
||||
try:
|
||||
|
||||
pile, num = command.split(',')
|
||||
num = int(num)
|
||||
pile = int(pile)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
if 'not enough values' in str(e):
|
||||
print('\nNot a valid command. Your command should be in the form of "1,3", Try Again\n')
|
||||
|
||||
else:
|
||||
print('\nError, Try again\n')
|
||||
return None
|
||||
|
||||
if self._command_integrity(num, pile) == True:
|
||||
self.Piles[pile] -= num
|
||||
else:
|
||||
print('\nInvalid value of either Peg or Pile\n')
|
||||
|
||||
def get_AI_move(self):
|
||||
|
||||
possible_pile = []
|
||||
for k,v in self.Piles.items():
|
||||
if v != 0:
|
||||
possible_pile.append(k)
|
||||
|
||||
pile = random.choice(possible_pile)
|
||||
|
||||
num = random.randint(1,self.Piles[pile])
|
||||
|
||||
return pile, num
|
||||
|
||||
def _command_integrity(self, num, pile):
|
||||
|
||||
if pile <= 4 and pile >= 1:
|
||||
if num <= self.Piles[pile]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def print_pegs(self):
|
||||
|
||||
for pile, peg in self.Piles.items():
|
||||
print('Pile {} : {}'.format(pile, 'O '*peg))
|
||||
|
||||
def Help(self):
|
||||
|
||||
print('-'*10)
|
||||
print('\nThe Game is player with a number of Piles of Objects("O" == one peg)')
|
||||
print('\nThe Piles are arranged as given below(Tradional NIM)\n')
|
||||
self.print_pegs()
|
||||
print('\nAny Number of of Objects are removed one pile by "YOU" and the machine alternatively')
|
||||
print('\nOn your turn, you may take all the objects that remain in any pile')
|
||||
print('but you must take ATLEAST one object')
|
||||
print('\nAnd you may take objects from only one pile on a single turn.')
|
||||
print('\nThe winner is defined as the one that picks the last remaning object')
|
||||
print('-'*10)
|
||||
|
||||
def Checkforwin(self):
|
||||
|
||||
sum = 0
|
||||
for k,v in self.Piles.items():
|
||||
sum += v
|
||||
|
||||
if sum == 0:
|
||||
return True
|
||||
|
||||
else:
|
||||
return False
|
||||
|
||||
#main program
|
||||
if __name__ == "__main__":
|
||||
|
||||
#Game initialization
|
||||
game = NIM()
|
||||
|
||||
print('Hello, This is a game of NIM')
|
||||
help = input('Do You Need Instruction (YES or NO): ')
|
||||
|
||||
if help == 'yes' or help == 'YES' or help == 'Yes':
|
||||
|
||||
#Printing Game Instruction
|
||||
game.Help()
|
||||
|
||||
#Start game loop
|
||||
input('\nPress Enter to start the Game:\n')
|
||||
End = False
|
||||
while True:
|
||||
|
||||
game.print_pegs()
|
||||
|
||||
#Players Move
|
||||
command = input('\nYOUR MOVE - Number of PILE, Number of Object? ')
|
||||
game.Remove_pegs(command)
|
||||
End = game.Checkforwin()
|
||||
if End == True:
|
||||
print('\nPlayer Wins the Game, Congratulations!!')
|
||||
input('\nPress any key to exit')
|
||||
break
|
||||
|
||||
#Computers Move
|
||||
command = game.get_AI_move()
|
||||
print('\nA.I MOVE - A.I Removed {} pegs from Pile {}'.format(command[1],command[0]))
|
||||
game.Remove_pegs(str(command[0]) +',' + str(command[1]))
|
||||
End = game.Checkforwin()
|
||||
if End == True:
|
||||
print('\nComputer Wins the Game, Better Luck Next Time\n')
|
||||
input('Press any key to exit')
|
||||
break
|
||||
@@ -1,3 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Oracle Java](https://openjdk.java.net/)
|
||||
Conversion to [Java](https://openjdk.java.net/)
|
||||
|
||||
357
81_Splat/java/src/Splat.java
Normal file
357
81_Splat/java/src/Splat.java
Normal file
@@ -0,0 +1,357 @@
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* SPLAT simulates a parachute jump in which you try to open your parachute at the last possible moment without going
|
||||
* splat! You may select your own terminal velocity or let the computer do it for you. You many also select the
|
||||
* acceleration due to gravity or, again, let the computer do it in which case you might wind up on any of eight
|
||||
* planets (out to Neptune), the moon, or the sun.
|
||||
* <p>
|
||||
* The computer then tells you the height you’re jumping from and asks for the seconds of free fall. It then divides
|
||||
* your free fall time into eight intervals and gives you progress reports on your way down. The computer also keeps
|
||||
* track of all prior jumps in the array A and lets you know how you compared with previous successful jumps. If you
|
||||
* want to recall information from previous runs, then you should store array A in a disk or take file and read it
|
||||
* before each run.
|
||||
* <p>
|
||||
* John Yegge created this program while at the Oak Ridge Associated Universities.
|
||||
* <p>
|
||||
* Ported from BASIC by jason plumb (@breedx2)
|
||||
* </p>
|
||||
*/
|
||||
public class Splat {
|
||||
private static final Random random = new Random();
|
||||
private final Scanner scanner = new Scanner(System.in);
|
||||
private final List<Float> pastSuccessfulJumpDistances = new ArrayList<>();
|
||||
|
||||
public static void main(String[] args) {
|
||||
new Splat().run();
|
||||
}
|
||||
|
||||
public void run() {
|
||||
showIntroduction();
|
||||
|
||||
while (true) {
|
||||
|
||||
InitialJumpConditions initial = buildInitialConditions();
|
||||
|
||||
System.out.println();
|
||||
System.out.printf(" ALTITUDE = %d FT\n", initial.getAltitude());
|
||||
System.out.printf(" TERM. VELOCITY = %.2f FT/SEC +/-5%%\n", initial.getOriginalTerminalVelocity());
|
||||
System.out.printf(" ACCELERATION = %.2f FT/SEC/SEC +/-5%%\n", initial.getOriginalAcceleration());
|
||||
|
||||
System.out.println("SET THE TIMER FOR YOUR FREEFALL.");
|
||||
float freefallTime = promptFloat("HOW MANY SECONDS ");
|
||||
System.out.println("HERE WE GO.\n");
|
||||
System.out.println("TIME (SEC) DIST TO FALL (FT)");
|
||||
System.out.println("========== =================");
|
||||
|
||||
JumpResult jump = executeJump(initial, freefallTime);
|
||||
showJumpResults(initial, jump);
|
||||
|
||||
if (!playAgain()) {
|
||||
System.out.println("SSSSSSSSSS.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showIntroduction() {
|
||||
System.out.printf("%33s%s\n", " ", "SPLAT");
|
||||
System.out.printf("%15s%s\n", " ", "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY");
|
||||
System.out.print("\n\n\n");
|
||||
System.out.println("WELCOME TO 'SPLAT' -- THE GAME THAT SIMULATES A PARACHUTE");
|
||||
System.out.println("JUMP. TRY TO OPEN YOUR CHUTE AT THE LAST POSSIBLE");
|
||||
System.out.println("MOMENT WITHOUT GOING SPLAT.");
|
||||
}
|
||||
|
||||
private InitialJumpConditions buildInitialConditions() {
|
||||
System.out.print("\n\n");
|
||||
float terminalVelocity = promptTerminalVelocity();
|
||||
float acceleration = promptGravitationalAcceleration();
|
||||
return InitialJumpConditions.create(terminalVelocity, acceleration);
|
||||
}
|
||||
|
||||
private float promptTerminalVelocity() {
|
||||
if (askYesNo("SELECT YOUR OWN TERMINAL VELOCITY")) {
|
||||
float terminalVelocity = promptFloat("WHAT TERMINAL VELOCITY (MI/HR) ");
|
||||
return mphToFeetPerSec(terminalVelocity);
|
||||
}
|
||||
float terminalVelocity = (int) (1000 * random.nextFloat());
|
||||
System.out.printf("OK. TERMINAL VELOCITY = %.2f MI/HR\n", terminalVelocity);
|
||||
return mphToFeetPerSec(terminalVelocity);
|
||||
}
|
||||
|
||||
private float promptFloat(String prompt){
|
||||
while(true){
|
||||
System.out.print(prompt);
|
||||
try {
|
||||
return scanner.nextFloat();
|
||||
} catch (Exception e) {
|
||||
scanner.next(); // clear current input
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float promptGravitationalAcceleration() {
|
||||
if (askYesNo("WANT TO SELECT ACCELERATION DUE TO GRAVITY")) {
|
||||
return promptFloat("WHAT ACCELERATION (FT/SEC/SEC) ");
|
||||
}
|
||||
return chooseRandomAcceleration();
|
||||
}
|
||||
|
||||
private JumpResult executeJump(InitialJumpConditions initial, float chuteOpenTime) {
|
||||
JumpResult jump = new JumpResult(initial.getAltitude());
|
||||
for (float time = 0.0f; time < chuteOpenTime; time += chuteOpenTime / 8) {
|
||||
if (!jump.hasReachedTerminalVelocity() && time > initial.getTimeOfTerminalAccelerationReached()) {
|
||||
jump.setReachedTerminalVelocity();
|
||||
System.out.printf("TERMINAL VELOCITY REACHED AT T PLUS %f SECONDS.\n", initial.getTimeOfTerminalAccelerationReached());
|
||||
}
|
||||
float newDistance = computeDistance(initial, time, jump.hasReachedTerminalVelocity());
|
||||
jump.setDistance(newDistance);
|
||||
|
||||
if (jump.isSplat()) {
|
||||
return jump;
|
||||
}
|
||||
System.out.printf("%10.2f %f\n", time, jump.getDistance());
|
||||
}
|
||||
return jump;
|
||||
}
|
||||
|
||||
private float computeDistance(InitialJumpConditions initial, float i, boolean hasReachedTerminalVelocity) {
|
||||
final float V = initial.getTerminalVelocity();
|
||||
final float A = initial.getAcceleration();
|
||||
if (hasReachedTerminalVelocity) {
|
||||
return initial.getAltitude() - ((V * V / (2 * A)) + (V * (i - (V / A))));
|
||||
}
|
||||
return initial.getAltitude() - ((A / 2) * i * i);
|
||||
}
|
||||
|
||||
private void showJumpResults(InitialJumpConditions initial, JumpResult jump) {
|
||||
if (jump.isSplat()) {
|
||||
showSplatMessage(initial, jump);
|
||||
showCleverSplatMessage();
|
||||
return;
|
||||
}
|
||||
System.out.println("CHUTE OPEN");
|
||||
int worseJumpCount = countWorseHistoricalJumps(jump);
|
||||
int successfulJumpCt = pastSuccessfulJumpDistances.size();
|
||||
pastSuccessfulJumpDistances.add(jump.getDistance());
|
||||
|
||||
if (pastSuccessfulJumpDistances.size() <= 2) {
|
||||
List<String> ordinals = Arrays.asList("1ST", "2ND", "3RD");
|
||||
System.out.printf("AMAZING!!! NOT BAD FOR YOUR %s SUCCESSFUL JUMP!!!\n", ordinals.get(successfulJumpCt));
|
||||
return;
|
||||
}
|
||||
|
||||
int betterThanCount = successfulJumpCt - worseJumpCount;
|
||||
if (betterThanCount <= 0.1 * successfulJumpCt) {
|
||||
System.out.printf("WOW! THAT'S SOME JUMPING. OF THE %d SUCCESSFUL JUMPS\n", successfulJumpCt);
|
||||
System.out.printf("BEFORE YOURS, ONLY %d OPENED THEIR CHUTES LOWER THAN\n", betterThanCount);
|
||||
System.out.println("YOU DID.");
|
||||
} else if (betterThanCount <= 0.25 * successfulJumpCt) {
|
||||
System.out.printf("PRETTY GOOD! %d SUCCESSFUL JUMPS PRECEDED YOURS AND ONLY\n", successfulJumpCt);
|
||||
System.out.printf("%d OF THEM GOT LOWER THAN YOU DID BEFORE THEIR CHUTES\n", betterThanCount);
|
||||
System.out.println("OPENED.");
|
||||
} else if (betterThanCount <= 0.5 * successfulJumpCt) {
|
||||
System.out.printf("NOT BAD. THERE HAVE BEEN %d SUCCESSFUL JUMPS BEFORE YOURS.\n", successfulJumpCt);
|
||||
System.out.printf("YOU WERE BEATEN OUT BY %d OF THEM.\n", betterThanCount);
|
||||
} else if (betterThanCount <= 0.75 * successfulJumpCt) {
|
||||
System.out.printf("CONSERVATIVE, AREN'T YOU? YOU RANKED ONLY %d IN THE\n", betterThanCount);
|
||||
System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS.\n", successfulJumpCt);
|
||||
} else if (betterThanCount <= -0.9 * successfulJumpCt) {
|
||||
System.out.println("HUMPH! DON'T YOU HAVE ANY SPORTING BLOOD? THERE WERE");
|
||||
System.out.printf("%d SUCCESSFUL JUMPS BEFORE YOURS AND YOU CAME IN %d JUMPS\n", successfulJumpCt, worseJumpCount);
|
||||
System.out.println("BETTER THAN THE WORST. SHAPE UP!!!\n");
|
||||
} else {
|
||||
System.out.printf("HEY! YOU PULLED THE RIP CORD MUCH TOO SOON. %d SUCCESSFUL\n", successfulJumpCt);
|
||||
System.out.printf("JUMPS BEFORE YOURS AND YOU CAME IN NUMBER %d! GET WITH IT!\n", betterThanCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void showSplatMessage(InitialJumpConditions initial, JumpResult jump) {
|
||||
double timeOfSplat = computeTimeOfSplat(initial, jump);
|
||||
System.out.printf("%10.2f SPLAT\n", timeOfSplat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of jumps for which this jump was better
|
||||
*/
|
||||
private double computeTimeOfSplat(InitialJumpConditions initial, JumpResult jump) {
|
||||
final float V = initial.getTerminalVelocity();
|
||||
final float A = initial.getAcceleration();
|
||||
if (jump.hasReachedTerminalVelocity()) {
|
||||
return (V / A) + ((initial.getAltitude() - (V * V / (2 * A))) / V);
|
||||
}
|
||||
return Math.sqrt(2 * initial.getAltitude() / A);
|
||||
}
|
||||
|
||||
private int countWorseHistoricalJumps(JumpResult jump) {
|
||||
return (int) pastSuccessfulJumpDistances.stream()
|
||||
.filter(distance -> jump.getDistance() < distance)
|
||||
.count();
|
||||
}
|
||||
|
||||
private void showCleverSplatMessage() {
|
||||
List<String> messages = Arrays.asList(
|
||||
"REQUIESCAT IN PACE.",
|
||||
"MAY THE ANGEL OF HEAVEN LEAD YOU INTO PARADISE.",
|
||||
"REST IN PEACE.",
|
||||
"SON-OF-A-GUN.",
|
||||
"#$%&&%!$",
|
||||
"A KICK IN THE PANTS IS A BOOST IF YOU'RE HEADED RIGHT.",
|
||||
"HMMM. SHOULD HAVE PICKED A SHORTER TIME.",
|
||||
"MUTTER. MUTTER. MUTTER.",
|
||||
"PUSHING UP DAISIES.",
|
||||
"EASY COME, EASY GO."
|
||||
);
|
||||
System.out.println(messages.get(random.nextInt(10)));
|
||||
}
|
||||
|
||||
private boolean playAgain() {
|
||||
if (askYesNo("DO YOU WANT TO PLAY AGAIN ")) {
|
||||
return true;
|
||||
}
|
||||
return askYesNo("PLEASE");
|
||||
}
|
||||
|
||||
private float mphToFeetPerSec(float speed) {
|
||||
return speed * (5280.0f / 3600.0f);
|
||||
}
|
||||
|
||||
private boolean askYesNo(String prompt) {
|
||||
System.out.printf("%s (YES OR NO) ", prompt);
|
||||
while (true) {
|
||||
String answer = scanner.next();
|
||||
switch (answer) {
|
||||
case "YES":
|
||||
return true;
|
||||
case "NO":
|
||||
return false;
|
||||
default:
|
||||
System.out.print("YES OR NO ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float chooseRandomAcceleration() {
|
||||
Planet planet = Planet.pickRandom();
|
||||
System.out.printf("%s %s. ACCELERATION=%.2f FT/SEC/SEC.\n", planet.getMessage(), planet.name(), planet.getAcceleration());
|
||||
return planet.getAcceleration();
|
||||
}
|
||||
|
||||
enum Planet {
|
||||
MERCURY("FINE. YOU'RE ON", 12.2f),
|
||||
VENUS("ALL RIGHT. YOU'RE ON", 28.3f),
|
||||
EARTH("THEN YOU'RE ON", 32.16f),
|
||||
MOON("FINE. YOU'RE ON THE", 5.15f),
|
||||
MARS("ALL RIGHT. YOU'RE ON", 12.5f),
|
||||
JUPITER("THEN YOU'RE ON", 85.2f),
|
||||
SATURN("FINE. YOU'RE ON", 37.6f),
|
||||
URANUS("ALL RIGHT. YOU'RE ON", 33.8f),
|
||||
NEPTUNE("THEN YOU'RE ON", 39.6f),
|
||||
SUN("FINE. YOU'RE ON THE", 896.0f);
|
||||
|
||||
private static final Random random = new Random();
|
||||
private final String message;
|
||||
private final float acceleration;
|
||||
|
||||
Planet(String message, float acceleration) {
|
||||
this.message = message;
|
||||
this.acceleration = acceleration;
|
||||
}
|
||||
|
||||
static Planet pickRandom() {
|
||||
return values()[random.nextInt(Planet.values().length)];
|
||||
}
|
||||
|
||||
String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
float getAcceleration() {
|
||||
return acceleration;
|
||||
}
|
||||
}
|
||||
|
||||
// Mutable
|
||||
static class JumpResult {
|
||||
private boolean reachedTerminalVelocity = false;
|
||||
private float distance; // from the ground
|
||||
|
||||
public JumpResult(float distance) {
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
boolean isSplat() {
|
||||
return distance <= 0;
|
||||
}
|
||||
|
||||
boolean hasReachedTerminalVelocity() {
|
||||
return reachedTerminalVelocity;
|
||||
}
|
||||
|
||||
float getDistance() {
|
||||
return distance;
|
||||
}
|
||||
|
||||
void setDistance(float distance) {
|
||||
this.distance = distance;
|
||||
}
|
||||
|
||||
void setReachedTerminalVelocity() {
|
||||
reachedTerminalVelocity = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Immutable
|
||||
static class InitialJumpConditions {
|
||||
private final float originalTerminalVelocity;
|
||||
private final float originalAcceleration;
|
||||
private final float terminalVelocity;
|
||||
private final float acceleration;
|
||||
private final int altitude;
|
||||
|
||||
private InitialJumpConditions(float originalTerminalVelocity, float originalAcceleration,
|
||||
float terminalVelocity, float acceleration, int altitude) {
|
||||
this.originalTerminalVelocity = originalTerminalVelocity;
|
||||
this.originalAcceleration = originalAcceleration;
|
||||
this.terminalVelocity = terminalVelocity;
|
||||
this.acceleration = acceleration;
|
||||
this.altitude = altitude;
|
||||
}
|
||||
|
||||
// Create initial jump conditions with adjusted velocity/acceleration and a random initial altitude
|
||||
private static InitialJumpConditions create(float terminalVelocity, float gravitationalAcceleration) {
|
||||
final int altitude = (int) (9001.0f * random.nextFloat() + 1000);
|
||||
return new InitialJumpConditions(terminalVelocity, gravitationalAcceleration,
|
||||
plusMinus5Percent(terminalVelocity), plusMinus5Percent(gravitationalAcceleration), altitude);
|
||||
}
|
||||
|
||||
private static float plusMinus5Percent(float value) {
|
||||
return value + ((value * random.nextFloat()) / 20.0f) - ((value * random.nextFloat()) / 20.0f);
|
||||
}
|
||||
|
||||
float getOriginalTerminalVelocity() {
|
||||
return originalTerminalVelocity;
|
||||
}
|
||||
|
||||
float getOriginalAcceleration() {
|
||||
return originalAcceleration;
|
||||
}
|
||||
|
||||
float getTerminalVelocity() {
|
||||
return terminalVelocity;
|
||||
}
|
||||
|
||||
float getAcceleration() {
|
||||
return acceleration;
|
||||
}
|
||||
|
||||
int getAltitude() {
|
||||
return altitude;
|
||||
}
|
||||
|
||||
float getTimeOfTerminalAccelerationReached() {
|
||||
return terminalVelocity / acceleration;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,4 +101,4 @@ Instructions in this directory at
|
||||
instructions.txt
|
||||
|
||||
#### External Links
|
||||
- Super Star Trek in C++ : https://www.codeproject.com/Articles/28399/The-Object-Oriented-Text-Star-Trek-Game-in-C
|
||||
- C++: https://www.codeproject.com/Articles/28399/The-Object-Oriented-Text-Star-Trek-Game-in-C
|
||||
|
||||
3
85_Synonym/kotlin/README.md
Normal file
3
85_Synonym/kotlin/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Original source downloaded [from Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Conversion to [Kotlin](https://kotlinlang.org/)
|
||||
73
85_Synonym/kotlin/Synonym.kt
Normal file
73
85_Synonym/kotlin/Synonym.kt
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Game of Synonym
|
||||
*
|
||||
*
|
||||
* Based on the Basic game of Synonym here
|
||||
* https://github.com/coding-horror/basic-computer-games/blob/main/85%20Synonym/synonym.bas
|
||||
*
|
||||
*
|
||||
* Note: The idea was to create a version of the 1970's Basic game in Java, without introducing
|
||||
* new features - no additional text, error checking, etc has been added.
|
||||
*/
|
||||
|
||||
fun main() {
|
||||
println(introText)
|
||||
synonyms.forEach {
|
||||
it.testUser()
|
||||
}
|
||||
println("SYNONYM DRILL COMPLETED.")
|
||||
}
|
||||
// We could put this inside of SynonymList, but this keeps the core implementation
|
||||
// right here at the top
|
||||
private fun SynonymList.testUser() {
|
||||
do {
|
||||
val answer = ask(" WHAT IS A SYNONYM OF $word ? ")
|
||||
when {
|
||||
answer == "HELP" ->
|
||||
println("""**** A SYNONYM OF $word IS ${synonyms.random()}.""")
|
||||
synonyms.contains(answer) ->
|
||||
println(AFFIRMATIONS.random())
|
||||
else ->
|
||||
println("TRY AGAIN.")
|
||||
}
|
||||
} while (!synonyms.contains(answer))
|
||||
}
|
||||
|
||||
val introText = """
|
||||
${tab(33)}SYNONYM
|
||||
${tab(15)}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||
A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH
|
||||
LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME
|
||||
MEANING.
|
||||
I CHOOSE A WORD -- YOU TYPE A SYNONYM.
|
||||
IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'
|
||||
AND I WILL TELL YOU A SYNONYM.
|
||||
|
||||
"""
|
||||
|
||||
// prints a question and reads a string (and converts to uppercase)
|
||||
private fun ask(text: String): String {
|
||||
print(text)
|
||||
return readln().uppercase()
|
||||
}
|
||||
|
||||
// Just like TAB in BASIC
|
||||
private fun tab(spaces: Int): String = " ".repeat(spaces)
|
||||
|
||||
val AFFIRMATIONS = arrayOf("RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK")
|
||||
|
||||
// List of words and synonyms
|
||||
private val synonyms = listOf(
|
||||
SynonymList("FIRST", listOf("START", "BEGINNING", "ONSET", "INITIAL")),
|
||||
SynonymList("SIMILAR", listOf("SAME", "LIKE", "RESEMBLING")),
|
||||
SynonymList("MODEL", listOf("PATTERN", "PROTOTYPE", "STANDARD", "CRITERION")),
|
||||
SynonymList("SMALL", listOf("INSIGNIFICANT", "LITTLE", "TINY", "MINUTE")),
|
||||
SynonymList("STOP", listOf("HALT", "STAY", "ARREST", "CHECK", "STANDSTILL")),
|
||||
SynonymList("HOUSE", listOf("DWELLING", "RESIDENCE", "DOMICILE", "LODGING", "HABITATION")),
|
||||
SynonymList("PIT", listOf("HOLE", "HOLLOW", "WELL", "GULF", "CHASM", "ABYSS")),
|
||||
SynonymList("PUSH", listOf("SHOVE", "THRUST", "PROD", "POKE", "BUTT", "PRESS")),
|
||||
SynonymList("RED", listOf("ROUGE", "SCARLET", "CRIMSON", "FLAME", "RUBY")),
|
||||
SynonymList("PAIN", listOf("SUFFERING", "HURT", "MISERY", "DISTRESS", "ACHE", "DISCOMFORT"))
|
||||
)
|
||||
|
||||
class SynonymList(val word: String, val synonyms: List<String>)
|
||||
94
85_Synonym/ruby/synonim.rb
Normal file
94
85_Synonym/ruby/synonim.rb
Normal file
@@ -0,0 +1,94 @@
|
||||
########################################################
|
||||
#
|
||||
# Synonym
|
||||
#
|
||||
# From Basic Computer Games (1978)
|
||||
#
|
||||
# A synonym of a word is another word (in the English language) which has the same,
|
||||
# or very nearly the same, meaning. This program tests your knowledge of synonyms
|
||||
# of a few common words.
|
||||
#
|
||||
# The computer chooses a word and asks you for a synonym. The computer then tells
|
||||
# you whether you’re right or wrong. If you can’t think of a synonym, type “HELP”
|
||||
# which causes a synonym to be printed.
|
||||
# You may put in words of your choice in the data statements.
|
||||
# The number following DATA in Statement 500 is the total number of data statements.
|
||||
# In each data statement, the first number is the number of words in that statement.
|
||||
#
|
||||
# Can you think of a way to make this into a more general kind of CAI program for any subject?
|
||||
# Walt Koetke of Lexington High School, Massachusetts created this program.
|
||||
#
|
||||
#
|
||||
########################################################
|
||||
|
||||
puts <<~INSTRUCTIONS
|
||||
SYNONYM
|
||||
CREATIVE COMPUTING MORRISTOWN, NEW JERSEY
|
||||
|
||||
A SYNONYM OF A WORD MEANS ANOTHER WORD IN THE ENGLISH
|
||||
LANGUAGE WHICH HAS THE SAME OR VERY NEARLY THE SAME MEANING.
|
||||
I CHOOSE A WORD -- YOU TYPE A SYNONYM.
|
||||
IF YOU CAN'T THINK OF A SYNONYM, TYPE THE WORD 'HELP'
|
||||
AND I WILL TELL YOU A SYNONYM.
|
||||
|
||||
|
||||
INSTRUCTIONS
|
||||
|
||||
right_words = ["RIGHT", "CORRECT", "FINE", "GOOD!", "CHECK"]
|
||||
|
||||
synonym_words = [
|
||||
["FIRST", "START", "BEGINNING", "ONSET", "INITIAL"],
|
||||
["SIMILAR", "ALIKE", "SAME", "LIKE", "RESEMBLING"],
|
||||
["MODEL", "PATTERN", "PROTOTYPE", "STANDARD", "CRITERION"],
|
||||
["SMALL", "INSIGNIFICANT", "LITTLE", "TINY", "MINUTE"],
|
||||
["STOP", "HALT", "STAY", "ARREST", "CHECK", "STANDSTILL"],
|
||||
["HOUSE", "DWELLING", "RESIDENCE", "DOMICILE", "LODGING", "HABITATION"],
|
||||
["PIT", "HOLE", "HOLLOW", "WELL", "GULF", "CHASM", "ABYSS"],
|
||||
["PUSH", "SHOVE", "THRUST", "PROD", "POKE", "BUTT", "PRESS"],
|
||||
["RED", "ROUGE", "SCARLET", "CRIMSON", "FLAME", "RUBY"],
|
||||
["PAIN", "SUFFERING", "HURT", "MISERY", "DISTRESS", "ACHE", "DISCOMFORT"],
|
||||
]
|
||||
|
||||
synonym_words.shuffle.each {|words_ar|
|
||||
|
||||
}
|
||||
|
||||
|
||||
synonym_words.each {|words_ar|
|
||||
answer = false
|
||||
keyword = words_ar.shift
|
||||
|
||||
while not answer and words_ar.length != 0
|
||||
puts " WHAT IS A SYNONYM OF #{keyword}? "
|
||||
inp = gets.chomp.upcase
|
||||
|
||||
if inp == "HELP"
|
||||
clue = words_ar.sample
|
||||
puts "**** A SYNONYM OF #{keyword} IS #{clue}."
|
||||
words_ar.delete(clue)
|
||||
elsif words_ar.include? inp
|
||||
puts right_words.sample
|
||||
answer = true
|
||||
else
|
||||
puts "TRY AGAIN."
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
}
|
||||
|
||||
puts "SYNONYM DRILL COMPLETED"
|
||||
|
||||
|
||||
######################################################################
|
||||
#
|
||||
# Porting notes
|
||||
#
|
||||
# There is a bug in the original program where if you keep asking for
|
||||
# synoyms of a given word it ends up running out of synonyms
|
||||
# in the array and the program crashes.
|
||||
# The bug has been fixed in this version and now when
|
||||
# it runs out of words it continues with the next
|
||||
# array.
|
||||
#
|
||||
######################################################################
|
||||
2
87_3-D_Plot/d/.gitignore
vendored
Normal file
2
87_3-D_Plot/d/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.exe
|
||||
*.obj
|
||||
182
87_3-D_Plot/d/README.md
Normal file
182
87_3-D_Plot/d/README.md
Normal file
@@ -0,0 +1,182 @@
|
||||
Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).
|
||||
|
||||
## Running the code
|
||||
|
||||
Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:
|
||||
```shell
|
||||
dmd -dip1000 -run threedeeplot.d
|
||||
```
|
||||
|
||||
[Other compilers](https://dlang.org/download.html) also exist.
|
||||
|
||||
## On rounding floating point values to integer values
|
||||
|
||||
The D equivalent of Basic `INT` is [`floor`](https://dlang.org/phobos/std_math_rounding.html#.floor),
|
||||
which rounds towards negative infinity. If you change occurrences of `floor` to
|
||||
[`lrint`](https://dlang.org/phobos/std_math_rounding.html#.lrint), you'll see that the plots show a bit more detail,
|
||||
as is done in the bonus below.
|
||||
|
||||
## Bonus: Self-writing programs
|
||||
|
||||
With a small modification to the source, the program can be extended to **plot a random function**, and **print its formula**.
|
||||
|
||||
```shell
|
||||
rdmd -dip1000 threedeeplot_random.d
|
||||
```
|
||||
(`rdmd` caches the executable, which results in speedy execution when the source does not change.)
|
||||
|
||||
### Example output
|
||||
```
|
||||
3D Plot
|
||||
(After Creative Computing Morristown, New Jersey)
|
||||
|
||||
|
||||
f(z) = 30 * sin(z / 10.0)
|
||||
|
||||
*
|
||||
* * * *
|
||||
* * * * *
|
||||
* * * * *
|
||||
* * * * * *
|
||||
* * * * * *
|
||||
* * * * * **
|
||||
* * * * * * *
|
||||
* * * * * * **
|
||||
* * * * * * * *
|
||||
* * * * * * * *
|
||||
* * * * * * * **
|
||||
* * * * * * * * *
|
||||
* * * * ** * * * *
|
||||
* * * * ** * * *
|
||||
* * * * * * * *
|
||||
* * * * * * * *
|
||||
* * * ** * * **
|
||||
* * * ** * **
|
||||
* * * * * **
|
||||
* * * * * **
|
||||
* * * * * **
|
||||
* * * ** * **
|
||||
* * * ** * * **
|
||||
* * * * * * * *
|
||||
* * * * * * * *
|
||||
* * * * ** * * *
|
||||
* * * * ** * * * *
|
||||
* * * * * * * * *
|
||||
* * * * * * * **
|
||||
* * * * * * * *
|
||||
* * * * * * * *
|
||||
* * * * * * **
|
||||
* * * * * * *
|
||||
* * * * * **
|
||||
* * * * * *
|
||||
* * * * * *
|
||||
* * * * *
|
||||
* * * * *
|
||||
* * * *
|
||||
*
|
||||
```
|
||||
|
||||
### Breakdown of differences
|
||||
|
||||
Have a look at the relevant differences between `threedeeplot.d` and `threedeeplot_random.d`.
|
||||
This is the original function with the single expression that is evaluated for the plot:
|
||||
```d
|
||||
static float fna(float z)
|
||||
{
|
||||
return 30.0 * exp(-z * z / 100.0);
|
||||
}
|
||||
```
|
||||
Here `static` means that the nested function does not need acces to its enclosing scope.
|
||||
|
||||
Now, by inserting the following:
|
||||
```d
|
||||
enum functions = ["30.0 * exp(-z * z / 100.0)",
|
||||
"sqrt(900.01 - z * z) * .9 - 2",
|
||||
"30 * (cos(z / 16.0) + .5)",
|
||||
"30 - 30 * sin(z / 18.0)",
|
||||
"30 * exp(-cos(z / 16.0)) - 30",
|
||||
"30 * sin(z / 10.0)"];
|
||||
|
||||
size_t index = uniform(0, functions.length);
|
||||
writeln(center("f(z) = " ~ functions[index], width), "\n");
|
||||
```
|
||||
and changing the implementation of `fna` to
|
||||
```d
|
||||
float fna(float z)
|
||||
{
|
||||
final switch (index)
|
||||
{
|
||||
static foreach (i, f; functions)
|
||||
case i:
|
||||
mixin("return " ~ f ~ ";");
|
||||
}
|
||||
}
|
||||
```
|
||||
we unlock some very special abilities of D. Let's break it down:
|
||||
|
||||
```d
|
||||
enum functions = ["30.0 * exp(-z * z / 100.0)", /*...*/];
|
||||
```
|
||||
This defines an array of strings, each containing a mathematical expression. Due to the `enum` keyword, this is an
|
||||
array that really only exists at compile-time.
|
||||
|
||||
```d
|
||||
size_t index = uniform(0, functions.length);
|
||||
```
|
||||
This defines a random index into the array. `functions.length` is evaluated at compile-time, due to D's compile-time
|
||||
function evaluation (CTFE).
|
||||
|
||||
```d
|
||||
writeln(center("f(z) = " ~ functions[index], width), "\n");
|
||||
```
|
||||
Unmistakenly, this prints the formula centered on a line. What happens behind the scenes is that `functions` (which
|
||||
only existed at compile-time before now) is pasted in, so that an instance of that array actually exists at run-time
|
||||
at this spot, and is instantly indexed.
|
||||
|
||||
```d
|
||||
float fna(float z)
|
||||
{
|
||||
final switch (index)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
}
|
||||
```
|
||||
`static` has been dropped from the nested function because we want to evaluate `index` inside it. The function contains
|
||||
an ordinary `switch`, with `final` providing some extra robustness. It disallows a `default` case and produces an error
|
||||
when the switch doesn't handle all cases. The `switch` body is where the magic happens and consists of these three
|
||||
lines:
|
||||
```d
|
||||
static foreach (i, f; functions)
|
||||
case i:
|
||||
mixin("return " ~ f ~ ";");
|
||||
```
|
||||
The `static foreach` iterates over `functions` at compile-time, producing one `case` for every element in `functions`.
|
||||
`mixin` takes a string, which is constructed at compile-time, and pastes it right into the source.
|
||||
|
||||
In effect, the implementation of `float fna(float z)` unrolls itself into
|
||||
```d
|
||||
float fna(float z)
|
||||
{
|
||||
final switch (index)
|
||||
{
|
||||
case 0:
|
||||
return 30.0 * exp(-z * z / 100.0);
|
||||
case 1:
|
||||
return sqrt(900.01 - z * z) * .9 - 2;
|
||||
case 2:
|
||||
return 30 * (cos(z / 16.0) + .5);
|
||||
case 3:
|
||||
return 30 - 30 * sin(z / 18.0);
|
||||
case 4:
|
||||
return 30 * exp(-cos(z / 16.0)) - 30;
|
||||
case 5:
|
||||
return 30 * sin(z / 10.0)";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
So if you feel like adding another function, all you need to do is append it to the `functions` array, and the rest of
|
||||
the program *rewrites itself...*
|
||||
35
87_3-D_Plot/d/threedeeplot.d
Normal file
35
87_3-D_Plot/d/threedeeplot.d
Normal file
@@ -0,0 +1,35 @@
|
||||
@safe: // Make @safe the default for this file, enforcing memory-safety.
|
||||
import std.stdio, std.string, std.math, std.range, std.conv, std.algorithm;
|
||||
|
||||
void main()
|
||||
{
|
||||
enum width = 80;
|
||||
writeln(center("3D Plot", width));
|
||||
writeln(center("(After Creative Computing Morristown, New Jersey)\n\n\n", width));
|
||||
|
||||
static float fna(float z)
|
||||
{
|
||||
return 30.0 * exp(-z * z / 100.0);
|
||||
}
|
||||
|
||||
char[] row;
|
||||
|
||||
for (float x = -30.0; x <= 30.0; x += 1.5)
|
||||
{
|
||||
size_t max_z = 0L;
|
||||
auto y1 = 5 * floor((sqrt(900 - x * x)) / 5.0);
|
||||
for (float y = y1; y >= -y1; y -= 5)
|
||||
{
|
||||
auto z = to!size_t(max(0, floor(25 + fna(sqrt(x * x + y * y)) - .7 * y)));
|
||||
if (z > max_z) // Visible
|
||||
{
|
||||
max_z = z;
|
||||
if (z + 1 > row.length) // row needs to grow
|
||||
row ~= ' '.repeat(z + 1 - row.length).array;
|
||||
row[z] = '*';
|
||||
}
|
||||
}
|
||||
writeln(row);
|
||||
row = null;
|
||||
}
|
||||
}
|
||||
50
87_3-D_Plot/d/threedeeplot_random.d
Normal file
50
87_3-D_Plot/d/threedeeplot_random.d
Normal file
@@ -0,0 +1,50 @@
|
||||
@safe: // Make @safe the default for this file, enforcing memory-safety.
|
||||
import std.stdio, std.string, std.math, std.range, std.conv, std.random, std.algorithm;
|
||||
|
||||
void main()
|
||||
{
|
||||
enum width = 80;
|
||||
writeln(center("3D Plot", width));
|
||||
writeln(center("(After Creative Computing Morristown, New Jersey)\n\n", width));
|
||||
|
||||
enum functions = ["30.0 * exp(-z * z / 100.0)",
|
||||
"sqrt(900.01 - z * z) * .9 - 2",
|
||||
"30 * (cos(z / 16.0) + .5)",
|
||||
"30 - 30 * sin(z / 18.0)",
|
||||
"30 * exp(-cos(z / 16.0)) - 30",
|
||||
"30 * sin(z / 10.0)"];
|
||||
|
||||
size_t index = uniform(0, functions.length);
|
||||
writeln(center("f(z) = " ~ functions[index], width), "\n");
|
||||
|
||||
float fna(float z)
|
||||
{
|
||||
final switch (index)
|
||||
{
|
||||
static foreach (i, f; functions)
|
||||
case i:
|
||||
mixin("return " ~ f ~ ";");
|
||||
}
|
||||
}
|
||||
|
||||
char[] row;
|
||||
|
||||
for (float x = -30.0; x <= 30.0; x += 1.5)
|
||||
{
|
||||
size_t max_z = 0L;
|
||||
auto y1 = 5 * lrint((sqrt(900 - x * x)) / 5.0);
|
||||
for (float y = y1; y >= -y1; y -= 5)
|
||||
{
|
||||
auto z = to!size_t(max(0, lrint(25 + fna(sqrt(x * x + y * y)) - .7 * y)));
|
||||
if (z > max_z) // Visible
|
||||
{
|
||||
max_z = z;
|
||||
if (z + 1 > row.length) // row needs to grow
|
||||
row ~= ' '.repeat(z + 1 - row.length).array;
|
||||
row[z] = '*';
|
||||
}
|
||||
}
|
||||
writeln(row);
|
||||
row = null;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +1,95 @@
|
||||
// WAR
|
||||
//
|
||||
// Converted from BASIC to Javascript by Oscar Toledo G. (nanochess)
|
||||
// Original conversion from BASIC to Javascript by Oscar Toledo G. (nanochess)
|
||||
//
|
||||
|
||||
function print(str)
|
||||
{
|
||||
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)
|
||||
function tab(space) {
|
||||
let str = "";
|
||||
while (space-- > 0) {
|
||||
str += " ";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
var a = [, "S-2","H-2","C-2","D-2","S-3","H-3","C-3","D-3",
|
||||
"S-4","H-4","C-4","D-4","S-5","H-5","C-5","D-5",
|
||||
"S-6","H-6","C-6","D-6","S-7","H-7","C-7","D-7",
|
||||
"S-8","H-8","C-8","D-8","S-9","H-9","C-9","D-9",
|
||||
"S-10","H-10","C-10","D-10","S-J","H-J","C-J","D-J",
|
||||
"S-Q","H-Q","C-Q","D-Q","S-K","H-K","C-K","D-K",
|
||||
"S-A","H-A","C-A","D-A"];
|
||||
function input() {
|
||||
return new Promise(function (resolve) {
|
||||
const input_element = document.createElement("INPUT");
|
||||
|
||||
var l = [];
|
||||
print("? ");
|
||||
input_element.setAttribute("type", "text");
|
||||
input_element.setAttribute("length", "50");
|
||||
document.getElementById("output").appendChild(input_element);
|
||||
input_element.focus();
|
||||
input_element.addEventListener("keydown", function (event) {
|
||||
if (event.keyCode == 13) {
|
||||
const input_str = input_element.value;
|
||||
document.getElementById("output").removeChild(input_element);
|
||||
print(input_str);
|
||||
print("\n");
|
||||
resolve(input_str);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Main control section
|
||||
async function main()
|
||||
{
|
||||
async function askYesOrNo(question) {
|
||||
while (1) {
|
||||
print(question);
|
||||
const str = await input();
|
||||
if (str == "YES") {
|
||||
return true;
|
||||
}
|
||||
else if (str == "NO") {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
print("YES OR NO, PLEASE. ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function askAboutInstructions() {
|
||||
const playerWantsInstructions = await askYesOrNo("DO YOU WANT DIRECTIONS");
|
||||
if (playerWantsInstructions) {
|
||||
print("THE COMPUTER GIVES YOU AND IT A 'CARD'. THE HIGHER CARD\n");
|
||||
print("(NUMERICALLY) WINS. THE GAME ENDS WHEN YOU CHOOSE NOT TO\n");
|
||||
print("CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\n");
|
||||
}
|
||||
print("\n");
|
||||
print("\n");
|
||||
}
|
||||
|
||||
function createGameDeck(cards, gameSize) {
|
||||
const deck = [];
|
||||
const deckSize = cards.length;
|
||||
for (let j = 0; j < gameSize; j++) {
|
||||
let card;
|
||||
|
||||
// Compute a new card index until we find one that isn't already in the new deck
|
||||
do {
|
||||
card = Math.floor(deckSize * Math.random());
|
||||
} while (deck.includes(card));
|
||||
deck.push(card);
|
||||
}
|
||||
return deck;
|
||||
}
|
||||
|
||||
function computeCardValue(cardIndex) {
|
||||
return Math.floor(cardIndex / 4);
|
||||
}
|
||||
|
||||
function printGameOver(playerScore, computerScore) {
|
||||
print("\n");
|
||||
print("\n");
|
||||
print(`WE HAVE RUN OUT OF CARDS. FINAL SCORE: YOU: ${playerScore} THE COMPUTER: ${computerScore}\n`);
|
||||
print("\n");
|
||||
}
|
||||
|
||||
function printTitle() {
|
||||
print(tab(33) + "WAR\n");
|
||||
print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
|
||||
print("\n");
|
||||
@@ -62,72 +97,65 @@ async function main()
|
||||
print("\n");
|
||||
print("THIS IS THE CARD GAME OF WAR. EACH CARD IS GIVEN BY SUIT-#\n");
|
||||
print("AS S-7 FOR SPADE 7. ");
|
||||
while (1) {
|
||||
print("DO YOU WANT DIRECTIONS");
|
||||
str = await input();
|
||||
if (str == "YES") {
|
||||
print("THE COMPUTER GIVES YOU AND IT A 'CARD'. THE HIGHER CARD\n");
|
||||
print("(NUMERICALLY) WINS. THE GAME ENDS WHEN YOU CHOOSE NOT TO\n");
|
||||
print("CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\n");
|
||||
break;
|
||||
}
|
||||
if (str == "NO")
|
||||
break;
|
||||
print("YES OR NO, PLEASE. ");
|
||||
}
|
||||
print("\n");
|
||||
}
|
||||
|
||||
function printCards(playerCard, computerCard) {
|
||||
print("\n");
|
||||
print(`YOU: ${playerCard}\tCOMPUTER: ${computerCard}\n`);
|
||||
}
|
||||
|
||||
const cards = [
|
||||
"S-2", "H-2", "C-2", "D-2",
|
||||
"S-3", "H-3", "C-3", "D-3",
|
||||
"S-4", "H-4", "C-4", "D-4",
|
||||
"S-5", "H-5", "C-5", "D-5",
|
||||
"S-6", "H-6", "C-6", "D-6",
|
||||
"S-7", "H-7", "C-7", "D-7",
|
||||
"S-8", "H-8", "C-8", "D-8",
|
||||
"S-9", "H-9", "C-9", "D-9",
|
||||
"S-10", "H-10", "C-10", "D-10",
|
||||
"S-J", "H-J", "C-J", "D-J",
|
||||
"S-Q", "H-Q", "C-Q", "D-Q",
|
||||
"S-K", "H-K", "C-K", "D-K",
|
||||
"S-A", "H-A", "C-A", "D-A"
|
||||
];
|
||||
|
||||
// Main control section
|
||||
async function main() {
|
||||
printTitle();
|
||||
await askAboutInstructions();
|
||||
|
||||
a1 = 0;
|
||||
b1 = 0;
|
||||
p = 0;
|
||||
let computerScore = 0;
|
||||
let playerScore = 0;
|
||||
|
||||
// Generate a random deck
|
||||
for (j = 1; j <= 52; j++) {
|
||||
do {
|
||||
l[j] = Math.floor(52 * Math.random()) + 1;
|
||||
for (k = 1; k < j; k++) {
|
||||
if (l[k] == l[j]) // Already in deck?
|
||||
break;
|
||||
}
|
||||
} while (j != 1 && k < j) ;
|
||||
}
|
||||
l[j] = 0; // Mark the end of the deck
|
||||
const gameSize = cards.length; // Number of cards to shuffle into the game deck. Can be <= cards.length.
|
||||
const deck = createGameDeck(cards, gameSize);
|
||||
let shouldContinuePlaying = true;
|
||||
|
||||
while (1) {
|
||||
m1 = l[++p]; // Take a card
|
||||
m2 = l[++p]; // Take a card
|
||||
print("\n");
|
||||
print("YOU: " + a[m1] + "\tCOMPUTER: " + a[m2] + "\n");
|
||||
n1 = Math.floor((m1 - 0.5) / 4);
|
||||
n2 = Math.floor((m2 - 0.5) / 4);
|
||||
if (n1 < n2) {
|
||||
a1++;
|
||||
print("THE COMPUTER WINS!!! YOU HAVE " + b1 + " AND THE COMPUTER HAS " + a1 + "\n");
|
||||
} else if (n1 > n2) {
|
||||
b1++;
|
||||
print("YOU WIN. YOU HAVE " + b1 + " AND THE COMPUTER HAS " + a1 + "\n");
|
||||
while (deck.length > 0 && shouldContinuePlaying) {
|
||||
const playerCard = deck.shift(); // Take a card
|
||||
const computerCard = deck.shift(); // Take a card
|
||||
printCards(cards[playerCard], cards[computerCard]);
|
||||
|
||||
const playerCardValue = computeCardValue(playerCard);
|
||||
const computerCardValue = computeCardValue(computerCard);
|
||||
if (playerCardValue < computerCardValue) {
|
||||
computerScore++;
|
||||
print("THE COMPUTER WINS!!! YOU HAVE " + playerScore + " AND THE COMPUTER HAS " + computerScore + "\n");
|
||||
} else if (playerCardValue > computerCardValue) {
|
||||
playerScore++;
|
||||
print("YOU WIN. YOU HAVE " + playerScore + " AND THE COMPUTER HAS " + computerScore + "\n");
|
||||
} else {
|
||||
print("TIE. NO SCORE CHANGE.\n");
|
||||
}
|
||||
if (l[p + 1] == 0) {
|
||||
print("\n");
|
||||
print("\n");
|
||||
print("WE HAVE RUN OUT OF CARDS. FINAL SCORE: YOU: " + b1 + " THE COMPUTER: " + a1 + "\n");
|
||||
print("\n");
|
||||
break;
|
||||
|
||||
if (deck.length === 0) {
|
||||
printGameOver(playerScore, computerScore);
|
||||
}
|
||||
while (1) {
|
||||
print("DO YOU WANT TO CONTINUE");
|
||||
str = await input();
|
||||
if (str == "YES")
|
||||
break;
|
||||
if (str == "NO")
|
||||
break;
|
||||
print("YES OR NO, PLEASE. ");
|
||||
else {
|
||||
shouldContinuePlaying = await askYesOrNo("DO YOU WANT TO CONTINUE");
|
||||
}
|
||||
if (str == "NO")
|
||||
break;
|
||||
}
|
||||
print("THANKS FOR PLAYING. IT WAS FUN.\n");
|
||||
print("\n");
|
||||
|
||||
2
96_Word/d/.gitignore
vendored
Normal file
2
96_Word/d/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
*.exe
|
||||
*.obj
|
||||
15
96_Word/d/README.md
Normal file
15
96_Word/d/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
Original source downloaded from [Vintage Basic](http://www.vintage-basic.net/games.html)
|
||||
|
||||
Converted to [D](https://dlang.org/) by [Bastiaan Veelo](https://github.com/veelo).
|
||||
|
||||
The Basic original required words to be exactly five letters in length for the program to behave correctly.
|
||||
This version does not replicate that limitation, and the test for that requirement is commented out.
|
||||
|
||||
## Running the code
|
||||
|
||||
Assuming the reference [dmd](https://dlang.org/download.html#dmd) compiler:
|
||||
```shell
|
||||
dmd -dip1000 -run word.d
|
||||
```
|
||||
|
||||
[Other compilers](https://dlang.org/download.html) also exist.
|
||||
85
96_Word/d/word.d
Normal file
85
96_Word/d/word.d
Normal file
@@ -0,0 +1,85 @@
|
||||
@safe: // Make @safe the default for this file, enforcing memory-safety.
|
||||
import std;
|
||||
|
||||
void main()
|
||||
{
|
||||
enum width = 80;
|
||||
writeln(center("Word", width));
|
||||
writeln(center("(After Creative Computing Morristown, New Jersey)\n\n\n", width));
|
||||
writeln(wrap("I am thinking of a word -- you guess it. I will give you " ~
|
||||
"clues to help you get it. Good luck!!\n\n", width));
|
||||
|
||||
string[] words = ["dinky", "smoke", "water", "grass", "train", "might", "first",
|
||||
"candy", "champ", "would", "clump", "dopey"];
|
||||
|
||||
playLoop: while (true)
|
||||
{
|
||||
writeln("\n\nYou are starting a new game...");
|
||||
|
||||
string word = words[uniform(0, $-1)]; // $ is a short-hand for words.length.
|
||||
int guesses = 0;
|
||||
string knownLetters = '-'.repeat(word.length).array;
|
||||
|
||||
while (true)
|
||||
{
|
||||
writeln("Guess a ", word.length, " letter word");
|
||||
string guess = readString.toLower;
|
||||
if (guess == "?")
|
||||
{
|
||||
writeln("The secret word is ", word, "\n");
|
||||
continue playLoop; // Start a new game.
|
||||
}
|
||||
/* Uncomment this for equivalence with Basic.
|
||||
if (guess.length != 5)
|
||||
{
|
||||
writeln("You must guess a 5 letter word. Start again.");
|
||||
continue; // Ask for new guess.
|
||||
}
|
||||
*/
|
||||
guesses++;
|
||||
if (guess == word)
|
||||
break; // Done guessing
|
||||
string commonLetters;
|
||||
foreach (i, wordLetter; word)
|
||||
foreach (j, guessLetter; guess)
|
||||
if (guessLetter == wordLetter)
|
||||
{
|
||||
commonLetters ~= guessLetter;
|
||||
if (i == j)
|
||||
knownLetters.replaceInPlace(i, i + 1, [guessLetter]);
|
||||
}
|
||||
writeln("There were ", commonLetters.length, " matches and the common letters were... ", commonLetters);
|
||||
writeln("From the exact letter matches, you know................ ", knownLetters);
|
||||
if (knownLetters == word)
|
||||
break; // Done guessing
|
||||
if (commonLetters.length < 2)
|
||||
writeln("If you give up, type '?' for your next guess.");
|
||||
writeln;
|
||||
}
|
||||
|
||||
writeln("You have guessed the word. It took ", guesses, " guesses!");
|
||||
write("\n\nWant to play again? ");
|
||||
if (readString.toLower != "yes")
|
||||
break; // Terminate playLoop
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a string from standard input, stripping newline and other enclosing whitespace.
|
||||
string readString() nothrow
|
||||
{
|
||||
try
|
||||
return trustedReadln.strip;
|
||||
catch (Exception) // readln throws on I/O and Unicode errors, which we handle here.
|
||||
return "";
|
||||
}
|
||||
|
||||
/** An @trusted wrapper around readln.
|
||||
*
|
||||
* This is the only function that formally requires manual review for memory-safety.
|
||||
* [Arguably readln should be safe already](https://forum.dlang.org/post/rab398$1up$1@digitalmars.com)
|
||||
* which would remove the need to have any @trusted code in this program.
|
||||
*/
|
||||
string trustedReadln() @trusted
|
||||
{
|
||||
return readln;
|
||||
}
|
||||
85
HOW_TO_RUN_THE_GAMES.md
Normal file
85
HOW_TO_RUN_THE_GAMES.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# How to run the games
|
||||
|
||||
The games in this repository have been translated into a number of different languages. How to run them depends on the target language.
|
||||
|
||||
## csharp
|
||||
|
||||
### dotnet command-line
|
||||
|
||||
The best cross-platform method for running the csharp examples is with the `dotnet` command-line tool. This can be downloaded for **MacOS**, **Windows** and **Linux** from [dotnet.microsoft.com](https://dotnet.microsoft.com/).
|
||||
|
||||
From there, the program can be run by
|
||||
|
||||
1. Opening a terminal window
|
||||
1. Navigating to the corresponding directory
|
||||
1. Starting with `dotnet run`
|
||||
|
||||
### Visual Studio
|
||||
|
||||
Alternatively, for non-dotnet compatible translations, you will need [Visual Studio](https://visualstudio.microsoft.com/vs/community/) which can be used to both open the project and run the example.
|
||||
|
||||
1. Open the corresponding `.csproj` or `.sln` file
|
||||
1. Click `Run` from within the Visual Studio IDE
|
||||
|
||||
## java
|
||||
|
||||
The Java translations can be run via the command line or from an IDE such as [Eclipse](https://www.eclipse.org/downloads/packages/release/kepler/sr1/eclipse-ide-java-developers) or [IntelliJ](https://www.jetbrains.com/idea/)
|
||||
|
||||
To run from the command line, you will need a Java SDK (eg. [Oracle JDK](https://www.oracle.com/java/technologies/downloads/) or [Open JDK](https://openjdk.java.net/)).
|
||||
|
||||
1. Navigate to the corresponding directory.
|
||||
1. Compile the program with `javac`:
|
||||
* eg. `javac AceyDuceyGame.java`
|
||||
1. Run the compiled program with `java`:
|
||||
* eg. `java AceyDuceyGame`
|
||||
|
||||
## javascript
|
||||
|
||||
The javascript examples can be run from within your web browser:
|
||||
|
||||
1. Simply open the corresponding `.html` file from your web browser.
|
||||
|
||||
## pascal
|
||||
|
||||
The pascal examples can be run using [Free Pascal](https://www.freepascal.org/). Additionally, `.lsi` project files can be opened with the [Lazarus Project IDE](https://www.lazarus-ide.org/).
|
||||
|
||||
The pascal examples include both *simple* (single-file) and *object-oriented* (in the `/object-pascal`directories) examples.
|
||||
|
||||
1. You can compile the program from the command line with the `fpc` command.
|
||||
* eg. `fpc amazing.pas`
|
||||
1. The output is an executable file that can be run directly.
|
||||
|
||||
## perl
|
||||
|
||||
The perl translations can be run using a perl interpreter (a copy can be downloaded from [perl.org](https://www.perl.org/)) if not already installed.
|
||||
|
||||
1. From the command-line, navigate to the corresponding directory.
|
||||
1. Invoke with the `perl` command.
|
||||
* eg. `perl aceyducey.pl`
|
||||
|
||||
## python
|
||||
|
||||
The python translations can be run from the command line by using the `py` interpreter. If not already installed, a copy can be downloaded from [python.org](https://www.python.org/downloads/) for **Windows**, **MacOS** and **Linux**.
|
||||
|
||||
1. From the command-line, navigate to the corresponding directory.
|
||||
1. Invoke with the `py` or `python` interpreter (depending on your python version).
|
||||
* eg. `py acey_ducey_oo.py`
|
||||
* eg. `python aceyducey.py`
|
||||
|
||||
**Note**
|
||||
|
||||
Some translations include multiple versions for python, such as `acey ducey` which features versions for Python 2 (`aceyducey.py`) and Python 3 (`acey_ducey.py`) as well as an extra object-oriented version (`acey_ducey_oo.py`).
|
||||
|
||||
You can manage and use different versions of python with [pip](https://pypi.org/project/pip/).
|
||||
|
||||
## ruby
|
||||
|
||||
If you don't already have a ruby interpreter, you can download it from the [ruby project site](https://www.ruby-lang.org/en/).
|
||||
|
||||
1. From the command-line, navigate to the corresponding directory.
|
||||
1. Invoke with the `ruby` tool.
|
||||
* eg. `ruby aceyducey.rb`
|
||||
|
||||
## vbnet
|
||||
|
||||
Follow the same steps as for the [csharp](#csharp) translations. This can be run with `dotnet` or `Visual Studio`.
|
||||
Reference in New Issue
Block a user