mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-17 06:06:00 -06:00
935 lines
34 KiB
C++
935 lines
34 KiB
C++
#include "VegaMain.h"
|
|
#include "Tournament.h"
|
|
|
|
int RoundData::MakeNextPairing()
|
|
{ extern void SortPairs(int round);
|
|
return 10;
|
|
}
|
|
|
|
|
|
void RoundData::SaveRound(int flag)
|
|
//
|
|
// save the round file
|
|
// flag = 0, save the file at the current round
|
|
// flag = 1, save a backup file at current round
|
|
//
|
|
{ int i, j, npair, numPlayers = NPlayer;
|
|
int round = currentRound;
|
|
String filename, s;
|
|
if (flag==0) filename = PATHDIR + FILETORNEO + ".rnd";
|
|
else filename = PATHDIR + FILETORNEO + AsString(TD.currentRound) + ".rnd";
|
|
FileOut out(filename);
|
|
|
|
out.PutLine( NFormat("%2d # current round", currentRound ) );
|
|
out.PutLine( " 1 # not used" );
|
|
out.PutLine( " 1 # not used" );
|
|
out.PutLine( " 1 # not used" );
|
|
out.PutLine( NFormat("%2d # STATUS_ROUND", STATUS_ROUND) );
|
|
out.PutLine( " 1 # not used" );
|
|
out.PutLine( " 1 # not used" );
|
|
|
|
out.PutLine( "# players color" );
|
|
for (i=1; i<=NPlayer; i++)
|
|
{ String s = NFormat("%3d ", i);
|
|
for (j=1; j<=round; j++)
|
|
{ s << NFormat("%3d ", playerColor[i][j]);
|
|
}
|
|
out.PutLine( s );
|
|
}
|
|
|
|
out.PutLine("# players opponent" );
|
|
for (i=1; i<=NPlayer; i++)
|
|
{ String s = NFormat("%3d ", i);
|
|
for (j=1; j<=round; j++) s << NFormat("%3d ", playerOpponent[i][j]);
|
|
out.PutLine( s );
|
|
}
|
|
|
|
out.PutLine( "# players floater");
|
|
for (i=1; i<=NPlayer; i++)
|
|
{ String s = NFormat("%3d ", i);
|
|
for (j=1; j<=round; j++) s << NFormat("%d ", playerFloater[i][j]);
|
|
out.PutLine( s );
|
|
}
|
|
|
|
out.PutLine( "# round results");
|
|
for (i=1; i<=NPlayer; i++)
|
|
{ String s = NFormat("%3d ", i);
|
|
for (j=1; j<=round; j++) s << NFormat("%d ", roundResult[i][j]);
|
|
out.PutLine( s );
|
|
}
|
|
|
|
out.PutLine( "# code pairing");
|
|
if (NPlayer & 1) npair = (NPlayer-1)/2 + 1;
|
|
else npair = NPlayer/2;
|
|
for (i=0; i<=npair; i++)
|
|
{ String s = "";
|
|
for (j=1; j<=round; j++) s << NFormat("%7d ", pairing[i][j]);
|
|
out.PutLine( s );
|
|
}
|
|
if (out.IsError()) Exclamation(t_("Error while writing .rnd file"));
|
|
out.Close();
|
|
}
|
|
|
|
|
|
void RoundData::LoadRound(String filename)
|
|
{ FileIn in(filename);
|
|
int i, j, npair, numPlayers = NPlayer;
|
|
/* if ((in=fopen(filename, "r"))==NULL)
|
|
{ WarningMessage(sss[S_NOREADR], sss[S_CLOSE]);
|
|
return;
|
|
}
|
|
*/
|
|
TD.currentRound = StrIntValue( in.GetLine() );
|
|
in.GetLine(); //skip this line
|
|
in.GetLine(); //skip this line
|
|
in.GetLine(); //skip this line
|
|
STATUS_ROUND = StrIntValue( in.GetLine() );
|
|
in.GetLine(); //skip this line
|
|
in.GetLine(); //skip this line
|
|
|
|
in.GetLine(); //skip this line // "# players color\n"
|
|
for (i=1; i<=numPlayers; i++)
|
|
{ Vector<String> field = Split(in.GetLine(), ' ');
|
|
//field.GetCount() coincide with currentRound
|
|
for (j=1; j<field.GetCount(); j++) playerColor[i][j] = StrIntValue( field[j] );
|
|
}
|
|
|
|
in.GetLine(); //skip this line // "# players opponent\n"
|
|
for (i=1; i<=numPlayers; i++)
|
|
{ Vector<String> field = Split(in.GetLine(), ' ');
|
|
//field.GetCount() coincide with currentRound
|
|
for (j=1; j<field.GetCount(); j++) playerOpponent[i][j] = StrIntValue( field[j] );
|
|
}
|
|
|
|
in.GetLine(); //skip this line // "# players opponent\n"
|
|
for (i=1; i<=numPlayers; i++)
|
|
{ Vector<String> field = Split(in.GetLine(), ' ');
|
|
//field.GetCount() coincide with currentRound
|
|
for (j=1; j<field.GetCount(); j++) playerFloater[i][j] = StrIntValue( field[j] );
|
|
}
|
|
|
|
in.GetLine(); //skip this line // "# players result\n"
|
|
for (i=1; i<=numPlayers; i++)
|
|
{ Vector<String> field = Split(in.GetLine(), ' ');
|
|
//field.GetCount() coincide with currentRound
|
|
for (j=1; j<field.GetCount(); j++) roundResult[i][j] = StrIntValue( field[j] );
|
|
}
|
|
|
|
// now reads the pairing
|
|
in.GetLine(); //skip this line // "# code pairing\n"
|
|
if (numPlayers & 1) npair = (numPlayers-1)/2 + 1;
|
|
else npair = numPlayers/2;
|
|
for (i=0; i<=npair; i++)
|
|
{ Vector<String> field = Split(in.GetLine(), ' ');
|
|
for (j=1; j<=field.GetCount(); j++) pairing[i][j] = StrIntValue( field[j-1] );
|
|
}
|
|
in.Close();
|
|
}
|
|
|
|
|
|
void RoundData::AdjournPlayerState(int round)
|
|
//
|
|
// NOTE: it is called by MakeNextPairing and determine the state
|
|
// of each player at round 'round' necessary to calculate the next pairing
|
|
//
|
|
{ int id, j, np, maxcol;
|
|
int diffcolor, jopp, jump, maxjump;
|
|
int countblack, countwhite;
|
|
double score, aro, buc;
|
|
|
|
maxjump = 3; if (NRounds>9) maxjump=4; //set the maximum number of upfloating
|
|
maxcol = 2 + PERMIT3COLOR; // PERMIT3COLOR = 0, 1
|
|
if (round==NRounds-1 && PLAY_SYSTEM==LIM) maxcol = 3; // last round exception
|
|
|
|
for (id=1; id<=NPlayer; id++)
|
|
{
|
|
//determine the due color
|
|
diffcolor = 0;
|
|
for (j=1; j<=round; j++) diffcolor += playerColor[id][j];
|
|
player[id].colorDiff = diffcolor; // useful to assign color in case of equalization
|
|
|
|
if (diffcolor>0) player[id].duecolor = BLACK;
|
|
else if (diffcolor<0) player[id].duecolor = WHITE;
|
|
else { //equal black & white games
|
|
j=round;
|
|
while (playerColor[id][j] == NO_COLOR) j--; // go back in history
|
|
if (playerColor[id][j] == WHITE) player[id].duecolor = BLACK;
|
|
else player[id].duecolor = WHITE;
|
|
// useful for player that got the BYE
|
|
if (round==1 && playerColor[id][round]==NO_COLOR) player[id].duecolor = -1;
|
|
// WARNING!!!! the previous player should be in the color group with less players
|
|
}
|
|
//set the currentDuecolor equal to the duecolor
|
|
player[id].currentDuecolor = player[id].duecolor;
|
|
|
|
//set flag canChangeDuecolor to met 2.3 and 2.4
|
|
player[id].canChangeDuecolor = true; //default
|
|
if ( (diffcolor == maxcol) || (diffcolor == -maxcol)) player[id].canChangeDuecolor=false;
|
|
else player[id].canChangeDuecolor = true;
|
|
countblack = countwhite = 0;
|
|
if (player[id].duecolor==WHITE) {
|
|
for (j=round; j>=1; j--) {//check for consecutive black to met 2.4
|
|
if (playerColor[id][j]==BLACK_COLOR) countblack++;
|
|
else if (playerColor[id][j]==WHITE_COLOR) break;
|
|
}
|
|
if (countblack==maxcol) player[id].canChangeDuecolor = false;
|
|
if ( countblack==maxcol && currentRound==NRounds && !PERMIT3COLOR //permit3color is gia' contato in maxcol o si rischia 4 color
|
|
&& PLAY_SYSTEM==USCF) player[id].canChangeDuecolor = true;
|
|
}
|
|
if (player[id].duecolor==BLACK) {
|
|
for (j=round; j>=1; j--) {//check for consecutive white to met 2.4
|
|
if (playerColor[id][j]==WHITE_COLOR) countwhite++;
|
|
else if (playerColor[id][j]==BLACK_COLOR) break;
|
|
}
|
|
if (countwhite==maxcol) player[id].canChangeDuecolor=false;
|
|
else if (countwhite==maxcol && currentRound==NRounds && !PERMIT3COLOR //permit3color is gia' contato in maxcol o si rischia 4 color
|
|
&& PLAY_SYSTEM==USCF) player[id].canChangeDuecolor = true;
|
|
}
|
|
|
|
if (PLAY_SYSTEM==USCF) {
|
|
countblack = countwhite = 0;
|
|
for (j=round; j>=1; j--) {//check for consecutive black
|
|
if (playerColor[id][j]==BLACK_COLOR) countblack++;
|
|
else if (playerColor[id][j]==WHITE_COLOR) break;
|
|
}
|
|
for (j=round; j>=1; j--) {//check for consecutive white
|
|
if (playerColor[id][j]==WHITE_COLOR) countwhite++;
|
|
else if (playerColor[id][j]==BLACK_COLOR) break;
|
|
}
|
|
// duecolor = 1 for white
|
|
// duecolor = 0 for black
|
|
// duecolor = -1 for neutral
|
|
if ( countblack == 0 && countwhite == 0) player[id].duecolor = -1;
|
|
else if ( countblack > 0 ) player[id].colorCons = countblack;
|
|
else if ( countwhite > 0 ) player[id].colorCons = countwhite;
|
|
}
|
|
|
|
//set ARO
|
|
aro = 0.;
|
|
np = 0;
|
|
for (j=1; j<=round; j++) {
|
|
jopp = playerOpponent[id][j];
|
|
if (jopp != 0 && (roundResult[id][j] < 3)) // no BYE o game won for forfait
|
|
{ aro += (double) player[jopp].RATING; np++;}
|
|
}
|
|
if (np != 0) player[id].tiebreak[ARO] = player[id].aro = (float) (aro/np);
|
|
else player[id].tiebreak[ARO] = player[id].aro = (float) 0.;
|
|
|
|
//set score
|
|
score = 0.;
|
|
for (j=1; j<=round; j++) {
|
|
if (roundResult[id][j]==1 || roundResult[id][j]==3) score += WON;
|
|
else if (roundResult[id][j]==2 || roundResult[id][j]==6 || roundResult[id][j]==8) score += DRAW;
|
|
}
|
|
player[id].tiebreak[SCORE] = (float) score;
|
|
if (NAccRound && NAccRound>currentRound && id<=NPlayer/2)
|
|
player[id].tiebreak[SCORE] += WON; //accelerated rounds
|
|
|
|
//set flag canUpfloat
|
|
jump = 0;
|
|
if (PLAY_SYSTEM == DUBOV) {
|
|
for (j=1; j<=round; j++) if (playerFloater[id][j]) jump++;
|
|
if (jump >= maxjump) player[id].canUpfloat = false;
|
|
else if ( (jump < maxjump) && (playerFloater[id][round]) && (round<NRounds-1))
|
|
player[id].canUpfloat = false;
|
|
else if ( (jump < maxjump) && (playerFloater[id][round]) && (round==NRounds-1))
|
|
player[id].canUpfloat = true;
|
|
else player[id].canUpfloat = true;
|
|
}
|
|
if (PLAY_SYSTEM == LIM) { // downfloat
|
|
// if ( playerFloater[id][round]==1 ) playerState[id].canDownfloat = NO;
|
|
// else playerState[id].canDownfloat = YES;
|
|
if ( playerFloater[id][round]==1 ) player[id].canUpfloat = false;
|
|
else player[id].canUpfloat = true;
|
|
}
|
|
|
|
//set flag canGetBYE: who got 1 point without to play will not get the bye
|
|
// who got 1/2 point can get the bye if there are not player with flag 1
|
|
player[id].canGetBYE = 1;
|
|
for (j=1; j<=round; j++)
|
|
{ if (roundResult[id][j]==3) // won for forfeit
|
|
{ player[id].canGetBYE = 0;
|
|
break;
|
|
}
|
|
else if (roundResult[id][j]==6 || roundResult[id][j]==8)
|
|
player[id].canGetBYE = 2;
|
|
}
|
|
//set remaining flags
|
|
player[id].isAlreadyTested = false;
|
|
|
|
//set bucholz for pairing
|
|
if (PLAY_SYSTEM == VEGA) {
|
|
//calculate Buccholz
|
|
buc = 0.;
|
|
for (j=1; j<=round; j++)
|
|
{ jopp = playerOpponent[id][j];
|
|
if ( (jopp != 0) && (roundResult[id][j]<3) ) // no BYE, no forfait
|
|
{ buc += player[jopp].tiebreak[SCORE];
|
|
}
|
|
else if (roundResult[id][j]>2 && (roundResult[id][j] != 8)) // BYE, forfait but NOT draw without bucholz
|
|
buc += player[id].tiebreak[SCORE]; // sum his score to the bucholz
|
|
}
|
|
|
|
player[id].rating = (int) (buc*10);
|
|
player[id].aro = buc*10.;
|
|
}
|
|
/* else if (PLAY_SYSTEM == BURST) {
|
|
//calculate Extended Buccholz
|
|
buc = 0.;
|
|
for (j=1; j<=round; j++)
|
|
{ jopp = playerOpponent[id][j];
|
|
if ( (jopp != 0) && (roundResult[id][j]<3) ) // no BYE, no forfait
|
|
{ buc += playerResult[jopp][SCORE];
|
|
}
|
|
else if (roundResult[id][j]>2 && (roundResult[id][j] != 8)) // BYE, forfait but NOT draw without bucholz
|
|
buc += playerResult[id][SCORE]; // sum his score to the bucholz
|
|
}
|
|
player[id].aro = buc+playerResult[id][SCORE]; // Extende Buccholz
|
|
player[id].rating = player[id].RATING;
|
|
}
|
|
*/
|
|
else player[id].rating = player[id].RATING;
|
|
}
|
|
|
|
// set the _BYE_
|
|
player[0].duecolor = -1; // nessun colore
|
|
player[0].canChangeDuecolor = true;
|
|
}
|
|
|
|
void RoundData::AdjournCrossTableSwiss(int round)
|
|
//
|
|
// NOTE: it is called just after the iserting the result of the round
|
|
// so at round N, the state refer to the previous N-1 rounds
|
|
//
|
|
{ int id, j, np;
|
|
int jopp;
|
|
double score, aro, buc, min, max, sb;
|
|
double totscore, sumtotscore, modifiedscore[N_PLAYER_MAX+1];
|
|
|
|
for (id=1; id<=NPlayer; id++)
|
|
{
|
|
//set ARO
|
|
aro = 0.;
|
|
np = 0;
|
|
for (j=1; j<=round; j++)
|
|
{ jopp = playerOpponent[id][j];
|
|
if (jopp != 0 && roundResult[id][j] < 3) // no BYE o game won for forfait
|
|
{ aro += (double) player[jopp].RATING;
|
|
np++;
|
|
}
|
|
}
|
|
if (np != 0) player[id].tiebreak[ARO] = (float) aro/np;
|
|
else player[id].tiebreak[ARO] = (float) 0.;
|
|
|
|
score = 0.; //set score, cumulative points and most blacks
|
|
totscore=0.; //progressive score : 1, 2, 2.5, ...
|
|
sumtotscore = 0.; //cumulative points 1, 3, 5.5, ...
|
|
player[id].tiebreak[MOST_BLACKS] = modifiedscore[id] = 0.;
|
|
player[id].tiebreak[MOST_WINS] = 0.;
|
|
|
|
// calculate modified score useful for bucholz
|
|
for (j=1; j<=round; j++) {
|
|
switch (roundResult[id][j])
|
|
{ case 1:
|
|
totscore += WON; sumtotscore += totscore;
|
|
score += WON; player[id].tiebreak[MOST_WINS] += 1.;
|
|
modifiedscore[id] += WON;
|
|
break;
|
|
case 3: // win to forfeit
|
|
totscore += DRAW; sumtotscore += totscore;
|
|
score += WON; // playerResult[id][MOST_WINS] += 1; // forfeit count as draw
|
|
modifiedscore[id] += DRAW; // forfeit count as draw
|
|
break;
|
|
case 2: // draw
|
|
totscore += DRAW; sumtotscore += totscore;
|
|
score += DRAW;
|
|
modifiedscore[id] += DRAW; // forfeit count as draw
|
|
break;
|
|
case 6: // draw to forfeit
|
|
totscore += DRAW; sumtotscore += totscore;
|
|
score += DRAW;
|
|
modifiedscore[id] += DRAW; // forfeit count as draw
|
|
break;
|
|
|
|
case 0:
|
|
if (playerOpponent[id][j] !=0 ) sumtotscore += totscore;
|
|
else {
|
|
sumtotscore += totscore;
|
|
modifiedscore[id] += DRAW; // forfeit count as draw
|
|
}
|
|
break;
|
|
case 4: // lost to forfeit
|
|
sumtotscore += totscore + DRAW;
|
|
modifiedscore[id] += DRAW; // forfeit count as draw
|
|
break;
|
|
case 8:
|
|
sumtotscore += totscore;
|
|
score += DRAW;
|
|
modifiedscore[id] += DRAW;
|
|
break;
|
|
}
|
|
if (roundResult[id][j]==1 && playerColor[id][j]==-1)
|
|
player[id].tiebreak[MOST_BLACKS] += (float) 1.;
|
|
}
|
|
player[id].tiebreak[SCORE] = score;
|
|
if (NAccRound && NAccRound>currentRound && id<=NPlayer/2)
|
|
player[id].tiebreak[SCORE] += (float) WON; //accelerated rounds
|
|
player[id].tiebreak[CUMUL] = (float) sumtotscore;
|
|
}
|
|
|
|
for (id=1; id<=NPlayer; id++)
|
|
{ //set Buccholz
|
|
buc = 0.;
|
|
min = 10000.;
|
|
max = 0.;
|
|
for (j=1; j<=round; j++)
|
|
{ jopp = playerOpponent[id][j];
|
|
if ( (jopp != 0) && (roundResult[id][j]<3) ) // no BYE, no forfait
|
|
{ // buc += playerResult[jopp][SCORE];
|
|
buc += modifiedscore[jopp];
|
|
|
|
if (modifiedscore[jopp]<min) min = modifiedscore[jopp];
|
|
if (modifiedscore[jopp]>max) max = modifiedscore[jopp];
|
|
}
|
|
else if ( (roundResult[id][j]>2 && (roundResult[id][j] < 8)) || playerOpponent[id][j] ==0 ) // BYE, forfait but NOT draw without bucholz
|
|
{ buc += modifiedscore[id]; // sum his score to the bucholz
|
|
|
|
if (modifiedscore[id]<min) min = modifiedscore[id];
|
|
if (modifiedscore[id]>max) max = modifiedscore[id];
|
|
}
|
|
else if ( roundResult[id][j] == 8 ) // without bucholz
|
|
{
|
|
min = 0;
|
|
}
|
|
}
|
|
|
|
if (buc > min) player[id].tiebreak[BUC_CUT1] = (float) buc-min;
|
|
else player[id].tiebreak[BUC_CUT1] = 0.;
|
|
|
|
if (buc - min > max ) player[id].tiebreak[BUC_MED] = (float) (buc - min - max);
|
|
else player[id].tiebreak[BUC_MED] = 0.;
|
|
|
|
player[id].tiebreak[BUC_TOT] = (float) buc;
|
|
}
|
|
|
|
for (id=1; id<=NPlayer; id++)
|
|
{ //set Sonneborg-Berger
|
|
sb = 0.;
|
|
for (j=1; j<=round; j++)
|
|
{ jopp = playerOpponent[id][j];
|
|
if ( jopp != 0 && roundResult[id][j]==1 ) // win, no forfait
|
|
sb += modifiedscore[jopp];
|
|
|
|
else if ( (jopp != 0) && (roundResult[id][j]==2) ) // draw, no forfait
|
|
sb += modifiedscore[jopp]/2.;
|
|
|
|
else if ( ((jopp == 0) || (roundResult[id][j]>2)) && (roundResult[id][j] < 8) ) // draw with himself (forfait)
|
|
sb += modifiedscore[id]/2.; // sum his half score to the bucholz
|
|
}
|
|
player[id].tiebreak[SONN_BERG] = (float) sb;
|
|
}
|
|
// adjourn the rest of cross table
|
|
CalcVarElo(NPlayer);
|
|
//ShowClassificationByname(numberPlayer);
|
|
// PrepareHTMLindex();
|
|
NationalPlayerCard(NPlayer); // here is calculated the performance rating
|
|
setAPRO(round, NPlayer);
|
|
ShowTableScore(NPlayer);
|
|
CrossTableSwiss();
|
|
ShowTableCategoryScore(NPlayer);
|
|
}
|
|
|
|
|
|
void RoundData::CrossTableSwiss()
|
|
{ int i, j, index;
|
|
String stringa, str, strname;
|
|
int *roundRes;
|
|
int *playerCol;
|
|
int *playerOpp;
|
|
|
|
if (IS_SWISS) {
|
|
playerOpp = &playerOpponent[0][0];
|
|
roundRes = &roundResult[0][0];
|
|
playerCol = &playerColor[0][0];
|
|
}
|
|
|
|
FileOut save(PATHDIR + "crosstbl.txt");
|
|
FileOut savehtml (PATHDIRWWW + "crosstbl.html");
|
|
|
|
save << NAMETORNEO << "\n";
|
|
save << PLACETORNEO << " - " << DATATORNEO_B <<", "<<DATATORNEO_E << "\n\n";
|
|
save << t_(" Cross Table at round ")<< currentRound << "\n\n";
|
|
save << " ID NAME Rtg Tit Fed Scr |";
|
|
|
|
// produce HTML files
|
|
savehtml << TD.HTMLCommonHeader();
|
|
savehtml << HTMLNavBar();
|
|
savehtml << "<h2>" << NAMETORNEO << "</h2>\n";
|
|
savehtml << "<h2>" << PLACETORNEO << " - " << DATATORNEO_B <<", "<<DATATORNEO_E << "</h2>\n";
|
|
savehtml << "<h3> " << t_(" Cross Table at round ") << currentRound<< "</h3>\n";
|
|
savehtml << "<table bgcolor=#efefef cellpadding=4 cellspacing=0 border=0> \n";
|
|
savehtml << "<tbody>\n";
|
|
savehtml << "<tr>";
|
|
savehtml << "<th>ID</th> <th >NAME</th> <th>Rat</th> <th>PRat</th> <th>Nat</th> <th>Scr</th>\n";
|
|
|
|
for(j=1; j<=currentRound; j++) {
|
|
str = NFormat( " %3d ", j);
|
|
save << str;
|
|
savehtml << "<th>" << str << "</th>";
|
|
}
|
|
save << "\n";
|
|
savehtml << "</tr> \n";
|
|
|
|
save << "--------------------------------------------";
|
|
for(j=1; j<=currentRound; j++) save << "------";
|
|
save << "\n";
|
|
for (i=1; i<=NPlayer; i++)
|
|
{ if (player[i].isAvailable != "0") strname = NFormat("%-20.20s", player[i].name);
|
|
else strname = NFormat("%-17.17s(W)", player[i].name);
|
|
|
|
stringa = NFormat("%3d %-20.20s %4d %3.3s %3.3s %4.1f | ",
|
|
i, strname, player[i].RATING, player[i].codetitle, player[i].country, player[i].tiebreak[SCORE]);
|
|
save << stringa;
|
|
|
|
stringa = NFormat("<td> %3d </td> <td> <a href=\"playercard.html#%d\"> %s %s </a> </td> <td>%4d</td> <td align=center bgcolor=#EEEEEE>%4d</td> <td align=center>%3.3s</td> <td>%4.1f</td>",
|
|
i, i, player[i].codetitle, strname, player[i].RATING,
|
|
(int) player[i].tiebreak[PER_RAT], player[i].country, player[i].tiebreak[SCORE]);
|
|
if (i&1) savehtml <<"<tr bgcolor=#e2e2f8> ";
|
|
else savehtml << "<tr bgcolor=#ffffff> ";
|
|
savehtml << stringa;
|
|
|
|
for(j=1; j<=currentRound; j++)
|
|
{ if (PLAY_SYSTEM != ROUND_ROBIN && PLAY_SYSTEM != ROUND_ROBIN2) index = i*(N_ROUND_MAX+1) + j;
|
|
else index = i*(N_ROUND_MAX_RR+1) + j;
|
|
|
|
if (playerOpp[index]==0 && roundRes[index]==0) { //for late-comer - not played
|
|
stringa = " -- ";
|
|
save<< stringa;
|
|
savehtml << "<td>" << stringa << "</td>";
|
|
}
|
|
else if (playerOpp[index]==0 && roundRes[index]==3) { //for BYE: 1F - 0
|
|
stringa = "+BYE ";
|
|
save << stringa;
|
|
savehtml << "<td>" << stringa << "</td>";
|
|
}
|
|
else if (playerOpp[index]==0 && roundRes[index]==4) { //for BYE: 1F - 0
|
|
stringa = "-BYE ";
|
|
save << stringa;
|
|
savehtml << "<td>" << stringa << "</td>";
|
|
}
|
|
else if (playerOpp[index]==0 && (roundRes[index]==6 || roundRes[index]==8)) { //for BYE: XF
|
|
stringa = "=BYE ";
|
|
save<< stringa;
|
|
savehtml << "<td>" << stringa << "</td>";
|
|
}
|
|
else
|
|
{ savehtml << "<td>";
|
|
|
|
if (roundRes[index]==0 || roundRes[index]==4) {save<<"-"; savehtml << "-";}
|
|
else if (roundRes[index]==1 || roundRes[index]==3) {save<<"+"; savehtml << "+";}
|
|
else if (roundRes[index]==2 || roundRes[index]==6 || roundRes[index]==8) {save<<"="; savehtml << "=";}
|
|
|
|
if (playerCol[index]==-1) {save<<"B";savehtml << "B";}
|
|
else if (playerCol[index]==1) {save<<"W";savehtml << "W";}
|
|
else if (playerCol[index]==0) {save<<"N";savehtml << "N";}
|
|
|
|
stringa = NFormat("%-3d ", playerOpp[index]);
|
|
save << stringa;
|
|
|
|
savehtml << stringa << "</td>";
|
|
}
|
|
}
|
|
save << "\n";
|
|
savehtml << "</tr>\n";
|
|
}
|
|
save.Close();
|
|
|
|
savehtml << "</tbody>\n";
|
|
savehtml << "</table>\n";
|
|
savehtml << "<br> <a href=\"http://www.vegachess.com\"> Generated by Vega </a> \n";
|
|
savehtml << "</DIV></body>\n</html>\n";
|
|
savehtml.Close();
|
|
}
|
|
|
|
int RoundData::AssignColorLIM(int id1, int id2, int round)
|
|
//
|
|
// PURPOSE: determine the color for the players id1 and id2
|
|
//
|
|
// INPUT VARIABLE
|
|
// id1 = player1 with his duecolor
|
|
// id2 = player2 with his duecolor
|
|
// round = current round
|
|
//
|
|
// OUTPUT VARIABLE
|
|
// 1 to confirm the duecolor of id1 and change that of id2
|
|
// 0 to confirm both duecolor
|
|
// -1 to confirm the duecolor of id2 and change that of id1
|
|
// >1 flag of special operation when color history is the same
|
|
//
|
|
{ int j=0;
|
|
int id1due, id2due, diffcolor1, diffcolor2;
|
|
double maxscore = TD.WON*(round-1)/2.;
|
|
//char str[30];
|
|
|
|
// sprintf(str, "median = %4.1f", maxscore);
|
|
// WarningMessage(str, sss[S_CLOSE]);
|
|
|
|
if (id2==0) return TD.CodifyResult(id1, id2, 3); //return the BYE and the result
|
|
if (id1==0) return TD.CodifyResult(id1, id2, 4); //return the BYE and the result
|
|
|
|
id1due = player[id1].duecolor;
|
|
id2due = player[id2].duecolor;
|
|
|
|
if (id1due != id2due) return 0; // confirm their duecolor
|
|
|
|
// here both have the same duecolor one must change... who?
|
|
|
|
// 1. let's see if only one can change duecolor
|
|
else if ((player[id1].canChangeDuecolor) &&
|
|
(!player[id2].canChangeDuecolor) ) return -1;
|
|
else if ((!player[id1].canChangeDuecolor) &&
|
|
(player[id2].canChangeDuecolor) ) return 1;
|
|
|
|
// 2. both have same duecolor and can change it,
|
|
// let's see the biggest diffcolor to equalize the color
|
|
diffcolor1 = 0;
|
|
for (j=1; j<=round; j++) diffcolor1 += playerColor[id1][j];
|
|
diffcolor2 = 0;
|
|
for (j=1; j<=round; j++) diffcolor2 += playerColor[id2][j];
|
|
if ( abs(diffcolor1) > abs(diffcolor2) ) return 1;
|
|
else if ( abs(diffcolor1) < abs(diffcolor2) ) return -1;
|
|
|
|
// 3. both have same duecolor and can change it and same diff: see history
|
|
else {
|
|
j = round;
|
|
while (playerColor[id1][j]==playerColor[id2][j] && j>0) j--;
|
|
if (j==0) {
|
|
|
|
// median group or above: duecolor to the higher ranked
|
|
if (player[id1].tiebreak[SCORE] > player[id2].tiebreak[SCORE]
|
|
&& player[id1].tiebreak[SCORE] >= maxscore) {
|
|
return 1;
|
|
}
|
|
else if (player[id2].tiebreak[SCORE] > player[id1].tiebreak[SCORE]
|
|
&& player[id2].tiebreak[SCORE] >= maxscore) {
|
|
return -1;
|
|
}
|
|
// below the median group: duecolor to the lower ranked
|
|
else if (player[id1].tiebreak[SCORE] > player[id2].tiebreak[SCORE]
|
|
&& player[id1].tiebreak[SCORE] < maxscore) {
|
|
return -1;
|
|
}
|
|
else if (player[id2].tiebreak[SCORE] > player[id1].tiebreak[SCORE]
|
|
&& player[id2].tiebreak[SCORE] < maxscore) {
|
|
return 1;
|
|
}
|
|
|
|
//same score: will decide the rating as before
|
|
// above or median group
|
|
if (player[id1].rating > player[id2].rating
|
|
&& player[id1].tiebreak[SCORE] >= maxscore ) {
|
|
return 1;
|
|
}
|
|
else if (player[id2].rating > player[id1].rating
|
|
&& player [id2].tiebreak[SCORE] >= maxscore ) {
|
|
return -1;
|
|
}
|
|
//same score: below median group
|
|
else if (player[id1].rating > player[id2].rating
|
|
&& player[id1].tiebreak[SCORE] < maxscore ) {
|
|
return -1;
|
|
}
|
|
else if (player[id2].rating > player[id1].rating
|
|
&& player[id2].tiebreak[SCORE] < maxscore ) {
|
|
return 1;
|
|
}
|
|
|
|
|
|
// same rating, see alphabetical order!
|
|
// above or median group
|
|
if ( strcmp(player[id1].name,player[id2].name) < 0
|
|
&& player[id1].tiebreak[SCORE] >= maxscore ) {
|
|
return 1;
|
|
}
|
|
else if ( strcmp(player[id2].name,player[id1].name) < 0
|
|
&& player[id2].tiebreak[SCORE] >= maxscore ) {
|
|
return -1;
|
|
}
|
|
// below median group
|
|
else if ( strcmp(player[id1].name,player[id2].name) < 0
|
|
&& player[id1].tiebreak[SCORE] < maxscore ) {
|
|
return -1;
|
|
}
|
|
else if ( strcmp(player[id2].name,player[id1].name) < 0
|
|
&& player[id2].tiebreak[SCORE] < maxscore ) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// il primo a cambiare gli viene confermato il proprio duecolor
|
|
else if ( player[id1].duecolor && (playerColor[id1][j] == BLACK_COLOR)) return 1;
|
|
else if ( (!player[id1].duecolor) && (playerColor[id1][j] == WHITE_COLOR)) return 1;
|
|
else return -1;
|
|
}
|
|
return 0; // fictitious return to remove a silly warning message
|
|
}
|
|
|
|
|
|
int RoundData::AssignColor(int id1, int id2, int round)
|
|
//
|
|
// PURPOSE: determine the color for the players id1 and id2
|
|
//
|
|
// INPUT VARIABLE
|
|
// id1 = player1 with his duecolor
|
|
// id2 = player2 with his duecolor
|
|
// round = current round
|
|
//
|
|
// OUTPUT VARIABLE
|
|
// 1 to confirm the duecolor of id1 and change that of id2
|
|
// 0 to confirm both duecolor
|
|
// -1 to confirm the duecolor of id2 and change that of id1
|
|
// >1 flag of special operation when color history is the same
|
|
//
|
|
{ int j=0;
|
|
int id1due, id2due;
|
|
|
|
if (id2==0) return TD.CodifyResult(id1, id2, 3); //return the BYE and the result
|
|
if (id1==0) return TD.CodifyResult(id2, id1, 3); //return the BYE and the result
|
|
|
|
id1due = player[id1].duecolor;
|
|
id2due = player[id2].duecolor;
|
|
|
|
if (id1due != id2due) return 0; // confirm their duecolor
|
|
|
|
// here both have the same duecolor one must change... who?
|
|
|
|
// 1. let's see if only one can change duecolor
|
|
else if ((player[id1].canChangeDuecolor) &&
|
|
(!player[id2].canChangeDuecolor) ) return -1;
|
|
else if ((!player[id1].canChangeDuecolor) &&
|
|
(player[id2].canChangeDuecolor) ) return 1;
|
|
|
|
// 2. both have same duecolor and can change it, let's see the diffcolor to equalize
|
|
/* diffcolor1 = 0;
|
|
for (j=1; j<=round; j++) diffcolor1 += playerColor[id1][j];
|
|
diffcolor2 = 0;
|
|
for (j=1; j<=round; j++) diffcolor2 += playerColor[id2][j];
|
|
if ( abs(diffcolor1) > abs(diffcolor2) ) return 1;
|
|
else if ( abs(diffcolor1) < abs(diffcolor2) ) return -1;
|
|
*/
|
|
if ( abs(player[id1].colorDiff) > abs(player[id2].colorDiff) ) return 1;
|
|
else if ( abs(player[id1].colorDiff) < abs(player[id2].colorDiff) ) return -1;
|
|
|
|
// 3. same diffcolor, let's test the alternation
|
|
else { //
|
|
j = round;
|
|
while (TD.playerColor[id1][j]==TD.playerColor[id2][j] && j>0) j--;
|
|
if (j==0) { // same history, let's see highest ARO, rating, etc
|
|
|
|
if (TD.PLAY_SYSTEM==USCF) {
|
|
if (player[id1].tiebreak[SCORE] > player[id2].tiebreak[SCORE]) {
|
|
//return CodifyResult(id1, id2, 9);
|
|
return 1;
|
|
}
|
|
else if (player[id2].tiebreak[SCORE] > player[id1].tiebreak[SCORE]) {
|
|
//return CodifyResult(id2, id1, 9);
|
|
return -1;
|
|
}
|
|
// same SCORE, let's see max rating
|
|
else if (player[id2].rating > player[id1].rating) {
|
|
//return CodifyResult(id2, id1, 9);
|
|
return -1;
|
|
}
|
|
else if (player[id1].rating > player[id2].rating) {
|
|
//return CodifyResult(id1, id2, 9);
|
|
return 1;
|
|
}
|
|
// same rating, see alphabetical order!
|
|
else if ( strcmp(player[id1].name,player[id2].name) < 0 ) {
|
|
//return CodifyResult(id1, id2, 9);
|
|
return 1;
|
|
}
|
|
else if ( strcmp(player[id1].name,player[id2].name) > 0 ) {
|
|
//return CodifyResult(id2, id1, 9);
|
|
return -1;
|
|
}
|
|
}
|
|
else { // dubov, vega
|
|
if (player[id1].aro > player[id2].aro) {
|
|
return TD.CodifyResult(id1, id2, 9);
|
|
}
|
|
else if (player[id2].aro > player[id1].aro) {
|
|
return TD.CodifyResult(id2, id1, 9);
|
|
}
|
|
// same ARO, let's see min rating
|
|
else if (player[id1].rating < player[id2].rating) {
|
|
return TD.CodifyResult(id1, id2, 9);
|
|
}
|
|
else if (player[id2].rating < player[id1].rating) {
|
|
return TD.CodifyResult(id2, id1, 9);
|
|
}
|
|
// same rating, see alphabetical order!
|
|
else if ( strcmp(player[id1].name,player[id2].name) < 0 ) {
|
|
return TD.CodifyResult(id1, id2, 9);
|
|
}
|
|
else if ( strcmp(player[id1].name,player[id2].name) > 0 ) {
|
|
return TD.CodifyResult(id2, id1, 9);
|
|
}
|
|
}
|
|
}
|
|
|
|
// il primo a cambiare gli viene confermato il proprio duecolor
|
|
else if ( player[id1].duecolor && (TD.playerColor[id1][j] == BLACK_COLOR)) return 1;
|
|
else if ( (!player[id1].duecolor) && (TD.playerColor[id1][j] == WHITE_COLOR)) return 1;
|
|
else return -1;
|
|
}
|
|
return 0; // fictitious return to remove a silly warning message
|
|
}
|
|
|
|
void RoundData::VerifyColor(int round)
|
|
//
|
|
// PURPOSE: determine the color for each pair of the round 'round'
|
|
//
|
|
// INPUT VARIABLE
|
|
// round = current round
|
|
//
|
|
{ int i, npairs, id1, id2, res, code, flag;
|
|
npairs = TD.pairing[0][round];
|
|
for (i=1; i<=npairs; i++)
|
|
{ code = TD.pairing[i][round];
|
|
TD.DecodeResult(code, &id1, &id2, &res);
|
|
// -----------BUG !!!! aggiungi LIM, fatto il 24.10.2006
|
|
// il problema si presenta solo nella versione compilata con msc8
|
|
if (TD.PLAY_SYSTEM==LIM) flag = AssignColorLIM(id1, id2, round);
|
|
else flag = AssignColor(id1, id2, round);
|
|
|
|
if (flag==1) { // confirm id1 and change id2 color
|
|
if (player[id1].duecolor)
|
|
{ TD.pairing[i][round] = TD.CodifyResult(id1, id2, 9);
|
|
}
|
|
else { TD.pairing[i][round] = TD.CodifyResult(id2, id1, 9);
|
|
}
|
|
}
|
|
else if (flag==0) { // confirm both
|
|
if (player[id1].duecolor)
|
|
{ TD.pairing[i][round] = TD.CodifyResult(id1, id2, 9);
|
|
}
|
|
else { TD.pairing[i][round] = TD.CodifyResult(id2, id1, 9);
|
|
}
|
|
}
|
|
else if (flag==-1) { // confirm id2 and change id1 color
|
|
if (player[id2].duecolor)
|
|
{ TD.pairing[i][round] = TD.CodifyResult(id2, id1, 9);
|
|
}
|
|
else { TD.pairing[i][round] = TD.CodifyResult(id1, id2, 9);
|
|
}
|
|
}
|
|
else if (flag>1) TD.pairing[i][round] = flag;
|
|
}
|
|
}
|
|
|
|
void RoundData::DoFirstRound()
|
|
//
|
|
// PURPOSE: prepare the pairing for the first round
|
|
{ int nhalf, ans=1, n2, groupOdd = 0;
|
|
int i, k, id, prating, kshift, ratbye=1000000;
|
|
int idbye, id1, id2, playerAvailable[N_PLAYER_MAX+1], countAvailable=0;
|
|
|
|
//if (!RANDOM_SORT) ans = QuestionMessage(sss[S_HPWHI], sss[S_NO], sss[S_YES], NULL);//who get the white?
|
|
|
|
ans = PromptYesNo(t_("Do you want to assign the WHITE&to the higher rated players?"));
|
|
|
|
for (i=1; i<=NPlayer; i++)
|
|
{ if (player[i].isAvailable == "1") // get only available player
|
|
{ countAvailable++;
|
|
playerAvailable[countAvailable] = i;
|
|
idbye = i; // he is the last available as they are sorted by rating
|
|
//playerState[i].canChangeDuecolor = true;
|
|
}
|
|
}
|
|
if (countAvailable & 1) { // if number player odd
|
|
if (PLAY_SYSTEM != USCF) pairing[countAvailable/2+1][currentRound] = CodifyResult(idbye, 0, 3);
|
|
else { // USCF treatmet
|
|
for (k=countAvailable; k>=1; k--)
|
|
{ id = playerAvailable[k];
|
|
prating = player[id].RATING;
|
|
if (prating==0) prating = 10000; //unrated treatment
|
|
if (prating < ratbye)
|
|
{ idbye = id;
|
|
ratbye = prating;
|
|
kshift = k;
|
|
}
|
|
}
|
|
for (k=kshift; k<=countAvailable; k++) //remove the bye from the list
|
|
{ playerAvailable[k] = playerAvailable[k+1];
|
|
}
|
|
pairing[countAvailable/2+1][currentRound] = CodifyResult(idbye, 0, 3);
|
|
}
|
|
groupOdd = 1;
|
|
}
|
|
|
|
nhalf = countAvailable/2;
|
|
// set pair and colors for first round; by default the first player has white
|
|
if (NAccRound) { // accelerated rounds
|
|
n2 = nhalf/2;
|
|
for (i=1; i<=n2; i++) // first group made by nhalf player, i.e. n2 pairs
|
|
{ id1 = playerAvailable[i];
|
|
//if (PLAY_SYSTEM!=BURST) id2 = playerAvailable[i+n2];
|
|
//else id2 = playerAvailable[2*n2+1-i];
|
|
id2 = playerAvailable[i+n2];
|
|
|
|
if (ans) { // white at highest rated
|
|
if (i & 1) pairing[i][1] = CodifyResult(id1, id2, 9); // coppie dispari
|
|
else pairing[i][1] = CodifyResult(id2, id1, 9);
|
|
}
|
|
else {
|
|
if (i & 1) pairing[i][1] = CodifyResult(id2, id1, 9); // coppie dispari
|
|
else pairing[i][1] = CodifyResult(id1, id2, 9);
|
|
}
|
|
}
|
|
for (i=n2+1; i<=nhalf; i++) // second group made by nhalf player, i.e. n2 pairs
|
|
{ id1 = playerAvailable[i + n2];
|
|
if (PLAY_SYSTEM!=BURST) id2 = playerAvailable[i + nhalf];
|
|
else id2 = playerAvailable[2*nhalf+n2+1-i];
|
|
if (ans) { // white at highest rated
|
|
if (i & 1) pairing[i][1] = CodifyResult(id1, id2, 9); // coppie dispari
|
|
else pairing[i][1] = CodifyResult(id2, id1, 9);
|
|
}
|
|
else {
|
|
if (i & 1) pairing[i][1] = CodifyResult(id2, id1, 9); // coppie dispari
|
|
else pairing[i][1] = CodifyResult(id1, id2, 9);
|
|
}
|
|
}
|
|
}
|
|
else { // not accelerated rounds
|
|
for (i=1; i<=nhalf; i++)
|
|
{ id1 = playerAvailable[i];
|
|
//if (PLAY_SYSTEM!=BURST) id2 = playerAvailable[i+nhalf];
|
|
//else id2 = playerAvailable[2*nhalf+1-i];
|
|
id2 = playerAvailable[i+nhalf];
|
|
|
|
if (ans) { // white at highest rated
|
|
if (i & 1) pairing[i][1] = CodifyResult(id1, id2, 9); // coppie dispari
|
|
else pairing[i][1] = CodifyResult(id2, id1, 9);
|
|
}
|
|
else {
|
|
if (i & 1) pairing[i][1] = CodifyResult(id2, id1, 9); // coppie dispari
|
|
else pairing[i][1] = CodifyResult(id1, id2, 9);
|
|
}
|
|
}
|
|
}
|
|
//----------- adesso aggiungere le coppie formate da chi ha avuto il BYE ---------!!!
|
|
// save the number of pairs
|
|
if (groupOdd) pairing[0][1] = nhalf+1;
|
|
else pairing[0][1] = nhalf;
|
|
|
|
//set the players that got a BYE
|
|
for (i=1; i<=NPlayer; i++) {
|
|
if ( IsNull(player[i].isAvailable) ) { // get byed player
|
|
playerOpponent[i][currentRound] = 0; // BYE assigned
|
|
roundResult[i][currentRound] = 3; // result 1F-0
|
|
playerColor[i][currentRound] = 0; // no-color
|
|
}
|
|
}
|
|
|
|
}
|