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