Go Fish/Raku: Difference between revisions
< Go Fish
Content added Content deleted
m (remove unneeded parens and 'do') |
Thundergnat (talk | contribs) (→{{header|Perl 6}}: Update to work with modern Rakudo) |
||
Line 1:
{{collection|Go Fish}}
{{works with|Rakudo|
<lang perl6>constant BOOKSIZE = 4;
constant HANDSIZE = 9;
constant
# The elements of @pips are only names. Pips are represented internally
# as indices of this array.
constant
constant
constant
constant $foe_nominative_pronoun = pick 1, <he she it e xe>;
Line 21:
sub find ($x, *@a) {
for @a.kv -> $k, $v {
$v
}
fail 'Not found';
Line 28:
sub maxes (&f, *@a) {
my $x = [max] map &f, @a;
return @a.grep: { f($^e) eqv $x }
}
Line 43:
loop {
print 'For what do you ask? (', join(', ', @shortpips[@choices]), '): ';
my $in = substr
my $pip = find $in, @shortpips;
if defined $pip {
Line 75 ⟶ 76:
class Player {
has
# @h[$n] is number of cards of pip $n in this player's hand.
has $.deck;
Line 83 ⟶ 84:
has Knowledge @.know;
method new ( $cpu, @deck
my
++@h[$_] for @deck[^HANDSIZE];
@deck = @deck[HANDSIZE ..^ @deck];
Player.bless(
h => @h, cpu => $cpu,
deck =>
know => ($cpu ?? map { Knowledge.new() }, @pips !! ())
);
Line 111 ⟶ 112:
}
method getcards (Int $quantity,
@!h[$pip] += $quantity;
@.h[$pip] == BOOKSIZE or return;
Line 123 ⟶ 124:
}
method losecards (
@.h[$pip] = 0;
while none @.h and $.deck.elems {
Line 133 ⟶ 134:
}
method learn (
method notice_draw () { .incr for @.know }
method choose_request ()
#self.showhand;
#say 'Know: ', join ', ', map
Line 143 ⟶ 144:
# @.know;
my @ps = map { .key }, grep { .value }, pairs @.h;
return
# Most of all we should ask for cards we know the
# user has.
@ps.grep
# Then try asking for one we haven't requested
# before.
@ps.grep
# Then try asking for one we least recently
# asked about.
maxes { @.know[$^p].n }, @ps ).roll;
}
}
Line 158 ⟶ 160:
sub play () {
my
# Shuffle the deck until the first two hands contain no books.
# (If BOOKSIZE is greater than 2 and HANDSIZE is reasonably
# small, this'll probably take only one shuffle.)
repeat { @deck =
until none(map { count $^x, @deck[^HANDSIZE] }, ^@pips) >= BOOKSIZE and
none(map { count $^x, @deck[HANDSIZE ..^ 2*HANDSIZE] }, ^@pips) >= BOOKSIZE;
Line 168 ⟶ 170:
my Player $user .= new(False, @deck);
my Player $foe .= new(True, @deck);
while any |$user.h or any |$foe.h {
# The user goes first.
while any |$user.h {
|
Revision as of 15:37, 1 April 2017
Go Fish/Raku is part of Go Fish. You may find other members of Go Fish at Category:Go Fish.
<lang perl6>constant BOOKSIZE = 4; constant HANDSIZE = 9; constant @pips = <two three four five six seven eight nine ten jack queen king ace>;
# The elements of @pips are only names. Pips are represented internally # as indices of this array.
constant @piparticles = <a a a a a a an a a a a a an>; constant @ppips = <deuces threes fours fives sixes sevens eights nines tens jacks queens kings aces>; constant @shortpips = <2 3 4 5 6 7 8 9 T J Q K A>; constant $foe_nominative_pronoun = pick 1, <he she it e xe>;
sub count ($x, *@a) {
my $n = 0; $_ eqv $x and ++$n for @a; return $n;
}
sub find ($x, *@a) {
for @a.kv -> $k, $v { $v eq $x and return $k; } fail 'Not found';
}
sub maxes (&f, *@a) {
my $x = [max] map &f, @a; return @a.grep: { f($^e) eqv $x };
}
sub ncard ($n, $pip) {
$n > 1 ?? "$n {@ppips[$pip]}" !! "{@piparticles[$pip]} {@pips[$pip]}"
}
sub readpip (@user_hand) {
my @choices = grep { @user_hand[$^p] }, ^@pips; if @choices == 1 { say "You're obliged to ask for { @ppips[@choices[0]] }."; return @choices[0]; } loop { print 'For what do you ask? (', join(', ', @shortpips[@choices]), '): '; my $in = substr ($*IN.get.uc or next), 0, 1;
my $pip = find $in, @shortpips; if defined $pip { @user_hand[$pip] and return $pip; say "You don't have any { @ppips[$pip] }."; } else { say 'No such rank.'; } }
}
enum Maybe <No Yes Dunno>;
class Knowledge {
- The computer player has an instance of this class for each pip.
- Each instance tracks whether the computer thinks the user has at
- least one card of the corresponding pip.
has Maybe $.maybe = Dunno; # Yes if the user definitely has this pip, No if they didn't # have it the last time we checked, Dunno if we haven't yet # checked. has Int $.n = 0; # If $.maybe is No, $.n counts how many cards the user # has drawn since we last checked.
method set (Maybe $!maybe) { $!n = 0 }
method incr { $.maybe == No and ++$!n }
}
class Player {
has @.h; # @h[$n] is number of cards of pip $n in this player's hand. has $.deck; # A reference to whatever deck the player's playing with. has Int $.books = 0; has Bool $.cpu; has Knowledge @.know;
method new ( $cpu, @deck ) { my @h = 0 xx @pips; ++@h[$_] for @deck[^HANDSIZE]; @deck = @deck[HANDSIZE ..^ @deck]; Player.bless( h => @h, cpu => $cpu, deck => @deck, know => ($cpu ?? map { Knowledge.new() }, @pips !! ()) ); }
method showhand { say ($.cpu ?? 'The dealer has ' !! 'You have '), join(' ', map { join ' ', @shortpips[.key] xx .value }, grep { .value }, pairs @.h), '.'; }
method draw () { my $new = shift $.deck; $.cpu or print "You got { ncard 1, $new }. "; say "({ $.deck.elems or 'No' } card{ $.deck.elems == 1 ?? !! 's' } left.)"; self.getcards(1, $new); }
method getcards (Int $quantity, $pip) { @!h[$pip] += $quantity; @.h[$pip] == BOOKSIZE or return; ++$!books; say ($.cpu ?? "The dealer puts down a book of { @ppips[$pip] }" !! "That's a book"), " (for a total of $.books book{ $.books == 1 ?? !! 's' })."; self.losecards($pip); }
method losecards ($pip) { @.h[$pip] = 0; while none @.h and $.deck.elems { say $.cpu ?? "The dealer's hand is empty, so $foe_nominative_pronoun draws a new card." !! "Your hand's empty, so you draw a new card."; self.draw; } }
method learn ($pip, Maybe $m) { @.know[$pip].set($m) }
method notice_draw () { .incr for @.know }
method choose_request () { #self.showhand; #say 'Know: ', join ', ', map # { .maybe ~~ Yes ?? 'Yes' !! .maybe ~~ Dunno ?? 'Dunno' !! .n }, # @.know; my @ps = map { .key }, grep { .value }, pairs @.h;
return ( maxes { @.h[$^p] }, # Most of all we should ask for cards we know the # user has. @ps.grep({ @.know[$^p].maybe ~~ Yes }).flat || # Then try asking for one we haven't requested # before. @ps.grep({ @.know[$^p].maybe ~~ Dunno }).flat || # Then try asking for one we least recently # asked about. maxes { @.know[$^p].n }, @ps ).roll; }
}
sub play () {
my @deck; # Shuffle the deck until the first two hands contain no books. # (If BOOKSIZE is greater than 2 and HANDSIZE is reasonably # small, this'll probably take only one shuffle.) repeat { @deck = (flat ^@pips xx BOOKSIZE).pick(*) } until none(map { count $^x, @deck[^HANDSIZE] }, ^@pips) >= BOOKSIZE and none(map { count $^x, @deck[HANDSIZE ..^ 2*HANDSIZE] }, ^@pips) >= BOOKSIZE;
my Player $user .= new(False, @deck); my Player $foe .= new(True, @deck);
while any |$user.h or any |$foe.h {
# The user goes first. while any |$user.h { say ; $user.showhand; my $request = readpip $user.h; $foe.learn($request, Yes); if $foe.h[$request] -> $quantity is copy { say 'The dealer reluctantly hands over ', ncard($quantity, $request), '.'; $foe.losecards($request); $user.getcards($quantity, $request); } else { say '"Go fish!"'; $user.draw; $foe.notice_draw; last; } }
while any |$foe.h { my $request = $foe.choose_request; say "\n\"Got any ", @ppips[$request], '?"'; $foe.learn($request, No); if $user.h[$request] -> $quantity is copy { say '"Thanks!"'; $foe.getcards($quantity, $request); $user.losecards($request); } else { say 'The dealer goes fishing.'; $foe.draw; last; } }
}
say "\nGame over!"; say 'Your books: ', $user.books; say "The dealer's books: ", $foe.books; say do $user.books > $foe.books ?? 'A winner is you!' !! $user.books < $foe.books ?? 'Alas, you have lost.' # A draw is possible if @pips !% 2. !! "It's a draw.";
}
sub MAIN () { play }</lang>