mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 23:26:40 -08:00
Merge branch 'coding-horror:main' into main
This commit is contained in:
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!");
|
||||||
|
}
|
||||||
@@ -12,3 +12,7 @@ As published in Basic Computer Games (1978):
|
|||||||
|
|
||||||
Downloaded from Vintage Basic at
|
Downloaded from Vintage Basic at
|
||||||
http://www.vintage-basic.net/games.html
|
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
|
975 V(R,S)=3:Q=0:GOTO 1000
|
||||||
980 V(R,S)=1:Q=0:R=1:S=1:GOTO 250
|
980 V(R,S)=1:Q=0:R=1:S=1:GOTO 250
|
||||||
1000 GOTO 210
|
1000 GOTO 210
|
||||||
1010 FOR J=1 TO V
|
1010 IF Z=1 THEN 1015
|
||||||
1011 PRINT "I";
|
1011 X=INT(RND(1)*H+1)
|
||||||
1012 FOR I=1 TO H
|
1012 IF V(X,V)=0 THEN 1014
|
||||||
1013 IF V(I,J)<2 THEN 1030
|
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 " ";
|
1020 PRINT " ";
|
||||||
1021 GOTO 1040
|
1021 GOTO 1040
|
||||||
1030 PRINT " I";
|
1030 PRINT " I";
|
||||||
|
|||||||
223
03_Animal/perl/animal.pl
Executable file
223
03_Animal/perl/animal.pl
Executable file
@@ -0,0 +1,223 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use 5.010; # To get 'state' and 'say'
|
||||||
|
|
||||||
|
use strict; # Require explicit declaration of variables
|
||||||
|
use warnings; # Enable optional compiler warnings
|
||||||
|
|
||||||
|
use English; # Use more friendly names for Perl's magic variables
|
||||||
|
use Term::ReadLine; # Prompt and return user input
|
||||||
|
|
||||||
|
our $VERSION = '0.000_01';
|
||||||
|
|
||||||
|
# The Perl ref() built-in returns 'HASH' for a hash reference. But we
|
||||||
|
# make it a manifest constant just to avoid typos.
|
||||||
|
use constant REF_HASH => ref {};
|
||||||
|
|
||||||
|
print <<'EOD';
|
||||||
|
ANIMAL
|
||||||
|
Creative Computing Morristown, New Jersey
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Play 'Guess the Animal'
|
||||||
|
Think of an animal and the computer will try to guess it.
|
||||||
|
|
||||||
|
EOD
|
||||||
|
|
||||||
|
# We keep the accumulated data in a tree structure, initialized here. As
|
||||||
|
# we accumulate animals, we replace the 'yes' or 'no' keys with new hash
|
||||||
|
# references.
|
||||||
|
my $database = {
|
||||||
|
question => 'Does it swim', # Initial question
|
||||||
|
yes => 'fish', # Result of answering 'y'
|
||||||
|
no => 'bird', # Result of answering 'n'
|
||||||
|
};
|
||||||
|
|
||||||
|
while ( 1 ) {
|
||||||
|
|
||||||
|
my $resp = get_input(
|
||||||
|
'Are you thinking of an an animal? [y/n/list]: '
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( $resp =~ m/ \A y /smxi ) {
|
||||||
|
# If we got an answer beginning with 'y', walk the database
|
||||||
|
walk_tree( $database );
|
||||||
|
} elsif ( $resp =~ m/ \A list \z /smxi ) {
|
||||||
|
# If we got 'list', list the currently-known animals.
|
||||||
|
say '';
|
||||||
|
say 'Animals I already know are:';
|
||||||
|
say " $_" for sort( list_animals( $database ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get input from the user. The arguments are:
|
||||||
|
# * The prompt
|
||||||
|
# * A reference to validation code. This code receives the response in
|
||||||
|
# $ARG and returns true for a valid response.
|
||||||
|
# * A warning to print if the response is not valid. This must end in a
|
||||||
|
# return.
|
||||||
|
# The first valid response is returned. An end-of-file terminates the
|
||||||
|
# script.
|
||||||
|
sub get_input {
|
||||||
|
my ( $prompt, $validate, $warning ) = @ARG;
|
||||||
|
|
||||||
|
# If no validator is passed, default to one that always returns
|
||||||
|
# true.
|
||||||
|
$validate ||= sub { 1 };
|
||||||
|
|
||||||
|
# Create the readline object. The 'state' causes the variable to be
|
||||||
|
# initialized only once, no matter how many times this subroutine is
|
||||||
|
# called. The do { ... } is a compound statement used because we
|
||||||
|
# need to tweak the created object before we store it.
|
||||||
|
state $term = do {
|
||||||
|
my $obj = Term::ReadLine->new( 'animal' );
|
||||||
|
$obj->ornaments( 0 );
|
||||||
|
$obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
while ( 1 ) { # Iterate indefinitely
|
||||||
|
|
||||||
|
# Read the input into the topic variable, localized to prevent
|
||||||
|
# Spooky Action at a Distance. We exit on undef, which signals
|
||||||
|
# end-of-file.
|
||||||
|
exit unless defined( local $ARG = $term->readline( $prompt ) );
|
||||||
|
|
||||||
|
# Return the input if it is valid.
|
||||||
|
return $ARG if $validate->();
|
||||||
|
|
||||||
|
# Issue the warning, and go around the merry-go-round again.
|
||||||
|
warn $warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get a yes-or-no answer. The argument is the prompt, which will have
|
||||||
|
# '? [y/n]: ' appended. The donkey work is done by get_input(), which is
|
||||||
|
# requested to validate the response as beginning with 'y' or 'n',
|
||||||
|
# case-insensitive. The return is a true value for 'y' and a false value
|
||||||
|
# for 'n'.
|
||||||
|
sub get_yes_no {
|
||||||
|
my ( $prompt ) = @ARG;
|
||||||
|
state $map_answer = {
|
||||||
|
n => 0,
|
||||||
|
y => 1,
|
||||||
|
};
|
||||||
|
my $resp = lc get_input(
|
||||||
|
"$prompt? [y/n]: ",
|
||||||
|
sub { m/ \A [yn] /smxi },
|
||||||
|
"Please respond 'y' or 'n'\n",
|
||||||
|
);
|
||||||
|
return $map_answer->{ substr $resp, 0, 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
# Recurse through the database, returning the names of all animals in
|
||||||
|
# it, in an undefined order.
|
||||||
|
sub list_animals {
|
||||||
|
my ( $node ) = @ARG;
|
||||||
|
return $node unless REF_HASH eq ref $node;
|
||||||
|
return( map { list_animals( $node->{$_} ) } qw{ yes no } );
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find or create the desired animal.
|
||||||
|
# Ask the question stored in the node given in its argument. If the key
|
||||||
|
# selected by the answer ('yes' or 'no') is another node, recurse. If it
|
||||||
|
# is an animal name, confirm it, or add a new animal as appropriate.
|
||||||
|
sub walk_tree {
|
||||||
|
my ( $node ) = @ARG;
|
||||||
|
|
||||||
|
# Ask the question associated with this node. Turn the true/false
|
||||||
|
# response into 'yes' or 'no', since those are the names of the
|
||||||
|
# respective keys.
|
||||||
|
my $resp = get_yes_no ( $node->{question} ) ? 'yes' : 'no';
|
||||||
|
|
||||||
|
# Chose the datum for the response.
|
||||||
|
my $choice = $node->{ $resp };
|
||||||
|
|
||||||
|
# If the datum is a hash reference
|
||||||
|
if ( REF_HASH eq ref $choice ) {
|
||||||
|
|
||||||
|
# Recurse into it
|
||||||
|
walk_tree( $choice );
|
||||||
|
|
||||||
|
# Otherwise it is an actual animal (i.e. terminal node). Check it.
|
||||||
|
} else {
|
||||||
|
|
||||||
|
# If this is not the animal the player was thinking of
|
||||||
|
unless ( get_yes_no( "Is it a $choice" ) ) {
|
||||||
|
|
||||||
|
# Find out what animal the player was thinking of
|
||||||
|
my $animal = lc get_input(
|
||||||
|
'The animal you were thinking of was a ',
|
||||||
|
);
|
||||||
|
|
||||||
|
# Get a yes/no question that distinguishes the animal the
|
||||||
|
# player was thinking of from the animal we found in the
|
||||||
|
# tree.
|
||||||
|
say 'Please type in a question that would distinguish a';
|
||||||
|
my $question = get_input( "$animal from a $choice: " );
|
||||||
|
|
||||||
|
# Find out whether the new animal is selected by 'yes' or
|
||||||
|
# 'no'. If 'no', swap the original animal with the new one
|
||||||
|
# for convenience.
|
||||||
|
( $choice, $animal ) = ( $animal, $choice ) if get_yes_no(
|
||||||
|
"For a $animal the answer would be",
|
||||||
|
);
|
||||||
|
|
||||||
|
# Replace the animal we originally found by a new node
|
||||||
|
# giving the original animal, the new animal, and the
|
||||||
|
# question that distinguishes them.
|
||||||
|
$node->{ $resp } = {
|
||||||
|
question => $question,
|
||||||
|
no => $animal,
|
||||||
|
yes => $choice,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
# Find out if the player wants to play again. If not, exit. If
|
||||||
|
# so, just return.
|
||||||
|
say '';
|
||||||
|
exit unless get_yes_no( 'Why not try another animal' );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 TITLE
|
||||||
|
|
||||||
|
animal.pl - Play the game 'animal' from Basic Computer Games
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
animal.pl
|
||||||
|
|
||||||
|
=head1 DETAILS
|
||||||
|
|
||||||
|
This Perl script is a port of C<animal>, which is the 3ed entry in Basic
|
||||||
|
Computer Games.
|
||||||
|
|
||||||
|
The original BASIC was greatly complicated by the need to emulate a
|
||||||
|
binary tree with an array. The implementation using hashes as nodes in
|
||||||
|
an actual binary tree is much simpler.
|
||||||
|
|
||||||
|
=head1 PORTED BY
|
||||||
|
|
||||||
|
Thomas R. Wyant, III F<wyant at cpan dot org>
|
||||||
|
|
||||||
|
=head1 COPYRIGHT AND LICENSE
|
||||||
|
|
||||||
|
Copyright (C) 2022 by Thomas R. Wyant, III
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the same terms as Perl 5.10.0. For more details, see the Artistic
|
||||||
|
License 1.0 at
|
||||||
|
L<https://www.perlfoundation.org/artistic-license-10.html>, and/or the
|
||||||
|
Gnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but
|
||||||
|
without any warranty; without even the implied warranty of
|
||||||
|
merchantability or fitness for a particular purpose.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# ex: set expandtab tabstop=4 textwidth=72 :
|
||||||
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
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
|
||||||
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";
|
||||||
173
26_Chomp/perl/chomp.pl
Normal file
173
26_Chomp/perl/chomp.pl
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
|
||||||
|
my @cookie;
|
||||||
|
|
||||||
|
&main;
|
||||||
|
|
||||||
|
sub main {
|
||||||
|
my $answer = 1;
|
||||||
|
until ($answer == 0) {
|
||||||
|
$answer=&game_play;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub game_play {
|
||||||
|
|
||||||
|
# the initial game set up
|
||||||
|
&print_intro;
|
||||||
|
my ($players,$rows,$cols) = &get_user_info;
|
||||||
|
&create_gameboard($rows,$cols);
|
||||||
|
&print_gameboard($rows,$cols);
|
||||||
|
my $game_over = 0;
|
||||||
|
my $player = 0;
|
||||||
|
|
||||||
|
# continuous loop until the poison pill is swallowed
|
||||||
|
until ($game_over == 1) {
|
||||||
|
if ($player > ($players-1)) { #checks to make sure we're just looping thru valid players
|
||||||
|
$player = 0;
|
||||||
|
}
|
||||||
|
$player++;
|
||||||
|
my ($user_row,$user_col) = &get_player_row_col($player,$rows,$cols);
|
||||||
|
if ($cookie[$user_row][$user_col] == -1) {
|
||||||
|
print "YOU LOSE, PLAYER $player\n\n";
|
||||||
|
print "AGAIN (1=YES, 0=NO!)\n";
|
||||||
|
my $answer=<STDIN>;
|
||||||
|
chomp($answer);
|
||||||
|
return($answer);
|
||||||
|
}
|
||||||
|
&modify_gameboard($rows,$cols,$user_row,$user_col);
|
||||||
|
&print_gameboard($rows,$cols);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_player_row_col {
|
||||||
|
my ($player,$row,$col) = @_;
|
||||||
|
my @coords;
|
||||||
|
my $validity="invalid";
|
||||||
|
# Getting coordinates from user
|
||||||
|
until ($validity eq "valid") {
|
||||||
|
print "PLAYER $player COORDINATES OF CHOMP (ROW,COLUMN)\n";
|
||||||
|
my $input=<STDIN>;
|
||||||
|
chomp($input);
|
||||||
|
@coords = split/,/,$input;
|
||||||
|
|
||||||
|
#verifying coordinates are valid
|
||||||
|
if ($coords[0] < 1 || $coords[0] > $row || $coords[1] < 1 || $coords[1] > $col || $cookie[$coords[0]][$coords[1]] == 0) {
|
||||||
|
print "NO FAIR. YOU'RE TRYING TO CHOMP ON EMPTY SPACE!\n";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$validity="valid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return($coords[0],$coords[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_user_info {
|
||||||
|
my ($players,$rows,$cols)=0;
|
||||||
|
until ($players > 0) {
|
||||||
|
print "HOW MANY PLAYERS\n";
|
||||||
|
$players=<STDIN>;
|
||||||
|
chomp($players);
|
||||||
|
}
|
||||||
|
until ($rows > 0 && $rows < 10) {
|
||||||
|
print "HOW MANY ROWS\n";
|
||||||
|
$rows=<STDIN>;
|
||||||
|
chomp($rows);
|
||||||
|
if ($rows > 9) {
|
||||||
|
print "TOO MANY ROWS (9 IS MAXIMUM). NOW, ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
until ($cols > 0 && $cols < 10) {
|
||||||
|
print "HOW MANY COLUMNS\n";
|
||||||
|
$cols=<STDIN>;
|
||||||
|
chomp($cols);
|
||||||
|
if ($cols > 9) {
|
||||||
|
print "TOO MANY COLUMNS (9 IS MAXIMUM). NOW, ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return($players,$rows,$cols);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub print_intro{
|
||||||
|
print ' ' x 33 . "CHOMP\n";
|
||||||
|
print ' ' x 15 . "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n\n";
|
||||||
|
print "THIS IS THE GAME OF CHOMP (SCIENTIFIC AMERICAN, JAN 1973)\n";
|
||||||
|
print "DO YOU WANT THE RULES (1=YES, 0=NO!)";
|
||||||
|
my $answer = <STDIN>;
|
||||||
|
chomp($answer);
|
||||||
|
if ($answer == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "CHOMP IS FOR 1 OR MORE PLAYERS (HUMANS ONLY).\n\n";
|
||||||
|
print "HERE'S HOW A BOARD LOOKS (THIS ONE IS 5 BY 7):\n";
|
||||||
|
&create_gameboard(5,7);
|
||||||
|
&print_gameboard(5,7);
|
||||||
|
print "THE BOARD IS A BIG COOKIE - R ROWS HIGH AND C COLUMNS\n";
|
||||||
|
print "WIDE. YOU INPUT R AND C AT THE START. IN THE UPPER LEFT\n";
|
||||||
|
print "CORNER OF THE COOKIE IS A POISON SQUARE (P). THE ONE WHO\n";
|
||||||
|
print "CHOMPS THE POISON SQUARE LOSES. TO TAKE A CHOMP, TYPE THE\n";
|
||||||
|
print "ROW AND COLUMN OF ONE OF THE SQUARES ON THE COOKIE.\n";
|
||||||
|
print "ALL OF THE SQUARES BELOW AND TO THE RIGHT OF THAT SQUARE\n";
|
||||||
|
print "(INCLUDING THAT SQUARE, TOO) DISAPPEAR -- CHOMP!!\n";
|
||||||
|
print "NO FAIR CHOMPING SQUARES THAT HAVE ALREADY BEEN CHOMPED,\n";
|
||||||
|
print "OR THAT ARE OUTSIDE THE ORIGINAL DIMENSIONS OF THE COOKIE.\n\n";
|
||||||
|
print "HERE WE GO...\n";
|
||||||
|
undef @cookie;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#initial creation of the gameboard
|
||||||
|
sub create_gameboard {
|
||||||
|
my $rows = shift;
|
||||||
|
my $cols = shift;
|
||||||
|
foreach my $row (1..($rows)) {
|
||||||
|
foreach my $col (1..($cols)) {
|
||||||
|
$cookie[$row][$col]=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$cookie[1][1]=-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#modification of the gameboard based on the input from the player
|
||||||
|
sub modify_gameboard {
|
||||||
|
my ($rows,$cols,$user_row,$user_col) = @_;
|
||||||
|
foreach my $row ($user_row..($rows)) {
|
||||||
|
foreach my $col ($user_col..($cols)) {
|
||||||
|
$cookie[$row][$col]=" ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#prints the gameboard based on the current state of the gameboard
|
||||||
|
sub print_gameboard {
|
||||||
|
my ($rows,$cols) = @_;
|
||||||
|
foreach my $col (1..$cols) {
|
||||||
|
if ($col == $cols) {
|
||||||
|
print "$col\n";
|
||||||
|
}
|
||||||
|
elsif ($col == 1) {
|
||||||
|
print "\t $col ";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print "$col ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach my $row (1..($rows)) {
|
||||||
|
print "\t$row ";
|
||||||
|
foreach my $col (1..($cols)) {
|
||||||
|
if ($cookie[$row][$col] == 1) {
|
||||||
|
print "* ";
|
||||||
|
}
|
||||||
|
if ($cookie[$row][$col] == 0) {
|
||||||
|
print " ";
|
||||||
|
}
|
||||||
|
if ($cookie[$row][$col] == -1) {
|
||||||
|
print "P ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
print "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
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()
|
break if ! get_input_another_game()
|
||||||
end
|
end
|
||||||
|
|
||||||
# 420 PRINT "OK. HOPE YOU ENJOYED YOURSELF." : GOTO 600
|
|
||||||
printf("OK. HOPE YOU ENJOYED YOURSELF.\n")
|
printf("OK. HOPE YOU ENJOYED YOURSELF.\n")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -51,7 +50,7 @@ class DepthCharge
|
|||||||
|
|
||||||
the_input = Integer(value) rescue nil
|
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")
|
printf("PLEASE ENTER A POSITIVE NUMBER\n\n")
|
||||||
next
|
next
|
||||||
|
|
||||||
@@ -61,25 +60,7 @@ class DepthCharge
|
|||||||
end
|
end
|
||||||
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
|
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
|
printf( <<~INSTRUCTIONS
|
||||||
YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER
|
YOU ARE THE CAPTAIN OF THE DESTROYER USS COMPUTER
|
||||||
AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR
|
AN ENEMY SUB HAS BEEN CAUSING YOU TROUBLE. YOUR
|
||||||
@@ -110,19 +91,21 @@ GOOD LUCK !
|
|||||||
end
|
end
|
||||||
|
|
||||||
def setup_game
|
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()
|
setup_enemy()
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup_enemy
|
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_x = rand(1..@search_area_dimension)
|
||||||
@enemy_y = rand(1..@search_area_dimension)
|
@enemy_y = rand(1..@search_area_dimension)
|
||||||
@enemy_z = rand(1..@search_area_dimension)
|
@enemy_z = rand(1..@search_area_dimension)
|
||||||
end
|
end
|
||||||
|
|
||||||
def game_loop
|
def game_loop
|
||||||
# 120 FOR D=1 TO N : PRINT : PRINT "TRIAL #";D; : INPUT X,Y,Z
|
|
||||||
for @trial in 1..@num_tries do
|
for @trial in 1..@num_tries do
|
||||||
output_game_status()
|
output_game_status()
|
||||||
|
|
||||||
@@ -130,7 +113,6 @@ GOOD LUCK !
|
|||||||
@shot_y = get_input_positive_integer("Y: ")
|
@shot_y = get_input_positive_integer("Y: ")
|
||||||
@shot_z = get_input_positive_integer("Z: ")
|
@shot_z = get_input_positive_integer("Z: ")
|
||||||
|
|
||||||
# 130 IF ABS(X-A)+ABS(Y-B)+ABS(Z-C)=0 THEN 300
|
|
||||||
if (
|
if (
|
||||||
(@enemy_x - @shot_x).abs \
|
(@enemy_x - @shot_x).abs \
|
||||||
+ (@enemy_y - @shot_y).abs \
|
+ (@enemy_y - @shot_y).abs \
|
||||||
@@ -140,7 +122,6 @@ GOOD LUCK !
|
|||||||
you_win()
|
you_win()
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
# 140 GOSUB 500 : PRINT : NEXT D
|
|
||||||
missed_shot()
|
missed_shot()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -156,54 +137,41 @@ GOOD LUCK !
|
|||||||
printf("TRIAL \#%d\n", @trial)
|
printf("TRIAL \#%d\n", @trial)
|
||||||
end
|
end
|
||||||
def you_win
|
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
|
end
|
||||||
def missed_shot
|
def missed_shot
|
||||||
missed_directions = []
|
missed_directions = []
|
||||||
|
|
||||||
# 530 IF X>A THEN PRINT "EAST";
|
|
||||||
# 540 IF X<A THEN PRINT "WEST";
|
|
||||||
if @shot_x > @enemy_x
|
if @shot_x > @enemy_x
|
||||||
missed_directions.push('TOO FAR EAST')
|
missed_directions.push('TOO FAR EAST')
|
||||||
elsif @shot_x < @enemy_x
|
elsif @shot_x < @enemy_x
|
||||||
missed_directions.push('TOO FAR WEST')
|
missed_directions.push('TOO FAR WEST')
|
||||||
end
|
end
|
||||||
|
|
||||||
# 510 IF Y>B THEN PRINT "NORTH";
|
|
||||||
# 520 IF Y<B THEN PRINT "SOUTH";
|
|
||||||
if @shot_y > @enemy_y
|
if @shot_y > @enemy_y
|
||||||
missed_directions.push('TOO FAR NORTH')
|
missed_directions.push('TOO FAR NORTH')
|
||||||
elsif @shot_y < @enemy_y
|
elsif @shot_y < @enemy_y
|
||||||
missed_directions.push('TOO FAR SOUTH')
|
missed_directions.push('TOO FAR SOUTH')
|
||||||
end
|
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
|
if @shot_z > @enemy_z
|
||||||
missed_directions.push('TOO DEEP')
|
missed_directions.push('TOO DEEP')
|
||||||
elsif @shot_z < @enemy_z
|
elsif @shot_z < @enemy_z
|
||||||
missed_directions.push('TOO SHALLOW')
|
missed_directions.push('TOO SHALLOW')
|
||||||
end
|
end
|
||||||
|
|
||||||
# 500 PRINT "SONAR REPORTS SHOT WAS ";
|
|
||||||
printf("SONAR REPORTS SHOT WAS: \n")
|
printf("SONAR REPORTS SHOT WAS: \n")
|
||||||
printf("%s\n", "\t" + missed_directions.join("\n\t"))
|
printf("%s\n", "\t" + missed_directions.join("\n\t"))
|
||||||
# 550 IF Y<>B OR X<>A THEN PRINT " AND";
|
|
||||||
# 590 RETURN
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def you_lose
|
def you_lose
|
||||||
# You took too long!
|
|
||||||
printf("YOU HAVE BEEN TORPEDOED! ABANDON SHIP!\n")
|
printf("YOU HAVE BEEN TORPEDOED! ABANDON SHIP!\n")
|
||||||
printf("THE SUBMARINE WAS AT %d %d %d\n", @enemy_x, @enemy_y, @enemy_z)
|
printf("THE SUBMARINE WAS AT %d %d %d\n", @enemy_x, @enemy_y, @enemy_z)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_input_another_game
|
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): ")
|
return get_input_y_or_n("ANOTHER GAME (Y OR N): ")
|
||||||
# 410 IF A$="Y" THEN 100
|
|
||||||
end
|
end
|
||||||
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";
|
||||||
|
}
|
||||||
@@ -144,15 +144,30 @@ def game_over():
|
|||||||
def computer_turn():
|
def computer_turn():
|
||||||
global marbles_in_middle
|
global marbles_in_middle
|
||||||
global computer_marbles
|
global computer_marbles
|
||||||
|
global human_marbles
|
||||||
|
|
||||||
|
marbles_to_take=0
|
||||||
|
|
||||||
print("It's the computer's turn ...")
|
print("It's the computer's turn ...")
|
||||||
max_choice = min(4, marbles_in_middle)
|
r = marbles_in_middle - 6 * int((marbles_in_middle/6)) #line 500
|
||||||
|
|
||||||
# choose at random
|
if int(human_marbles/2) == human_marbles/2: #line 510
|
||||||
n = random.randint(1, max_choice)
|
if r < 1.5 or r > 5.3: #lines 710 and 720
|
||||||
print(f'Computer takes {marbles_str(n)} ...')
|
marbles_to_take = 1
|
||||||
marbles_in_middle -= n
|
else:
|
||||||
computer_marbles += n
|
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():
|
def play_game():
|
||||||
global marbles_in_middle
|
global marbles_in_middle
|
||||||
|
|||||||
@@ -8,6 +8,28 @@ The money system is Rollods; each person needs 100 Rallods per year to survive.
|
|||||||
|
|
||||||
The author of this program is James A. Storer who wrote it while a student at Lexington High School.
|
The author of this program is James A. Storer who wrote it while a student at Lexington High School.
|
||||||
|
|
||||||
|
## Bugs
|
||||||
|
|
||||||
|
Implementers should be aware that this game contains at least one bug.
|
||||||
|
|
||||||
|
On basic line 1450
|
||||||
|
|
||||||
|
1450 V3=INT(A+V3)
|
||||||
|
1451 A=INT(A+V3)
|
||||||
|
|
||||||
|
...where A is the current treasury, and V3 is initially zero.
|
||||||
|
This would mean that the treasury doubles at the end of the first year, and all calculations for an increase in the treasury due to tourism are discarded.
|
||||||
|
Possibly, this made the game more playable, although impossible for the player to understand why the treasury was increasing?
|
||||||
|
|
||||||
|
A quick fix for this bug in the original code would be
|
||||||
|
|
||||||
|
1450 V3=ABS(INT(V1-V2))
|
||||||
|
1451 A=INT(A+V3)
|
||||||
|
|
||||||
|
...judging from the description of tourist income on basic line 1410
|
||||||
|
|
||||||
|
1410 PRINT " YOU MADE";ABS(INT(V1-V2));"RALLODS FROM TOURIST TRADE."
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
As published in Basic Computer Games (1978):
|
As published in Basic Computer Games (1978):
|
||||||
|
|||||||
306
53_King/king_variable_update.bas
Normal file
306
53_King/king_variable_update.bas
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
1 PRINT TAB(34);"KING"
|
||||||
|
2 PRINT TAB(15);"CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"
|
||||||
|
3 PRINT:PRINT:PRINT
|
||||||
|
4 PRINT "DO YOU WANT INSTRUCTIONS";
|
||||||
|
5 INPUT Z$
|
||||||
|
6 YEARS_REQUIRED=8
|
||||||
|
10 IF LEFT$(Z$,1)="N" THEN 47
|
||||||
|
11 IF Z$="AGAIN" THEN 1960
|
||||||
|
12 PRINT:PRINT:PRINT
|
||||||
|
20 PRINT "CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS"
|
||||||
|
22 PRINT "DETINU, RALLODS SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR"
|
||||||
|
24 PRINT "JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE"
|
||||||
|
26 PRINT "MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY."
|
||||||
|
28 PRINT "THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100"
|
||||||
|
30 PRINT "RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES"
|
||||||
|
32 PRINT "FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT"
|
||||||
|
34 PRINT "FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND"
|
||||||
|
36 PRINT "WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD"
|
||||||
|
38 PRINT "TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT"
|
||||||
|
40 PRINT "THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER"
|
||||||
|
42 PRINT "SQUARE MILE TO PLANT."
|
||||||
|
44 PRINT "YOUR GOAL IS TO COMPLETE YOUR";YEARS_REQUIRED;"YEAR TERM OF OFFICE."
|
||||||
|
46 PRINT "GOOD LUCK!"
|
||||||
|
|
||||||
|
47 PRINT
|
||||||
|
|
||||||
|
50 RALLODS=INT(60000+(1000*RND(1))-(1000*RND(1)))
|
||||||
|
55 COUNTRYMEN=INT(500+(10*RND(1))-(10*RND(1)))
|
||||||
|
65 LANDAREA=2000
|
||||||
|
100 LANDPRICE=INT(10*RND(1)+95)
|
||||||
|
102 PRINT
|
||||||
|
105 PRINT "YOU NOW HAVE ";RALLODS;" RALLODS IN THE TREASURY."
|
||||||
|
110 PRINT INT(COUNTRYMEN);:PRINT "COUNTRYMEN, ";
|
||||||
|
115 COST_TO_PLANT=INT(((RND(1)/2)*10+10))
|
||||||
|
120 IF FOREIGN_WORKERS=0 THEN 140
|
||||||
|
130 PRINT INT(FOREIGN_WORKERS);"FOREIGN WORKERS, ";
|
||||||
|
140 PRINT "AND";INT(LANDAREA);"SQ. MILES OF LAND."
|
||||||
|
150 PRINT "THIS YEAR INDUSTRY WILL BUY LAND FOR";LANDPRICE;
|
||||||
|
152 PRINT "RALLODS PER SQUARE MILE."
|
||||||
|
155 PRINT "LAND CURRENTLY COSTS";COST_TO_PLANT;"RALLODS PER SQUARE MILE TO PLANT."
|
||||||
|
162 PRINT
|
||||||
|
|
||||||
|
200 PRINT "HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY";
|
||||||
|
210 INPUT SELL_TO_INDUSTRY
|
||||||
|
215 IF SELL_TO_INDUSTRY<0 THEN 200
|
||||||
|
220 IF SELL_TO_INDUSTRY<=LANDAREA-1000 THEN 300
|
||||||
|
230 PRINT "*** THINK AGAIN. YOU ONLY HAVE";LANDAREA-1000;"SQUARE MILES OF FARM LAND."
|
||||||
|
|
||||||
|
240 IF EXPLANATION_GIVEN THEN 200
|
||||||
|
250 PRINT:PRINT "(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE"
|
||||||
|
260 PRINT "FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,"
|
||||||
|
270 PRINT "THICKER TOP SOIL, ETC.)"
|
||||||
|
280 EXPLANATION_GIVEN=TRUE
|
||||||
|
299 GOTO 200
|
||||||
|
|
||||||
|
300 LANDAREA=INT(LANDAREA-SELL_TO_INDUSTRY)
|
||||||
|
310 RALLODS=INT(RALLODS+(SELL_TO_INDUSTRY*LANDPRICE))
|
||||||
|
320 PRINT "HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN";
|
||||||
|
340 INPUT WELFARE
|
||||||
|
342 IF WELFARE<0 THEN 320
|
||||||
|
350 IF WELFARE<RALLODS THEN 400
|
||||||
|
360 IF WELFARE=RALLODS THEN 380
|
||||||
|
370 PRINT " THINK AGAIN. YOU'VE ONLY";RALLODS;" RALLODS IN THE TREASURY"
|
||||||
|
375 GOTO 320
|
||||||
|
|
||||||
|
380 PLANTING_AREA=0
|
||||||
|
390 MONEY_SPENT_ON_POLLUTION_CONTROL=0
|
||||||
|
395 RALLODS=0
|
||||||
|
399 GOTO 1000
|
||||||
|
400 RALLODS=INT(RALLODS-WELFARE)
|
||||||
|
|
||||||
|
410 PRINT "HOW MANY SQUARE MILES DO YOU WISH TO PLANT";
|
||||||
|
420 INPUT PLANTING_AREA
|
||||||
|
421 IF PLANTING_AREA<0 THEN 410
|
||||||
|
422 IF PLANTING_AREA<=COUNTRYMEN*2 THEN 426
|
||||||
|
423 PRINT " SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES."
|
||||||
|
424 GOTO 410
|
||||||
|
|
||||||
|
426 IF PLANTING_AREA<=LANDAREA-1000 THEN 430
|
||||||
|
427 PRINT " SORRY, BUT YOU'VE ONLY";LANDAREA-1000;"SQ. MILES OF FARM LAND."
|
||||||
|
428 GOTO 410
|
||||||
|
|
||||||
|
430 MONEY_SPENT_ON_PLANTING=INT(PLANTING_AREA*COST_TO_PLANT)
|
||||||
|
435 IF MONEY_SPENT_ON_PLANTING<RALLODS THEN 500
|
||||||
|
440 IF MONEY_SPENT_ON_PLANTING=RALLODS THEN 490
|
||||||
|
450 PRINT " THINK AGAIN. YOU'VE ONLY";RALLODS;" RALLODS LEFT IN THE TREASURY."
|
||||||
|
460 GOTO 410
|
||||||
|
|
||||||
|
490 MONEY_SPENT_ON_POLLUTION_CONTROL=0
|
||||||
|
495 RALLODS=0
|
||||||
|
499 GOTO 1000
|
||||||
|
|
||||||
|
500 RALLODS=RALLODS-MONEY_SPENT_ON_PLANTING
|
||||||
|
|
||||||
|
510 PRINT "HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL";
|
||||||
|
520 INPUT MONEY_SPENT_ON_POLLUTION_CONTROL
|
||||||
|
|
||||||
|
522 IF MONEY_SPENT_ON_POLLUTION_CONTROL<0 THEN 510
|
||||||
|
530 IF MONEY_SPENT_ON_POLLUTION_CONTROL<=RALLODS THEN 1000
|
||||||
|
540 PRINT " THINK AGAIN. YOU ONLY HAVE ";RALLODS;" RALLODS REMAINING."
|
||||||
|
550 GOTO 510
|
||||||
|
|
||||||
|
600 IF SELL_TO_INDUSTRY<>0 THEN 1002
|
||||||
|
602 IF WELFARE<>0 THEN 1002
|
||||||
|
604 IF PLANTING_AREA<>0 THEN 1002
|
||||||
|
606 IF MONEY_SPENT_ON_POLLUTION_CONTROL<>0 THEN 1002
|
||||||
|
|
||||||
|
609 PRINT
|
||||||
|
612 PRINT "GOODBYE."
|
||||||
|
614 PRINT "(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER"
|
||||||
|
616 PRINT "'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START"
|
||||||
|
617 PRINT "OF THE GAME)."
|
||||||
|
618 STOP
|
||||||
|
|
||||||
|
1000 GOTO 600
|
||||||
|
|
||||||
|
1002 PRINT
|
||||||
|
1003 PRINT
|
||||||
|
|
||||||
|
1010 RALLODS=INT(RALLODS-MONEY_SPENT_ON_POLLUTION_CONTROL)
|
||||||
|
1020 ORIGINAL_RALLODS=RALLODS
|
||||||
|
|
||||||
|
1100 IF INT(WELFARE/100-COUNTRYMEN)>=0 THEN 1120
|
||||||
|
1105 IF WELFARE/100<50 THEN 1700
|
||||||
|
1110 PRINT INT(COUNTRYMEN-(WELFARE/100));"COUNTRYMEN DIED OF STARVATION"
|
||||||
|
|
||||||
|
1120 POLLUTION_DEATHS=INT(RND(1)*(2000-LANDAREA))
|
||||||
|
1122 IF MONEY_SPENT_ON_POLLUTION_CONTROL<25 THEN 1130
|
||||||
|
1125 POLLUTION_DEATHS=INT(POLLUTION_DEATHS/(MONEY_SPENT_ON_POLLUTION_CONTROL/25))
|
||||||
|
|
||||||
|
1130 IF POLLUTION_DEATHS<=0 THEN 1150
|
||||||
|
1140 PRINT POLLUTION_DEATHS;"COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION"
|
||||||
|
|
||||||
|
1150 IF INT((WELFARE/100)-COUNTRYMEN)<0 THEN 1170
|
||||||
|
1160 IF POLLUTION_DEATHS>0 THEN 1180
|
||||||
|
1165 GOTO 1200
|
||||||
|
|
||||||
|
1170 PRINT " YOU WERE FORCED TO SPEND";INT((POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))*9);
|
||||||
|
1172 PRINT "RALLODS ON FUNERAL EXPENSES"
|
||||||
|
1174 DEATHS=INT(POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))
|
||||||
|
1175 RALLODS=INT(RALLODS-((POLLUTION_DEATHS+(COUNTRYMEN-(WELFARE/100)))*9))
|
||||||
|
1176 GOTO 1185
|
||||||
|
|
||||||
|
1180 PRINT " YOU WERE FORCED TO SPEND ";INT(POLLUTION_DEATHS*9);"RALLODS ON ";
|
||||||
|
1181 PRINT "FUNERAL EXPENSES."
|
||||||
|
1182 DEATHS=POLLUTION_DEATHS
|
||||||
|
1183 RALLODS=INT(RALLODS-(POLLUTION_DEATHS*9))
|
||||||
|
|
||||||
|
1185 IF RALLODS>=0 THEN 1194
|
||||||
|
1187 PRINT " INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD"
|
||||||
|
1189 LANDAREA=INT(LANDAREA+(RALLODS/LANDPRICE))
|
||||||
|
1190 RALLODS=0
|
||||||
|
|
||||||
|
1194 COUNTRYMEN=INT(COUNTRYMEN-DEATHS)
|
||||||
|
|
||||||
|
1200 IF SELL_TO_INDUSTRY=0 THEN 1250
|
||||||
|
1220 NEW_FOREIGNERS=INT(SELL_TO_INDUSTRY+(RND(1)*10)-(RND(1)*20))
|
||||||
|
1224 IF FOREIGN_WORKERS>0 THEN 1230
|
||||||
|
1226 NEW_FOREIGNERS=NEW_FOREIGNERS+20
|
||||||
|
|
||||||
|
1230 PRINT NEW_FOREIGNERS;"WORKERS CAME TO THE COUNTRY AND";
|
||||||
|
|
||||||
|
1250 IMMIGRATION=INT(((WELFARE/100-COUNTRYMEN)/10)+(MONEY_SPENT_ON_POLLUTION_CONTROL/25)-((2000-LANDAREA)/50)-(POLLUTION_DEATHS/2))
|
||||||
|
1255 PRINT ABS(IMMIGRATION);"COUNTRYMEN ";
|
||||||
|
1260 IF IMMIGRATION<0 THEN 1275
|
||||||
|
1265 PRINT "CAME TO";
|
||||||
|
1270 GOTO 1280
|
||||||
|
1275 PRINT "LEFT";
|
||||||
|
1280 PRINT " THE ISLAND."
|
||||||
|
1290 COUNTRYMEN=INT(COUNTRYMEN+IMMIGRATION)
|
||||||
|
|
||||||
|
|
||||||
|
1292 FOREIGN_WORKERS=INT(FOREIGN_WORKERS+NEW_FOREIGNERS)
|
||||||
|
|
||||||
|
1305 CROP_LOSS=INT(((2000-LANDAREA)*((RND(1)+1.5)/2)))
|
||||||
|
1310 IF FOREIGN_WORKERS=0 THEN 1324
|
||||||
|
1320 PRINT "OF ";INT(PLANTING_AREA);"SQ. MILES PLANTED,";
|
||||||
|
1324 IF PLANTING_AREA>CROP_LOSS THEN 1330
|
||||||
|
1326 CROP_LOSS=PLANTING_AREA
|
||||||
|
1330 PRINT " YOU HARVESTED ";INT(PLANTING_AREA-CROP_LOSS);"SQ. MILES OF CROPS."
|
||||||
|
1340 IF CROP_LOSS=0 THEN 1370
|
||||||
|
1344 IF T1>=2 THEN 1370
|
||||||
|
1350 PRINT " (DUE TO ";
|
||||||
|
1355 IF T1=0 THEN 1365
|
||||||
|
1360 PRINT "INCREASED ";
|
||||||
|
1365 PRINT "AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY.)"
|
||||||
|
1370 AGRICULTURAL_INCOME=INT((PLANTING_AREA-CROP_LOSS)*(LANDPRICE/2))
|
||||||
|
1380 PRINT "MAKING";INT(AGRICULTURAL_INCOME);"RALLODS."
|
||||||
|
1390 RALLODS=INT(RALLODS+AGRICULTURAL_INCOME)
|
||||||
|
|
||||||
|
REM I think tourism calculations are actually wrong in the original code!
|
||||||
|
|
||||||
|
1400 V1=INT(((COUNTRYMEN-IMMIGRATION)*22)+(RND(1)*500))
|
||||||
|
1405 V2=INT((2000-LANDAREA)*15)
|
||||||
|
1410 PRINT " YOU MADE";ABS(INT(V1-V2));"RALLODS FROM TOURIST TRADE."
|
||||||
|
1420 IF V2=0 THEN 1450
|
||||||
|
1425 IF V1-V2>=V3 THEN 1450
|
||||||
|
1430 PRINT " DECREASE BECAUSE ";
|
||||||
|
1435 G1=10*RND(1)
|
||||||
|
1440 IF G1<=2 THEN 1460
|
||||||
|
1442 IF G1<=4 THEN 1465
|
||||||
|
1444 IF G1<=6 THEN 1470
|
||||||
|
1446 IF G1<=8 THEN 1475
|
||||||
|
1448 IF G1<=10 THEN 1480
|
||||||
|
1450 V3=INT(RALLODS+V3)
|
||||||
|
1451 RALLODS=INT(RALLODS+V3)
|
||||||
|
1452 GOTO 1500
|
||||||
|
1460 PRINT "FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION."
|
||||||
|
1462 GOTO 1450
|
||||||
|
1465 PRINT "AIR POLLUTION IS KILLING GAME BIRD POPULATION."
|
||||||
|
1467 GOTO 1450
|
||||||
|
1470 PRINT "MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION."
|
||||||
|
1472 GOTO 1450
|
||||||
|
1475 PRINT "UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS."
|
||||||
|
1477 GOTO 1450
|
||||||
|
1480 PRINT "HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT."
|
||||||
|
1482 GOTO 1450
|
||||||
|
1500 IF DEATHS>200 THEN 1600
|
||||||
|
1505 IF COUNTRYMEN<343 THEN 1700
|
||||||
|
1510 IF (ORIGINAL_RALLODS/100)>5 THEN 1800
|
||||||
|
1515 IF FOREIGN_WORKERS>COUNTRYMEN THEN 1550
|
||||||
|
1520 IF YEARS_REQUIRED-1=X5 THEN 1900
|
||||||
|
1545 GOTO 2000
|
||||||
|
1550 PRINT
|
||||||
|
1552 PRINT
|
||||||
|
1560 PRINT "THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER"
|
||||||
|
1562 PRINT "OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND"
|
||||||
|
1564 PRINT "TAKEN OVER THE COUNTRY."
|
||||||
|
1570 IF RND(1)<=.5 THEN 1580
|
||||||
|
1574 PRINT "YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW"
|
||||||
|
1576 PRINT "RESIDING IN PRISON."
|
||||||
|
1578 GOTO 1590
|
||||||
|
1580 PRINT "YOU HAVE BEEN ASSASSINATED."
|
||||||
|
1590 PRINT
|
||||||
|
1592 PRINT
|
||||||
|
1596 STOP
|
||||||
|
1600 PRINT
|
||||||
|
1602 PRINT
|
||||||
|
1610 PRINT DEATHS;"COUNTRYMEN DIED IN ONE YEAR!!!!!"
|
||||||
|
1615 PRINT "DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY"
|
||||||
|
1620 PRINT "BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU"
|
||||||
|
1622 M6=INT(RND(1)*10)
|
||||||
|
1625 IF M6<=3 THEN 1670
|
||||||
|
1630 IF M6<=6 THEN 1680
|
||||||
|
1635 IF M6<=10 THEN 1690
|
||||||
|
1670 PRINT "ALSO HAD YOUR LEFT EYE GOUGED OUT!"
|
||||||
|
1672 GOTO 1590
|
||||||
|
1680 PRINT "HAVE ALSO GAINED A VERY BAD REPUTATION."
|
||||||
|
1682 GOTO 1590
|
||||||
|
1690 PRINT "HAVE ALSO BEEN DECLARED NATIONAL FINK."
|
||||||
|
1692 GOTO 1590
|
||||||
|
|
||||||
|
1700 PRINT
|
||||||
|
1702 PRINT
|
||||||
|
1710 PRINT "OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU"
|
||||||
|
1715 PRINT "WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)"
|
||||||
|
1720 PRINT "HATE YOUR GUTS."
|
||||||
|
1730 GOTO 1570
|
||||||
|
1800 IF DEATHS-POLLUTION_DEATHS<2 THEN 1515
|
||||||
|
1807 PRINT
|
||||||
|
1815 PRINT "MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID"
|
||||||
|
1820 PRINT "NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED"
|
||||||
|
1825 PRINT "OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE"
|
||||||
|
1830 PRINT "BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE."
|
||||||
|
1835 PRINT "THE CHOICE IS YOURS."
|
||||||
|
1840 PRINT "IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER"
|
||||||
|
1845 PRINT "BEFORE PROCEEDING."
|
||||||
|
1850 GOTO 1590
|
||||||
|
1900 PRINT
|
||||||
|
1902 PRINT
|
||||||
|
1920 PRINT "CONGRATULATIONS!!!!!!!!!!!!!!!!!!"
|
||||||
|
1925 PRINT "YOU HAVE SUCCESFULLY COMPLETED YOUR";YEARS_REQUIRED;"YEAR TERM"
|
||||||
|
1930 PRINT "OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT"
|
||||||
|
1935 PRINT "NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD"
|
||||||
|
1940 PRINT "LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT"
|
||||||
|
1945 PRINT "PLAYS THIS GAME."
|
||||||
|
1950 GOTO 1590
|
||||||
|
|
||||||
|
1960 PRINT "HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED";
|
||||||
|
1961 INPUT X5
|
||||||
|
1962 IF X5<0 THEN 1590
|
||||||
|
1963 IF X5<8 THEN 1969
|
||||||
|
1965 PRINT " COME ON, YOUR TERM IN OFFICE IS ONLY";YEARS_REQUIRED;"YEARS."
|
||||||
|
1967 GOTO 1960
|
||||||
|
1969 PRINT "HOW MUCH DID YOU HAVE IN THE TREASURY";
|
||||||
|
1970 INPUT RALLODS
|
||||||
|
1971 IF RALLODS<0 THEN 1590
|
||||||
|
1975 PRINT "HOW MANY COUNTRYMEN";
|
||||||
|
1976 INPUT COUNTRYMEN
|
||||||
|
1977 IF COUNTRYMEN<0 THEN 1590
|
||||||
|
1980 PRINT "HOW MANY WORKERS";
|
||||||
|
1981 INPUT FOREIGN_WORKERS
|
||||||
|
1982 IF FOREIGN_WORKERS<0 THEN 1590
|
||||||
|
1990 PRINT "HOW MANY SQUARE MILES OF LAND";
|
||||||
|
1991 INPUT LANDAREA
|
||||||
|
1992 IF LANDAREA<0 THEN 1590
|
||||||
|
1993 IF LANDAREA>2000 THEN 1996
|
||||||
|
1994 IF LANDAREA>1000 THEN 100
|
||||||
|
1996 PRINT " COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND"
|
||||||
|
1997 PRINT " AND 10,000 SQ. MILES OF FOREST LAND."
|
||||||
|
1998 GOTO 1990
|
||||||
|
|
||||||
|
2000 X5=X5+1
|
||||||
|
2020 DEATHS=0
|
||||||
|
2040 GOTO 100
|
||||||
|
2046 END
|
||||||
600
53_King/kotlin/King.kt
Normal file
600
53_King/kotlin/King.kt
Normal file
@@ -0,0 +1,600 @@
|
|||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.random.Random
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
lateinit var gameState: GameState
|
||||||
|
const val INCLUDE_BUGS_FROM_ORIGINAL = false
|
||||||
|
|
||||||
|
val rnd: Double get() = Random.nextDouble()
|
||||||
|
fun tab(i: Int) = " ".repeat(i)
|
||||||
|
class EndOfInputException : Throwable()
|
||||||
|
|
||||||
|
fun main() {
|
||||||
|
header()
|
||||||
|
|
||||||
|
print("DO YOU WANT INSTRUCTIONS? ")
|
||||||
|
readLine()?.apply {
|
||||||
|
gameState = if (startsWith("AGAIN")) loadOldGame() else GameState()
|
||||||
|
if (startsWith("Y")) instructions(gameState.yearsRequired)
|
||||||
|
}
|
||||||
|
?: throw EndOfInputException()
|
||||||
|
|
||||||
|
try {
|
||||||
|
with(gameState) {
|
||||||
|
while(currentYear < yearsRequired) {
|
||||||
|
recalculateLandCost()
|
||||||
|
displayStatus()
|
||||||
|
inputLandSale()
|
||||||
|
performLandSale()
|
||||||
|
inputWelfare()
|
||||||
|
performWelfare()
|
||||||
|
inputPlantingArea()
|
||||||
|
performPlanting()
|
||||||
|
inputPollutionControl()
|
||||||
|
if (zeroInput()) {
|
||||||
|
displayExitMessage()
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
simulateOneYear()
|
||||||
|
currentYear ++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
win(gameState.yearsRequired)
|
||||||
|
} catch (e: GameEndingException) {
|
||||||
|
e.displayConsequences()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun header() {
|
||||||
|
println("${tab(34)}KING")
|
||||||
|
println("${tab(14)}CREATIVE COMPUTING MORRISTOWN, NEW JERSEY")
|
||||||
|
println()
|
||||||
|
println()
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun instructions(yearsRequired: Int) {
|
||||||
|
println("""
|
||||||
|
|
||||||
|
|
||||||
|
CONGRATULATIONS! YOU'VE JUST BEEN ELECTED PREMIER OF SETATS
|
||||||
|
DETINU, A SMALL COMMUNIST ISLAND 30 BY 70 MILES LONG. YOUR
|
||||||
|
JOB IS TO DECIDE UPON THE CONTRY'S BUDGET AND DISTRIBUTE
|
||||||
|
MONEY TO YOUR COUNTRYMEN FROM THE COMMUNAL TREASURY.
|
||||||
|
THE MONEY SYSTEM IS RALLODS, AND EACH PERSON NEEDS 100
|
||||||
|
RALLODS PER YEAR TO SURVIVE. YOUR COUNTRY'S INCOME COMES
|
||||||
|
FROM FARM PRODUCE AND TOURISTS VISITING YOUR MAGNIFICENT
|
||||||
|
FORESTS, HUNTING, FISHING, ETC. HALF YOUR LAND IS FARM LAND
|
||||||
|
WHICH ALSO HAS AN EXCELLENT MINERAL CONTENT AND MAY BE SOLD
|
||||||
|
TO FOREIGN INDUSTRY (STRIP MINING) WHO IMPORT AND SUPPORT
|
||||||
|
THEIR OWN WORKERS. CROPS COST BETWEEN 10 AND 15 RALLODS PER
|
||||||
|
SQUARE MILE TO PLANT.
|
||||||
|
YOUR GOAL IS TO COMPLETE YOUR $yearsRequired YEAR TERM OF OFFICE.
|
||||||
|
GOOD LUCK!
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadOldGame(): GameState = GameState().apply {
|
||||||
|
|
||||||
|
do {
|
||||||
|
var retry = false
|
||||||
|
print("HOW MANY YEARS HAD YOU BEEN IN OFFICE WHEN INTERRUPTED? ")
|
||||||
|
currentYear = numberInput()
|
||||||
|
|
||||||
|
if (currentYear <= 0)
|
||||||
|
throw GameEndingException.DataEntryValidation()
|
||||||
|
|
||||||
|
if (currentYear >= yearsRequired) {
|
||||||
|
println(" COME ON, YOUR TERM IN OFFICE IS ONLY $yearsRequired YEARS.")
|
||||||
|
retry = true
|
||||||
|
}
|
||||||
|
} while (retry)
|
||||||
|
|
||||||
|
print("HOW MUCH DID YOU HAVE IN THE TREASURY? ")
|
||||||
|
rallods = numberInput()
|
||||||
|
if (rallods < 0)
|
||||||
|
throw GameEndingException.DataEntryValidation()
|
||||||
|
|
||||||
|
print("HOW MANY WORKERS? ")
|
||||||
|
foreignWorkers = numberInput()
|
||||||
|
if (foreignWorkers < 0)
|
||||||
|
throw GameEndingException.DataEntryValidation()
|
||||||
|
|
||||||
|
do {
|
||||||
|
var retry = false
|
||||||
|
print("HOW MANY SQUARE MILES OF LAND? ")
|
||||||
|
landArea = numberInput()
|
||||||
|
if (landArea<0)
|
||||||
|
throw GameEndingException.DataEntryValidation()
|
||||||
|
if (landArea > 2000 || landArea <= 1000) {
|
||||||
|
println(" COME ON, YOU STARTED WITH 1000 SQ. MILES OF FARM LAND")
|
||||||
|
println(" AND 10,000 SQ. MILES OF FOREST LAND.")
|
||||||
|
retry = true
|
||||||
|
}
|
||||||
|
} while (retry)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All exceptions which indicate the premature ending of the game, due
|
||||||
|
* to mismanagement, starvation, revolution, or mis-entry of a game state.
|
||||||
|
*/
|
||||||
|
sealed class GameEndingException : Throwable() {
|
||||||
|
abstract fun displayConsequences()
|
||||||
|
|
||||||
|
fun finalFate() {
|
||||||
|
if (rnd < .5) {
|
||||||
|
println("YOU HAVE BEEN THROWN OUT OF OFFICE AND ARE NOW")
|
||||||
|
println("RESIDING IN PRISON.")
|
||||||
|
} else {
|
||||||
|
println("YOU HAVE BEEN ASSASSINATED.")
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExtremeMismanagement(private val death: Int) : GameEndingException() {
|
||||||
|
override fun displayConsequences() {
|
||||||
|
println()
|
||||||
|
println("$death COUNTRYMEN DIED IN ONE YEAR!!!!!")
|
||||||
|
println("DUE TO THIS EXTREME MISMANAGEMENT, YOU HAVE NOT ONLY")
|
||||||
|
println("BEEN IMPEACHED AND THROWN OUT OF OFFICE, BUT YOU")
|
||||||
|
println(
|
||||||
|
when ((rnd * 10.0).toInt()) {
|
||||||
|
in 0..3 -> "ALSO HAD YOUR LEFT EYE GOUGED OUT!"
|
||||||
|
in 4..6 -> "HAVE ALSO GAINED A VERY BAD REPUTATION."
|
||||||
|
else -> "HAVE ALSO BEEN DECLARED NATIONAL FINK."
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TooManyPeopleDead : GameEndingException() {
|
||||||
|
// The mistyping of "population" is in the original game.
|
||||||
|
override fun displayConsequences() {
|
||||||
|
println("""
|
||||||
|
|
||||||
|
|
||||||
|
OVER ONE THIRD OF THE POPULTATION HAS DIED SINCE YOU
|
||||||
|
WERE ELECTED TO OFFICE. THE PEOPLE (REMAINING)
|
||||||
|
HATE YOUR GUTS.
|
||||||
|
""".trimIndent())
|
||||||
|
finalFate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AntiImmigrationRevolution : GameEndingException() {
|
||||||
|
override fun displayConsequences() {
|
||||||
|
println("""
|
||||||
|
THE NUMBER OF FOREIGN WORKERS HAS EXCEEDED THE NUMBER
|
||||||
|
OF COUNTRYMEN. AS A MINORITY, THEY HAVE REVOLTED AND
|
||||||
|
TAKEN OVER THE COUNTRY.
|
||||||
|
""".trimIndent())
|
||||||
|
finalFate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StarvationWithFullTreasury : GameEndingException() {
|
||||||
|
override fun displayConsequences() {
|
||||||
|
println("""
|
||||||
|
MONEY WAS LEFT OVER IN THE TREASURY WHICH YOU DID
|
||||||
|
NOT SPEND. AS A RESULT, SOME OF YOUR COUNTRYMEN DIED
|
||||||
|
OF STARVATION. THE PUBLIC IS ENRAGED AND YOU HAVE
|
||||||
|
BEEN FORCED TO EITHER RESIGN OR COMMIT SUICIDE.
|
||||||
|
THE CHOICE IS YOURS.
|
||||||
|
IF YOU CHOOSE THE LATTER, PLEASE TURN OFF YOUR COMPUTER
|
||||||
|
BEFORE PROCEEDING.
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DataEntryValidation : GameEndingException() {
|
||||||
|
override fun displayConsequences() {
|
||||||
|
// no action
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun win(yearsRequired: Int) {
|
||||||
|
// The misspelling of "successfully" is in the original code.
|
||||||
|
println("""
|
||||||
|
|
||||||
|
CONGRATULATIONS!!!!!!!!!!!!!!!!!!
|
||||||
|
YOU HAVE SUCCESFULLY COMPLETED YOUR $yearsRequired YEAR TERM
|
||||||
|
OF OFFICE. YOU WERE, OF COURSE, EXTREMELY LUCKY, BUT
|
||||||
|
NEVERTHELESS, IT'S QUITE AN ACHIEVEMENT. GOODBYE AND GOOD
|
||||||
|
LUCK - YOU'LL PROBABLY NEED IT IF YOU'RE THE TYPE THAT
|
||||||
|
PLAYS THIS GAME.
|
||||||
|
|
||||||
|
|
||||||
|
""".trimIndent())
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record data, allow data input, and process the simulation for the game.
|
||||||
|
*/
|
||||||
|
class GameState(val yearsRequired: Int = 8) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current year. Years start with zero, but we never
|
||||||
|
* output the current year.
|
||||||
|
*/
|
||||||
|
var currentYear = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of countrymen who have died of either pollution
|
||||||
|
* or starvation this year.
|
||||||
|
* It costs 9 rallods to bury a body.
|
||||||
|
* If you lose 200 people in one year, you will throw an {@see ExtremeMismanagementException}
|
||||||
|
*/
|
||||||
|
private var death = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last year's tourist numbers. Use this to check whether the number
|
||||||
|
* of tourists has gone up or down each year.
|
||||||
|
*/
|
||||||
|
private var tourists = 0
|
||||||
|
|
||||||
|
private var moneySpentOnPollutionControl = 0
|
||||||
|
private var moneySpentOnPlanting = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current stock of rallods.
|
||||||
|
* Player starts with between 59000 and 61000 rallods, but
|
||||||
|
* mostly distributed close to 60000. 75% of the time it's
|
||||||
|
* between 59500 and 60500.
|
||||||
|
*/
|
||||||
|
var rallods = (60000.0 + (1000.0 * rnd) - (1000.0 * rnd)).toInt()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Population.
|
||||||
|
* Initial population is about to 500.
|
||||||
|
* 75% of the time it's between 495 and 505.
|
||||||
|
*/
|
||||||
|
private var countrymen = (500 + (10 * rnd) - (10 * rnd)).toInt()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Land sale price is evenly between 95 and 104 rallods per
|
||||||
|
* square mile.
|
||||||
|
* Price doesn't change over the course of the game.
|
||||||
|
*/
|
||||||
|
private var landPrice = (10 * rnd + 95).toInt()
|
||||||
|
|
||||||
|
private var plantingArea = 0
|
||||||
|
private var welfareThisYear = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Land area in square miles. Arable land is 1000 square miles less.
|
||||||
|
* Almost all calculations use landArea-1000 because only arable
|
||||||
|
* land is of any use.
|
||||||
|
*/
|
||||||
|
var landArea = 2000
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of foreigners brought in by companies to whom you
|
||||||
|
* have sold land. If this gets higher than your population, there will
|
||||||
|
* be a revolution.
|
||||||
|
*/
|
||||||
|
var foreignWorkers = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Planting cost is recalculated every year.
|
||||||
|
*/
|
||||||
|
private var costToPlant: Int = 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
* There is a brief explanation of land selling only
|
||||||
|
* on the first turn.
|
||||||
|
*/
|
||||||
|
private var explanationOfSellingGiven = false
|
||||||
|
|
||||||
|
private var sellThisYear: Int = 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Planting cost is recalculated every year
|
||||||
|
* at between 10 and 14 rallods.
|
||||||
|
*/
|
||||||
|
fun recalculateLandCost() {
|
||||||
|
costToPlant = ((rnd / 2.0) * 10.0 + 10.0).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the current status of the world.
|
||||||
|
*/
|
||||||
|
fun displayStatus() {
|
||||||
|
println()
|
||||||
|
println("YOU NOW HAVE $rallods RALLODS IN THE TREASURY.")
|
||||||
|
print("$countrymen COUNTRYMEN, ")
|
||||||
|
if (foreignWorkers != 0) {
|
||||||
|
println("$foreignWorkers FOREIGN WORKERS, ")
|
||||||
|
}
|
||||||
|
println("AND $landArea SQ. MILES OF LAND.")
|
||||||
|
println("THIS YEAR INDUSTRY WILL BUY LAND FOR $landPrice")
|
||||||
|
println("RALLODS PER SQUARE MILE.")
|
||||||
|
println("LAND CURRENTLY COSTS $costToPlant RALLODS PER SQUARE MILE TO PLANT.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun displayExitMessage() {
|
||||||
|
println()
|
||||||
|
println("GOODBYE.")
|
||||||
|
println("(IF YOU WISH TO CONTINUE THIS GAME AT A LATER DATE, ANSWER")
|
||||||
|
println("'AGAIN' WHEN ASKED IF YOU WANT INSTRUCTIONS AT THE START")
|
||||||
|
println("OF THE GAME).")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun performLandSale() {
|
||||||
|
landArea -= sellThisYear
|
||||||
|
rallods += sellThisYear * landPrice
|
||||||
|
}
|
||||||
|
|
||||||
|
fun performPlanting() {
|
||||||
|
rallods -= moneySpentOnPlanting
|
||||||
|
}
|
||||||
|
|
||||||
|
fun performWelfare() {
|
||||||
|
rallods -= welfareThisYear
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ask how much land we want to sell. Immediately get the money.
|
||||||
|
* The player has to do the calculations to work out how much
|
||||||
|
* money that makes.
|
||||||
|
*/
|
||||||
|
fun inputLandSale() {
|
||||||
|
do {
|
||||||
|
print("HOW MANY SQUARE MILES DO YOU WISH TO SELL TO INDUSTRY? ")
|
||||||
|
sellThisYear = numberInput()
|
||||||
|
if (sellThisYear > landArea - 1000) {
|
||||||
|
println("*** THINK AGAIN. YOU ONLY HAVE ${landArea - 1000} SQUARE MILES OF FARM LAND.")
|
||||||
|
if (!explanationOfSellingGiven) {
|
||||||
|
println()
|
||||||
|
println("(FOREIGN INDUSTRY WILL ONLY BUY FARM LAND BECAUSE")
|
||||||
|
println("FOREST LAND IS UNECONOMICAL TO STRIP MINE DUE TO TREES,")
|
||||||
|
println("THICKER TOP SOIL, ETC.)")
|
||||||
|
explanationOfSellingGiven = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (sellThisYear < 0 || sellThisYear > landArea - 1000)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input the value of `welfareThisYear`
|
||||||
|
*/
|
||||||
|
fun inputWelfare() {
|
||||||
|
do {
|
||||||
|
var retry = false
|
||||||
|
print("HOW MANY RALLODS WILL YOU DISTRIBUTE AMONG YOUR COUNTRYMEN? ")
|
||||||
|
welfareThisYear = numberInput()
|
||||||
|
|
||||||
|
if (welfareThisYear > rallods) {
|
||||||
|
println(" THINK AGAIN. YOU'VE ONLY $rallods RALLODS IN THE TREASURY")
|
||||||
|
retry = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (welfareThisYear < 0) {
|
||||||
|
retry = true
|
||||||
|
}
|
||||||
|
} while (retry)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the number of square miles to plant this year.
|
||||||
|
* Validate the response:
|
||||||
|
* Each countryman can only plant 2 square miles.
|
||||||
|
* You can only plant on arable land.
|
||||||
|
* You may not spend more on planting than your treasury.
|
||||||
|
*/
|
||||||
|
fun inputPlantingArea() {
|
||||||
|
if (welfareThisYear == rallods) {
|
||||||
|
plantingArea = 0
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
var retry = false
|
||||||
|
print("HOW MANY SQUARE MILES DO YOU WISH TO PLANT? ")
|
||||||
|
plantingArea = numberInput()
|
||||||
|
val moneySpentOnPlanting = plantingArea * costToPlant
|
||||||
|
|
||||||
|
if (plantingArea < 0) {
|
||||||
|
retry = true
|
||||||
|
} else if (plantingArea >= 0 && plantingArea > countrymen * 2) {
|
||||||
|
println(" SORRY, BUT EACH COUNTRYMAN CAN ONLY PLANT 2 SQ. MILES.")
|
||||||
|
retry = true
|
||||||
|
} else if (plantingArea > landArea - 1000) {
|
||||||
|
println(" SORRY, BUT YOU'VE ONLY ${landArea - 1000} SQ. MILES OF FARM LAND.")
|
||||||
|
retry = true
|
||||||
|
} else if (moneySpentOnPlanting > rallods) {
|
||||||
|
println(" THINK AGAIN. YOU'VE ONLY $rallods RALLODS LEFT IN THE TREASURY.")
|
||||||
|
retry = true
|
||||||
|
}
|
||||||
|
} while (retry)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enter amount for pollution control.
|
||||||
|
* Validate that this does not exceed treasury.
|
||||||
|
*/
|
||||||
|
fun inputPollutionControl() {
|
||||||
|
do {
|
||||||
|
var retry = false
|
||||||
|
print("HOW MANY RALLODS DO YOU WISH TO SPEND ON POLLUTION CONTROL? ")
|
||||||
|
moneySpentOnPollutionControl = numberInput()
|
||||||
|
|
||||||
|
if (rallods < 0) {
|
||||||
|
retry = true
|
||||||
|
} else if (moneySpentOnPollutionControl > rallods) {
|
||||||
|
println(" THINK AGAIN. YOU ONLY HAVE $rallods RALLODS REMAINING.")
|
||||||
|
retry = true
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (retry)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if all data entered so far has been zero.
|
||||||
|
*/
|
||||||
|
fun zeroInput() = sellThisYear == 0 &&
|
||||||
|
welfareThisYear == 0 &&
|
||||||
|
plantingArea == 0 &&
|
||||||
|
moneySpentOnPollutionControl == 0
|
||||||
|
|
||||||
|
fun simulateOneYear() {
|
||||||
|
rallods -= moneySpentOnPollutionControl
|
||||||
|
val rallodsAfterPollutionControl = rallods
|
||||||
|
|
||||||
|
var starvationDeaths = 0
|
||||||
|
if (welfareThisYear / 100.0 - countrymen < 0) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Wait, WHAT?
|
||||||
|
If you spend less than 5000 rallods on welfare, no matter the current size of the
|
||||||
|
population, then you will end the game, with the game claiming that too many
|
||||||
|
people have died, without showing exactly how many have died?
|
||||||
|
|
||||||
|
https://github.com/coding-horror/basic-computer-games/blob/main/53_King/king.bas#:~:text=1105%20IF%20I/100%3C50%20THEN%201700
|
||||||
|
*/
|
||||||
|
if (welfareThisYear / 100.0 < 50)
|
||||||
|
throw GameEndingException.TooManyPeopleDead()
|
||||||
|
|
||||||
|
starvationDeaths = (countrymen - (welfareThisYear / 100.0)).toInt()
|
||||||
|
println("$starvationDeaths COUNTRYMEN DIED OF STARVATION")
|
||||||
|
}
|
||||||
|
|
||||||
|
var pollutionDeaths = (rnd * (2000 - landArea)).toInt()
|
||||||
|
if (moneySpentOnPollutionControl >= 25) {
|
||||||
|
pollutionDeaths = (pollutionDeaths / (moneySpentOnPollutionControl / 25.0)).toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pollutionDeaths > 0) {
|
||||||
|
println("$pollutionDeaths COUNTRYMEN DIED OF CARBON-MONOXIDE AND DUST INHALATION")
|
||||||
|
}
|
||||||
|
|
||||||
|
death = pollutionDeaths + starvationDeaths
|
||||||
|
if (death > 0) {
|
||||||
|
println(" YOU WERE FORCED TO SPEND ${death * 9}")
|
||||||
|
println("RALLODS ON FUNERAL EXPENSES")
|
||||||
|
rallods -= death * 9
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rallods < 0) {
|
||||||
|
println(" INSUFFICIENT RESERVES TO COVER COST - LAND WAS SOLD")
|
||||||
|
landArea += rallods / landPrice
|
||||||
|
rallods = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
countrymen -= death
|
||||||
|
|
||||||
|
val newForeigners =
|
||||||
|
if (sellThisYear > 0) {
|
||||||
|
(sellThisYear + rnd * 10.0 + rnd * 20.0).toInt() + (if (foreignWorkers <= 0) 20 else 0)
|
||||||
|
} else 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
Immigration is calculated as
|
||||||
|
One for every thousand rallods more welfare than strictly required
|
||||||
|
minus one for every 10 starvation deaths
|
||||||
|
plus One for every 25 rallods spent on pollution control
|
||||||
|
plus one for every 50 square miles of arable land
|
||||||
|
minus one for every 2 pollution deaths
|
||||||
|
*/
|
||||||
|
val immigration = (
|
||||||
|
(welfareThisYear / 100.0 - countrymen) / 10.0 +
|
||||||
|
moneySpentOnPollutionControl / 25.0 -
|
||||||
|
(2000 - landArea) / 50.0 -
|
||||||
|
pollutionDeaths / 2.0
|
||||||
|
).toInt()
|
||||||
|
println(
|
||||||
|
"$newForeigners WORKERS CAME TO THE COUNTRY AND" +
|
||||||
|
" ${abs(immigration)} COUNTRYMEN ${if (immigration < 0) "LEFT" else "CAME TO"}" +
|
||||||
|
" THE ISLAND."
|
||||||
|
)
|
||||||
|
|
||||||
|
countrymen += immigration
|
||||||
|
foreignWorkers += newForeigners
|
||||||
|
|
||||||
|
/*
|
||||||
|
Crop loss is between 75% and 125% of the land sold to industry,
|
||||||
|
due to the pollution that industry causes.
|
||||||
|
Money spent on pollution control reduces pollution deaths among
|
||||||
|
the population, but does not affect crop losses.
|
||||||
|
*/
|
||||||
|
var cropLoss = ((2000 - landArea) * (rnd + 1.5) / 2.0).toInt()
|
||||||
|
val cropLossWorse = false
|
||||||
|
if (foreignWorkers > 0)
|
||||||
|
print("OF $plantingArea SQ. MILES PLANTED,")
|
||||||
|
if (plantingArea <= cropLoss)
|
||||||
|
cropLoss = plantingArea
|
||||||
|
println(" YOU HARVESTED ${plantingArea - cropLoss} SQ. MILES OF CROPS.")
|
||||||
|
|
||||||
|
if (cropLoss > 0) {
|
||||||
|
println(" (DUE TO ${if (cropLossWorse) "INCREASED " else ""}AIR AND WATER POLLUTION FROM FOREIGN INDUSTRY)")
|
||||||
|
}
|
||||||
|
|
||||||
|
val agriculturalIncome = ((plantingArea - cropLoss) * landPrice / 2.0).toInt()
|
||||||
|
println("MAKING $agriculturalIncome RALLODS.")
|
||||||
|
rallods += agriculturalIncome
|
||||||
|
|
||||||
|
val v1 = (((countrymen - immigration) * 22.0) + rnd * 500).toInt()
|
||||||
|
val v2 = ((2000.0 - landArea) * 15.0).toInt()
|
||||||
|
println(" YOU MADE ${abs(v1 - v2)} RALLODS FROM TOURIST TRADE.")
|
||||||
|
if (v2 != 0 && v1 - v2 < tourists) {
|
||||||
|
print(" DECREASE BECAUSE ")
|
||||||
|
println(
|
||||||
|
when ((10 * rnd).toInt()) {
|
||||||
|
in 0..2 -> "FISH POPULATION HAS DWINDLED DUE TO WATER POLLUTION."
|
||||||
|
in 3..4 -> "AIR POLLUTION IS KILLING GAME BIRD POPULATION."
|
||||||
|
in 5..6 -> "MINERAL BATHS ARE BEING RUINED BY WATER POLLUTION."
|
||||||
|
in 7..8 -> "UNPLEASANT SMOG IS DISCOURAGING SUN BATHERS."
|
||||||
|
else -> "HOTELS ARE LOOKING SHABBY DUE TO SMOG GRIT."
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
The original code was incorrect.
|
||||||
|
If v3 starts at 0, for example, our money doubles, when we
|
||||||
|
have already been told that "YOU MADE ${abs(v1 - v2)} RALLODS
|
||||||
|
FROM TOURIST TRADE"
|
||||||
|
|
||||||
|
See the original code
|
||||||
|
1450 V3=INT(A+V3)
|
||||||
|
1451 A=INT(A+V3)
|
||||||
|
|
||||||
|
https://github.com/coding-horror/basic-computer-games/blob/main/53_King/king.bas#:~:text=1450%20V3%3DINT,INT(A%2BV3)
|
||||||
|
*/
|
||||||
|
if (INCLUDE_BUGS_FROM_ORIGINAL) {
|
||||||
|
tourists += rallods
|
||||||
|
} else {
|
||||||
|
tourists = abs(v1 - v2)
|
||||||
|
}
|
||||||
|
rallods += tourists
|
||||||
|
|
||||||
|
if (death > 200)
|
||||||
|
throw GameEndingException.ExtremeMismanagement(death)
|
||||||
|
if (countrymen < 343)
|
||||||
|
throw GameEndingException.TooManyPeopleDead()
|
||||||
|
if (rallodsAfterPollutionControl / 100 > 5 && death - pollutionDeaths >= 2)
|
||||||
|
throw GameEndingException.StarvationWithFullTreasury()
|
||||||
|
if (foreignWorkers > countrymen)
|
||||||
|
throw GameEndingException.AntiImmigrationRevolution()
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun numberInput() = try {
|
||||||
|
readLine()?.toInt() ?: throw EndOfInputException()
|
||||||
|
} catch (r: NumberFormatException) {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
234
73_Reverse/perl/reverse.pl
Executable file
234
73_Reverse/perl/reverse.pl
Executable file
@@ -0,0 +1,234 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use 5.010; # To get 'state' and 'say'
|
||||||
|
|
||||||
|
use strict; # Require explicit declaration of variables
|
||||||
|
use warnings; # Enable optional compiler warnings
|
||||||
|
|
||||||
|
use English; # Use more friendly names for Perl's magic variables
|
||||||
|
use List::Util qw{ shuffle }; # Shuffle an array.
|
||||||
|
use Term::ReadLine; # Prompt and return user input
|
||||||
|
|
||||||
|
our $VERSION = '0.000_01';
|
||||||
|
|
||||||
|
# Manifest constant for size of list.
|
||||||
|
use constant NUMBER_OF_NUMBERS => 9;
|
||||||
|
|
||||||
|
print <<'EOD';
|
||||||
|
REVERSE
|
||||||
|
Creative Computing Morristown, New Jersey
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Reverse -- a game of skill
|
||||||
|
|
||||||
|
EOD
|
||||||
|
|
||||||
|
# Display the rules if desired. There is no straightforward way to
|
||||||
|
# interpolate a manifest constant into a string, but @{[ ... ]} will
|
||||||
|
# interpolate any expression.
|
||||||
|
print <<"EOD" if get_yes_no( 'Do you want the rules' );
|
||||||
|
|
||||||
|
This is the game of 'Reverse'. To win, all you have
|
||||||
|
to do is arrange a list of numbers (1 through @{[ NUMBER_OF_NUMBERS ]})
|
||||||
|
in numerical order from left to right. To move, you
|
||||||
|
tell me how many numbers (counting from the left) to
|
||||||
|
reverse. For example, if the current list is:
|
||||||
|
|
||||||
|
2 3 4 5 1 6 7 8 9
|
||||||
|
|
||||||
|
and you reverse 4, the result will be:
|
||||||
|
|
||||||
|
5 4 3 2 1 6 7 8 9
|
||||||
|
|
||||||
|
Now if you reverse 5, you win!
|
||||||
|
|
||||||
|
1 2 3 4 5 6 7 8 9
|
||||||
|
|
||||||
|
No doubt you will like this game, but
|
||||||
|
if you want to quit, reverse 0 (zero).
|
||||||
|
|
||||||
|
EOD
|
||||||
|
|
||||||
|
while ( 1 ) { # Iterate until something interrupts us.
|
||||||
|
|
||||||
|
# Populate the list with the integers from 1, shuffled. If we
|
||||||
|
# accidentally generate a winning list, just redo the loop.
|
||||||
|
my @list = shuffle( 1 .. NUMBER_OF_NUMBERS );
|
||||||
|
redo if is_win( \@list );
|
||||||
|
|
||||||
|
print <<"EOD";
|
||||||
|
|
||||||
|
Here we go ... The list is:
|
||||||
|
EOD
|
||||||
|
|
||||||
|
my $moves = 0; # Move counter
|
||||||
|
|
||||||
|
while ( 1 ) { # Iterate until something interrupts us.
|
||||||
|
print <<"EOD";
|
||||||
|
|
||||||
|
@list
|
||||||
|
|
||||||
|
EOD
|
||||||
|
|
||||||
|
# Read the number of values to reverse. Zero is special-cased to
|
||||||
|
# take us out of this loop.
|
||||||
|
last unless my $max_index = get_input(
|
||||||
|
'How many shall I reverse (0 to quit)? ',
|
||||||
|
sub {
|
||||||
|
return m/ \A [0-9]+ \z /smx &&
|
||||||
|
$ARG <= NUMBER_OF_NUMBERS;
|
||||||
|
},
|
||||||
|
"Oops! Too many! I can reverse at most " .
|
||||||
|
NUMBER_OF_NUMBERS,
|
||||||
|
);
|
||||||
|
|
||||||
|
--$max_index; # Convert number to reverse to upper index
|
||||||
|
|
||||||
|
# Use a Perl array slice and the reverse() built-in to reverse
|
||||||
|
# the beginning of the list.
|
||||||
|
@list[ 0 .. $max_index ] = reverse @list[ 0 .. $max_index ];
|
||||||
|
|
||||||
|
$moves++; # Count a move
|
||||||
|
|
||||||
|
# If we have not won, iterate again.
|
||||||
|
next unless is_win( \@list );
|
||||||
|
|
||||||
|
# Announce the win, and drop out of the loop.
|
||||||
|
print <<"EOD";
|
||||||
|
|
||||||
|
You won it in $moves moves!!!
|
||||||
|
EOD
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Drop out of this loop unless the player wants to play again.
|
||||||
|
say '';
|
||||||
|
last unless get_yes_no( 'Try again' );
|
||||||
|
}
|
||||||
|
|
||||||
|
print <<'EOD';
|
||||||
|
|
||||||
|
O.K. Hope you had fun!!
|
||||||
|
EOD
|
||||||
|
|
||||||
|
# Get input from the user. The arguments are:
|
||||||
|
# * The prompt
|
||||||
|
# * A reference to validation code. This code receives the response in
|
||||||
|
# $ARG and returns true for a valid response.
|
||||||
|
# * A warning to print if the response is not valid. This must end in a
|
||||||
|
# return.
|
||||||
|
# The first valid response is returned. An end-of-file terminates the
|
||||||
|
# script.
|
||||||
|
sub get_input {
|
||||||
|
my ( $prompt, $validate, $warning ) = @ARG;
|
||||||
|
|
||||||
|
# If no validator is passed, default to one that always returns
|
||||||
|
# true.
|
||||||
|
$validate ||= sub { 1 };
|
||||||
|
|
||||||
|
# Create the readline object. The 'state' causes the variable to be
|
||||||
|
# initialized only once, no matter how many times this subroutine is
|
||||||
|
# called. The do { ... } is a compound statement used because we
|
||||||
|
# need to tweak the created object before we store it.
|
||||||
|
state $term = do {
|
||||||
|
my $obj = Term::ReadLine->new( 'reverse' );
|
||||||
|
$obj->ornaments( 0 );
|
||||||
|
$obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
while ( 1 ) { # Iterate indefinitely
|
||||||
|
|
||||||
|
# Read the input into the topic variable, localized to prevent
|
||||||
|
# Spooky Action at a Distance. We exit on undef, which signals
|
||||||
|
# end-of-file.
|
||||||
|
exit unless defined( local $ARG = $term->readline( $prompt ) );
|
||||||
|
|
||||||
|
# Return the input if it is valid.
|
||||||
|
return $ARG if $validate->();
|
||||||
|
|
||||||
|
# Issue the warning, and go around the merry-go-round again.
|
||||||
|
warn $warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get a yes-or-no answer. The argument is the prompt, which will have
|
||||||
|
# '? [y/n]: ' appended. The donkey work is done by get_input(), which is
|
||||||
|
# requested to validate the response as beginning with 'y' or 'n',
|
||||||
|
# case-insensitive. The return is a true value for 'y' and a false value
|
||||||
|
# for 'n'.
|
||||||
|
sub get_yes_no {
|
||||||
|
my ( $prompt ) = @ARG;
|
||||||
|
state $map_answer = {
|
||||||
|
n => 0,
|
||||||
|
y => 1,
|
||||||
|
};
|
||||||
|
my $resp = lc get_input(
|
||||||
|
"$prompt? [y/n]: ",
|
||||||
|
sub { m/ \A [yn] /smxi },
|
||||||
|
"Please respond 'y' or 'n'\n",
|
||||||
|
);
|
||||||
|
return $map_answer->{ substr $resp, 0, 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
# Determine if a given list represents a win. The argument is a
|
||||||
|
# reference to the array containing the list. We return a true value for
|
||||||
|
# a win, or a false value otherwise.
|
||||||
|
sub is_win {
|
||||||
|
my ( $list ) = @_;
|
||||||
|
my $expect = 1; # We expect the first element to be 1;
|
||||||
|
|
||||||
|
# Iterate over the array.
|
||||||
|
foreach my $element ( @{ $list } ) {
|
||||||
|
|
||||||
|
# If the element does not have the expected value, we return
|
||||||
|
# false. We post-increment the expected value en passant.
|
||||||
|
$element == $expect++
|
||||||
|
or return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# All elements had the expected value, so we won. Return a true
|
||||||
|
# value.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 TITLE
|
||||||
|
|
||||||
|
reverse.pl - Play the game 'reverse' from Basic Computer Games
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
reverse.pl
|
||||||
|
|
||||||
|
=head1 DETAILS
|
||||||
|
|
||||||
|
This Perl script is a port of C<reverse>, which is the 73rd entry in
|
||||||
|
Basic Computer Games.
|
||||||
|
|
||||||
|
The cool thing about this port is the fact that, in a language with
|
||||||
|
array slices, list assignments, and a C<reverse()> built-in, the
|
||||||
|
reversal is a single assignment statement.
|
||||||
|
|
||||||
|
=head1 PORTED BY
|
||||||
|
|
||||||
|
Thomas R. Wyant, III F<wyant at cpan dot org>
|
||||||
|
|
||||||
|
=head1 COPYRIGHT AND LICENSE
|
||||||
|
|
||||||
|
Copyright (C) 2022 by Thomas R. Wyant, III
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it
|
||||||
|
under the same terms as Perl 5.10.0. For more details, see the Artistic
|
||||||
|
License 1.0 at
|
||||||
|
L<https://www.perlfoundation.org/artistic-license-10.html>, and/or the
|
||||||
|
Gnu GPL at L<http://www.gnu.org/licenses/old-licenses/gpl-1.0.txt>.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but
|
||||||
|
without any warranty; without even the implied warranty of
|
||||||
|
merchantability or fitness for a particular purpose.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
||||||
|
# ex: set expandtab tabstop=4 textwidth=72 :
|
||||||
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>)
|
||||||
@@ -1,30 +1,32 @@
|
|||||||
// WAR
|
// 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));
|
document.getElementById("output").appendChild(document.createTextNode(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
function input()
|
function tab(space) {
|
||||||
{
|
let str = "";
|
||||||
var input_element;
|
while (space-- > 0) {
|
||||||
var input_str;
|
str += " ";
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
function input() {
|
||||||
return new Promise(function (resolve) {
|
return new Promise(function (resolve) {
|
||||||
input_element = document.createElement("INPUT");
|
const input_element = document.createElement("INPUT");
|
||||||
|
|
||||||
print("? ");
|
print("? ");
|
||||||
input_element.setAttribute("type", "text");
|
input_element.setAttribute("type", "text");
|
||||||
input_element.setAttribute("length", "50");
|
input_element.setAttribute("length", "50");
|
||||||
document.getElementById("output").appendChild(input_element);
|
document.getElementById("output").appendChild(input_element);
|
||||||
input_element.focus();
|
input_element.focus();
|
||||||
input_str = undefined;
|
|
||||||
input_element.addEventListener("keydown", function (event) {
|
input_element.addEventListener("keydown", function (event) {
|
||||||
if (event.keyCode == 13) {
|
if (event.keyCode == 13) {
|
||||||
input_str = input_element.value;
|
const input_str = input_element.value;
|
||||||
document.getElementById("output").removeChild(input_element);
|
document.getElementById("output").removeChild(input_element);
|
||||||
print(input_str);
|
print(input_str);
|
||||||
print("\n");
|
print("\n");
|
||||||
@@ -34,27 +36,60 @@ function input()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function tab(space)
|
async function askYesOrNo(question) {
|
||||||
{
|
while (1) {
|
||||||
var str = "";
|
print(question);
|
||||||
while (space-- > 0)
|
const str = await input();
|
||||||
str += " ";
|
if (str == "YES") {
|
||||||
return str;
|
return true;
|
||||||
|
}
|
||||||
|
else if (str == "NO") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print("YES OR NO, PLEASE. ");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var a = [, "S-2","H-2","C-2","D-2","S-3","H-3","C-3","D-3",
|
async function askAboutInstructions() {
|
||||||
"S-4","H-4","C-4","D-4","S-5","H-5","C-5","D-5",
|
const playerWantsInstructions = await askYesOrNo("DO YOU WANT DIRECTIONS");
|
||||||
"S-6","H-6","C-6","D-6","S-7","H-7","C-7","D-7",
|
if (playerWantsInstructions) {
|
||||||
"S-8","H-8","C-8","D-8","S-9","H-9","C-9","D-9",
|
print("THE COMPUTER GIVES YOU AND IT A 'CARD'. THE HIGHER CARD\n");
|
||||||
"S-10","H-10","C-10","D-10","S-J","H-J","C-J","D-J",
|
print("(NUMERICALLY) WINS. THE GAME ENDS WHEN YOU CHOOSE NOT TO\n");
|
||||||
"S-Q","H-Q","C-Q","D-Q","S-K","H-K","C-K","D-K",
|
print("CONTINUE OR WHEN YOU HAVE FINISHED THE PACK.\n");
|
||||||
"S-A","H-A","C-A","D-A"];
|
}
|
||||||
|
print("\n");
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
var l = [];
|
function createGameDeck(cards, gameSize) {
|
||||||
|
const deck = [];
|
||||||
|
const deckSize = cards.length;
|
||||||
|
for (let j = 0; j < gameSize; j++) {
|
||||||
|
let card;
|
||||||
|
|
||||||
// Main control section
|
// Compute a new card index until we find one that isn't already in the new deck
|
||||||
async function main()
|
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(33) + "WAR\n");
|
||||||
print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
|
print(tab(15) + "CREATIVE COMPUTING MORRISTOWN, NEW JERSEY\n");
|
||||||
print("\n");
|
print("\n");
|
||||||
@@ -62,72 +97,65 @@ async function main()
|
|||||||
print("\n");
|
print("\n");
|
||||||
print("THIS IS THE CARD GAME OF WAR. EACH CARD IS GIVEN BY SUIT-#\n");
|
print("THIS IS THE CARD GAME OF WAR. EACH CARD IS GIVEN BY SUIT-#\n");
|
||||||
print("AS S-7 FOR SPADE 7. ");
|
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");
|
|
||||||
print("\n");
|
|
||||||
|
|
||||||
a1 = 0;
|
function printCards(playerCard, computerCard) {
|
||||||
b1 = 0;
|
print("\n");
|
||||||
p = 0;
|
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();
|
||||||
|
|
||||||
|
let computerScore = 0;
|
||||||
|
let playerScore = 0;
|
||||||
|
|
||||||
// Generate a random deck
|
// Generate a random deck
|
||||||
for (j = 1; j <= 52; j++) {
|
const gameSize = cards.length; // Number of cards to shuffle into the game deck. Can be <= cards.length.
|
||||||
do {
|
const deck = createGameDeck(cards, gameSize);
|
||||||
l[j] = Math.floor(52 * Math.random()) + 1;
|
let shouldContinuePlaying = true;
|
||||||
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
|
|
||||||
|
|
||||||
while (1) {
|
while (deck.length > 0 && shouldContinuePlaying) {
|
||||||
m1 = l[++p]; // Take a card
|
const playerCard = deck.shift(); // Take a card
|
||||||
m2 = l[++p]; // Take a card
|
const computerCard = deck.shift(); // Take a card
|
||||||
print("\n");
|
printCards(cards[playerCard], cards[computerCard]);
|
||||||
print("YOU: " + a[m1] + "\tCOMPUTER: " + a[m2] + "\n");
|
|
||||||
n1 = Math.floor((m1 - 0.5) / 4);
|
const playerCardValue = computeCardValue(playerCard);
|
||||||
n2 = Math.floor((m2 - 0.5) / 4);
|
const computerCardValue = computeCardValue(computerCard);
|
||||||
if (n1 < n2) {
|
if (playerCardValue < computerCardValue) {
|
||||||
a1++;
|
computerScore++;
|
||||||
print("THE COMPUTER WINS!!! YOU HAVE " + b1 + " AND THE COMPUTER HAS " + a1 + "\n");
|
print("THE COMPUTER WINS!!! YOU HAVE " + playerScore + " AND THE COMPUTER HAS " + computerScore + "\n");
|
||||||
} else if (n1 > n2) {
|
} else if (playerCardValue > computerCardValue) {
|
||||||
b1++;
|
playerScore++;
|
||||||
print("YOU WIN. YOU HAVE " + b1 + " AND THE COMPUTER HAS " + a1 + "\n");
|
print("YOU WIN. YOU HAVE " + playerScore + " AND THE COMPUTER HAS " + computerScore + "\n");
|
||||||
} else {
|
} else {
|
||||||
print("TIE. NO SCORE CHANGE.\n");
|
print("TIE. NO SCORE CHANGE.\n");
|
||||||
}
|
}
|
||||||
if (l[p + 1] == 0) {
|
|
||||||
print("\n");
|
if (deck.length === 0) {
|
||||||
print("\n");
|
printGameOver(playerScore, computerScore);
|
||||||
print("WE HAVE RUN OUT OF CARDS. FINAL SCORE: YOU: " + b1 + " THE COMPUTER: " + a1 + "\n");
|
|
||||||
print("\n");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
while (1) {
|
else {
|
||||||
print("DO YOU WANT TO CONTINUE");
|
shouldContinuePlaying = await askYesOrNo("DO YOU WANT TO CONTINUE");
|
||||||
str = await input();
|
|
||||||
if (str == "YES")
|
|
||||||
break;
|
|
||||||
if (str == "NO")
|
|
||||||
break;
|
|
||||||
print("YES OR NO, PLEASE. ");
|
|
||||||
}
|
}
|
||||||
if (str == "NO")
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
print("THANKS FOR PLAYING. IT WAS FUN.\n");
|
print("THANKS FOR PLAYING. IT WAS FUN.\n");
|
||||||
print("\n");
|
print("\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user