home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #3 / amigamamagazinepolishissue1998.iso / szachy / chaos / src / pairings.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  20KB  |  858 lines

  1. /*  Chaos:                  The Chess HAppening Organisation System     V5.3
  2.     Copyright (C)   1993    Jochen Wiedmann
  3.  
  4.     This program is free software; you can redistribute it and/or modify
  5.     it under the terms of the GNU General Public License as published by
  6.     the Free Software Foundation; either version 2 of the License, or
  7.     (at your option) any later version.
  8.  
  9.     This program is distributed in the hope that it will be useful,
  10.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.     GNU General Public License for more details.
  13.  
  14.     You should have received a copy of the GNU General Public License
  15.     along with this program; if not, write to the Free Software
  16.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18.  
  19.     $RCSfile: Pairings.c,v $
  20.     $Revision: 3.3 $
  21.     $Date: 1994/12/03 18:02:26 $
  22.  
  23.     This file contains the pairing-functions. The algorithm of the
  24.     swiss-pairing is described in the function LoseGroup().
  25.  
  26.     Computer:   Amiga 1200                  Compiler:   Dice 2.07.54 (3.0)
  27.  
  28.     Author:     Jochen Wiedmann
  29.         Am Eisteich 9
  30.       72555 Metzingen
  31.         Tel. 07123 / 14881
  32.         Internet: jochen.wiedmann@zdv.uni-tuebingen.de
  33. */
  34.  
  35.  
  36. #ifndef CHAOS_H
  37. #include "chaos.h"
  38. #endif
  39.  
  40.  
  41.  
  42.  
  43. /*
  44.     GameAddress() returns the address of a game-structure.
  45.  
  46.     Inputs: t - player, whose game list will be searched
  47.         r - number of the round, which's game structure will be
  48.         returned. This may be 0, in which case the address of
  49.         t->First_Game will be returned.
  50.  
  51.     Result: pointer to the game structure corresponding to player t, round r
  52. */
  53. struct Game *GameAddress(struct Player *t, int r)
  54.  
  55. { struct Game *g;
  56.  
  57.   for (g = (struct Game *) &(t->First_Game);  r != 0;
  58.        g = g->Next, r--)
  59.   {
  60.   }
  61.   return(g);
  62. }
  63.  
  64.  
  65.  
  66. /*
  67.     The NewGames() function gets called after each round that has been
  68.     paired. It assumes, that each players Opponent, GFlags and BoardNr fields
  69.     are initialized.
  70.  
  71.     Inputs: memlistptr - pointer to the memory list, where the allocated
  72.              memory will be included.
  73.         fpoints    - number of points, that free players will receive
  74.              (2 for swiss pairing, 0 for round robin)
  75.  
  76.     Result: TRUE, if successful, FALSE otherwise
  77. */
  78. static int NewGames(void **memlistptr, int fpoints)
  79.  
  80. { struct Game *g, *gmem;
  81.   struct Player *t;
  82.   int NumGames = 0;
  83.  
  84.   /*
  85.       Allocate new game structures.
  86.   */
  87.   if ((gmem = GetMem(memlistptr, sizeof(*g)*NumPlayers))  ==  NULL)
  88.   { return(FALSE);
  89.   }
  90.   NumRounds++;
  91.  
  92.   /*
  93.       Initialize the game structures.
  94.   */
  95.   for (t = ((struct Player *) PlayerList.lh_Head), g = gmem;
  96.        t->Tn_Node.ln_Succ != NULL;
  97.        t = (struct Player *) t->Tn_Node.ln_Succ, g++)
  98.   { if (t->Flags & TNFLAGSF_WITHDRAWN)
  99.     { t->GFlags |= GMFLAGSF_NOFIGHT;
  100.     }
  101.     else if (t->Opponent == NULL)
  102.     { t->GFlags |= GMFLAGSF_NOFIGHT|GMFLAGSF_POINTFORFREE;
  103.     }
  104.  
  105.     GameAddress(t, NumRounds-1)->Next = g;
  106.  
  107.     g->Next = NULL;
  108.     g->Opponent = t->Opponent;
  109.     g->Flags = t->GFlags;
  110.     g->BoardNr = t->BoardNr;
  111.  
  112.     if (g->Flags & GMFLAGSF_NOFIGHT)
  113.     { if (t->Flags & TNFLAGSF_WITHDRAWN)
  114.       { g->Result = 0;
  115.     g->Flags = GMFLAGSF_WITHDRAWN;
  116.       }
  117.       else
  118.       { t->Points += fpoints;
  119.     g->Result = fpoints;
  120.     t->Flags |= TNFLAGSF_HADFREE;
  121.       }
  122.     }
  123.     else
  124.     { NumGames++;
  125.       g->Result = -1;
  126.       if (g->Flags & GMFLAGSF_WHITE)
  127.       { t->HowMuchWhite++;
  128.     if (t->HowMuchWhiteLast > 0)
  129.     { t->HowMuchWhiteLast++;
  130.     }
  131.     else
  132.     { t->HowMuchWhiteLast = 1;
  133.     }
  134.       }
  135.       else
  136.       { t->HowMuchWhite--;
  137.     if (t->HowMuchWhiteLast < 0)
  138.     { t->HowMuchWhiteLast--;
  139.     }
  140.     else
  141.     { t->HowMuchWhiteLast = -1;
  142.     }
  143.       }
  144.     }
  145.   }
  146.  
  147.   NumGamesMissing = NumGames/2;
  148.   return(TRUE);;
  149. }
  150.  
  151.  
  152.  
  153.  
  154. /*
  155.     The function CreateRankings() creates the internal ranking list.
  156.     The list is sorted by ELO numbers (if players have one) and by DWZ
  157.     numbers otherwise.
  158.     Players without rating number will appear at the tail of the list
  159. */
  160. void CreateRankings(void)
  161.  
  162. { struct Player *t, **tptr;
  163.   int t1, t2;
  164.  
  165.   RankingFirst = NULL;
  166.   for (t = (struct Player *) PlayerList.lh_Head;
  167.        t->Tn_Node.ln_Succ != NULL;
  168.        t = (struct Player *) t->Tn_Node.ln_Succ)
  169.   { /*
  170.     Get the curremt players (t) rating number into t1.
  171.     */
  172.     if ((t1 = t->ELO)  ==  0)
  173.     { t1 = tdwz(t);
  174.     }
  175.  
  176.     /*
  177.     Insert t into the internal ranking list
  178.     */
  179.     for (tptr = &RankingFirst;  *tptr != NULL;
  180.      tptr = &((*tptr)->RankNext))
  181.     { if (t1 != 0)
  182.       { if ((t2 = (*tptr)->ELO)  ==  0)
  183.     { t2 = tdwz(*tptr);
  184.     }
  185.     if (t1 > t2)
  186.     { break;
  187.     }
  188.       }
  189.     }
  190.  
  191.     t->RankNext = *tptr;
  192.     *tptr = t;
  193.   }
  194. }
  195.  
  196.  
  197.  
  198.  
  199. /*
  200.     DoSwissPairingFirst() makes the pairings of the first round of a
  201.     Swiss pairing tournament.
  202.  
  203.     Inputs: user - True, if the user may set games
  204. */
  205. static int DoSwissPairingFirst(int user)
  206.  
  207. { struct Player *t, *thelp;
  208.   int NumGames, NumFreePlayers;
  209.   int i, j;
  210.   int flag;
  211.   int BoardNr;
  212.  
  213.   /*
  214.       Build the internal ranking list
  215.   */
  216.   CreateRankings();
  217.  
  218.  
  219.   /*
  220.       Allow the user to make settings.
  221.   */
  222.   if ((BoardNr = GetSettings(user))  ==  -1)
  223.   { return(FALSE);
  224.   }
  225.  
  226. #ifdef DEBUG_PAIRINGS
  227.   printf("Setting results:\n");
  228.   for (t = RankingFirst;  t != NULL;  t = t->RankNext)
  229.   { if (t->Opponent)
  230.     { printf("Player %s paired against %s.\n", t->Name, t->Opponent->Name);
  231.     }
  232.     else if (t->GFlags & GMFLAGSF_NOFIGHT)
  233.     { printf("One point bye: %s\n", t->Name);
  234.     }
  235.     else
  236.     { printf("Player %s not set\n", t->Name);
  237.     }
  238.   }
  239. #endif
  240.  
  241.   /*
  242.       get colour of player 1
  243.   */
  244.   flag = (RangeRand(2) == 0)  ?  GMFLAGSF_WHITE  :  0;
  245.  
  246.  
  247.  
  248.   /*
  249.       Count the number of players without opponent. Get the number of players
  250.       with minimal rating. Additionally setup the colors for set players.
  251.   */
  252.   NumFreePlayers = 0;
  253.   for (t = RankingFirst;  t != NULL;  t = t->RankNext)
  254.   { if (t->Opponent == NULL  &&  (t->GFlags & GMFLAGSF_NOFIGHT) == 0)
  255.     { NumFreePlayers++;
  256.     }
  257.     else if (t->Opponent)
  258.     { if ((t->GFlags & GMFLAGSF_WHITE) == 0  &&
  259.       (t->Opponent->GFlags & GMFLAGSF_WHITE) == 0)
  260.       { t->GFlags = flag;
  261.     flag = GMFLAGSF_WHITE - flag;
  262.     t->Opponent->GFlags = flag;
  263.       }
  264. #ifdef DEBUG_PAIRINGS
  265.       printf("Game set: %s : %s (%d)\n",
  266.          flag ? t->Opponent->Name : t->Name,
  267.          flag ? t->Name : t->Opponent->Name, BoardNr);
  268.     }
  269.     else
  270.     { printf("One point bye set: %s\n", t->Name);
  271. #endif
  272.     }
  273.   }
  274.  
  275.  
  276.   /*
  277.       If the number of free players is odd, select a player which receives a
  278.       one point bye.
  279.   */
  280. #ifdef DEBUG_PAIRINGS
  281.   printf("Number of players not set: %d\n", NumFreePlayers);
  282. #endif
  283.   if (NumFreePlayers % 2)
  284.   { int i, ihelp;
  285.  
  286.     /*
  287.     Find the 5 players with the lowest ranking.
  288.     */
  289.     int MinPlayers = (NumFreePlayers > 5) ? 5 : NumFreePlayers;
  290.  
  291.     i = ihelp = NumFreePlayers;
  292.     t = thelp = RankingFirst;
  293.     for (t = thelp = RankingFirst;  t != NULL;  t = t->RankNext)
  294.     { if (t->Opponent == NULL)
  295.       { if (thelp->Opponent != NULL)
  296.     { thelp = t;
  297.       ihelp = i;
  298.     }
  299.     if (tdwz(t) < tdwz(thelp))
  300.     { if (i >= MinPlayers)
  301.       { thelp = t;
  302.         ihelp = i;
  303.       }
  304.     }
  305.     --i;
  306.       }
  307.     }
  308. #ifdef DEBUG_PAIRINGS
  309.     printf("Looking for one point bye beginning with %s.\n", thelp->Name);
  310. #endif
  311.  
  312.     /*
  313.     Now thelp points to the last ihelp players. Select one of them.
  314.     */
  315.     j = RangeRand(ihelp);
  316.  
  317.     while(j > 0  ||  thelp->Opponent)
  318.     { if (!thelp->Opponent)
  319.       { --j;
  320.       }
  321.       thelp = thelp->RankNext;
  322.     }
  323.  
  324. #ifdef DEBUG_PAIRINGS
  325.     printf("Player %s gets a one point bye.\n", thelp->Name);
  326. #endif
  327.     thelp->GFlags = GMFLAGSF_POINTFORFREE|GMFLAGSF_NOFIGHT;
  328.     --NumFreePlayers;
  329.   }
  330.  
  331.  
  332.  
  333.  
  334.  
  335.   /*
  336.       Do the other pairings. t points into the upper and thelp into the
  337.       lower half of the players.
  338.   */
  339.   if ((NumGames = NumFreePlayers/2))
  340.   { /*
  341.     Initialize thelp
  342.     */
  343.     thelp = RankingFirst;
  344.     for (i = NumGames;  i;  thelp = thelp->RankNext)
  345.     { if (thelp->Opponent == NULL  &&
  346.       (thelp->GFlags & GMFLAGSF_NOFIGHT)  ==  0)
  347.       { i--;
  348.       }
  349.     }
  350.  
  351.     for (t = RankingFirst, i = NumGames;  i;  --i)
  352.     {
  353. #ifdef DEBUG_PAIRINGS
  354.       printf("Looking for next game: Upper half player %s, lower half player %s\n",
  355.          t->Name, thelp->Name);
  356. #endif
  357.       /*
  358.       t and thelp must not point on free or set players!
  359.       */
  360.       while ((t->GFlags & GMFLAGSF_NOFIGHT)  !=  0   ||
  361.          t->Opponent != NULL)
  362.       { t = t->RankNext;
  363.       }
  364.       while ((thelp->GFlags & GMFLAGSF_NOFIGHT)  !=  0   ||
  365.          thelp->Opponent != NULL)
  366.       { thelp = thelp->RankNext;
  367.       }
  368.  
  369.       t->Opponent = thelp;
  370.       thelp->Opponent = t;
  371.       t->BoardNr = ++BoardNr;
  372.       thelp->BoardNr = BoardNr;
  373.       t->GFlags = flag;
  374.       flag = GMFLAGSF_WHITE - flag;
  375.       thelp->GFlags = flag;
  376. #ifdef DEBUG_PAIRINGS
  377.       printf("Pairing %s : %s (%d)\n",
  378.          flag ? thelp->Name : t->Name,
  379.          flag ? t->Name : thelp->Name, t->BoardNr);
  380. #endif
  381.       t = t->RankNext;
  382.       thelp = thelp->RankNext;
  383.     }
  384.   }
  385.  
  386.   return(TRUE);
  387. }
  388.  
  389.  
  390.  
  391.  
  392.  
  393. /*
  394.     The DoSwissPairing() function gets called instead of
  395.     DoSwissPairingFirst() for round 2 and later.
  396.  
  397.     Inputs: user - TRUE, if the user may set games
  398.  
  399.     Result: TRUE, if succesfull, FALSE otherwise
  400. */
  401. static int DoSwissPairing(int user)
  402.  
  403. { struct Player *t, *thelp, **tptr;
  404.   void *PKey = NULL;
  405.   int BoardNr;
  406.   int result;
  407.  
  408.   /*
  409.       First create the new ranking list
  410.   */
  411.   t = RankingFirst;
  412.   RankingFirst = NULL;
  413.   while (t != NULL)
  414.   { for (tptr = &RankingFirst;  *tptr != NULL;
  415.      tptr = &((*tptr)->RankNext))
  416.     { if (t->Points > (*tptr)->Points)
  417.       { break;
  418.       }
  419.     }
  420.     thelp = t->RankNext;
  421.     t->RankNext = *tptr;
  422.     *tptr = t;
  423.     t = thelp;
  424.   }
  425. #ifdef DEBUG_PAIRINGS
  426.   { int i;
  427.  
  428.     printf("New rankings:\n");
  429.     for (i = 1, t = RankingFirst;  t != NULL;  t = t->RankNext, ++i)
  430.     { printf("%5d. %s\n", i, t->Name);
  431.     }
  432.   }
  433. #endif
  434.  
  435.  
  436.   /*
  437.       Allow the user to make settings.
  438.   */
  439.   if ((BoardNr = GetSettings(user))  ==  -1)
  440.   { return(FALSE);
  441.   }
  442.  
  443.  
  444.  
  445.   /*
  446.       Do the pairings
  447.   */
  448. #ifdef AMIGA
  449.   set(App, MUIA_Application_Sleep, TRUE);
  450. #endif
  451.   { result = DoFirstGroup();
  452.   }
  453. #ifdef AMIGA
  454.   set(App, MUIA_Application_Sleep, FALSE);
  455. #endif
  456.  
  457.   if (!result)
  458.   { ShowError((char *) MSG_NO_PAIRING);
  459.     PutMemList(&PKey);
  460.     return(FALSE);
  461.   }
  462.  
  463.   /*
  464.       Select colors
  465.   */
  466.   for (t = RankingFirst;  t != NULL;  t = t->RankNext)
  467.   { if (t->Flags & TNFLAGSF_WITHDRAWN)
  468.     { continue;
  469.     }
  470.     if (t->Opponent == NULL)
  471.     { t->GFlags = GMFLAGSF_POINTFORFREE|GMFLAGSF_NOFIGHT;
  472.     }
  473.     else
  474.     { /*
  475.       Select colors
  476.       */
  477.       thelp = t->Opponent;
  478.       if ((t->GFlags & GMFLAGSF_WHITE) == 0  &&
  479.       (thelp->GFlags & GMFLAGSF_WHITE) == 0)
  480.       { if (t->HowMuchWhiteLast < thelp->HowMuchWhiteLast  ||
  481.         (t->HowMuchWhiteLast == thelp->HowMuchWhiteLast  &&
  482.          (t->HowMuchWhite < thelp->HowMuchWhite  ||
  483.           (t->HowMuchWhite == thelp->HowMuchWhite  &&
  484.            t->Nr > thelp->Nr))))
  485.     { thelp = t;
  486.     }
  487.     thelp->GFlags = GMFLAGSF_WHITE;
  488.       }
  489.     }
  490.   }
  491.   return(TRUE);
  492. }
  493.  
  494.  
  495.  
  496.  
  497. /*
  498.     DoRoundRobin() does the Round Robin pairings. Here all rounds are paired
  499.     at once.
  500.  
  501.     Inputs: mode - 0 for FIDE system, TNMODEF_SHIFT_SYSTEM for shift system
  502.  
  503.     Result: TRUE, if successfull, FALSE otherwise
  504. */
  505. static int DoRoundRobin(int mode)
  506.  
  507. { struct Player *t, **ttab, *tg;
  508.   int i, j, k, l;
  509.   int NumGames;
  510.   int GamesMissing = 0;
  511.   short flag, BoardNr;
  512.   void *PMem = NULL, *GMem = NULL;
  513.  
  514.   /*
  515.       Allocate a table of player numbers
  516.   */
  517.   if ((ttab = GetMem(&PMem, sizeof(*ttab)*NumPlayers))  ==  NULL)
  518.   { MemError();
  519.     return(FALSE);
  520.   }
  521.  
  522.   /*
  523.       Give any player a different, random number
  524.   */
  525.   { struct Player **PTab;
  526.     int i, j;
  527.  
  528.     if (!(PTab = GetMem(&PMem, sizeof(*PTab)*NumPlayers)))
  529.     { PutMemList(&PMem);
  530.       MemError();
  531.       return(FALSE);
  532.     }
  533.  
  534.     for (i = 0, t = (struct Player *) PlayerList.lh_Head;
  535.      t->Tn_Node.ln_Succ;
  536.      i++, t = (struct Player *) t->Tn_Node.ln_Succ)
  537.     { PTab[i] = t;
  538.     }
  539.     while(i)
  540.     { j = RangeRand(i);
  541.       t = PTab[j];
  542.       PTab[j] = PTab[i-1];
  543.       t->Nr = i;
  544.       ttab[--i] = t;
  545.     }
  546.  
  547.     PutMem(PTab);
  548.   }
  549.   NumGames = (NumPlayers+1)/2;
  550.  
  551.   if ((mode & TNMODEF_SHIFT_SYSTEM)  ==  0)
  552.   { /*
  553.     Here comes the FIDE-system.
  554.  
  555.     Assume n=NumPlayers (n=NumPlayers+1 for an odd number of players)
  556.     The FIDE system wants the following pairings for round 1:
  557.     1:n, 2:n-1, 3:n-2, 4:n-3 and so on. (n as opponent means free round,
  558.     if the number of players is odd.)
  559.     */
  560.     for (i = 0;  i < NumGames; i++)
  561.     { t = ttab[i];
  562.       if(i == 0  &&  ((NumPlayers%2) != 0))    /*  Spielfrei   */
  563.       { t->Opponent = NULL;
  564.     t->BoardNr = i;
  565.     t->GFlags = GMFLAGSF_POINTFORFREE|GMFLAGSF_NOFIGHT;
  566.       }
  567.       else
  568.       { tg = ttab[NumGames*2-i-1];
  569.  
  570.     t->Opponent = tg;
  571.     tg->Opponent = t;
  572.     t->BoardNr = tg->BoardNr = i+1;
  573.     t->GFlags = GMFLAGSF_WHITE;
  574.     tg->GFlags = 0;
  575.     GamesMissing++;
  576.       }
  577.     }
  578.  
  579.     if (!NewGames(&GMem, 0))
  580.     { goto Error;
  581.     }
  582.  
  583.     /*
  584.     The following rounds are determined by a simple algorithm:
  585.     (See Ernst Schubart, Helmut Noettger: "Turnierleiterhandbuch des
  586.     Deutschen Schachbundes" (The official german chess federation's
  587.     guide to managing chess-tournaments), p.64
  588.  
  589.     - In the odd rounds the players 1, 2, 3 and so on have player n as
  590.       opponent (or have a free round, if the number of players is even.
  591.       In the even rounds n plays against k+1, k+2, k+3 and so on, where
  592.       k=n/2.
  593.     - All other participants play against the player whose number is the
  594.       number of their last opponent, incremented by 1. Player n is left
  595.       out, player 1 comes after n-1.
  596.     - If the number of players is even, the players 1, 2, ..., k have
  597.       white, when playing against opponent n. The other players have
  598.       black in that case.
  599.     - In all other games the player with the lower number has the white
  600.       pieces, if the sum of the two player-numbers is odd. Otherwise he
  601.       gets the black pieces.
  602.     */
  603.     for (j = 1;  j < NumGames*2-1;  j++)
  604.     { /*
  605.       First get an opponent for player n.
  606.       */
  607.       k = (((j%2) == 0) ? 0 : NumGames) + j/2 + 1;
  608.       t = ttab[k-1];
  609.       if ((NumPlayers%2) == 0) /*  No point for free    */
  610.       { tg = ttab[NumPlayers-1];
  611.     t->BoardNr = tg->BoardNr = BoardNr = 0;
  612.     t->GFlags = (t->Nr <= NumGames) ? GMFLAGSF_WHITE : 0;
  613.     tg->GFlags = GMFLAGSF_WHITE - t->GFlags;
  614.     tg->Opponent = t;
  615.     GamesMissing++;
  616.       }
  617.       else
  618.       { tg = NULL;
  619.     t->BoardNr = BoardNr = -1;
  620.     t->GFlags = GMFLAGSF_POINTFORFREE|GMFLAGSF_NOFIGHT;
  621.       }
  622.       t->Opponent = tg;
  623.  
  624.       /*
  625.       Get the other games
  626.       */
  627.       for (i = 1;  i < NumGames;  i++)
  628.       { if (++k == NumGames*2)
  629.     { k = 1;
  630.     }
  631.     t = ttab[k-1];
  632.     if ((tg = GameAddress(t, j)->Opponent) == NULL  ||
  633.         tg->Nr == NumGames*2)
  634.     { l = t->Nr;
  635.     }
  636.     else
  637.     { l = tg->Nr;
  638.     }
  639.     if (++l == NumGames*2)
  640.     { l = 1;
  641.     }
  642.     tg = ttab[l-1];
  643.     flag = (((t->Nr+tg->Nr) % 2) != 0) ? GMFLAGSF_WHITE : 0;
  644.     if (t->Nr > tg->Nr)
  645.     { flag = GMFLAGSF_WHITE-flag;
  646.     }
  647.     t->GFlags = flag;
  648.     tg->GFlags = GMFLAGSF_WHITE-flag;
  649.     t->BoardNr = tg->BoardNr = ++BoardNr;
  650.     t->Opponent = tg;
  651.     tg->Opponent = t;
  652.     GamesMissing++;
  653.       }
  654.  
  655.       if (!NewGames(&GMem, 0))
  656.       { goto Error;
  657.       }
  658.     }
  659.   }
  660.   else
  661.   { /*
  662.     Here comes the shift system. Its algorithm is rather easy, if you
  663.     have seen it in practice.
  664.  
  665.     The boards are placed reverted on the table and all players sit down
  666.     for the first round in the following order:
  667.                 1 : k
  668.                 2 : k+1
  669.                 3 : k+2
  670.                   .
  671.                   .
  672.                   .
  673.               k-1 : n
  674.     (We assume again, that n is the number of players is even and
  675.     k = n/2. If this isn't true, we add a virtual player n. Playing
  676.     against n means having a free game.)
  677.  
  678.     After each round the players 1, 2, 3, ..., n-1 are shifted clockwise.
  679.     All boards remain unchanged, except for the board of player n, who
  680.     may keep his place, but has to revert his board.
  681.  
  682.     Below the array ttab is used to simulate the table. (That's probably
  683.     why it's got his name...)
  684.     */
  685.     int lastflag;
  686.  
  687.     for (i = 0;  i < NumGames*2-1;  i++)
  688.     { for (j = 0, flag = GMFLAGSF_WHITE;  j < NumGames; j++)
  689.       { t = ttab[j];
  690.     if (j+NumGames < NumPlayers)
  691.     { tg = ttab[j+NumGames];
  692.       t->GFlags = flag;
  693.       flag = GMFLAGSF_WHITE-flag;
  694.       tg->GFlags = flag;
  695.       tg->Opponent = t;
  696.       tg->BoardNr = j+1;
  697.     }
  698.     else
  699.     { tg = NULL;
  700.     }
  701.     t->Opponent = tg;
  702.     t->BoardNr = j+1;
  703.       }
  704.       if (i == 0)
  705.       { lastflag = flag;
  706.       }
  707.       else if (NumPlayers == NumGames*2)
  708.       { t = ttab[NumGames-1];
  709.     tg = ttab[NumGames*2-1];
  710.     t->GFlags = lastflag;
  711.     lastflag = GMFLAGSF_WHITE-lastflag;
  712.     tg->GFlags = lastflag;
  713.       }
  714.     if (!NewGames(&GMem, 0))
  715.     { goto Error;
  716.     }
  717.  
  718.     /*
  719.     Shift all players except for n.
  720.     */
  721.     t = ttab[0];
  722.     for (j = 0;  j < NumGames-1;  j++)
  723.     { ttab[j] = ttab[j+1];
  724.     }
  725.     ttab[NumGames-1] = ttab[NumGames*2-2];
  726.     for (j = NumGames*2-3;  j >= NumGames;  j--)
  727.     { ttab[j+1] = ttab[j];
  728.     }
  729.     ttab[NumGames] = t;
  730.     }
  731.   }
  732.  
  733.   PutMem(ttab);
  734.   MoveMemList(&GMem, &TrnMem);
  735.   NumGamesMissing = GamesMissing;
  736.   return(TRUE);
  737.  
  738. Error:
  739.   for (t = (struct Player *) PlayerList.lh_Head;
  740.        t->Tn_Node.ln_Succ != NULL;
  741.        t = (struct Player *) t->Tn_Node.ln_Succ)
  742.   { t->First_Game = NULL;
  743.   }
  744.   PutMemList(&GMem);
  745.   PutMem(ttab);
  746.   NumRounds = 0;
  747.   return(FALSE);
  748. }
  749.  
  750.  
  751.  
  752.  
  753. /*
  754.     This function selects the boards, where the players should play.
  755. */
  756. static void SelectBoards(void)
  757.  
  758. { struct Player *p;
  759.   int BoardNr;
  760.  
  761.   for (p = RankingFirst;  p != NULL;  p = p->RankNext)
  762.   { p->BoardNr = -1;
  763.   }
  764.  
  765.   for (p = RankingFirst, BoardNr = 0;  p != NULL;  p = p->RankNext)
  766.   { if (p->BoardNr < 0  &&  p->Opponent != NULL)
  767.     { p->BoardNr = p->Opponent->BoardNr = BoardNr++;
  768.     }
  769.   }
  770. }
  771.  
  772.  
  773.  
  774.  
  775.  
  776. /*
  777.     DoPairings() is the function that gets called from the menu.
  778.  
  779.     Input:  mode - tournament mode (TNMODEF_SWISS_PAIRING or
  780.            TNMODEF_ROUND_ROBIN with or without TNMODEF_SHIFT_SYSTEM)
  781.         save - TRUE, if the user should be asked to save the tournament
  782.         user - TRUE, if the user may set games (ignored for Round
  783.            Robin tournaments)
  784.  
  785.     Result: TRUE, if successfull, FALSE otherwise
  786. */
  787. int DoPairings(int mode, int save, int user)
  788.  
  789. { struct Player *t, *rankingfirst;
  790.   char *name;
  791.   char trnfilename[TRNFILENAME_LEN+1];
  792.   char ending[20];
  793.   int len, endlen, oldNumRounds = NumRounds;
  794.  
  795.   /*
  796.       Copy the ranking pointers. This allows to undo the pairing calls, if
  797.       something goes wrong. Additionally the Opponent and GFlags fields
  798.       get initialized.
  799.   */
  800.   rankingfirst = RankingFirst;
  801.   for (t = (struct Player *) PlayerList.lh_Head;
  802.        t->Tn_Node.ln_Succ != NULL;
  803.        t = (struct Player *) t->Tn_Node.ln_Succ)
  804.   { t->Helpptr = t->RankNext;
  805.     t->Opponent = NULL;
  806.     t->GFlags = 0;
  807.   }
  808.  
  809.   if (mode & TNMODEF_SWISS_PAIRING)
  810.   { if (!((NumRounds == 0)  ?  DoSwissPairingFirst(user)  :
  811.                    DoSwissPairing(user)))
  812.     { goto Error;
  813.     }
  814.     SelectBoards();
  815.     NewGames(&TrnMem, WinnerPoints);
  816.   }
  817.   else
  818.   { if (!DoRoundRobin(mode))
  819.     { goto Error;
  820.     }
  821.   }
  822.   TrnMode |= mode;
  823.   IsSaved = FALSE;
  824.  
  825.  
  826.   /*
  827.       Offer the user to save data. If the convention "name.roundnumber.cdat"
  828.       was kept until now, we keep this.
  829.   */
  830.   if (save)
  831.   { strcpy(trnfilename, TrnFileName);
  832.     sprintf(ending, ".%d.cdat", oldNumRounds);
  833.     endlen = strlen(ending);
  834.     len = strlen(trnfilename);
  835.     if (len >= endlen  &&
  836.     Stricmp((STRPTR) trnfilename+(len-endlen), (STRPTR) ending)  ==  0)
  837.     { sprintf(trnfilename+(len-endlen), ".%d.cdat", NumRounds);
  838.     }
  839.     name = FileRequest(trnfilename, NULL, NULL, TRUE);
  840.     if (name  !=  NULL  &&  *name != '\0')
  841.     { return(SaveTournament(name));
  842.     }
  843.   }
  844.   return(TRUE);;
  845.  
  846. Error:
  847.   /*
  848.       Get the old ranking list
  849.   */
  850.   RankingFirst = rankingfirst;
  851.   for (t = (struct Player *) PlayerList.lh_Head;
  852.        t->Tn_Node.ln_Succ != NULL;
  853.        t = (struct Player *) t->Tn_Node.ln_Succ)
  854.   { t->RankNext = t->Helpptr;
  855.   }
  856.   return(FALSE);
  857. }
  858.