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