Go Fish/D
< Go Fish
Go Fish/D is part of Go Fish. You may find other members of Go Fish at Category:Go Fish.
Translation of: Python <lang d>import std.stdio, std.random, std.range, std.string, std.array,
std.algorithm, std.exception;
alias replicate = std.array.replicate; //
class EndGameException : Exception {
this() pure nothrow { super(""); }
}
class Deck {
string[] d; this(string[] deck_) { d = deck_; } alias d this;
}
abstract class Player {
string name; Deck deck; int[string] hand; int score = 0; string[] book;
this(Deck deck_) in { assert(deck_ !is null); } body { deck = deck_; }
void draw() in { assert(deck !is null); } body { auto cardDrawn = deck.back; deck.popBack; // Removes the last card from deck. hand[cardDrawn]++; // Adds card to hand. writefln("%s drew %s.", name, cardDrawn); checkForBooks; }
string makeTurn();
/// Removes all items of which are 4. void checkForBooks() { // We are modifying 'hand' in loop: foreach (key, val; zip(hand.keys, hand.values)) if (val == 4) { // completed a book book ~= key; writefln("%s completed the book of %s's.", name, key); score++; hand.remove(key); } emptyCheck; }
/// Checks if deck/hand is empty. void emptyCheck() { //if (!deck.empty && hand.empty) if (!deck.empty && hand.length == 0) draw(); }
/// If card in hand, returns count and removes the card from hand. int fishFor(string card) { if (card in hand) { // If card in hand, returns count and removes the // card from hand. auto val = hand[card]; hand.remove(card); emptyCheck; return val; } else return 0; }
void gotCard(string card, int amount) { hand[card] += amount; checkForBooks; }
}
class Human: Player {
this(Deck deck_) { super(deck_); "Name yourself: ".write; name = readln.strip; }
/// Displays current hand, cards separated by spaces. string displayHand() { //return " ".join(key for key, val in hand.iteritems() // for i in xrange(val)) string[] result; foreach (key, val; hand) result ~= [key].replicate(val); return result.join(" "); }
override string makeTurn() { writefln("%s's hand: %s", name, displayHand); "What card do you ask for? ".write; auto chooseCard = readln.strip; if (chooseCard == "quit") throw new EndGameException(); if (chooseCard !in hand) { writeln("You don't have that card. Try again!" ~ " (or enter quit to exit)"); chooseCard = makeTurn; } return chooseCard; }
}
class Computer: Player {
bool[string] opponentHas; // a Set.
this(Deck deck_) { super(deck_); name = "Computer"; }
// AI: guesses cards that knows you have, then tries cards he has // at random. Improvements: remember if the card was rejected // before, guess probabilities. override string makeTurn() { // print displayHand(), opponentHas // Checks for cards in hand that computer knows you have. auto candidates = opponentHas.keys.sort() .setIntersection(hand.keys.sort()).array; if (candidates.empty) // If no intersection between those two, random guess. candidates = hand.keys; auto move = candidates[uniform(0, $)]; writefln("%s fishes for %s.", name, move); return move; }
/// Same as for humans players, but adds the card fished // for to opponentHas list. override int fishFor(string card) { opponentHas[card] = true; return super.fishFor(card); }
override void gotCard(string card, int amount) { opponentHas.remove(card); super.gotCard(card, amount); }
}
class GoFish {
Deck deck; Player[] players;
this() { deck=new Deck("2 3 4 5 6 7 8 9 10 J Q K A".split.replicate(4));
// Makes counting turns easier. //players = [new Human(deck), new Computer(deck)]; players ~= new Human(deck); players ~= new Computer(deck); }
/// Checks if hands/decks are empty. bool endOfPlayCheck() { return !deck.empty || players[0].hand.length || players[1].hand.length; }
void play() { deck.d.randomShuffle; foreach (_; 0 .. 9) { // Deal the first cards players[0].draw; players[1].draw; }
auto turn = 0; while (endOfPlayCheck) { writefln("\nTurn %d (%s: %d, %s: %d) %d cards remaining.", turn, players[0].name, players[0].score, players[1].name, players[1].score, deck.length); auto whoseTurn = turn % 2; auto otherPlayer = (turn + 1) % 2; while (true) { // Loop until player finishes turn. auto cardFished = players[whoseTurn].makeTurn; auto result = players[otherPlayer].fishFor(cardFished); if (!result) { // Draws and ends turn. players[whoseTurn].draw; break; } writefln("%s got %d more %s.", players[whoseTurn].name, result, cardFished); players[whoseTurn].gotCard(cardFished, result); if (!endOfPlayCheck) break; } turn++; }
writefln("\nScores: \n%s: %d\n%s: %d\n", players[0].name, players[0].score, players[1].name, players[1].score); if (players[0].score > players[1].score) writeln(players[0].name, " won!"); else if (players[0].score == players[1].score) writeln("draw!"); else writefln(players[1].name, " won!"); }
}
void main() {
try { auto game = new GoFish; game.play; } catch (EndGameException) writeln("Game finished.");
}</lang>
The gameplay is the same as the Python entry.