source: tests/exceptions/hotpotato_checked.cfa@ 283fbdd

Last change on this file since 283fbdd was f0c9c9b, checked in by Peter A. Buhr <pabuhr@…>, 21 months ago

formatting

  • Property mode set to 100644
File size: 7.0 KB
Line 
1#include <fstream.hfa> // sin/sout
2#include <stdlib.hfa> // convert
3#include <string.h>
4#include <coroutine.hfa>
5
6struct Potato {
7 PRNG & prng;
8 unsigned int deadline; // when timer goes off
9 unsigned int timer; // up counter to deadline
10}; // Potato
11
12void reset( Potato & potato, unsigned int maxTicks = 10 );
13void ?{}( Potato & potato, PRNG & prng, unsigned int maxTicks = 10 );
14
15void ?{}( Potato & potato, PRNG & prng, unsigned int maxTicks ) with(potato) {
16 &potato.prng = &prng;
17 reset( potato, maxTicks );
18 } // Potato
19
20coroutine Player {
21 PRNG & prng;
22 int id; // player identity
23 Potato & potato; // potato being tossed
24 Player * partner[2]; // left and right player
25}; // Player
26
27void ?{}( Player & player, PRNG & prng, unsigned int id, Potato & potato ) {
28 &player.prng = &prng;
29 player.id = id;
30 &player.potato = &potato;
31 } // Player
32
33Player & umpire;
34
35ExceptionDecl( Explode );
36ExceptionDecl( Terminate, Player * victim; );
37ExceptionDecl( Election );
38ExceptionDecl( cmd_error ); // convert(...) throws out_of_range or invalid_argument
39
40void reset( Potato & potato, unsigned int maxTicks ) with(potato) {
41 if ( maxTicks < 2 ) abort( "Hot Potato initialized with less than 2 ticks" ); // optional
42 deadline = prng( prng, 1, maxTicks );
43 timer = 0;
44 sout | " POTATO goes off after " | deadline | " tick" | nosep | (deadline > 1 ? "s" : "");
45} // reset
46
47void countdown( Potato & potato ) with(potato) {
48 timer += 1;
49 if ( timer == deadline ) throwResume ExceptionInst( Explode );
50} // countdown
51
52static unsigned int rightOf( unsigned int me, unsigned int total ) {
53 return ( me + 1 ) % total;
54} // rightOf
55
56static unsigned int leftOf( unsigned int me, unsigned int total ) {
57 return ( me + total - 1) % total;
58} // leftOf
59
60enum { LEFT = 0, RIGHT = 1 };
61
62static void vote( Player & player ) { // cause partner to vote
63 resume( player ); checked_poll();
64} // vote
65
66static void terminate( Player & player ) { // resume umpire
67 resume( player );
68 checked_poll();
69 sout | "THIS SHOULD NOT BE REACHED";
70} // terminate
71
72void init( Player & player, Player & lp, Player & rp ) with(player) { // supply partners
73 partner[LEFT] = &lp;
74 partner[RIGHT] = &rp;
75 resume( player ); // establish main as starter for termination
76 checked_poll();
77} // init
78
79int getId( Player & player ) { // player id
80 return player.id;
81} // getId
82
83void toss( Player & player ) { // tossed the potato
84 resume( player );
85 checked_poll();
86} // toss
87
88void main( Player & player ) with(player) {
89 try {
90 enable_ehm(); // allow delivery of nonlocal exceptions
91 suspend; // return immediately after establishing starter
92 checked_poll();
93
94 for ( ;; ) {
95 checked_poll();
96 if ( partner[LEFT] == &player ) { // stop when only one player
97 sout | id | " wins the Match!";
98 return;
99 } // exit
100
101 countdown( potato ); // player is eliminated if countdown() returned true
102
103 size_t side = prng( prng, 2 );
104 sout | id | " -> " | nonl;
105 toss( *partner[ side ] ); // random toss left/right
106 } // for
107 disable_ehm();
108 } catchResume( Terminate * v ) {
109 v->victim->partner[LEFT]->partner[RIGHT] = v->victim->partner[RIGHT]; // unlink node
110 v->victim->partner[RIGHT]->partner[LEFT] = v->victim->partner[LEFT];
111 delete( v->victim );
112 reset( potato );
113 sout | "U " | nonl; // start new game
114 flush( sout );
115 } catchResume( Election * election ) {
116 sout | "election";
117 sout | " -> " | id | nonl;
118 if ( id > getId( umpire ) ) &umpire = &player; // set umpire to highest id so far
119 resumeAt( *partner[RIGHT], *election );
120 disable_ehm(); // disable ehm since we can't handle execption thrown in vote here and want to poll later
121 vote( *partner[RIGHT] );
122 enable_ehm(); // enable after vote
123 } catchResume( Explode * ) {
124 sout | id | " is eliminated";
125 if ( &player == &umpire ) {
126 try {
127 id = -1; // remove from election
128 resumeAt( *partner[RIGHT], ExceptionInst( Election ) );
129 vote( *partner[RIGHT] ); // start election
130 checked_poll();
131 } catchResume( Election * election ) {
132 sout | " : umpire " | getId( umpire );
133 } // try
134 } // if
135 resumeAt( umpire, ExceptionInst( Terminate, &player ) );
136 terminate( umpire );
137 assert( false ); // no return
138 } // try
139} // main
140
141
142int main( int argc, char * argv[] ) {
143 enum {
144 MinNoPlayers = 2, // minimum players in the game
145 MaxNoPlayers = 10, // maximum players in the game
146 DefaultGames = 5, // default games to play
147 };
148 intmax_t numGames = DefaultGames; // games to play
149 intmax_t numPlayers = 0; // players for a particular game
150 intmax_t seed = 42; // random-number seed
151 bool playersSet = false;
152 char * nosummary = getenv( "NOSUMMARY" ); // print extra output
153
154 try {
155 choose ( argc ) {
156 case 4:
157 if ( strcmp( argv[3], "d" ) != 0 ) { // default ?
158 seed = convert( argv[3] ); if ( seed < 1 ) throw ExceptionInst( cmd_error ); // invalid ?
159 } // if
160 fallthrough;
161 case 3:
162 if ( strcmp( argv[2], "d" ) != 0 ) { // default ?
163 numPlayers = convert( argv[2] ); if ( numPlayers < 2 ) throw ExceptionInst( cmd_error ); // invalid ?
164 playersSet = true;
165 } // if
166 fallthrough;
167 case 2:
168 if ( strcmp( argv[1], "d" ) != 0 ) { // default ?
169 numGames = convert( argv[1] ); if ( numGames < 0 ) throw ExceptionInst( cmd_error ); // invalid ?
170 } // if
171 fallthrough;
172 case 1: ; // defaults
173 default: // too many arguments
174 throw ExceptionInst( cmd_error );
175 } // choose
176 } catch( exception_t * ) { // catch any
177 exit | "Usage: " | argv[0]
178 | " [ games (>=0) | 'd' (default " | DefaultGames
179 | ") [ players (>=2) | 'd' (random " | MinNoPlayers | "-" | MaxNoPlayers
180 | ") [ seed (>0) | 'd' (random) ] ] ]";
181 } // try
182 sout | numGames | numPlayers | seed;
183
184 PRNG mprng, hprng, pprng;
185 if ( seed != 0 ) { // specified on command line ?
186 set_seed( mprng, seed ); set_seed( hprng, seed ); set_seed( pprng, seed );
187 } // if
188
189 for ( game; 1 ~= numGames ) {
190 if ( ! playersSet ) numPlayers = prng( mprng, MinNoPlayers, MaxNoPlayers );
191 sout | numPlayers | " players in the game";
192 {
193 Potato potato{ hprng }; // hot potato to be tossed
194 Player * players[numPlayers];
195
196 for ( unsigned int i = 0; i < (unsigned int)numPlayers; i += 1 ) { // start the players
197 players[i] = malloc();
198 ?{}( *players[i], pprng, i, potato );
199 } // for
200
201 // Do not swap player[0] with itself.
202 unsigned int rposn = prng( mprng, 1, numPlayers - 1 ); // swap random position with 0
203 swap( players[0], players[rposn] );
204
205 // Tell each player its partner.
206 for ( unsigned int i = 0; i < (unsigned int)numPlayers; i += 1 ) {
207 init( *players[i], *players[leftOf(i, numPlayers)], *players[rightOf(i, numPlayers)] );
208 } // for
209
210 &umpire = players[rposn]; // designate umpire and start game
211 sout | "U " | nonl;
212 toss( *players[rposn] );
213 delete( &umpire );
214 }
215 if ( game < (unsigned int)numGames ) sout | nl | nl; // whitespace between games
216 } // for
217} // main
218
219// Local Variables: //
220// compile-command: "make hotpotato" //
221// End: //
Note: See TracBrowser for help on using the repository browser.