source: liacs/ai/bridge/bridge.cc@ 263

Last change on this file since 263 was 2, checked in by Rick van der Zwet, 15 years ago

Initial import of data of old repository ('data') worth keeping (e.g. tracking
means of URL access statistics)

File size: 14.7 KB
Line 
1//
2// bridge.cc
3// Eerste programmeeropgave voor AI, 28 januari 2008, Bridge
4// Walter Kosters
5//
6
7#include <iostream>
8#include <iomanip>
9#include <cstdlib>
10#include <ctime>
11using namespace std;
12
13/* Maak array verwijzingen expliciet en uniform */
14#define NOORD 0
15#define OOST 1
16#define ZUID 2
17#define WEST 3
18
19/* Kaartdefinities */
20#define KLAVEREN 0
21#define RUITEN 1
22#define HARTEN 2
23#define SCHOPPEN 3
24
25/* Contract mogelijkheden */
26#define CONTRACT_RANDOM 0 /* Agent EEN */
27#define CONTRACT_SLIM 1 /* Agent DRIE */
28
29/* Niveau's */
30#define NIVEAU_RANDOM 0 /* Agent TWEE */
31#define NIVEAU_SLIM 1 /* Agent VIER */
32
33/* Speeltype */
34#define SPEEL_KOSTER_BRIDGE 0
35
36#define VERBOSE 1
37#define SILENT 0
38
39/* Afsluit codes, teveel is positief, teweinig negetief */
40#define GEHAALD = 0
41
42//sorteer array A (met n elementen) via bubblesort
43void bubblesort (int A[ ], int n) {
44 int i, j, temp;
45 for ( j = 1; j < n; j++ )
46 for ( i = 0; i < n-j; i++ )
47 if ( A[i] > A[i+1] ) {
48 temp = A[i];
49 A[i] = A[i+1];
50 A[i+1] = temp;
51 }//if
52}//bubblesort
53
54//welke getalswaarde heeft kaart i?
55//1..13 zijn Klaver1..13, 14..26 zijn Ruiten1..13,
56//27..39 zijn Harten1..13 en 40..52 zijn Schoppen1..13
57//eigenlijk is 13 de aas, dus 1 is een 2 ;-)
58int dewaarde (int i) {
59 if ( i <= 13 )
60 return i;
61 else if ( i <= 26 )
62 return i-13;
63 else if ( i <= 39 )
64 return i-26;
65 else
66 return i-39;
67}//dewaarde
68
69//welke kleurwaarde heeft kaart i?
70char dekleurwaarde (int i) {
71 if ( i <= 13 )
72 return KLAVEREN;
73 else if ( i <= 26 )
74 return RUITEN;
75 else if ( i <= 39 )
76 return HARTEN;
77 else
78 return SCHOPPEN;
79}//dekleur
80
81//welke kleur heeft kaart i?
82char dekleur (int i) {
83 switch ( dekleurwaarde (i) ) {
84 case KLAVEREN:
85 return 'K';
86 case RUITEN:
87 return 'R';
88 case HARTEN:
89 return 'H';
90 case SCHOPPEN:
91 return 'S';
92 }
93}//dekleur
94
95
96//print kaart i netjes
97void printkaart (int i) {
98 cout << dekleur (i) << dewaarde (i);
99 if ( dewaarde (i) < 10 )
100 cout << " ";
101}//printkaart
102
103//welke speler is i?
104char despeler (int i) {
105 switch ( i ) {
106 case NOORD: return 'N';
107 case OOST: return 'O';
108 case ZUID: return 'Z';
109 case WEST: return 'W';
110 }//switch
111 return 'X';
112}//despeler
113
114//===
115
116class spel {
117 public:
118 int aantalkaarten; //hoeveel kaarten heeft iedere speler?
119 char troef; //KRHS
120 int hoogte; //1..13
121 bool NZ; //true betekent NZ, false betekent OW
122 int dekaarten[4][13]; //N:0,O:1,Z:2,W:3
123 int slagenNZ; //aantal slagen voor NZ
124 int slagenOW; //idem voor OW
125 int spelerniveau[3]; /* Kwaliteit van speler */
126 void schud ( );
127 void print ( );
128 void maakcontract (int hoe, bool printdetails);
129 void afspelen (int speeltype, bool printdetails);
130 int trekkaart (int hoe, char kleur, int A[ ], int aantal);
131 int uitslag (bool printdetails);
132};//spel
133
134//verdeel de kaarten, en schud ze over de 4 spelers
135void spel::schud ( ) {
136 int kaarten[52];
137 int i, j, temp;
138 aantalkaarten = 13;
139 for ( i = 0; i < 52; i++ )
140 kaarten[i]= i+1;
141 for ( i = 52-1; i > 0; i-- ) {
142 j = rand ( ) % (i+1);
143 temp = kaarten[i];
144 kaarten[i] = kaarten[j];
145 kaarten[j] = temp;
146 }//for
147 for ( i = 0; i < 13; i++ ) {
148 dekaarten[NOORD][i] = kaarten[i];
149 dekaarten[OOST][i] = kaarten[i+13];
150 dekaarten[ZUID][i] = kaarten[i+26];
151 dekaarten[WEST][i] = kaarten[i+39];
152 }//for
153 bubblesort (dekaarten[NOORD],13);
154 bubblesort (dekaarten[OOST],13);
155 bubblesort (dekaarten[ZUID],13);
156 bubblesort (dekaarten[WEST],13);
157 slagenNZ = slagenOW = 0;
158}//spel::schud
159
160//print huidige kaarten
161void spel::print ( ) {
162 int i;
163 cout << "=Kaart configuratie=" <<endl;
164 cout << endl << "Noord : ";
165 for ( i = 0; i < aantalkaarten; i++ ) {
166 printkaart (dekaarten[NOORD][i]);
167 cout << " | ";
168 }//for
169 cout << endl;
170 cout << "Oost : ";
171 for ( i = 0; i < aantalkaarten; i++ ) {
172 printkaart (dekaarten[OOST][i]);
173 cout << " | ";
174 }//for
175 cout << endl;
176 cout << "Zuid : ";
177 for ( i = 0; i < aantalkaarten; i++ ) {
178 printkaart (dekaarten[ZUID][i]);
179 cout << " | ";
180 }//for
181 cout << endl;
182 cout << "West : ";
183 for ( i = 0; i < aantalkaarten; i++ ) {
184 printkaart (dekaarten[WEST][i]);
185 cout << " | ";
186 }//for
187 cout << endl;
188}//spel::print
189
190//maak een contract
191void spel::maakcontract (int hoe, bool printdetails) {
192 int spelerA, spelerB;
193 int zoekpuntA, zoekpuntB;
194 int slagen;
195 int kleurAantal[] = {0, 0, 0, 0};
196
197 /* Speler volledig random */
198 NZ = ( rand ( ) % 2 == 1 );
199
200 switch (hoe) {
201 case CONTRACT_RANDOM:
202 troef = dekleur (rand ( ) % 52);
203 hoogte = 1 + rand ( ) % 13;
204 break;
205 case CONTRACT_SLIM:
206 /* Variable om de juiste array rijen te selecteren */
207 if ( NZ ) {
208 spelerA = NOORD;
209 spelerB = ZUID;
210 } else {
211 spelerA = OOST;
212 spelerB = WEST;
213 }
214
215 /* Bepaal aantal kaarten per kleur */
216 for ( int i = 0; i < 13; i++ ) {
217 kleurAantal[dekleurwaarde (dekaarten[spelerA][i])]++;
218 kleurAantal[dekleurwaarde (dekaarten[spelerB][i])]++;
219 }
220
221 /* Troef is de meeste kaarten in handen */
222 troef = 0;
223 for ( int i = 1; i < 4; i++ )
224 if ( kleurAantal[i] > kleurAantal[i - 1] )
225 troef = i;
226
227 /* Elke troef levert een slag op */
228 hoogte = kleurAantal[troef];
229
230 /* Hoogste kaart(en) leveren ook slagen op */
231 slagen = 0;
232 /* i is de zoekkaart */
233 for (int i = 52; i >= 0;) {
234 while (zoekpuntA != -1 && dekaarten[spelerA][zoekpuntA] > i)
235 zoekpuntA--;
236 while (zoekpuntB != -1 && dekaarten[spelerB][zoekpuntB] > i)
237 zoekpuntB--;
238
239 /* Hebben we de kaart in bezit of moeten we naar een aas van
240 * een andere kleur gaan zoeken */
241 if (zoekpuntA == -1 && zoekpuntB == -1) {
242 break;
243 } else if (zoekpuntA != -1 && dekaarten[spelerA][zoekpuntA] == i) {
244 slagen++;
245 i--;
246 } else if (zoekpuntB != -1 && dekaarten[spelerB][zoekpuntB] == i) {
247 slagen++;
248 i--;
249 } else {
250 if ( i <= 13 ) {
251 /* KLAVEREN aas is niet in bezit */
252 break;
253 } else {
254 /* Spring naar de volgende aas */
255 if ((i % 13) == 0)
256 i = i - 13;
257 else
258 i = i - (i % 13);
259 }
260 }
261 }
262 hoogte = hoogte + slagen;
263
264 /* Set troef naar ASCII waarde om */
265 troef = dekleur ( (troef + 1) * 13);
266 break;
267 }
268
269 if (printdetails) {
270 cout << endl << "=Contract=" << endl;
271 cout << "Paar : " << ( NZ ? "NZ " : "OW " ) << endl;
272 cout << "Slagen : " << hoogte <<endl;
273 cout << "Troef : " << troef << endl << endl;
274 }
275}//spel::maakcontract
276
277//trek een random kaart uit A (die er aantal heeft)
278//voorkeur voor kleur, anders random
279int spel::trekkaart (int hoe, char kleur, int A[ ], int aantal) {
280 int j, i = rand ( ) % aantal, vanaf, totenmet, dekaart;
281 int hoogstekaart = 0;
282 bool heeftkleur = false;
283
284 /* Bepaal of gevraagde kleur in bezit is */
285 for ( j = 0; j < aantal; j++ ) {
286 if ( dekleur (A[j]) == kleur ) {
287 if ( heeftkleur )
288 totenmet = j;
289 else
290 totenmet = vanaf = j;
291 heeftkleur = true;
292 }//if
293 }//for
294
295 switch (hoe) {
296 case NIVEAU_RANDOM:
297 if ( heeftkleur )
298 i = vanaf + rand ( ) % ( totenmet - vanaf + 1 );
299 break;
300 case NIVEAU_SLIM:
301 /* Als eerste kiezen, levert bepaalde privileges */
302 if ( kleur == 'X' ) {
303 /* bepalen beste kaart, hoogste troef, dan hoogste andere kaart */
304 for ( j = 1; j < aantal; j++ ) {
305 if ( dewaarde (A[j]) > dewaarde (hoogstekaart) ) {
306 hoogstekaart = j;
307 } else if ( dewaarde (A[j]) == dewaarde (hoogstekaart) ) {
308 /* Troef is beter */
309 if ( dekleur (A[j]) == troef ) {
310 hoogstekaart = j;
311 }
312 }
313 }
314 i = hoogstekaart;
315 break;
316 }
317
318 /* Troef spelen, levert aparte regels */
319 if ( kleur == troef ) {
320 /* Hoogste troef als present, anders laagste kaart */
321 if ( heeftkleur )
322 i = totenmet;
323 else
324 i = 0;
325 break;
326 }
327
328 /* Als kleur present dan meespelen met hoogste kaart */
329 if ( heeftkleur ) {
330 i = totenmet;
331 break;
332 }
333
334 /* Bij ontbreken van kleur, bepaal of troef present is */
335 for ( j = 0; j < aantal; j++ )
336 if ( dekleur (A[j]) == troef ) {
337 if ( heeftkleur )
338 totenmet = j;
339 else
340 totenmet = vanaf = j;
341 heeftkleur = true;
342 }//if
343 /* 'Steel' het slag door kleinste troefje te spelen */
344 if ( heeftkleur ) {
345 i = vanaf;
346 break;
347 }
348
349 /* Niets kunnen betekenen hier, laagste kaart dan maar ;-) */
350 i = 0;
351 break;
352 }
353
354 /* Doe de boekhouding en werk het de eigen hand bij */
355 dekaart = A[i];
356 for ( j = i; j < aantal-1; j++ )
357 A[j] = A[j+1];
358 A[aantal-1] = 0;
359 return dekaart;
360}//spel::trekkaart
361
362//speel af; printdetails geeft meer informatie
363void spel::afspelen (int speeltype, bool printdetails) {
364 int speler, winnaar, hoogste, winkleur, vraagkleur;
365 int kaart[ ] = {0, 0, 0, 0};
366 int buurt = 1;
367
368 /* Laat random speler beginnen */
369 speler = rand ( ) % 4; // 0123
370
371 if (printdetails) {
372 cout << "=Spel=" <<endl;
373 cout << "S = Speelt, Kx = Kaart x" << endl;
374 cout << "Noord -> Oost -> Zuid -> West -> Noord --> Oost -> Zuid" <<endl;
375 cout << "Buurt | S | K1 | K2 | K3 | K4 | Winnaar |" << endl;
376 cout << "------|---|-----|-----|-----|-----|---------|" << endl;
377 }
378
379 switch (speeltype) {
380 case SPEEL_KOSTER_BRIDGE:
381 while ( aantalkaarten > 0 ) {
382 if (printdetails) {
383 if ( buurt < 10 )
384 cout << " ";
385 cout << buurt << " | ";
386 }
387
388 /* Initiele kaart, geen voorkeur voor kleur */
389 kaart[0] = trekkaart (spelerniveau[speler],'X',dekaarten[speler],
390 aantalkaarten);
391 vraagkleur = dekleur (kaart[0]);
392 if ( printdetails ) {
393 cout << despeler (speler) << " | ";
394 printkaart (kaart[0]);
395 cout << " | ";
396 }//if
397
398 /* Laat de rest bijspelen */
399 for (int i = 1; i <= 3; i++) {
400 kaart[i] = trekkaart (spelerniveau[i], vraagkleur,
401 dekaarten[(speler+i)%4],aantalkaarten);
402 if ( printdetails ) {
403 printkaart (kaart[i]);
404 cout << " | ";
405 }//if
406 }
407
408 aantalkaarten--;
409
410 /* controleer troef in het spel */
411 if ( dekleur(kaart[0]) == troef || dekleur(kaart[1]) == troef
412 || dekleur(kaart[2]) == troef || dekleur(kaart[3]) == troef )
413 winkleur = troef;
414 else
415 winkleur = dekleur (kaart[0]);
416
417 /* bepaal de winnende spelers */
418 hoogste = -1;
419 if ( dekleur (kaart[0]) == winkleur && kaart[0] > hoogste ) {
420 winnaar = speler;
421 hoogste = kaart[0];
422 }//if
423 if ( dekleur (kaart[1]) == winkleur && kaart[1] > hoogste ) {
424 winnaar = (speler+1) % 4;
425 hoogste = kaart[1];
426 }//if
427 if ( dekleur (kaart[2]) == winkleur && kaart[2] > hoogste ) {
428 winnaar = (speler+2) % 4;
429 hoogste = kaart[2];
430 }//if
431 if ( dekleur (kaart[3]) == winkleur && kaart[3] > hoogste ) {
432 winnaar = (speler+3) % 4;
433 hoogste = kaart[3];
434 }//if
435
436 if ( printdetails ) {
437 cout << despeler (winnaar) << " |" << endl;
438 }//if
439 if ( winnaar == 0 || winnaar == 2 )
440 slagenNZ++;
441 else
442 slagenOW++;
443 speler = winnaar;
444
445 buurt++;
446 }//while
447 break;
448 }//switch
449}//spel::afspelen
450
451//uitslag op scherm
452int spel::uitslag (bool printdetails) {
453 int slagen = ( NZ ? slagenNZ : slagenOW);
454 if (printdetails) {
455 cout << "=Uitslag=" << endl;
456 cout << "Slagen NZ : " << slagenNZ << endl;
457 cout << "Slagen OW : " << slagenOW << endl;
458 cout << "Contract bod : " << hoogte << endl;
459 cout << "Contract paar : " << ( NZ ? "NZ " : "OW " ) << endl;
460 cout << "Contact gehaald : ";
461 }
462 if ( slagen < hoogte ) {
463 if (printdetails)
464 cout << "TEKORT";
465 } else if ( slagen == hoogte ) {
466 if (printdetails)
467 cout << "CORRECT";
468 } else {
469 if (printdetails)
470 cout << "TEVEEL";
471 }
472 if (printdetails)
473 cout << " (" << slagen - hoogte << ")" << endl;
474
475 return (slagen - hoogte);
476}//spel::uitslag
477
478//===
479
480void printTotaalWaarde (string type, double waarde, double totaal) {
481 cout << setiosflags(ios::left);
482 cout << setw(10) << type << " : ";
483 cout << resetiosflags(ios::left);
484 double percent = (waarde / totaal) * 100;
485 cout.precision(8);
486 cout << setw(8) << waarde;
487 cout << " = ";
488 cout.precision(2);
489 cout << setw(7) << setiosflags(ios::fixed) << percent
490 <<resetiosflags(ios::fixed) << "%";
491 cout << endl;
492
493};
494
495int main ( ) {
496 int retcode = 0;
497 int tekort = 0;
498 int correct = 0;
499 int teveel = 0;
500 double eindscore = 0;
501 int fout, goed;
502
503 spel S;
504 int randInit;
505
506 /* Variabelen */
507 int logNiveau = SILENT; /* print niveau SILENT|VERBOSE */
508 double aantalKeer = 10000; /* aantal rondes */
509
510 /* initialiseer random-generator, maar print seed om debugging
511 * mogelijk te maken
512 */
513 randInit = time(0);
514 /* Spelen met vaste waarde om kaarten hetzelfde te houden */
515 randInit = 1203969568;
516 cout << "RandInit getal: " << randInit << endl;
517 srand (randInit);
518
519 /* Speel de potjes */
520 for (int i = 0; i < aantalKeer; i++) {
521 S.schud ( );
522 if (logNiveau)
523 S.print ( );
524
525 /* Niveau contract en spelers */
526 S.maakcontract (CONTRACT_SLIM, logNiveau);
527 S.spelerniveau[0] = NIVEAU_RANDOM;
528 S.spelerniveau[1] = NIVEAU_RANDOM;
529 S.spelerniveau[2] = NIVEAU_RANDOM;
530 S.spelerniveau[3] = NIVEAU_RANDOM;
531 if (logNiveau)
532 for (int i = 0; i <= 3; i++)
533 cout << "Niveau speler " << i << ":" << S.spelerniveau[i] << endl;
534
535 /* Afspelen bepaal type spel */
536 S.afspelen (SPEEL_KOSTER_BRIDGE, logNiveau);
537
538 if (logNiveau)
539 cout << endl;
540 retcode = S.uitslag (logNiveau);
541
542 /* Boekhouding, voor de eindscore berekening */
543 if (retcode > 0) {
544 teveel++;
545 /* elk punt teveel score: -10 */
546 eindscore = eindscore + retcode * -10;
547 } else if (retcode == 0) {
548 correct++;
549 /* elk goede score +20 */
550 eindscore = eindscore + 20;
551 } else {
552 tekort++;
553 /* elk punt tekort score: -20
554 * retcode is al negatief
555 */
556 eindscore = eindscore + (retcode * 20);
557 }
558 }
559
560 /* Bereken eindresultaat */
561 fout = tekort + teveel;
562 goed = correct;
563 printTotaalWaarde("Tekort", tekort, aantalKeer);
564 printTotaalWaarde("Correct", correct, aantalKeer);
565 printTotaalWaarde("Teveel", teveel, aantalKeer);
566 cout << endl;
567 printTotaalWaarde("Goed", goed, aantalKeer);
568 printTotaalWaarde ("Fout", fout, aantalKeer);
569 printTotaalWaarde ("EindScore", eindscore, aantalKeer * 20);
570}//main
571
Note: See TracBrowser for help on using the repository browser.