Category: | Fun Stuff |
Author/Contact Info | Joseph Jones jjdraco@acsalaska.net |
Description: | 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 ACM 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. well this is my solution to Problem 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. 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(). given the test cases on the website my results should print out: Win: 66 Loss: 82 Draw: 73 but the results I'm getting are: Win: 66 loss: 118 Draw: 75 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. Also I have a question on proper programming. 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 $self to them because they need that information. Is the way I did it poor style? How should I have done it? 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. 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? Thanks for any feedback jjdraco |
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 to +p 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 d +rawing # 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 play +ed $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"; } } } |
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: '96 ACM Problem A
by Anonymous Monk on Oct 12, 2002 at 00:32 UTC | |
by jjdraco (Scribe) on Oct 12, 2002 at 02:18 UTC |