Fix color assignment by mamer
[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   TourneyPlayers *tp = NULL;
403   status = CLOSED;
404   params.currentRound = 0;
405
406   LinkListIter<TourneyPlayers> playerIter(playerList);
407
408   startDate = time(0);
409
410   cout << "tourney started at: " << ctime(&startDate) << endl;
411
412   if(params.rounds == 0) { 
413     switch(params.style) {
414     case 'r':
415       params.rounds = GetPlayerCount() - 1;
416       break;
417     case 's':
418       params.rounds = (int)ceil(log22(GetPlayerCount())); 
419       break;
420     default:
421       params.rounds = DEFAULT_ROUNDS;
422       break;
423     }
424   }
425
426   // this is to stop a 4 player tourney from having 2 rounds
427   params.rounds = (params.rounds < MINIMUM_ROUNDS) ? MINIMUM_ROUNDS : params.rounds;
428   
429   playerIter.Reset(); // [HGM] this code moved here from SortPlayers
430   while((tp = playerIter.Next())) {
431     tp->ClearWhites();
432     tp->ClearBlacks();
433     tp->ClearTotalWhites();
434     tp->ClearTotalBlacks();
435   }
436
437   MakeAssignments();
438   TellThemWhoTheyPlay();  // tell them who they play 
439 }
440
441 int Tourney::PopLastPairedPlayer() {
442   Storage *p=NULL, *lastPlayer=NULL;
443   LinkListIter<Storage> pairedIter(pairedPlayers);
444   int last=0;
445
446   while((p = pairedIter.Next())) {
447     lastPlayer = p;
448     last = p->value;
449   }
450
451   if(last) {
452     cout << "Popping: " << lastPlayer->name << " from the paired list " << endl;
453     pairedPlayers.Delete(lastPlayer);
454   } else
455     cout << "Popping: _NOBODY_" << " from the paired list " << endl;
456
457   return last;
458 }
459
460 void Tourney::ClearPairedPlayers() {
461   Storage *p=NULL;
462   LinkListIter<Storage> pairedIter(pairedPlayers);
463
464   while((p = pairedIter.Next())) pairedPlayers.Delete(p);
465 }
466
467 int Tourney::MakeAssignments(void) {
468   TourneyPlayers *tp = NULL, *opponent = NULL, *bye = NULL;
469   Storage *newPairedPlayer=NULL;
470   Player *p=NULL, *opp=NULL;
471   int everybodyPaired=0, byeFlag=1, playerCount=0, i=1;
472   LinkListIter<TourneyPlayers> playerIter(playerList);
473   
474   params.currentRound++;
475   if(params.currentRound > params.rounds) {
476     cout << "Returning because current round is > rounds" << endl;
477     cerr << "Returning because current round is > rounds" << endl;
478     return 0;
479   }  
480   // Initialize a few things...make sure nobody is paired,
481   playerIter.Reset();
482   while((tp = playerIter.Next())) {
483     UnPairPlayer(tp);
484     if(strcmp(tp->name, "_BYE_") == 0)  { byeFlag = 0; }  // unset the byeFlag
485   }
486   playerCount = GetPlayerCount();
487   if((byeFlag) && (playerCount % 2)){   // we need to add a bye
488     bye = new TourneyPlayers("_BYE_", 0, 0);  
489     playerList.Append(bye);                  // add the bye to the tourney players list
490     SortPlayers();
491     playerCount++;
492   }
493   
494   // Set up the PairingScores
495   playerIter.Reset();
496   while((tp = playerIter.Next())) { if(!tp->IsPaired()) SetPairingScores(tp); }
497   
498   playerIter.Reset();
499   while((tp = playerIter.Next())) { UnPairPlayer(tp); tp->oppChoice=0; }  // unpair all the players
500   
501   i = 1;
502   ClearPairedPlayers();
503   while(everybodyPaired == 0) {
504     everybodyPaired = 0;
505     p = GetSortPlayer(i);
506     tp = GetPlayer(p->name);
507     opponent = (TourneyPlayers *)NULL;
508     // PrintPotentialLists();
509     if((tp->IsPaired() == FALSE) && tp->activeFlag) { // If I am not paired and I am active pair me
510       if((opponent = FindBestOpponent(tp))) {
511         newPairedPlayer = new Storage(tp->name, i);
512         pairedPlayers.Append(newPairedPlayer);
513         cerr << "Adding: " << tp->name << " " << i << " " << "to the paired list " << opponent->name << endl;
514         everybodyPaired = PairPlayers(tp, opponent);  // Actually Pair me
515         i++;                                // go to the next player
516       } else {                              // If there is no opponent for me go back and repair up the tree
517         if(tp->oppChoice > playerCount) {  // If I have tried all my opponents
518           tp->oppChoice = 0;               // reset me so I can try again later
519           i = PopLastPairedPlayer();          // returns the last player paired & removes him from the paired list
520           cerr << "i=" << i << endl;
521           if(i <= 0)  {                         // this would be really bad means we can't even find 
522             cout << "Returning because we can't find pairings" << endl;
523             cerr << "Returning because we can't find pairings" << endl;
524             return 0;                       // an opponent for the first player.  Tourney has to be over now
525           }
526           p = GetSortPlayer(i);
527           tp = GetPlayer(p->name);
528           opponent = GetPlayer(tp->oppName);
529           cout << "UnPairing: " << tp->name << " " << opponent->name << " choice: " << tp->oppChoice << endl;
530           tp->RemoveLastOpponent();           // removes the person we were planning on playing
531           opponent->RemoveLastOpponent();
532           UnPairPlayer(tp);                   // unpair us so we can be re-paired
533           UnPairPlayer(opponent);
534           tp->oppChoice++;                           // try his next possible opponent
535         } else {
536           tp->oppChoice++;   // Try my next opponent
537         }
538       }
539     } else {  // if I am already paired go to the next player and pair him
540       i++;
541     }
542   }
543
544   if(everybodyPaired > 0) {
545     playerIter.Reset();
546     while((tp = playerIter.Next())) UnPairPlayer(tp);  // unpair all players so we can use that to tell
547     playerIter.Reset();                                 // if they have been assiged a color
548     while((tp = playerIter.Next())) {
549       if((!tp->IsPaired()) && (tp->activeFlag != 0)) {
550         opponent = GetPlayer(tp->oppName);
551         AssignColors(tp, opponent);
552         tp->NowPaired(TRUE);               // mark BOTH players as having a color
553         opponent->NowPaired(TRUE);         // this is important for when we hit this player later in the Iter
554       }
555     }
556   }
557
558   playerIter.Reset();
559   while((tp = playerIter.Next()))  {
560     if(0 == strcmp(tp->name, "_BYE_")) {  // If I am the bye
561       LinkListIter<Player> opponentIter(tp->opponentList);
562       while((opp = opponentIter.Next())) { // Got through my opponents and find the one I am playing now
563         if(0 == strcasecmp(opp->name, tp->oppName)) { // & Give him a win
564           if(opp->value)
565             SetGameResult(tp->name, tp->oppName, 0);
566           else
567             SetGameResult(tp->oppName, tp->name, 1);
568           gMamer.XServerCom("tell %s you get a BYE this round.%s", opp->name, "\n");
569         }
570       }
571     }
572   }
573   return 1;
574 }
575
576 //- PrintPotentialLists
577 void Tourney::PrintPotentialLists() {
578   TourneyPlayers *tp=NULL;
579   Player *o=NULL;
580
581   LinkListIter<TourneyPlayers> playerIter(playerList);
582
583   while((tp = playerIter.Next())) {
584     printf("%-10s %i\n", tp->name, tp->oppChoice);
585     LinkListIter<Player> oppIter(tp->potentialOpponentList);    
586     while((o = oppIter.Next())) {
587       printf("%d %-10s ", o->value, o->name);
588     }
589     printf("\n\n");
590   }
591 }
592
593 //- Start of FindBestOpponent
594 TourneyPlayers *Tourney::FindBestOpponent(TourneyPlayers *tp) {
595   Player *tmp = NULL;
596   
597   LinkListIter<Player> opponentIter(tp->potentialOpponentList);
598   while((tmp = opponentIter.Next())) {
599     if((tmp->value == tp->oppChoice) && (0 == GetPlayer(tmp->name)->IsPaired())) {
600       return GetPlayer(tmp->name);
601     }
602   }
603
604   return NULL;
605 }
606
607 //- Start of SetPairingSores -------------------------------
608 void Tourney::SetPairingScores(TourneyPlayers *tp) {
609   double score;
610   TourneyPlayers *opponent = NULL;
611   Player *temp=NULL, *newOpp=NULL, *t=NULL, *me=NULL;
612   int offset=2, place=1, i=0, added=0;
613   
614   tp->RemovePotentialOppList();
615
616   LinkListIter<TourneyPlayers> playerIter(playerList);
617   
618   SortPlayers();
619   
620   while((opponent = playerIter.Next())) {
621     if((strcmp(tp->name, opponent->name) != 0) && 
622        (tp->score == opponent->score)) {
623       offset++;
624       if(opponent->rating > tp->rating) {
625         place++;
626       }
627     }
628   }
629   offset = offset / 2;
630   if(place > offset) { offset *= -1; }
631
632   me = GetSortPlayer(tp->name);
633   playerIter.Reset();
634   while((opponent = playerIter.Next())) {
635     if(strcmp(tp->name, opponent->name) && (tp->activeFlag !=0)) { // If this isn't MY name & I am active
636       if((!tp->AlreadyPlayed(opponent->name)) && (!opponent->IsPaired()) && (opponent->activeFlag != 0)) { 
637         // and I haven't played this person and this person is active. (not forfeited)
638         t = GetSortPlayer(opponent->name);
639         score = ((abs(t->value - (me->value + offset))) * 1000);
640         if(opponent->score >= tp->score) {
641           score = score + ((opponent->score - tp->score) * 10.0);
642         } else {
643           score = score + ((tp->score - opponent->score) * 10.0);
644         }
645         score += abs(opponent->ColorDue() - tp->ColorDue());
646         score += (abs(opponent->rating - tp->rating)) * 0.0001;
647
648         if(!strcmp(opponent->name, "_BYE_")) { score = 999999; }
649
650         added=0;
651         newOpp = new Player(opponent->name, score);
652         LinkListIter<Player> opponentIter(tp->potentialOpponentList);
653         opponentIter.Reset();
654         while((temp = opponentIter.Next())) {
655           if(score < temp->floatValue) {
656             tp->potentialOpponentList.Insert(temp, newOpp);
657             added = 1;
658             break;
659           }
660         }
661         if(!added)
662           tp->potentialOpponentList.Append(newOpp);
663         opponentIter.Reset();
664         i = 0;
665         while((temp = opponentIter.Next())) {
666           temp->value = i;
667           i++;
668         }
669       }
670     }
671   }
672 }
673
674 //- Start of PairPlayers ----------------------------------
675 int Tourney::PairPlayers(TourneyPlayers *p1, TourneyPlayers *p2) {
676   TourneyPlayers *tp;
677   Player *temp = NULL;
678
679   LinkListIter<TourneyPlayers> playerIter(playerList);
680
681   temp = new Player(p2->name, -1.0, 0, p2->rating);
682   p1->opponentList.Append(temp);
683   p1->NowPaired(TRUE);
684   strcpy(p1->oppName, p2->name);
685
686   temp = new Player(p1->name, -1.0, 0, p1->rating);
687   p2->opponentList.Append(temp);
688   p2->NowPaired(TRUE);
689   strcpy(p2->oppName, p1->name);
690
691   playerIter.Reset();
692   while((tp = playerIter.Next())) {
693     if((!tp->IsPaired()) && (tp->activeFlag != 0))
694       return 0;
695   }
696   
697   return 1;
698 }
699
700 //- Start of UnPairPlayer ----------------------------------
701 void Tourney::UnPairPlayer(TourneyPlayers *p1) {
702   if(p1 != NULL)
703     p1->NowPaired(FALSE);
704 }//- end of UnPairPlayer
705
706 //- intcmp ----
707 int Tourney::intcmp(int a, int b) {
708   if(a > b) {
709     return 1;
710   } else {
711     if (a == b) {
712       return 0;
713     } else {
714       return -1;
715     }
716   }
717 }
718 //- end intcmp ----
719
720 //- AssignColors ----------------------------------------------------------
721 void Tourney::AssignColors(TourneyPlayers *p1, TourneyPlayers *p2) {
722   int p1Color=0, rated = 1;
723   Game *g = NULL;
724   Player *opp1 = NULL, *opp2 = NULL;
725
726   cerr << "P1: " << p1->name << " due=" << p1->ColorDue() << " total=" << p1->GetTotalWhites() << "/" << p1->GetTotalBlacks()
727         << " consecutive=" << p1->GetConsecutiveWhites() << "/" << p1->GetConsecutiveBlacks() << endl;
728   cerr << "P2: " << p2->name << " due=" << p2->ColorDue() << " total=" << p2->GetTotalWhites() << "/" << p2->GetTotalBlacks()
729         << " consecutive=" << p2->GetConsecutiveWhites() << "/" << p2->GetConsecutiveBlacks() << endl;
730   if(params.mode != 'r') { rated = 0; }
731   if(intcmp(p1->ColorDue(), p2->ColorDue()) != 0) {
732     if(p1->ColorDue()) { p1Color = 1; }
733   } else {
734     if(p1->ColorDue()) {   // Both are due white; need to find out how due.
735       switch (intcmp(p1->GetConsecutiveBlacks(), p2->GetConsecutiveBlacks())) {
736       case 1:
737         p1Color = 1;
738         break;
739       case -1: break;
740       case 0:
741         switch (intcmp(p1->GetTotalBlacks(), p2->GetTotalBlacks())) {
742         case 1:
743           p1Color = 1;
744           break;
745         case -1: break;
746         case 0:
747           if((p1->score * 10000 + p1->rating) >= (p2->score * 10000 + p2->rating))
748             p1Color = 1;
749           break;
750         }
751         break;
752       }
753     } else {
754       switch (intcmp(p1->GetConsecutiveWhites(), p2->GetConsecutiveWhites())) {
755       case 1: break;
756       case -1:
757         p1Color = 1;
758         break;
759       case 0:
760         switch (intcmp(p1->GetTotalWhites(), p2->GetTotalWhites())) {
761         case 1: break;
762         case -1:
763           p1Color = 1;
764           break;
765         case 0:
766           if((p1->score * 10000 + p1->rating) >= (p2->score * 10000 + p2->rating))
767             p1Color = 1;
768           break;
769         }
770         break;
771       }
772     }
773   }
774   LinkListIter<Player> opponentIter1(p1->opponentList);
775   LinkListIter<Player> opponentIter2(p2->opponentList);
776   while((opp1 = opponentIter1.Next())) {
777     if(!strcasecmp(opp1->name, p2->name)) { break; }
778   }
779   while((opp2 = opponentIter2.Next())) {
780     if(!strcasecmp(opp2->name, p1->name)) { break; }
781   }
782   cerr << "assigned color = " << p1Color << endl;
783   if(p1Color) { 
784     p1->AddWhite(); p2->AddBlack();
785     opp1->value = 1;
786     g = new Game(p1->name, p2->name, params.time, params.inc, rated, 'r');
787   } else { 
788     p1->AddBlack(); p2->AddWhite();
789     opp2->value = 1;
790     g = new Game(p2->name, p1->name, params.time, params.inc, rated, 'r');
791   }
792   gameList.Append(g);
793 }
794
795 //- GetStatus --------------------------------------------------------
796 int Tourney::GetStatus(void) {
797   return status;
798 }
799
800 //- EndTourney -----------------------
801 void Tourney::EndTourney(void) {
802   status = DONE;
803 }//- End EndTourney
804
805 //- Announce ----------------------------------------------------------
806 void Tourney::Announce(void) {
807   char temp[128];
808   char *announce;
809   long now=0;
810
811   announce = new char[MAX_LINE_SIZE];
812   memset(announce, '\0', MAX_LINE_SIZE);
813   sprintf(announce, "*****Tourney Announcement***** %80s Trny #%d  %d %d %c ", 
814           "", number, params.time, params.inc, params.mode);
815   if(params.style == 's') { strcat(announce, " SWISS"); } else { strcat(announce, " RR"); }
816   switch(params.variant) {
817   case 'w':
818     strcat(announce, " Wild ");
819     strcat(announce, GetWild(params.wild));
820     break;
821   case 'b':
822     strcat(announce, " Bug"); break;
823   case 's':
824     strcat(announce, " Suicide"); break;
825   default:
826     break;
827   }
828   memset(temp, '\0', 128);
829   sprintf(temp, " %i-%i %i plr(s).  tell %s join %d. Avg: %5.1f", 
830           params.ratingLow, params.ratingHigh, GetPlayerCount(), gMamer.username, number, averageRating);
831   strcat(announce, temp);
832
833   printf("%s  + cha 49\n", announce);
834   fflush(stdout);
835   
836   gMamer.XServerCom("%s %i %s%s", "tell", gMamer.channelNumber, announce, "\n");
837
838   now = time(0);
839   if((now - lastCshouted) > (SEC_BETWEEN_CSHOUTS)) {
840     gMamer.XServerCom("%s %s%s", "cshout", announce, "\n");
841     lastCshouted = now;
842   }
843
844   delete(announce);
845 }
846
847 //- SetVariable ---------------------------------------------------------------
848 void Tourney::SetVariable(int why, int newValue) {
849
850   switch (why) {
851   case 0:
852     if((newValue >= 0) && (newValue <= MAX_TIME))
853       params.time = newValue;
854     break;
855   case 1:
856     if((newValue >= 0) && (newValue <= MAX_INCREMENT))
857       params.inc = newValue;
858     break;
859   case 2:
860     params.rounds = newValue;
861     params.rounds = MIN(params.rounds, MAX_ROUNDS);
862     params.rounds = MIN((params.maxPlayers - 1), params.rounds);
863     break;
864   case 6:
865     if(((newValue >= 0) && (newValue <= 5)) || 
866        ((newValue >= 8) || (newValue <= 10)))
867       params.wild = newValue;
868     break;
869   case 7:
870     params.ratingLow = newValue;
871     params.ratingLow = MAX(0, params.ratingLow);
872     if(params.ratingLow >= (params.ratingHigh - 200)) 
873       params.ratingLow = params.ratingHigh - 200;
874     break;
875   case 8:
876     params.ratingHigh = newValue;
877     if(params.ratingHigh <= (params.ratingLow + 200))
878       params.ratingHigh = params.ratingLow + 200;
879     break;
880   case 9:
881     params.maxPlayers = newValue;
882     params.maxPlayers = MAX(params.maxPlayers, MINIMUM_PLAYERS);
883     params.maxPlayers = MAX(params.maxPlayers, (params.rounds + 1));
884     break;
885   default:
886     break;
887   }
888 }//- End SetVariable
889
890 //- SetVariable ---------------------------------------------------------------
891 void Tourney::SetVariable(int why, char *newValue) {
892
893   switch (why) {
894   case 3:
895     if((newValue[0] == 's') || (newValue[0] == 'r')) 
896       params.style = newValue[0];
897     break;
898   case 4:
899     if((newValue[0] == 'r') || (newValue[0] == 'w') || (newValue[0] == 'b') || (newValue[0] == 's'))
900       params.variant = newValue[0];
901     break;
902   case 5:
903     if((newValue[0] == 'r') || (newValue[0] == 'u'))
904       params.mode = newValue[0];
905     break;
906   default:
907     break;
908   }
909 }//- End SetVariable
910
911 //- Begin GetWild - take a int return a string
912 char *Tourney::GetWild(int w) {
913   switch (w) {
914   case 0:
915     return "0";
916   case 1:
917     return "1";
918   case 2: 
919     return "2";
920   case 3:
921     return "3";
922   case 4:
923     return "4";
924   case 5:
925     return "5";
926   case 8:
927     return "8";
928   case 9:
929     return "8a";
930   case 10:
931     return "fr";
932   default:
933     return "";
934   }
935 }//- end GetWild
936
937 //- TellThemWhoTheyPlay ------------------------------------------
938 void Tourney::TellThemWhoTheyPlay() {
939   Game *g = NULL;
940   LinkListIter<Game> gameIter(gameList);  // List of games in this tourney
941   char *Variant=new char[MAX_LINE_SIZE];
942
943   memset(Variant, '\0', MAX_LINE_SIZE);
944
945   if(params.variant == 'w')
946     sprintf(Variant, "wild %2s", GetWild(params.wild));
947   else if(params.variant == 's')
948     sprintf(Variant, "suicide");
949   else if(params.variant == 'b')
950     sprintf(Variant, "bug");
951
952   while((g = gameIter.Next())) {
953           /* note that we rely on rmatch and on the ; separated commands from lasker */
954           gMamer.XServerCom("rmatch %s %s %i %i %c %s white ; rmatch %s %s %i %i %c %s black\n", 
955                             g->whiteName, g->blackName, g->time, g->inc, params.mode, Variant,
956                             g->blackName, g->whiteName, g->time, g->inc, params.mode, Variant);
957   }
958   delete(Variant);
959 }//- end TellThemWhoTheyPlay --------------------------------------
960
961 //- SetGameResult --------------------------------------------
962 int Tourney::SetGameResult(char *white, char *black, int result) {
963   Player *opp1 = NULL, *opp2 = NULL;
964   TourneyPlayers *tp1 = NULL, *tp2 = NULL;
965   Game *g = NULL;
966   int found=0;
967
968   tp1 = GetPlayer(white);
969   tp2 = GetPlayer(black);
970
971   if((NULL == tp1) || (NULL == tp2)) { return 0; }
972
973   LinkListIter<Player> opponentIter1(tp1->opponentList);  // List of opponents this player has had
974   while((opp1 = opponentIter1.Next())) {
975     if(!strcasecmp(opp1->name, black)) { break; }
976   }
977   LinkListIter<Player> opponentIter2(tp2->opponentList);
978   while((opp2 = opponentIter2.Next())) {
979     if(!strcasecmp(opp2->name, white)) { break; }
980   }
981   if((NULL == opp1) || (NULL == opp2)) { return -1; }
982
983   switch (result) {    // set the result
984   case 1:
985     opp1->floatValue = 1.0; 
986     opp2->floatValue = 0.0; 
987     break;
988   case 0:
989     opp1->floatValue = 0.0; 
990     opp2->floatValue = 1.0; 
991     break;
992   case 2:
993     opp1->floatValue = 0.5; 
994     opp2->floatValue = 0.5; 
995     break;
996   default:
997     return 0;
998   }
999   tp1->CalculateScore();  
1000   tp2->CalculateScore();
1001
1002   LinkListIter<Game> gameIter(gameList);  // List of games in this tourney
1003   while((g = gameIter.Next())) {
1004     if(!(strcasecmp(g->whiteName, white)) && !(strcasecmp(g->blackName, black))) {
1005       gameList.Delete(g);
1006       found=1;
1007       break;
1008     }
1009   }
1010   if(found) {
1011     gameIter.Reset();
1012     if((g = gameIter.Next())) {
1013       return 1;
1014     } else {
1015       return 2;
1016     }
1017   } else {
1018     return 1;
1019   }
1020 } //- End SetGameResult --------------------------------------
1021
1022 //- GetStartDate ---------------------------------------------
1023 long Tourney::GetStartDate() {
1024   return startDate;
1025 } //- end of GetStartDate ------------------------------------
1026
1027 //- GetEndDate ---------------------------------------------
1028 long Tourney::GetEndDate() {
1029   return endDate;
1030 } //- end of GetEndDate ------------------------------------