home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / s / sd-27.zip / sdtand.c < prev    next >
C/C++ Source or Header  |  1992-11-15  |  27KB  |  610 lines

  1. /* SD -- square dance caller's helper.
  2.  
  3.     Copyright (C) 1990, 1991, 1992  William B. Ackerman.
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 1, or (at your option)
  8.     any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     This is for version 27. */
  20.  
  21. /* This file contains stuff for tandem and as-couples moves. */
  22.  
  23. /* This defines the following functions:
  24.    tandem_couples_move
  25.    initialize_tandem_tables
  26. */
  27.  
  28. #include "sd.h"
  29.  
  30. typedef struct {
  31.    personrec real_front_people[MAX_PEOPLE];
  32.    personrec real_back_people[MAX_PEOPLE];
  33.    setup virtual_setup;
  34.    setup virtual_result;
  35.    int vertical_people[MAX_PEOPLE];    /* 1 if original people were near/far; 0 if lateral */
  36.    int twosomep[MAX_PEOPLE];           /* 0: solid / 1: twosome / 2: solid-to-twosome / 3: twosome-to-solid */
  37.    unsigned int single_mask;
  38.    } tandrec;
  39.  
  40. typedef struct {
  41.    int map1[8];
  42.    int map2[8];
  43.    unsigned int sidewaysmask;       /* lateral pairs in inside numbering -- only alternate bits used! */
  44.    unsigned int outsidemask;
  45.    int limit;
  46.    int rot;
  47.    unsigned int insinglemask;       /* relative to insetup numbering, those people that are NOT paired -- only alternate bits used! */
  48.    unsigned int outsinglemask;      /* relative to outsetup numbering, those people that are NOT paired */
  49.    unsigned int outunusedmask;
  50.    setup_kind insetup;
  51.    setup_kind outsetup;
  52.    } tm_thing;
  53.  
  54.  
  55. static tm_thing maps_isearch[] = {
  56.  
  57. /*         map1                              map2                  sidemask outsidemask limit rot            insetup outsetup            old name */
  58.    {{7, 6, 4, 5},                   {0, 1, 3, 2},                     0,     0000,         4, 0,  0,  0, 0,  s1x4,  s2x4},            /* "2x4_4" - see below */
  59.    {{0, 2, 5, 7},                   {1, 3, 4, 6},                  0x55,     0377,         4, 0,  0,  0, 0,  s2x2,  s2x4},
  60.    {{2, 5, 7, 0},                   {3, 4, 6, 1},                     0,     0377,         4, 1,  0,  0, 0,  s2x2,  s2x4},
  61.    {{3, 2},                         {0, 1},                           0,     0000,         2, 0,  0,  0, 0,  s_1x2, s2x2},
  62.    {{0, 3},                         {1, 2},                           0,     0017,         2, 1,  0,  0, 0,  s_1x2, s2x2},
  63.    {{0, 3},                         {1, 2},                         0x5,     0017,         2, 0,  0,  0, 0,  s_1x2, s1x4},
  64.    {{0},                            {1},                            0x1,     0003,         1, 0,  0,  0, 0,  s_1x1, s_1x2},           /* 1x2 */  /* this one is known to be good */
  65.    {{0},                            {1},                              0,     0003,         1, 1,  0,  0, 0,  s_1x1, s_1x2},           /* ????? */
  66.    {{0, 3, 5, 6},                   {1, 2, 4, 7},                  0x55,     0377,         4, 0,  0,  0, 0,  s1x4,  s1x8},
  67.    {{15, 14, 12, 13, 8, 9, 11, 10}, {0, 1, 3, 2, 7, 6, 4, 5},         0,     0000,         8, 0,  0,  0, 0,  s1x8,  s2x8},
  68.    {{11, 10, 9, 6, 7, 8},           {0, 1, 2, 5, 4, 3},               0,     0000,         6, 0,  0,  0, 0,  s_1x6, s2x6},
  69.    {{10, 15, 3, 1, 4, 5, 6, 8},     {12, 13, 14, 0, 2, 7, 11, 9},     0,     0000,         8, 0,  0,  0, 0,  s2x4,  s4x4},
  70.    {{14, 3, 7, 5, 8, 9, 10, 12},    {0, 1, 2, 4, 6, 11, 15, 13},      0,   0xFFFF,         8, 1,  0,  0, 0,  s2x4,  s4x4},
  71.    {{2, 5, 7, 9, 10, 0},            {3, 4, 6, 8, 11, 1},              0,   0x0FFF,         6, 1,  0,  0, 0,  s_2x3, s3x4},
  72.    {{0, 2, 4, 6, 9, 11, 13, 15},    {1, 3, 5, 7, 8, 10, 12, 14}, 0x5555,   0xFFFF,         8, 0,  0,  0, 0,  s2x4,  s2x8},
  73.  
  74.    /* Next one is for centers in tandem in lines, making a virtual bone6. */
  75.    {{0, 3, 5, 4, 7, 6},             {-1, -1, 2, -1, -1, 1},           0,     0000,         6, 0,  0,  0, 0,  s_bone6, s2x4},
  76.    /* Next two are for certain ends in tandem in an H, making a virtual bone6. */
  77.    {{10, 3, 5, 6, 9, 11},           {0, -1, -1, 4, -1, -1},           0,     0000,         6, 0,  0,  0, 0,  s_bone6, s3x4},
  78.    {{0, 4, 5, 6, 9, 11},            {-1, 3, -1, -1, 10, -1},          0,     0000,         6, 0,  0,  0, 0,  s_bone6, s3x4},
  79.    /* Next one is for ends in tandem in lines, making a virtual short6. */
  80.    {{2, 4, 5, 6, 7, 1},             {-1, 3, -1, -1, 0, -1},       0x104,     0000,         6, 1,  0,  0, 0,  s_short6, s2x4},
  81.    /* Next two are for certain center column people in tandem in a 1/4 tag, making a virtual short6. */
  82.    {{3, 2, 4, 5, 6, 0},             {1, -1, -1, 7, -1, -1},       0x041,     0000,         6, 1,  0,  0, 0,  s_short6, s_qtag},
  83.    {{1, 2, 4, 5, 6, 7},             {-1, -1, 3, -1, -1, 0},       0x410,     0000,         6, 1,  0,  0, 0,  s_short6, s_qtag},
  84.    /* Next three are for various people in tandem in columns of 8, making virtual columns of 6. */
  85.    {{0, 2, 3, 5, 6, 7},             {1, -1, -1, 4, -1, -1},       0x041,     0063,         6, 0,  0,  0, 0,  s_2x3, s2x4},
  86.    {{0, 1, 3, 4, 6, 7},             {-1, 2, -1, -1, 5, -1},       0x104,     0146,         6, 0,  0,  0, 0,  s_2x3, s2x4},
  87.    {{0, 1, 2, 4, 5, 7},             {-1, -1, 3, -1, -1, 6},       0x410,     0314,         6, 0,  0,  0, 0,  s_2x3, s2x4},
  88.    /* Next three are for various people as couples in a C1 phantom or 1/4 tag, making virtual columns of 6. */
  89.    {{3, 7, 5, 9, 15, 13},           {1, -1, -1, 11, -1, -1},          0,     0000,         6, 0,  0,  0, 0,  s_2x3, s_c1phan},
  90.    {{1, 3, 4, 5, 6, 0},             {-1, 2, -1, -1, 7, -1},           0,     0314,         6, 1,  0,  0, 0,  s_2x3, s_qtag},
  91.    {{0, 2, 6, 8, 10, 12},           {-1, -1, 4, -1, -1, 14},          0,     0000,         6, 0,  0,  0, 0,  s_2x3, s_c1phan},
  92.    /* Next three are for various people in tandem in a rigger or PTP diamonds, making a virtual line of 6. */
  93.    {{6, 7, 5, 2, 3, 4},             {-1, -1, 0, -1, -1, 1},           0,     0000,         6, 0,  0,  0, 0,  s_1x6, s_rigger},
  94.    {{0, 3, 2, 4, 5, 6},             {-1, 1, -1, -1, 7, -1},           0,     0000,         6, 0,  0,  0, 0,  s_1x6, s_ptpd},
  95.    {{5, 6, 7, 4, 2, 3},             {0, -1, -1, 1, -1, -1},           0,     0000,         6, 0,  0,  0, 0,  s_1x6, s_bone},
  96.  
  97.    {{0, 3, 5, 6},                   {1, 2, 4, 7},                     0,     0377,         4, 1,  0,  0, 0,  sdmd,  s_qtag},
  98.    {{3, 7, 9, 13},                  {1, 5, 11, 15},                0x44,   0xA0A0,         4, 0,  0,  0, 0,  s2x2,  s_c1phan},        /* xyz      */  
  99.    {{0, 6, 10, 12},                 {2, 4, 8, 14},                 0x11,   0x0505,         4, 0,  0,  0, 0,  s2x2,  s_c1phan},        /* pqr      */  
  100.    {{15, 3, 5, 9},                  {13, 1, 7, 11},                0x44,   0x0A0A,         4, 0,  0,  0, 0,  s2x2,  s4x4},      /* These do C1-phantom-like stuff from fudgy 4x4 */
  101.    {{10, 3, 7, 6},                  {15, 14, 2, 11},               0x11,   0x8484,         4, 0,  0,  0, 0,  s2x2,  s4x4},      /* They must follow the pair just above. */
  102.    {{6, 0, 3, 5},                   {7, 1, 2, 4},                  0x55,     0377,         4, 0,  0,  0, 0,  sdmd,  s_rigger},
  103.    {{6, 5, 3, 4},                   {7, 0, 2, 1},                  0x11,     0314,         4, 0,  0,  0, 0,  s1x4,  s_rigger},       /* must be after "2x4_4" */
  104.    {{5, 6, 4, 3},                   {0, 7, 1, 2},                  0x44,     0314,         4, 0,  0,  0, 0,  s1x4,  s_bone},
  105.    {{0, 3, 5, 6},                   {1, 2, 4, 7},                  0x11,     0063,         4, 0,  0,  0, 0,  sdmd,  s_crosswave},     /* crosswave*/  
  106.    {{7, 1, 4, 6},                   {0, 2, 3, 5},                  0x44,     0146,         4, 0,  0,  0, 0,  sdmd,  s2x4},         /* must be after "2x4_4" */
  107.    /* Next one is for so-and-so in tandem in a bone6, making a virtual line of 4. */
  108.    {{4, 5, 3, 2},                   {0, -1, 1, -1},                   0,     0000,         4, 0,  0,  0, 0,  s1x4,  s_bone6},
  109.    /* Next one is for so-and-so in tandem in a short6, making a virtual line of 4. */
  110.    {{1, 0, 4, 5},                   {-1, 2, -1, 3},                   0,     0055,         4, 1,  0,  0, 0,  s1x4,  s_short6},
  111.    /* Next three are for so-and-so as couples in a line of 8, making a virtual line of 6. */
  112.    {{0, 1, 3, 4, 5, 6},             {-1, -1, 2, -1, -1, 7},       0x410,     0314,         6, 0,  0,  0, 0,  s_1x6, s1x8},
  113.    {{0, 1, 2, 4, 7, 6},             {-1, 3, -1, -1, 5, -1},       0x104,     0252,         6, 0,  0,  0, 0,  s_1x6, s1x8},
  114.    {{0, 3, 2, 5, 7, 6},             {1, -1, -1, 4, -1, -1},       0x041,     0063,         6, 0,  0,  0, 0,  s_1x6, s1x8},
  115.    /* Next two are for so-and-so as couples in a line of 6, making a virtual line of 4. */
  116.    {{0, 1, 3, 5},                   {-1, 2, -1, 4},                0x44,     0066,         4, 0,  0,  0, 0,  s1x4,  s_1x6},
  117.    {{0, 2, 4, 5},                   {1, -1, 3, -1},                0x11,     0033,         4, 0,  0,  0, 0,  s1x4,  s_1x6},
  118.    /* Next 4 are for so-and-so in tandem from a column of 6, making a virtual column of 4.  The first two are the real maps,
  119.       and the other two take care of the reorientation that sometimes happens when coming out of a 2x2. */
  120.    {{0, 1, 3, 5},                   {-1, 2, -1, 4},                0x44,     0066,         4, 0,  0,  0, 0,  s2x2,  s_2x3},
  121.    {{0, 2, 4, 5},                   {1, -1, 3, -1},                0x11,     0033,         4, 0,  0,  0, 0,  s2x2,  s_2x3},
  122.    {{1, 3, 5, 0},                   {2, -1, 4, -1},                   0,     0066,         4, 1,  0,  0, 0,  s2x2,  s_2x3},
  123.    {{2, 4, 5, 0},                   {-1, 3, -1, 1},                   0,     0033,         4, 1,  0,  0, 0,  s2x2,  s_2x3},
  124.    {{0, 2, 4, 7, 9, 11},            {1, 3, 5, 6, 8, 10},          0x555,   0x0FFF,         6, 0,  0,  0, 0,  s_2x3, s2x6},
  125.  
  126.    {{0},                            {0},                              0,     0000,         0, 0,  0,  0, 0,  nothing,  nothing}};
  127.  
  128.  
  129. extern void initialize_tandem_tables(void)
  130. {
  131.    tm_thing *map_search;
  132.  
  133.    for (map_search = maps_isearch; map_search->outsetup != nothing; map_search++) {
  134.       int i;
  135.       unsigned int m;
  136.       unsigned int imask = 0;
  137.       unsigned int omask = 0;
  138.       unsigned int osidemask = 0;
  139.  
  140.       /* All 1's for people in outer setup. */
  141.       unsigned int alloutmask = (1 << (setup_limits[map_search->outsetup]+1))-1;
  142.  
  143.       for (i=0, m=1; i<map_search->limit; i++, m<<=2) {
  144.          alloutmask &= ~(1 << map_search->map1[i]);
  145.          if (map_search->map2[i] < 0) {
  146.             imask |= m;
  147.             omask |= 1 << map_search->map1[i];
  148.          }
  149.          else {
  150.             alloutmask &= ~(1 << map_search->map2[i]);
  151.             if (((map_search->sidewaysmask >> (i*2)) ^ map_search->rot) & 1) {
  152.                osidemask |= 1 << map_search->map1[i];
  153.                osidemask |= 1 << map_search->map2[i];
  154.             }
  155.          }
  156.       }
  157.  
  158.       map_search->insinglemask = imask;
  159.       map_search->outsinglemask = omask;
  160.       map_search->outunusedmask = alloutmask;
  161.  
  162.       /* We can't encode the virtual person number in the required 3-bit field if this is > 8. */
  163.       if (map_search->limit != setup_limits[map_search->insetup]+1) fail("Tandem table initialization failed: limit wrong.");
  164.       if (map_search->limit > 8) fail("Tandem table initialization failed: limit too big.");
  165.       if (map_search->outsidemask != osidemask) fail("Tandem table initialization failed: Smask.");
  166.    }
  167. }
  168.  
  169.  
  170. static void unpack_us(
  171.    tm_thing *map_ptr,
  172.    unsigned int orbitmask,
  173.    tandrec *tandstuff,
  174.    setup *result)
  175. {
  176.    int i;
  177.    unsigned int m, o;
  178.  
  179.    result->kind = map_ptr->outsetup;
  180.    result->rotation = tandstuff->virtual_result.rotation - map_ptr->rot;
  181.    result->setupflags = tandstuff->virtual_result.setupflags;
  182.  
  183.    for (i=0, m=map_ptr->insinglemask, o=orbitmask; i<map_ptr->limit; i++, m>>=2, o>>=2) {
  184.       int z = tandstuff->virtual_result.people[i].id1;
  185.  
  186.       if (map_ptr->rot) z = rotcw(z);
  187.  
  188.       if (m & 1) {
  189.          /* Unpack single person. */
  190.          if (z == 0) clear_person(result, map_ptr->map1[i]);
  191.          else {
  192.             personrec f;
  193.             int ii = (z & 0700) >> 6;
  194.             f = tandstuff->real_front_people[ii];
  195.             if (f.id1) f.id1 = (f.id1 & ~(ROLL_MASK|STABLE_MASK|077)) | (z & (ROLL_MASK|STABLE_MASK|013));
  196.             result->people[map_ptr->map1[i]] = f;
  197.          }
  198.       }
  199.       else {
  200.          /* Unpack tandem/couples person. */
  201.          personrec f, b;
  202.  
  203.          if (z == 0) {
  204.             clear_person(result, map_ptr->map1[i]);
  205.             clear_person(result, map_ptr->map2[i]);
  206.          }
  207.          else {
  208.             int ii = (z >> 6) & 7;
  209.             f = tandstuff->real_front_people[ii];
  210.             b = tandstuff->real_back_people[ii];
  211.             if (f.id1) f.id1 = (f.id1 & ~(ROLL_MASK|STABLE_MASK|077)) | (z & (ROLL_MASK|STABLE_MASK|013));
  212.             if (b.id1) b.id1 = (b.id1 & ~(ROLL_MASK|STABLE_MASK|077)) | (z & (ROLL_MASK|STABLE_MASK|013));
  213.  
  214.             if ((o + map_ptr->rot + 1) & 2) {
  215.                result->people[map_ptr->map1[i]] = b;
  216.                result->people[map_ptr->map2[i]] = f;
  217.             }
  218.             else {
  219.                result->people[map_ptr->map1[i]] = f;
  220.                result->people[map_ptr->map2[i]] = b;
  221.             }
  222.          }
  223.       }
  224.    }
  225.  
  226.    canonicalize_rotation(result);
  227. }
  228.  
  229.  
  230.  
  231.  
  232. /* Lat = 0 means the people we collapsed, relative to the incoming geometry, were one
  233.    behind the other.  Lat = 1 means they were lateral.  "Incoming geometry" does
  234.    not include the incoming rotation field, since we ignore it.  We are not responsible
  235.    for the rotation field of the incoming setup.
  236.  
  237.   The canonical storage of the real people, while we are doing the virtual call, is as follows:
  238.  
  239.    Real_front_people gets person on left (lat=1) near person (lat=0).
  240.    Real_back_people gets person on right (lat=1) or far person (lat=0). */
  241.  
  242. static void pack_us(
  243.    personrec *s,
  244.    tm_thing *map_ptr,
  245.    int fraction,
  246.    long_boolean twosome,
  247.    tandrec *tandstuff)
  248. {
  249.    int i;
  250.    int lat;
  251.    unsigned int m, sgl;
  252.  
  253.    tandstuff->virtual_setup.rotation = map_ptr->rot;
  254.    tandstuff->virtual_setup.kind = map_ptr->insetup;
  255.  
  256.    for (i=0, m=map_ptr->sidewaysmask, sgl=map_ptr->insinglemask; i<map_ptr->limit; i++, m>>=2, sgl>>=2) {
  257.       personrec f, b;
  258.       personrec *ptr = &tandstuff->virtual_setup.people[i];
  259.  
  260.       f = s[map_ptr->map1[i]];
  261.  
  262.       lat = (m ^ map_ptr->rot) & 1;
  263.  
  264.       if (sgl & 1) {
  265.          ptr->id1 = (f.id1 & ~0700) | (i << 6) | BIT_VIRTUAL;
  266.          ptr->id2 = f.id2;
  267.          b.id1 = 0xFFFFFFFF;
  268.       }
  269.       else {
  270.          b = s[map_ptr->map2[i]];
  271.  
  272.          if (!(tandstuff->virtual_setup.setupflags & SETUPFLAG__PHANTOMS) && ((b.id1 ^ f.id1) & BIT_PERSON))
  273.             fail("Use phantom tandem/phantom couples concept instead.");
  274.          
  275.          if (b.id1 | f.id1) {
  276.             unsigned int vp1;
  277.          
  278.             if (twosome >= 2) {
  279.                if ((b.id1 | f.id1) & STABLE_MASK)
  280.                   fail("Sorry, can't nest fractional stable/twosome.");
  281.             }
  282.  
  283.             /* Create the virtual person.  When both people are present, anding
  284.                the real peoples' id2 bits gets the right bits.  For example,
  285.                the virtual person will be a boy and able to do a tandem star thru
  286.                if both real people were boys.  Remove the identity field (700 bits)
  287.                from id1 and replace with a virtual person indicator.  Check that
  288.                direction, roll, and stability parts of id1 are consistent. */
  289.          
  290.             if (b.id1 & f.id1 & BIT_PERSON) {
  291.                /* If both people are real, check that they face the same way. */
  292.                if ((b.id1 ^ f.id1) & 077)
  293.                   fail("People not facing same way for tandem or as couples.");
  294.                vp1 = (b.id1 & f.id1 & ~0700) | (i << 6) | BIT_VIRTUAL;
  295.                /* If they have different fractional stability states, just clear them -- they can't do it. */
  296.                if ((b.id1 ^ f.id1) & STABLE_MASK) vp1 &= ~STABLE_MASK;
  297.                /* If they have different roll states, just clear them -- they can't roll. */
  298.                if ((b.id1 ^ f.id1) & ROLL_MASK) vp1 &= ~ROLL_MASK;
  299.                ptr->id1 = vp1;
  300.                ptr->id2 = b.id2 & f.id2;
  301.             }
  302.             else {
  303.                ptr->id1 = ((b.id1 | f.id1) & ~0700) | (i << 6) | BIT_VIRTUAL;
  304.                ptr->id2 = b.id2 | f.id2;
  305.             }
  306.  
  307.             if (twosome >= 2)
  308.                ptr->id1 |= STABLE_ENAB | (STABLE_RBIT * fraction);
  309.          }
  310.          else {
  311.             ptr->id1 = 0;
  312.             ptr->id2 = 0;
  313.          }
  314.       
  315.          tandstuff->vertical_people[i] = lat ^ 1;   /* 1 if original people were near/far; 0 if lateral */
  316.          tandstuff->twosomep[i] = twosome;
  317.       }
  318.  
  319.       if (map_ptr->rot)   /* Compensate for above rotation. */
  320.          (void) copy_rot(&tandstuff->virtual_setup, i, &tandstuff->virtual_setup, i, 033);
  321.  
  322.       tandstuff->real_front_people[i] = f;
  323.       tandstuff->real_back_people[i] = b;
  324.    }
  325. }
  326.  
  327.  
  328.  
  329.  
  330. extern void tandem_couples_move(
  331.    setup *ss,
  332.    parse_block *parseptr,
  333.    callspec_block *callspec,
  334.    final_set final_concepts,
  335.    selector_kind selector,
  336.    int twosome,               /* solid=0 / twosome=1 / solid-to-twosome=2 / twosome-to-solid=3 */
  337.    int fraction,              /* number, if doing fractional twosome/solid */
  338.    int phantom,               /* normal=0 / phantom=1 / gruesome=2 */
  339.    int tnd_cpl_siam,          /* tandem=0 / couples=1 / siamese=2 / skew=3 */
  340.    setup *result)
  341. {
  342.    selector_kind saved_selector;
  343.    parse_block *conceptptrcopy;
  344.    tandrec tandstuff;
  345.    tm_thing *map;
  346.    tm_thing *map_search;
  347.    unsigned int nsmask, ewmask, allmask;
  348.    int i;
  349.    unsigned int j, jbit;
  350.    unsigned int hmask;
  351.    unsigned int orbitmask;
  352.    unsigned int sglmask;
  353.    unsigned int livemask;
  354.    long_boolean fractional = FALSE;
  355.  
  356.    conceptptrcopy = parseptr;
  357.    tandstuff.single_mask = 0;
  358.  
  359.    if (setup_limits[ss->kind] < 0) fail("Can't do tandem/couples concept from this position.");
  360.  
  361.    /* We use the phantom indicator to forbid an already-distorted setup.
  362.       The act of forgiving phantom pairing is based on the setting of the
  363.       SETUPFLAG__PHANTOMS bit in the incoming setup, not on the phantom indicator. */
  364.  
  365.    if ((ss->setupflags & SETUPFLAG__DISTORTED) && (phantom != 0))
  366.       fail("Can't specify phantom tandem/couples in virtual or distorted setup.");
  367.  
  368.    /* Find out who is selected, if this is a "so-and-so are tandem". */
  369.    saved_selector = current_selector;
  370.    if (selector != selector_uninitialized)
  371.       current_selector = selector;
  372.  
  373.    nsmask = 0;
  374.    ewmask = 0;
  375.    allmask = 0;
  376.  
  377.    for (i=0, jbit=1; i<=setup_limits[ss->kind]; i++, jbit<<=1) {
  378.       unsigned int p = ss->people[i].id1;
  379.       if (p) {
  380.          allmask |= jbit;
  381.          if ((selector != selector_uninitialized) && !selectp(ss, i))
  382.             tandstuff.single_mask |= jbit;
  383.          else {
  384.             if (p & 1)
  385.                ewmask |= jbit;
  386.             else
  387.                nsmask |= jbit;
  388.          }
  389.       }
  390.    }
  391.    
  392.    current_selector = saved_selector;
  393.  
  394.    if (!allmask) {
  395.       result->kind = nothing;
  396.       return;
  397.    }
  398.  
  399.    if (twosome >= 2) fractional = TRUE;
  400.  
  401.    if (fractional && fraction > 4)
  402.       fail("Can't do fractional twosome more than 4/4.");
  403.  
  404.  
  405.    if (tnd_cpl_siam > 2)
  406.       fail("Sorry, can't do skew/skewsome.");
  407.    else if (tnd_cpl_siam > 1) {
  408.       /* Siamese. */
  409.       switch (ss->kind) {
  410.          case s_c1phan:
  411.             switch ((ewmask << 16) | nsmask) {
  412.                case 0x0000AAAA:
  413.                   j = 0xA0A0; goto foox;
  414.                case 0x00005555:
  415.                   j = 0x0505; goto foox;
  416.                case 0xAAAA0000:
  417.                   j = 0x0A0A; goto foox;
  418.                case 0x55550000:
  419.                   j = 0x5050; goto foox;
  420.             }
  421.             break;
  422.          case s4x4:
  423.             switch ((ewmask << 16) | nsmask) {
  424.                case 0x0000AAAA:
  425.                   j = 0x0A0A; goto foox;
  426.                case 0x0000CCCC:
  427.                   j = 0x8484; goto foox;
  428.                case 0xAAAA0000:
  429.                   j = 0xA0A0; goto foox;
  430.                case 0xCCCC0000:
  431.                   j = 0x4848; goto foox;
  432.             }
  433.             break;
  434.          case s_qtag:
  435.             switch ((ewmask << 8) | nsmask) {
  436.                case 0x33CC:
  437.                   warn(warn__ctrscpls_endstand);
  438.                   j = 0xCC; goto foox;
  439.                case 0xCC33:
  440.                   warn(warn__ctrstand_endscpls);
  441.                   j = 0x33; goto foox;
  442.             }
  443.             break;
  444.          case s_rigger:
  445.             switch ((ewmask << 8) | nsmask) {
  446.                case 0xFF00: case 0xCC33:
  447.                   warn(warn__ctrscpls_endstand);
  448.                   j = 0x33; goto foox;
  449.                case 0x00FF: case 0x33CC:
  450.                   warn(warn__ctrstand_endscpls);
  451.                   j = 0xCC; goto foox;
  452.             }
  453.             break;
  454.          case s_bone:
  455.             switch ((ewmask << 8) | nsmask) {
  456.                case 0xFF00:
  457.                   warn(warn__ctrstand_endscpls);
  458.                   j = 0x33; goto foox;
  459.                case 0x00FF:
  460.                   warn(warn__ctrscpls_endstand);
  461.                   j = 0xCC; goto foox;
  462.             }
  463.             break;
  464.          case s_crosswave:
  465.             switch ((ewmask << 8) | nsmask) {
  466.                case 0xFF00:
  467.                   warn(warn__ctrscpls_endstand);
  468.                   j = 0xCC; goto foox;
  469.                case 0x00FF:
  470.                   warn(warn__ctrstand_endscpls);
  471.                   j = 0x33; goto foox;
  472.             }
  473.             break;
  474.          case s2x4:
  475.             switch ((ewmask << 8) | nsmask) {
  476.                case 0xFF00: case 0x9966:
  477.                   warn(warn__ctrstand_endscpls);
  478.                   j = 0x99; goto foox;
  479.                case 0x00FF: case 6699:
  480.                   warn(warn__ctrscpls_endstand);
  481.                   j = 0x66; goto foox;
  482.                case 0x33CC:
  483.                   j = 0xCC; goto foox;
  484.                case 0xCC33:
  485.                   j = 0x33; goto foox;
  486.             }
  487.             break;
  488.       }
  489.  
  490.       fail("Can't do Siamese in this setup.");
  491.  
  492.       foox:
  493.       ewmask ^= j;
  494.       nsmask ^= j;
  495.    }
  496.    else if (tnd_cpl_siam & 1) {
  497.       /* Couples -- swap masks.  Tandem -- do nothing. */
  498.       j = ewmask;
  499.       ewmask = nsmask;
  500.       nsmask = j;
  501.    }
  502.  
  503.    /* Now ewmask and nsmask have the info about who is paired with whom. */
  504.    ewmask &= ~tandstuff.single_mask;         /* Clear out unpaired people. */
  505.    nsmask &= ~tandstuff.single_mask;
  506.  
  507.    map_search = maps_isearch;
  508.    while (map_search->outsetup != nothing) {
  509.       if ((map_search->outsetup == ss->kind) &&
  510.             (map_search->outsinglemask == tandstuff.single_mask) &&
  511.             (!(allmask & map_search->outunusedmask)) &&
  512.             (!(ewmask & (~map_search->outsidemask))) &&
  513.             (!(nsmask & map_search->outsidemask))) {
  514.          map = map_search;
  515.          goto fooy;
  516.       }
  517.       map_search++;
  518.    }
  519.    fail("Can't do this tandem or couples call in this setup or with these people selected.");
  520.  
  521.    fooy:
  522.  
  523.    /* We also use the subtle aspects of the phantom indicator to tell what kind
  524.       of setup we allow, and whether pairings must be parallel to the long axis. */
  525.  
  526.    if (phantom == 1) {
  527.       if (ss->kind != s2x8 && ss->kind != s4x4 && ss->kind != s3x4 && ss->kind != s2x6)
  528.          fail("Must have a 4x4, 2x8, 3x4, or 2x6 setup to do this concept.");
  529.    }
  530.    else if (phantom == 2) {
  531.       if (ss->kind != s2x8 || map->insetup != s2x4)
  532.          fail("Can't do gruesome concept in this setup.");
  533.    }
  534.  
  535.    tandstuff.virtual_setup.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  536.    pack_us(ss->people, map, fraction, twosome, &tandstuff);
  537.    update_id_bits(&tandstuff.virtual_setup);
  538.    move(&tandstuff.virtual_setup, conceptptrcopy, callspec, final_concepts, FALSE, &tandstuff.virtual_result);
  539.  
  540.    if (setup_limits[tandstuff.virtual_result.kind] < 0)
  541.       fail("Don't recognize ending position from this tandem or as couples call.");
  542.  
  543.    sglmask = 0;     /* Bits appear here in pairs!  Only low bit of each pair is used. */
  544.    livemask = 0;    /* Bits appear here in pairs!  Only low bit of each pair is used. */
  545.    orbitmask = 0;   /* Bits appear here in pairs! */
  546.  
  547.    /* Compute orbitmask, livemask, and sglmask.
  548.       Since we are synthesizing bit masks, we scan in reverse order to make things easier. */
  549.  
  550.    for (i=setup_limits[tandstuff.virtual_result.kind]; i>=0; i--) {
  551.       int p = tandstuff.virtual_result.people[i].id1;
  552.       sglmask <<= 2;
  553.       livemask <<= 2;
  554.       orbitmask <<= 2;
  555.  
  556.       if (p) {
  557.          int vpi;
  558.  
  559.          if (fractional) {
  560.             if (!(p & STABLE_ENAB))
  561.                fail("fractional twosome not supported for this call.");
  562.          }
  563.  
  564.          vpi = (p >> 6) & 7;
  565.          livemask |= 1;
  566.          if (tandstuff.real_back_people[vpi].id1 == 0xFFFFFFFF) {
  567.             sglmask |= 1;
  568.          }
  569.          else {
  570.             unsigned int orbit;
  571.  
  572.             orbit = p - tandstuff.virtual_setup.rotation +
  573.                   tandstuff.virtual_result.rotation - tandstuff.virtual_setup.people[vpi].id1;
  574.  
  575.             if (twosome == 2) {
  576.                orbit -= ((p & (STABLE_VBIT*3)) / STABLE_VBIT);
  577.             }
  578.             else if (twosome == 3) {
  579.                orbit = ((p & (STABLE_VBIT*3)) / STABLE_VBIT);
  580.             }
  581.             else if (twosome == 1) {
  582.                orbit = 0;
  583.             }
  584.  
  585.             orbitmask |= ((orbit - tandstuff.virtual_result.rotation - tandstuff.vertical_people[vpi]) & 3);
  586.          }
  587.  
  588.          if (fractional)
  589.             tandstuff.virtual_result.people[i].id1 &= ~STABLE_MASK;
  590.       }
  591.    }
  592.  
  593.    hmask = (~orbitmask) & livemask & ~sglmask & 0x55555555;    /* Pick out only low bits for map search,
  594.                                                                and only bits of live paired people. */
  595.  
  596.    map_search = maps_isearch;
  597.    while (map_search->outsetup != nothing) {
  598.       if ((map_search->insetup == tandstuff.virtual_result.kind) &&
  599.             (map_search->insinglemask == sglmask) &&
  600.             ((map_search->sidewaysmask & livemask) == hmask)) {
  601.          unpack_us(map_search, orbitmask, &tandstuff, result);
  602.          reinstate_rotation(ss, result);
  603.          return;
  604.       }
  605.       map_search++;
  606.    }
  607.  
  608.    fail("Don't recognize ending position from this tandem or as couples call.");
  609. }
  610.