source: tests/exceptions/cardgame.cfa @ 89a8bab

Last change on this file since 89a8bab was df8ba61a, checked in by caparson <caparson@…>, 8 months ago

added test case for non-local ehm memory leak

  • Property mode set to 100644
File size: 6.4 KB
Line 
1#include <fstream.hfa>                                                                  // sin/sout
2#include <stdlib.hfa>                                                                   // convert
3#include <string.h>
4#include <coroutine.hfa>
5
6ExceptionDecl( Schmilblick );
7
8enum { DEATH_DECK_DIVISOR = 7 };
9
10coroutine Player {
11        PRNG & prng;
12        unsigned int id;                                                                        // identity of the player
13        Player * partner[2];                                                            // task on the left and right
14        unsigned int deck;                                                                      // size of the deck currently in play
15}; // Player
16
17void players( unsigned int num );
18void ?{}( Player & player, PRNG & prng, unsigned int id );
19void start( Player & player, Player & lp, Player & rp ); // supply partners
20void play( Player & player,  unsigned int deck );
21void drink( Player & player );
22
23enum { RIGHT = 0, LEFT = 1 };
24
25enum {
26        MinCardsTaken = 1,                                                                      // minimum number of cards allowed to draw
27        MaxCardsTaken = 8                                                                       // maximum number of cards allowed to draw
28};
29
30static unsigned int NumPlayersRemaining;                                // number of players currently in the game
31static unsigned int rounds;                                                             // count rounds during Schmilblick
32
33static unsigned int MakePlay( Player & player, unsigned int RemainingCards ) with( player ) {
34        unsigned int took = min( RemainingCards, (typeof(RemainingCards))prng( prng, MinCardsTaken, MaxCardsTaken ) ); // cards drawn
35        unsigned int passing = RemainingCards - took;           // remaining cards in the deck to be passed
36        return passing;
37} // Player::MakePlay
38
39void main( Player & player ) with( player ) {
40        try {
41                suspend;                                                                                // return immediately after establishing starter
42                poll();
43
44                for ( ;; ) {
45                  if ( partner[LEFT] == &player ) {                             // stop when only one player
46                                break;
47                        } // exit
48
49                        bool die = (deck % DEATH_DECK_DIVISOR) == 0; // check before making a play
50                        deck = MakePlay( player, deck );                        // make a play
51                  if ( deck == 0 ) break;                                               // stop when no cards left
52
53                        if ( die ) {
54                                partner[LEFT]->partner[RIGHT] = partner[RIGHT]; // unlink node
55                                partner[RIGHT]->partner[LEFT] = partner[LEFT];
56                                NumPlayersRemaining -= 1;
57                        } else if ( prng( prng, 10 ) == 0 ) {
58                                try {
59                                        drink( *partner[RIGHT] );                       // have a drink
60                                        poll();
61                                } catchResume( Schmilblick * ) {                // stop cycle
62                                } // try
63                        } // if
64                        play( *partner[deck & 1], deck );                       // odd goes left, even goes right
65                } // for
66        } catchResume( Schmilblick * ) {
67                drink( *partner[RIGHT] );                                               // have a drink
68        } // try
69} // Player::main
70
71void ?{}( Player & player, PRNG & prng, unsigned int id ) with( player ) {
72        &player.prng = &prng;  player.id = id;
73} // Player::Player
74
75void start( Player & player, Player & lp, Player & rp ) with( player ) { // obtain the partner identifier
76        partner[LEFT] = &lp;
77        partner[RIGHT] = &rp;
78        resume( player );                                                                       // establish main as starter for termination
79} // Player::start
80
81void players( unsigned int num ) {
82        NumPlayersRemaining = num;
83} // Player::players
84
85void play( Player & player, unsigned int deck ) with( player ) { // send the deck to the partner
86        player.deck = deck;
87        resume( player );
88        poll();
89} // Player::play
90
91void drink( Player & player ) with( player ) {                  // cause partner to drink
92        resumeAt( player, ExceptionInst( Schmilblick ) );
93        resume( player );
94} // Player::drink
95
96static unsigned int rightOf( unsigned int me, unsigned int total ) {
97        return ( me + 1 ) % total;
98} // rightOf
99
100static unsigned int leftOf( unsigned int me, unsigned int total ) {
101        return ( me != 0 ) ? me - 1 : total - 1;
102} // leftOf
103
104// convert(...) throws out_of_range or invalid_argument
105ExceptionDecl( cmd_error );
106
107int main( int argc, char * argv[] ) {
108        enum {
109                MinNoPlayers = 2,                                                               // minimum players in the game
110                MaxNoPlayers = 10,                                                              // maximum players in the game
111                MinNoCards = 10,                                                                // minimum cards in the deck
112                MaxNoCards = 200,                                                               // maximum cards in the deck
113                DefaultGames = 50,                                                              // default games to play
114        };
115        intmax_t numGames = DefaultGames;                                       // games to play
116        intmax_t numPlayers = 0; bool playersSet = false;       // players for a particular game
117        intmax_t numCards = 0; bool cardsSet = false;           // cards in the deck for a game
118        intmax_t seed = 2423;                                                                   // random-number seed
119
120        try {
121                switch ( argc ) {
122                  case 5:
123                        if ( strcmp( argv[4], "d" ) != 0 ) {            // default ?
124                                seed = convert( argv[4] ); if ( seed < 1 ) throw ExceptionInst( cmd_error ); // invalid ?
125                        } // if
126                        // FALL THROUGH
127                  case 4:
128                        if ( strcmp( argv[3], "d" ) != 0 ) {            // default ?
129                                numCards = convert( argv[3] ); if ( numCards < 1 ) throw ExceptionInst( cmd_error ); // invalid ?
130                                cardsSet = true;
131                        } // if
132                        // FALL THROUGH
133                  case 3:
134                        if ( strcmp( argv[2], "d" ) != 0 ) {            // default ?
135                                numPlayers = convert( argv[2] ); if ( numPlayers < 2 ) throw ExceptionInst( cmd_error ); // invalid ?
136                                playersSet = true;
137                        } // if
138                        // FALL THROUGH
139                  case 2:
140                        if ( strcmp( argv[1], "d" ) != 0 ) {            // default ?
141                                numGames = convert( argv[1] ); if ( numGames < 0 ) throw ExceptionInst( cmd_error ); // invalid ?
142                        } // if
143                        // FALL THROUGH
144                  case 1:                                                                               // defaults
145                        break;
146                  default:                                                                              // wrong number of options
147                        throw ExceptionInst( cmd_error );
148                } // switch
149        } catch( exception_t * ) {                                                      // catch any
150                exit | "Usage: " | argv[0]
151                         | " [ games (>=0) | 'd' (default " | DefaultGames
152                         | ") [ players (>=2) | 'd' (random " | MinNoPlayers | "-" | MaxNoPlayers
153                         | ") [ cards (>0) | 'd' (random " | MinNoCards | "-" | MaxNoCards
154                         | ") [ seed (>0) | 'd' (random) ] ] ] ]";
155        } // try
156
157        PRNG mprng, pprng;
158        if ( seed != 0 ) {                                                                      // specified on command line ?
159                set_seed( mprng, seed );  set_seed( pprng, seed );
160        } // if
161        sout | "start";
162        for ( unsigned int game = 1; game <= (unsigned int)numGames; game += 1 ) {
163                if ( ! playersSet ) numPlayers = prng( mprng, MinNoPlayers, MaxNoPlayers );
164                if ( ! cardsSet ) numCards = prng( mprng, MinNoCards, MaxNoCards );
165                {
166                        Player * players[numPlayers];
167
168                        players( numPlayers );                                          // set number of players in game
169
170                        for ( unsigned int i = 0; i < (unsigned int)numPlayers; i += 1 ) { // start the players
171                                players[i] = &(*malloc()){ pprng, i };
172                        } // for
173
174                        // Tell each player who its partner is.
175                        for ( unsigned int i = 0; i < (unsigned int)numPlayers; i += 1 ) {
176                                start( *players[i], *players[leftOf(i, numPlayers)], *players[rightOf(i, numPlayers)] );
177                        } // for
178
179                        play( *players[ prng( mprng, numPlayers ) ], numCards ); // dealer starts the game
180                        sout | players[0]->deck;
181                        for ( unsigned int i = 0; i < (unsigned int)numPlayers; i += 1 ) { // delete players when the game is over
182                                delete( players[i] );
183                        } // for
184                }
185        } // for
186        sout | "done";
187} // main
Note: See TracBrowser for help on using the repository browser.