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