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