Let mamer take colors into account for pairing
[capablanca.git] / lasker-2.2.3 / bots / mamer / Tourney.cc
1 //--------------------------------------------------------------------------
2 // Tourney.cc - Source file for Tourney class
3 //
4 // Matthew E. Moses
5 //
6 // $Revision: 1.11 $
7 // $Date: 1998/09/10 19:57:17 $
8 //
9 // $Author: mlong $
10 // $Locker:  $
11 //
12 // $Log: Tourney.cc,v $
13 // Revision 1.11  1998/09/10 19:57:17  mlong
14 // lots of little bug fixes and a few new features
15 //
16 // Revision 1.10  1998/04/29 15:23:19  mlong
17 // prepairing for the move to daimi
18 // new sorting routine.
19 //
20 // Revision 1.9  1998/04/18 20:05:14  mlong
21 // fixed BYE bug
22 //
23 // Revision 1.8  1998/04/18 18:46:04  mlong
24 // fixed delete bug &
25 // added delete tourney function
26 //
27 // Revision 1.4  1997/10/08 21:03:35  chess
28 // preparing for move to oracle machine at eworks.
29 //
30 // Revision 1.3  1997/05/15 18:27:53  chess
31 // added pending and TourneyPlayers support
32 // added HandleGetPlayerInfo & HandleGetGameInfo
33 //
34 // Revision 1.2  1996/10/01 20:14:43  moses
35 // Added a new method IsTourney
36 //
37 // Revision 1.1  1996/09/30  20:52:48  moses
38 // Initial revision
39 //
40 //--------------------------------------------------------------------------
41
42 //static char RCSid[] = "$Id: Tourney.cc,v 1.11 1998/09/10 19:57:17 mlong Exp $";
43
44 #include "Tourney.hh"
45 #include "Mamer.hh"
46
47 extern Mamer gMamer;
48
49 //- Constructor ------------------------------------------------------------
50 Tourney::Tourney() {
51 } //- End of Tourney
52
53 Tourney::Tourney(int n,User *u, TourneyParameters *tp) {
54   InitTourney(n, u, tp->time, tp->inc, tp->mode, tp->style, tp->rounds, tp->variant, tp->ratingLow, tp->ratingHigh);
55 }
56
57 Tourney::Tourney(int n, User *u, TourneyParameters *tp, int t, int i, char m, char s, int r) {
58   InitTourney(n, u, t, i, m, s, r, tp->variant, tp->ratingLow, tp->ratingHigh);
59 }
60
61 Tourney::Tourney(int n, User *u, TourneyParameters *tp, int t, int i, char m, char s, int r, char v) {
62   InitTourney(n, u, t, i, m, s, r, v, tp->ratingLow, tp->ratingHigh);
63 }
64
65 void Tourney::InitTourney(int n, User *u, int t, int i, char m, char s, int r, char v, int rl, int rh) {
66   number = n;
67   strncpy(manager, u->name, NAMELEN - 1);
68   managerLevel = u->GetManagerLevel();
69   averageRating = 0;
70   params.time = t;
71   params.inc = i;
72   params.mode = m;
73   params.style = s;
74   params.rounds = r;
75   params.variant = v;
76   params.wild = 10;
77   params.ratingLow = rl;
78   params.ratingHigh = rh;
79   params.currentRound = 0;
80   params.maxPlayers = DEFAULT_MAX_PLAYERS;
81
82   startDate = 0;
83   endDate = 0;
84   persist = 0;
85   lastCshouted = 0;
86
87   status = NEW;
88 }
89
90 //- Deconstructor ---------------------------------------------------------
91 Tourney::~Tourney() {
92
93 } //- End of ~Tourney
94
95 //- IsTourney -------------------------------------------------------------
96 int Tourney::IsTourney(int tourn) {
97     if(tourn == number)
98         return(1);
99     else
100         return(0);
101 } //- End of IsTourney
102
103 //- IsNotNew-------------------------------------------------------------
104 short Tourney::IsNotNew(void) {
105   if(NEW != status)
106     return(TRUE);
107   return(FALSE);
108 }
109
110 //- IsNotClosed-------------------------------------------------------------
111 short Tourney::IsNotClosed(void) {
112   if(CLOSED != status)
113     return(TRUE);
114   return(FALSE);
115 }
116
117 //- AddPlayer ----------------------------------------------------------
118 int Tourney::AddPlayer(char *name, int rating, float score) {
119   TourneyPlayers *newPlayer = NULL, *tp = NULL;
120   Player *newSortPlayer = NULL;
121
122   if (status != OPEN) return 3;   // If we are not open then we can't enter the tourney
123   
124   tp = GetPlayer(name);
125
126   if(tp != NULL) return(2);   // if we are already in the tourney we can't enter it again/
127
128   if(rating >= params.ratingLow && rating <= params.ratingHigh && status == OPEN) {
129
130     newPlayer = new TourneyPlayers(name, rating, score);
131     newSortPlayer = new Player(name, 0);
132
133     playerList.Append(newPlayer);
134     SortPlayers();
135     gMamer.XServerCom("%s %i %s %s%i%s %s%i %i %s%s", "tell", gMamer.channelNumber, name, "(", rating, ")", 
136                       "has joined tourney #", number, GetPlayerCount(), "players now.", "\n");
137     CalculateAverage();
138     if(GetPlayerCount() >= params.maxPlayers)
139       CloseAndStart();
140     return(1);   // we entered the tourney
141   } else 
142     return(0); // sucks to be us cause our rating doesn't fit the params
143 }
144
145 //- RemovePlayer ----------------------------------------------------------
146 int Tourney::RemovePlayer(char *name) {
147   TourneyPlayers *tp = NULL, *p=NULL;
148   Player *opp=NULL;
149   int roundsRemaining=0;
150
151   tp = GetPlayer(name);
152   printf("forfeiting %s\n", tp->name);
153   if(tp == NULL) return -1; // Player not in THIS tourney
154
155   tp->activeFlag = 0;
156
157   roundsRemaining = GetRoundsRemaining();
158
159   // This code will go through a forfeited players list and give him a loss for current opponent
160   // with a quick modification it will give losses for all games played as well...
161   LinkListIter<Player> opponentIter(tp->opponentList);  // List of opponents this player has had
162   opponentIter.Reset();
163   while((opp = opponentIter.Next())) {
164     if(strcmp("_BYE_", opp->name) != 0) {  // If I am not _BYE_
165       p = GetPlayer(opp->name);
166       if(opp->floatValue == -1) {  // floatValue stores the game result for this player
167         if(opp->value) {  // if player leaving was white
168           SetGameResult(tp->name, opp->name, 0);
169         } else {
170           SetGameResult(opp->name, tp->name, 1);
171         }
172         roundsRemaining++;
173       }
174     }
175   }
176   
177   LinkListIter<TourneyPlayers> playerIter(playerList);
178   playerIter.Reset();
179   while((p = playerIter.Next())) {
180     if(strcmp(p->name, "_BYE_") == 0)  { 
181       if(p->activeFlag != 0)
182         p->activeFlag = 0;
183       else
184         p->activeFlag = 1;
185       break;
186     }
187   }
188
189   SortPlayers();
190
191   return roundsRemaining;
192 }
193
194 //- GetPlayer ----------------------------------------------------------
195 TourneyPlayers *Tourney::GetPlayer(char *name) {
196   LinkListIter<TourneyPlayers> playerIter(playerList);
197   TourneyPlayers *tp = NULL;
198   
199   playerIter.Reset();
200   while((tp = playerIter.Next()))
201     if(!strcasecmp(tp->name, name))  
202       return tp;
203   
204   return NULL;
205 }
206
207 //- GetRound ----------------------------------------------------------
208 int Tourney::GetRound() {
209   return params.currentRound;
210 }//- end of GetRound --------------------------------------------------
211
212 //- GetRoundsRemaining ------------------------------------------------
213 int Tourney::GetRoundsRemaining() {
214   return (params.rounds - params.currentRound);
215 }//- end of GetRoundsRemaining -----------------------------------------
216
217 //- SortPlayers ----------------------------------
218 void Tourney::SortPlayers() {
219   Player          *temp=NULL, *s=NULL;
220   TourneyPlayers  *tp = NULL;
221   int             i=0, added=0;
222
223   LinkListIter<TourneyPlayers> playerIter(playerList);
224   LinkListIter<Player> sortIter(sortList);
225
226   sortIter.Reset();
227   while((s = sortIter.Next())) sortList.Delete(s);
228
229   i=0;
230   while((tp = playerIter.Next())) {
231     (tp->activeFlag) ? tp->sortValue = (tp->score + tp->rating/10000.0) : tp->sortValue = -1.0;
232   //  tp->ClearWhites();
233   //  tp->ClearBlacks();
234     if((status == OPEN) && (i < (GetPlayerCount()/2)))
235       (i % 2) ? tp->AddWhite() : tp->AddBlack();
236     i++;
237   }
238
239   playerIter.Reset();
240   while((tp = playerIter.Next())) {
241     added=0;
242     sortIter.Reset();
243     temp = new Player(tp->name, tp->sortValue);
244     while((s = sortIter.Next())) {
245       if(tp->sortValue > s->floatValue) {
246         sortList.Insert(s, temp);
247         added = 1;
248         break;
249       }
250     }
251     if(!added)
252       sortList.Append(temp);
253   }
254
255   i = 1;
256   sortIter.Reset();
257   while((s = sortIter.Next())) { 
258     s->value = i;
259     if(gMamer.debugLevel >= 10) printf("%4d %-18s\n", s->value, s->name); 
260     i++;
261   }
262 }//- end of Sort Players ----------------------
263
264 //- GetSortValueCount -------------------------------------------------------
265 int Tourney::GetSortValueCount(double value) {
266   LinkListIter<TourneyPlayers> playerIter(playerList);
267   int count=0;
268   TourneyPlayers *tp=NULL;
269   Player *s=NULL;
270
271   while((tp = playerIter.Next())) {
272     if(tp->sortValue == value) {
273       s = GetSortPlayer(tp->name);
274       if(s->value != 0)
275         count++;
276     }
277   }
278   
279   return count;
280 }
281
282 //- GetSortPlayer ----------
283 Player *Tourney::GetSortPlayer(char *name) {
284   Player *p = NULL;
285   LinkListIter<Player> sortIter(sortList);
286
287   while((p = sortIter.Next())) {
288     if(strcasecmp(p->name, name) == 0) {
289       return p;
290     }
291   }
292
293   return p;
294 }//- end of GetSortPlayer -----
295
296 //- GetSortPlayer ------------------------------
297 Player *Tourney::GetSortPlayer(int place) {
298   Player *p = NULL;
299   LinkListIter<Player> sortIter(sortList);
300
301   while((p = sortIter.Next())) {
302     if(p->value == place) {
303       return p;
304     }
305   }
306   
307   return p;
308 }//- end of GetSortPlayer -----
309
310 //- CalculateAverage --------------------------------------------------
311 void Tourney::CalculateAverage(void) {
312   int total=0, count=0;
313   TourneyPlayers *p;
314   LinkListIter<TourneyPlayers> playerIter(playerList);
315   
316   while((p = playerIter.Next())) {
317     if(p->rating > 0) {
318       total += p->rating;
319       count++;
320     }
321   }
322   if(count)
323     averageRating = ((float)total/(float)count);
324   else
325     averageRating = 0;
326 }//- end CalculateAverage
327
328 //- GetAverageRating ----------------------------------------------------------
329 float Tourney::GetAverageRating(void) {
330   return averageRating;
331 }//end GetAverageRating
332
333 //- GetVariant ----------------------------------------------------------
334 int Tourney::GetVariant(void) {
335   float eTime;
336
337   switch(params.variant) {
338   case 'w':
339     return(0);
340   case 'r':
341     eTime = (float)params.time + (0.6666667 * (float)params.inc);
342     if(eTime < 3)
343       return(1);
344     else if(eTime < 15)
345       return(2);
346     else 
347       return(3);
348   case 'b':
349     return(4);
350   case 's':
351     return(5);
352   default:
353     return(2);
354   }
355 }
356
357 //- Open ----------------------------------------------------------
358 int Tourney::Open(void) {
359   if(status == NEW) {
360     status = OPEN;
361     return 1;
362   } else {
363     return 0;
364   }
365 }
366
367 //- GetPlayerCount ----------------------------------------------------------
368 int Tourney::GetPlayerCount() {
369   int count=0;
370   TourneyPlayers *p;
371   LinkListIter<TourneyPlayers> playerIter(playerList);
372   
373   while((p = playerIter.Next())) {
374     if(p->activeFlag != 0)
375       count++;
376   }
377
378   return count;
379 }//- end GetPlayerCount ----------------------------------
380
381 //- SetPersist -------------------------------------------------------------
382 void Tourney::SetPersist(int i) {
383   persist = i;
384 } //- end SetPersist
385
386 //- GetPersist -------------------------------------------------------------
387 int Tourney::GetPersist() {
388   return persist;
389 } //- end GetPersist
390
391 //- SetEndDate -------------------------------------------------------------
392 void Tourney::SetEndDate() {
393   endDate = time(0);
394 } //- end of SetEndDate ----------------------------------------------------
395
396 //- CloseAndStart ----------------------------------------------------------
397 void Tourney::CloseAndStart(void) {
398   TourneyPlayers *tp = NULL;
399   status = CLOSED;
400   params.currentRound = 0;
401
402   LinkListIter<TourneyPlayers> playerIter(playerList);
403
404   startDate = time(0);
405
406   cout << "tourney started at: " << ctime(&startDate) << endl;
407
408   if(params.rounds == 0) { 
409     switch(params.style) {
410     case 'r':
411       params.rounds = GetPlayerCount() - 1;
412       break;
413     case 's':
414       params.rounds = (int)ceil(log2(GetPlayerCount())); 
415       break;
416     default:
417       params.rounds = DEFAULT_ROUNDS;
418       break;
419     }
420   }
421
422   // this is to stop a 4 player tourney from having 2 rounds
423   params.rounds = (params.rounds < MINIMUM_ROUNDS) ? MINIMUM_ROUNDS : params.rounds;
424   
425   playerIter.Reset(); // [HGM] this code moved here from SortPlayers
426   while((tp = playerIter.Next())) {
427     tp->ClearWhites();
428     tp->ClearBlacks();
429     tp->ClearTotalWhites();
430     tp->ClearTotalBlacks();
431   }
432
433   MakeAssignments();
434   TellThemWhoTheyPlay();  // tell them who they play 
435 }
436
437 int Tourney::PopLastPairedPlayer() {
438   Storage *p=NULL, *lastPlayer=NULL;
439   LinkListIter<Storage> pairedIter(pairedPlayers);
440   int last=0;
441
442   while((p = pairedIter.Next())) {
443     lastPlayer = p;
444     last = p->value;
445   }
446
447   if(last) {
448     cout << "Popping: " << lastPlayer->name << " from the paired list " << endl;
449     pairedPlayers.Delete(lastPlayer);
450   } else
451     cout << "Popping: _NOBODY_" << " from the paired list " << endl;
452
453   return last;
454 }
455
456 void Tourney::ClearPairedPlayers() {
457   Storage *p=NULL;
458   LinkListIter<Storage> pairedIter(pairedPlayers);
459
460   while((p = pairedIter.Next())) pairedPlayers.Delete(p);
461 }
462
463 int Tourney::MakeAssignments(void) {
464   TourneyPlayers *tp = NULL, *opponent = NULL, *bye = NULL;
465   Storage *newPairedPlayer=NULL;
466   Player *p=NULL, *opp=NULL;
467   int everybodyPaired=0, byeFlag=1, playerCount=0, i=1;
468   LinkListIter<TourneyPlayers> playerIter(playerList);
469   
470   params.currentRound++;
471   if(params.currentRound > params.rounds) {
472     cout << "Returning because current round is > rounds" << endl;
473     cerr << "Returning because current round is > rounds" << endl;
474     return 0;
475   }  
476   // Initialize a few things...make sure nobody is paired,
477   playerIter.Reset();
478   while((tp = playerIter.Next())) {
479     UnPairPlayer(tp);
480     if(strcmp(tp->name, "_BYE_") == 0)  { byeFlag = 0; }  // unset the byeFlag
481   }
482   playerCount = GetPlayerCount();
483   if((byeFlag) && (playerCount % 2)){   // we need to add a bye
484     bye = new TourneyPlayers("_BYE_", 0, 0);  
485     playerList.Append(bye);                  // add the bye to the tourney players list
486     SortPlayers();
487     playerCount++;
488   }
489   
490   // Set up the PairingScores
491   playerIter.Reset();
492   while((tp = playerIter.Next())) { if(!tp->IsPaired()) SetPairingScores(tp); }
493   
494   playerIter.Reset();
495   while((tp = playerIter.Next())) { UnPairPlayer(tp); tp->oppChoice=0; }  // unpair all the players
496   
497   i = 1;
498   ClearPairedPlayers();
499   while(everybodyPaired == 0) {
500     everybodyPaired = 0;
501     p = GetSortPlayer(i);
502     tp = GetPlayer(p->name);
503     opponent = (TourneyPlayers *)NULL;
504     // PrintPotentialLists();
505     if((tp->IsPaired() == FALSE) && tp->activeFlag) { // If I am not paired and I am active pair me
506       if((opponent = FindBestOpponent(tp))) {
507         newPairedPlayer = new Storage(tp->name, i);
508         pairedPlayers.Append(newPairedPlayer);
509         cerr << "Adding: " << tp->name << " " << i << " " << "to the paired list " << opponent->name << endl;
510         everybodyPaired = PairPlayers(tp, opponent);  // Actually Pair me
511         i++;                                // go to the next player
512       } else {                              // If there is no opponent for me go back and repair up the tree
513         if(tp->oppChoice > playerCount) {  // If I have tried all my opponents
514           tp->oppChoice = 0;               // reset me so I can try again later
515           i = PopLastPairedPlayer();          // returns the last player paired & removes him from the paired list
516           cerr << "i=" << i << endl;
517           if(i <= 0)  {                         // this would be really bad means we can't even find 
518             cout << "Returning because we can't find pairings" << endl;
519             cerr << "Returning because we can't find pairings" << endl;
520             return 0;                       // an opponent for the first player.  Tourney has to be over now
521           }
522           p = GetSortPlayer(i);
523           tp = GetPlayer(p->name);
524           opponent = GetPlayer(tp->oppName);
525           cout << "UnPairing: " << tp->name << " " << opponent->name << " choice: " << tp->oppChoice << endl;
526           tp->RemoveLastOpponent();           // removes the person we were planning on playing
527           opponent->RemoveLastOpponent();
528           UnPairPlayer(tp);                   // unpair us so we can be re-paired
529           UnPairPlayer(opponent);
530           tp->oppChoice++;                           // try his next possible opponent
531         } else {
532           tp->oppChoice++;   // Try my next opponent
533         }
534       }
535     } else {  // if I am already paired go to the next player and pair him
536       i++;
537     }
538   }
539
540   if(everybodyPaired > 0) {
541     playerIter.Reset();
542     while((tp = playerIter.Next())) UnPairPlayer(tp);  // unpair all players so we can use that to tell
543     playerIter.Reset();                                 // if they have been assiged a color
544     while((tp = playerIter.Next())) {
545       if((!tp->IsPaired()) && (tp->activeFlag != 0)) {
546         opponent = GetPlayer(tp->oppName);
547         AssignColors(tp, opponent);
548         tp->NowPaired(TRUE);               // mark BOTH players as having a color
549         opponent->NowPaired(TRUE);         // this is important for when we hit this player later in the Iter
550       }
551     }
552   }
553
554   playerIter.Reset();
555   while((tp = playerIter.Next()))  {
556     if(0 == strcmp(tp->name, "_BYE_")) {  // If I am the bye
557       LinkListIter<Player> opponentIter(tp->opponentList);
558       while((opp = opponentIter.Next())) { // Got through my opponents and find the one I am playing now
559         if(0 == strcasecmp(opp->name, tp->oppName)) { // & Give him a win
560           if(opp->value)
561             SetGameResult(tp->name, tp->oppName, 0);
562           else
563             SetGameResult(tp->oppName, tp->name, 1);
564           gMamer.XServerCom("tell %s you get a BYE this round.%s", opp->name, "\n");
565         }
566       }
567     }
568   }
569   return 1;
570 }
571
572 //- PrintPotentialLists
573 void Tourney::PrintPotentialLists() {
574   TourneyPlayers *tp=NULL;
575   Player *o=NULL;
576
577   LinkListIter<TourneyPlayers> playerIter(playerList);
578
579   while((tp = playerIter.Next())) {
580     printf("%-10s %i\n", tp->name, tp->oppChoice);
581     LinkListIter<Player> oppIter(tp->potentialOpponentList);    
582     while((o = oppIter.Next())) {
583       printf("%d %-10s ", o->value, o->name);
584     }
585     printf("\n\n");
586   }
587 }
588
589 //- Start of FindBestOpponent
590 TourneyPlayers *Tourney::FindBestOpponent(TourneyPlayers *tp) {
591   Player *tmp = NULL;
592   
593   LinkListIter<Player> opponentIter(tp->potentialOpponentList);
594   while((tmp = opponentIter.Next())) {
595     if((tmp->value == tp->oppChoice) && (0 == GetPlayer(tmp->name)->IsPaired())) {
596       return GetPlayer(tmp->name);
597     }
598   }
599
600   return NULL;
601 }
602
603 //- Start of SetPairingSores -------------------------------
604 void Tourney::SetPairingScores(TourneyPlayers *tp) {
605   double score;
606   TourneyPlayers *opponent = NULL;
607   Player *temp=NULL, *newOpp=NULL, *t=NULL, *me=NULL;
608   int offset=2, place=1, i=0, added=0;
609   
610   tp->RemovePotentialOppList();
611
612   LinkListIter<TourneyPlayers> playerIter(playerList);
613   
614   SortPlayers();
615   
616   while((opponent = playerIter.Next())) {
617     if((strcmp(tp->name, opponent->name) != 0) && 
618        (tp->score == opponent->score)) {
619       offset++;
620       if(opponent->rating > tp->rating) {
621         place++;
622       }
623     }
624   }
625   offset = offset / 2;
626   if(place > offset) { offset *= -1; }
627
628   me = GetSortPlayer(tp->name);
629   playerIter.Reset();
630   while((opponent = playerIter.Next())) {
631     if(strcmp(tp->name, opponent->name) && (tp->activeFlag !=0)) { // If this isn't MY name & I am active
632       if((!tp->AlreadyPlayed(opponent->name)) && (!opponent->IsPaired()) && (opponent->activeFlag != 0)
633           && (tp->ColorDue() != opponent->ColorDue() // they are due different color, never a problem
634              || tp->ColorDue() ? // both are due white. Check if one of them could accept black without breaking 'absolute' color rules
635                                  tp->GetConsecutiveBlacks() < 2 &&
636                                  tp->GetTotalBlacks() - tp->GetTotalWhites() < 2 ||
637                                  opponent->GetConsecutiveBlacks() < 2 &&
638                                  opponent->GetTotalBlacks() - opponent->GetTotalWhites() < 2
639                                : // both are due black. Check if any of them can accept white
640                                  tp->GetConsecutiveWhites() < 2 &&
641                                  tp->GetTotalWhites() - tp->GetTotalBlacks() < 2 ||
642                                  opponent->GetConsecutiveWhites() < 2 &&
643                                  opponent->GetTotalWhites() - opponent->GetTotalBlacks() < 2
644              )
645         ) { 
646         // and I haven't played this person and this person is active. (not forfeited)
647         t = GetSortPlayer(opponent->name);
648         score = ((abs(t->value - (me->value + offset))) * 1000);
649         if(opponent->score >= tp->score) {
650           score = score + ((opponent->score - tp->score) * 10.0);
651         } else {
652           score = score + ((tp->score - opponent->score) * 10.0);
653         }
654         score += abs(opponent->ColorDue() - tp->ColorDue());
655         score += (abs(opponent->rating - tp->rating)) * 0.0001;
656
657         if(!strcmp(opponent->name, "_BYE_")) { score = 999999; }
658
659         added=0;
660         newOpp = new Player(opponent->name, score);
661         LinkListIter<Player> opponentIter(tp->potentialOpponentList);
662         opponentIter.Reset();
663         while((temp = opponentIter.Next())) {
664           if(score < temp->floatValue) {
665             tp->potentialOpponentList.Insert(temp, newOpp);
666             added = 1;
667             break;
668           }
669         }
670         if(!added)
671           tp->potentialOpponentList.Append(newOpp);
672         opponentIter.Reset();
673         i = 0;
674         while((temp = opponentIter.Next())) {
675           temp->value = i;
676           i++;
677         }
678       }
679     }
680   }
681 }
682
683 //- Start of PairPlayers ----------------------------------
684 int Tourney::PairPlayers(TourneyPlayers *p1, TourneyPlayers *p2) {
685   TourneyPlayers *tp;
686   Player *temp = NULL;
687
688   LinkListIter<TourneyPlayers> playerIter(playerList);
689
690   temp = new Player(p2->name, -1.0, 0, p2->rating);
691   p1->opponentList.Append(temp);
692   p1->NowPaired(TRUE);
693   strcpy(p1->oppName, p2->name);
694
695   temp = new Player(p1->name, -1.0, 0, p1->rating);
696   p2->opponentList.Append(temp);
697   p2->NowPaired(TRUE);
698   strcpy(p2->oppName, p1->name);
699
700   playerIter.Reset();
701   while((tp = playerIter.Next())) {
702     if((!tp->IsPaired()) && (tp->activeFlag != 0))
703       return 0;
704   }
705   
706   return 1;
707 }
708
709 //- Start of UnPairPlayer ----------------------------------
710 void Tourney::UnPairPlayer(TourneyPlayers *p1) {
711   if(p1 != NULL)
712     p1->NowPaired(FALSE);
713 }//- end of UnPairPlayer
714
715 //- intcmp ----
716 int Tourney::intcmp(int a, int b) {
717   if(a > b) {
718     return 1;
719   } else {
720     if (a == b) {
721       return 0;
722     } else {
723       return -1;
724     }
725   }
726 }
727 //- end intcmp ----
728
729 //- AssignColors ----------------------------------------------------------
730 void Tourney::AssignColors(TourneyPlayers *p1, TourneyPlayers *p2) {
731   int p1Color=0, rated = 1;
732   Game *g = NULL;
733   Player *opp1 = NULL, *opp2 = NULL;
734
735   cerr << "P1: " << p1->name << " due=" << p1->ColorDue() << " total=" << p1->GetTotalWhites() << "/" << p1->GetTotalBlacks()
736         << " consecutive=" << p1->GetConsecutiveWhites() << "/" << p1->GetConsecutiveBlacks() << endl;
737   cerr << "P2: " << p2->name << " due=" << p2->ColorDue() << " total=" << p2->GetTotalWhites() << "/" << p2->GetTotalBlacks()
738         << " consecutive=" << p2->GetConsecutiveWhites() << "/" << p2->GetConsecutiveBlacks() << endl;
739   if(params.mode != 'r') { rated = 0; }
740   if(intcmp(p1->ColorDue(), p2->ColorDue()) != 0) {
741     if(p1->ColorDue()) { p1Color = 1; }
742   } else {
743     if(p1->ColorDue()) {   // Both are due white; need to find out how due.
744       switch (intcmp(p1->GetConsecutiveBlacks(), p2->GetConsecutiveBlacks())) {
745       case 1:
746         p1Color = 1;
747         break;
748       case -1: break;
749       case 0:
750         switch (intcmp(p1->GetTotalBlacks(), p2->GetTotalBlacks())) {
751         case 1:
752           p1Color = 1;
753           break;
754         case -1: break;
755         case 0:
756           if((p1->score * 10000 + p1->rating) >= (p2->score * 10000 + p2->rating))
757             p1Color = 1;
758           break;
759         }
760         break;
761       }
762     } else {
763       switch (intcmp(p1->GetConsecutiveWhites(), p2->GetConsecutiveWhites())) {
764       case 1: break;
765       case -1:
766         p1Color = 1;
767         break;
768       case 0:
769         switch (intcmp(p1->GetTotalWhites(), p2->GetTotalWhites())) {
770         case 1: break;
771         case -1:
772           p1Color = 1;
773           break;
774         case 0:
775           if((p1->score * 10000 + p1->rating) >= (p2->score * 10000 + p2->rating))
776             p1Color = 1;
777           break;
778         }
779         break;
780       }
781     }
782   }
783   LinkListIter<Player> opponentIter1(p1->opponentList);
784   LinkListIter<Player> opponentIter2(p2->opponentList);
785   while((opp1 = opponentIter1.Next())) {
786     if(!strcasecmp(opp1->name, p2->name)) { break; }
787   }
788   while((opp2 = opponentIter2.Next())) {
789     if(!strcasecmp(opp2->name, p1->name)) { break; }
790   }
791   cerr << "assigned color = " << p1Color << endl;
792   if(p1Color) { 
793     p1->AddWhite(); p2->AddBlack();
794     opp1->value = 1;
795     g = new Game(p1->name, p2->name, params.time, params.inc, rated, 'r');
796   } else { 
797     p1->AddBlack(); p2->AddWhite();
798     opp2->value = 1;
799     g = new Game(p2->name, p1->name, params.time, params.inc, rated, 'r');
800   }
801   gameList.Append(g);
802 }
803
804 //- GetStatus --------------------------------------------------------
805 int Tourney::GetStatus(void) {
806   return status;
807 }
808
809 //- EndTourney -----------------------
810 void Tourney::EndTourney(void) {
811   status = DONE;
812 }//- End EndTourney
813
814 //- Announce ----------------------------------------------------------
815 void Tourney::Announce(void) {
816   char temp[128];
817   char *announce;
818   long now=0;
819
820   announce = new char[MAX_LINE_SIZE];
821   memset(announce, '\0', MAX_LINE_SIZE);
822   sprintf(announce, "*****Tourney Announcement***** %80s Trny #%d  %d %d %c ", 
823           "", number, params.time, params.inc, params.mode);
824   if(params.style == 's') { strcat(announce, " SWISS"); } else { strcat(announce, " RR"); }
825   switch(params.variant) {
826   case 'w':
827     strcat(announce, " Wild ");
828     strcat(announce, GetWild(params.wild));
829     break;
830   case 'b':
831     strcat(announce, " Bug"); break;
832   case 's':
833     strcat(announce, " Suicide"); break;
834   default:
835     break;
836   }
837   memset(temp, '\0', 128);
838   sprintf(temp, " %i-%i %i plr(s).  tell %s join %d. Avg: %5.1f", 
839           params.ratingLow, params.ratingHigh, GetPlayerCount(), gMamer.username, number, averageRating);
840   strcat(announce, temp);
841
842   printf("%s  + cha 49\n", announce);
843   fflush(stdout);
844   
845   gMamer.XServerCom("%s %i %s%s", "tell", gMamer.channelNumber, announce, "\n");
846
847   now = time(0);
848   if((now - lastCshouted) > (SEC_BETWEEN_CSHOUTS)) {
849     gMamer.XServerCom("%s %s%s", "cshout", announce, "\n");
850     lastCshouted = now;
851   }
852
853   delete(announce);
854 }
855
856 //- SetVariable ---------------------------------------------------------------
857 void Tourney::SetVariable(int why, int newValue) {
858
859   switch (why) {
860   case 0:
861     if((newValue >= 0) && (newValue <= MAX_TIME))
862       params.time = newValue;
863     break;
864   case 1:
865     if((newValue >= 0) && (newValue <= MAX_INCREMENT))
866       params.inc = newValue;
867     break;
868   case 2:
869     params.rounds = newValue;
870     params.rounds = MIN(params.rounds, MAX_ROUNDS);
871     params.rounds = MIN((params.maxPlayers - 1), params.rounds);
872     break;
873   case 6:
874     if(((newValue >= 0) && (newValue <= 5)) || 
875        ((newValue >= 8) || (newValue <= 10)))
876       params.wild = newValue;
877     break;
878   case 7:
879     params.ratingLow = newValue;
880     params.ratingLow = MAX(0, params.ratingLow);
881     if(params.ratingLow >= (params.ratingHigh - 200)) 
882       params.ratingLow = params.ratingHigh - 200;
883     break;
884   case 8:
885     params.ratingHigh = newValue;
886     if(params.ratingHigh <= (params.ratingLow + 200))
887       params.ratingHigh = params.ratingLow + 200;
888     break;
889   case 9:
890     params.maxPlayers = newValue;
891     params.maxPlayers = MAX(params.maxPlayers, MINIMUM_PLAYERS);
892     params.maxPlayers = MAX(params.maxPlayers, (params.rounds + 1));
893     break;
894   default:
895     break;
896   }
897 }//- End SetVariable
898
899 //- SetVariable ---------------------------------------------------------------
900 void Tourney::SetVariable(int why, char *newValue) {
901
902   switch (why) {
903   case 3:
904     if((newValue[0] == 's') || (newValue[0] == 'r')) 
905       params.style = newValue[0];
906     break;
907   case 4:
908     if((newValue[0] == 'r') || (newValue[0] == 'w') || (newValue[0] == 'b') || (newValue[0] == 's'))
909       params.variant = newValue[0];
910     break;
911   case 5:
912     if((newValue[0] == 'r') || (newValue[0] == 'u'))
913       params.mode = newValue[0];
914     break;
915   default:
916     break;
917   }
918 }//- End SetVariable
919
920 //- Begin GetWild - take a int return a string
921 char *Tourney::GetWild(int w) {
922   switch (w) {
923   case 0:
924     return "0";
925   case 1:
926     return "1";
927   case 2: 
928     return "2";
929   case 3:
930     return "3";
931   case 4:
932     return "4";
933   case 5:
934     return "5";
935   case 8:
936     return "8";
937   case 9:
938     return "8a";
939   case 10:
940     return "fr";
941   default:
942     return "";
943   }
944 }//- end GetWild
945
946 //- TellThemWhoTheyPlay ------------------------------------------
947 void Tourney::TellThemWhoTheyPlay() {
948   Game *g = NULL;
949   LinkListIter<Game> gameIter(gameList);  // List of games in this tourney
950   char *Variant=new char[MAX_LINE_SIZE];
951
952   memset(Variant, '\0', MAX_LINE_SIZE);
953
954   if(params.variant == 'w')
955     sprintf(Variant, "wild %2s", GetWild(params.wild));
956   else if(params.variant == 's')
957     sprintf(Variant, "suicide");
958   else if(params.variant == 'b')
959     sprintf(Variant, "bug");
960
961   while((g = gameIter.Next())) {
962           /* note that we rely on rmatch and on the ; separated commands from lasker */
963           gMamer.XServerCom("rmatch %s %s %i %i %c %s white ; rmatch %s %s %i %i %c %s black\n", 
964                             g->whiteName, g->blackName, g->time, g->inc, params.mode, Variant,
965                             g->blackName, g->whiteName, g->time, g->inc, params.mode, Variant);
966   }
967   delete(Variant);
968 }//- end TellThemWhoTheyPlay --------------------------------------
969
970 //- SetGameResult --------------------------------------------
971 int Tourney::SetGameResult(char *white, char *black, int result) {
972   Player *opp1 = NULL, *opp2 = NULL;
973   TourneyPlayers *tp1 = NULL, *tp2 = NULL;
974   Game *g = NULL;
975   int found=0;
976
977   tp1 = GetPlayer(white);
978   tp2 = GetPlayer(black);
979
980   if((NULL == tp1) || (NULL == tp2)) { return 0; }
981
982   LinkListIter<Player> opponentIter1(tp1->opponentList);  // List of opponents this player has had
983   while((opp1 = opponentIter1.Next())) {
984     if(!strcasecmp(opp1->name, black)) { break; }
985   }
986   LinkListIter<Player> opponentIter2(tp2->opponentList);
987   while((opp2 = opponentIter2.Next())) {
988     if(!strcasecmp(opp2->name, white)) { break; }
989   }
990   if((NULL == opp1) || (NULL == opp2)) { return -1; }
991
992   switch (result) {    // set the result
993   case 1:
994     opp1->floatValue = 1.0; 
995     opp2->floatValue = 0.0; 
996     break;
997   case 0:
998     opp1->floatValue = 0.0; 
999     opp2->floatValue = 1.0; 
1000     break;
1001   case 2:
1002     opp1->floatValue = 0.5; 
1003     opp2->floatValue = 0.5; 
1004     break;
1005   default:
1006     return 0;
1007   }
1008   tp1->CalculateScore();  
1009   tp2->CalculateScore();
1010
1011   LinkListIter<Game> gameIter(gameList);  // List of games in this tourney
1012   while((g = gameIter.Next())) {
1013     if(!(strcasecmp(g->whiteName, white)) && !(strcasecmp(g->blackName, black))) {
1014       gameList.Delete(g);
1015       found=1;
1016       break;
1017     }
1018   }
1019   if(found) {
1020     gameIter.Reset();
1021     if((g = gameIter.Next())) {
1022       return 1;
1023     } else {
1024       return 2;
1025     }
1026   } else {
1027     return 1;
1028   }
1029 } //- End SetGameResult --------------------------------------
1030
1031 //- GetStartDate ---------------------------------------------
1032 long Tourney::GetStartDate() {
1033   return startDate;
1034 } //- end of GetStartDate ------------------------------------
1035
1036 //- GetEndDate ---------------------------------------------
1037 long Tourney::GetEndDate() {
1038   return endDate;
1039 } //- end of GetEndDate ------------------------------------