mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-22 07:10:42 -08:00
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!");
|
||||
}
|
||||
Reference in New Issue
Block a user