sourcecode
jjdraco
<code>package TenTwentyThirty;
use strict;
use warnings;
sub new {
my $class = shift;
my $self = { DECK => shift,# a references to an array
RESULTS => 0, # scalar for play, win,
# lose, draw
# integers are 0, 1, 2,
# 3 respectfully
DEALT => 0, # scalor for number of
# cards dealt
TABLE => [ # list of lists
[],
[],
[],
[],
[],
[],
[]
],
};
bless $self,$class;
return $self;
} #### end of constructor
sub play { # this will play the game
my $self = shift;
my $testres; # used to store
# return value of
# _checkSum()
do{ # do..until game over
DONE: for my $pile (0..6) { # works through one pile at a time
no warnings; # first time for each pile
# in TABLE its undef
if( $self->{'TABLE'}->[$pile]->[0] != -1) {
use warnings;
last DONE if @{$self->{'DECK'}} == 0;
# exits for loop if no more
# cards can be dealt
push @{$self->{'TABLE'}->[$pile]}, shift @{$self->{'DECK'}};
$self->{'DEALT'}++;
# takes card from top of deck and puts on
# top of pile
# I feel I have to go into detail on what I mean by top of deck and top of pile
# for someone might get confused on why i did the above statement this way
# when you play cards, all the cards in the deck are face down and the top
# of the deck is the first card in the deck, that is where you'll be drawing
# cards from, the top
# know you'll be placing cards on the pile face up, the first card on the
# pile will end up being at the bottom of the pile as you place more
# cards on the pile, and the top of the pile is the last card you played
$testres = _checkSum($self,$pile);
# not sure if this is
# in good style
_removeCards($self,$testres,$pile);
# still not sure if this
# is in good style
} # end of if
} # end of for
}until(_gameOver($self)); # loop until game over
} #### end of play method
sub display { # this will display the results
# of the game
my $self = shift;
print "\n#########\n";
if( $self->{'RESULTS'} == 1) {
print "WIN : ";
} elsif( $self->{'RESULTS'} == 2) {
print "LOSS: ";
} elsif( $self->{'RESULTS'} == 3) {
print "DRAW: ";
} else {
print "INVALID RESULTS: ";
}
print $self->{'DEALT'};
print "\n#########\n";
} #### end of display method
# _checkSum makes 3 checks to a
# given array that is referenced
# by @{$self->{'TABLE'}->[$pile]}
# checks for sum of 10,20, or 30
# for following array elements
# 1. first, second, last
# 2. first, and last two
# 3. last three
# returns 0 if none sum right
# returns 1,2,3 for the respected
# test case that summed right
sub _checkSum {
my $self = shift;
my $pile = shift;
my $check;
if( @{$self->{'TABLE'}->[$pile]} >= 3 ) {
$check = $self->{'TABLE'}->[$pile]->[0] +
$self->{'TABLE'}->[$pile]->[1] +
$self->{'TABLE'}->[$pile]->[-1];
if( $check == 10 ||
$check == 20 ||
$check == 30 ) { return 1; }
$check = $self->{'TABLE'}->[$pile]->[0] +
$self->{'TABLE'}->[$pile]->[-1] +
$self->{'TABLE'}->[$pile]->[-2];
if( $check == 10 ||
$check == 20 ||
$check == 30 ) { return 2; }
$check = $self->{'TABLE'}->[$pile]->[-1] +
$self->{'TABLE'}->[$pile]->[-2] +
$self->{'TABLE'}->[$pile]->[-3];
if( $check == 10 ||
$check == 20 ||
$check == 30 ) { return 3; }
} # end of if
return 0;
} #### end of _checkSum method
sub _removeCards {
my ($self,$results,$pile) = @_;
if( $results==1) {
push @{$self->{'DECK'}}, shift @{$self->{'TABLE'}->[$pile]};
push @{$self->{'DECK'}}, shift @{$self->{'TABLE'}->[$pile]};
push @{$self->{'DECK'}}, pop @{$self->{'TABLE'}->[$pile]};
} elsif( $results==2 ) {
push @{$self->{'DECK'}}, shift @{$self->{'TABLE'}->[$pile]};
push @{$self->{'DECK'}}, splice( @{$self->{'TABLE'}->[$pile]}, -2);
} elsif( $results==3 ) {
push @{$self->{'DECK'}}, splice( @{$self->{'TABLE'}->[$pile]}, -3);
}
$self->{'TABLE'}->[$pile]->[0] = -1 if( @{$self->{'TABLE'}->[$pile]}==0 );
} #### end of _removeCards method
{
my @history;
sub _gameOver {
my $self = shift;
my $emptyPile = 0; # count number of
# empty piles
foreach my $pile (@{$self->{'TABLE'}}) {
$emptyPile++ if( $pile->[0] == -1);
}
# all piles must be empty
# to win the game
if( $emptyPile == 7) {
$self->{'RESULTS'} = 1;
return 1; # game over WIN
} elsif( @{$self->{'DECK'}} == 0) {
$self->{'RESULTS'} = 2;
return 1; # game over LOSS
} elsif(_draw($self)) {
$self->{'RESULTS'} = 3;
return 1; # game over DRAW
} else {
my $table;
for my $pile (0..6) {
$table .= join(" ",@{$self->{'TABLE'}->[$pile]});
$table .= " ";
}
push @history, $table;
return 0;
# game not over
}
} #### end of _gameOver method
sub _draw {
my $self = shift;
foreach my $table (@history) {
my $currentTable;
for my $pile (0..6) {
$currentTable .= join(" ",@{$self->{'TABLE'}->[$pile]});
$currentTable .= " ";
}
return 1 if($currentTable eq $table);
}
return 0;
}
}
1; #### end of TenTwentThirty.pm
#!perl
use strict;
use warnings;
use TenTwentyThirty;
use Array::Reform;
my @decks;
ReadCards(\@decks);
foreach my $deck (@decks) {
my $ttt = TenTwentyThirty->new($deck); # starts a new game
$ttt->play(); # Plays a game
$ttt->display(); # displays results of game
}
sub ReadCards {
my $decks = shift;
READ: while(<>) {
push @{$decks}, $_;
last READ if(/\b0/);
}
chomp @{$decks};
@{$decks} = split /\s+/,join(" ", @{$decks});
@{$decks} = Array::Reform->reform(52,\@{$decks});
pop @{$decks};
my $i = 0;
foreach my $item (@{$decks}) {
$i++;
if ( @{$item} != 52 ) {
die "$i doesn't have 52 cards\n";
}
}
}</code>
I've searched long and hard for programming problems to try so that i could practice writing programs and improve my skills. i cam a cross <a href="http://icpc.baylor.edu/icpc/">ACM</a> which hold an annual programming contest for College students. Even though I'm probably not elegable to enter the compatition, I did find that they keep an archive of all they're past problems for they're contest, so theres nothing stopping me from writing my on solution to the problem for the benefit of bettering myself.<br><br>
well this is my solution to <a href="http://www.acm.org/contest/96/finals/attt.html">Problem A</a> in the 1996 contest. You can go and read the full problem, but basicly given a standard deck of 52 cards it plays a solitaire card game called 10-20-30 and prints out the results: Win, Loss, Draw and the number of cards dealt in that game.<br>
I have a few conserns with my solution however. I think theres still some bugs in it and I can't find them, but I think its in the subroutine _gameOver(), or _draw().<br>
given the test cases on the <a href="http://acm.org/contest/96/finals/attt.html">website</a> my results should print out:<br>
Win: 66<br>
Loss: 82<br>
Draw: 73<br>
but the results I'm getting are:<br>
Win: 66<br>
loss: 118<br>
Draw: 75<br>
As of yet I haven't found out why my results don't match theres. I'm tempted to sit down and play the game with a deck of cards myself and see if I still get the same results.<br>
Also I have a question on proper programming.<br>
I have subroutines that I don't expect to get called outside the module. I name all these subroutines with a '_' underscore in front of their names, I also still pass <strong>$self</strong> to them because they need that information. Is the way I did it poor style? How should I have done it?<br>
I would also like to appologies for the really long comment in the play() subroutine, but I thought someone might not understand my line of thinking.<br>
And the last consern I have with this program, or the last one I can think of is...@history, which holds the previous states of the game. I use this to test for draw since a draw happens when a state repeats itself. I defined it outside of _gameOver() and _draw() but in a block so that both functions could see it and it would hold its contents through multipule calls to the two functions. Should I have down this some other way?<br><br>
Thanks for any feedback<br>
[jjdraco]
Fun Stuff
Joseph Jones
jjdraco@acsalaska.net