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 / sdconc.c < prev    next >
C/C++ Source or Header  |  1992-11-29  |  88KB  |  1,799 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 defines the following functions:
  22.    concentric_move
  23.    normalize_concentric
  24.    merge_setups
  25.    on_your_own_move
  26.    so_and_so_only_move
  27. */
  28.  
  29. #include "sd.h"
  30.  
  31.  
  32. typedef enum {
  33.    analyzer_NORMAL,
  34.    analyzer_CHECKPT,
  35.    analyzer_2X6,
  36.    analyzer_6X2,
  37.    analyzer_STAR12,
  38.    analyzer_SINGLE,
  39.    analyzer_VERTICAL6,
  40.    analyzer_LATERAL6,
  41.    analyzer_DIAMOND_LINE } analyzer_kind;
  42.  
  43.  
  44. typedef struct {
  45.    veryshort mapin[8];
  46.    veryshort mapout[8];
  47.    short inlimit;
  48.    short outlimit;
  49.    setup_kind bigsetup;
  50.    setup_kind insetup;
  51.    setup_kind outsetup;
  52.    int bigsize;
  53.    int inner_rot;    /* 1 if inner setup is rotated CCW relative to big setup */
  54.    int outer_rot;    /* 1 if outer setup is rotated CCW relative to big setup */
  55.    int mapelong;
  56.    } cm_thing;
  57.  
  58. /*                                                                                                         mapelong --------|
  59.                                                                                                           outer_rot -----|  |
  60.                                                                                                    inner_rot ---------|  |  |
  61.                                                              outlimit -----|                          bigsize ----|   |  |  |
  62.                                   mapin           mapout       inlimit -|  |  bigsetup      insetup  outsetup     |   |  |  |   */
  63.  
  64. static cm_thing map1x2_1x2 =        {{1, 3},       {0, 2},              2, 2, s1x4,           s_1x2,    s_1x2,    4,  0, 0, 0};
  65. static cm_thing oddmap1x2_1x2 =     {{3, 1},       {0, 2},              2, 2, sdmd,           s_1x2,    s_1x2,    4,  1, 0, 0};
  66. static cm_thing mapdmd_dmd =        {{1, 3, 5, 7}, {0, 2, 4, 6},        4, 4, s_crosswave,    sdmd,     sdmd,     8,  0, 0, 9};
  67. static cm_thing oddmapdmd_1x4 =     {{1, 2, 5, 6}, {7, 0, 3, 4},        4, 4, s_3x1dmd,       s1x4,     sdmd,     8,  0, 1, 9};
  68. static cm_thing mapdmd_1x4 =        {{1, 2, 5, 6}, {0, 3, 4, 7},        4, 4, s_3x1dmd,       s1x4,     sdmd,     8,  0, 0, 9};
  69. static cm_thing oddmap_s_dmd_1x4 =  {{1, 2, 5, 6}, {7, 0, 3, 4},        4, 4, s_wingedstar,   s1x4,     sdmd,     8,  0, 1, 9};
  70. static cm_thing map_s_dmd_1x4 =     {{1, 2, 5, 6}, {0, 3, 4, 7},        4, 4, s_wingedstar,   s1x4,     sdmd,     8,  0, 0, 9};
  71. static cm_thing map_cs_1x4_dmd =    {{0, 3, 4, 7}, {1, 2, 5, 6},        4, 4, s_wingedstar,   sdmd,     s1x4,     8,  0, 0, 9};
  72. static cm_thing oddmap_s_star_1x4 = {{1, 2, 5, 6}, {7, 0, 3, 4},        4, 4, s_wingedstar,   s1x4,     s_star,   8,  0, 1, 9};
  73. static cm_thing map_s_star_1x4 =    {{1, 2, 5, 6}, {0, 3, 4, 7},        4, 4, s_wingedstar,   s1x4,     s_star,   8,  0, 0, 9};
  74. static cm_thing oddmap_s_short_1x6 = {{1, 2, 4, 7, 8, 10},
  75.                                              {11, 0, 3, 5, 6, 9},       6, 6, s_wingedstar12, s_1x6,    s_short6, 12, 0, 1, 9};
  76. static cm_thing map_spec_star12 =   {{2, 3, 4, 11}, {0, 1, 6, 7},       4, 4, s_wingedstar12, s_star,   s1x4,     12, 0, 0, 0};
  77. static cm_thing map_spec_star12v =  {{11, 2, 3, 4}, {0, 1, 6, 7},       4, 4, s_wingedstar12, s_star,   s1x4,     12, 1, 0, 0};
  78. static cm_thing mapdmd_2x2h =       {{1, 3, 5, 7}, {0, 2, 4, 6},        4, 4, s_galaxy,       s2x2,     sdmd,     8,  0, 0, 9};
  79. static cm_thing mapdmd_2x2v =       {{7, 1, 3, 5}, {0, 2, 4, 6},        4, 4, s_galaxy,       s2x2,     sdmd,     8,  1, 0, 9};
  80. static cm_thing map2x3_1x2 =        {{11, 5}, {0, 1, 2, 6, 7, 8},       2, 6, s_3dmd,         s_1x2,    s_2x3,    12, 0, 0, 9};
  81. static cm_thing map1x4_1x4 =        {{3, 2, 7, 6}, {0, 1, 4, 5},        4, 4, s1x8,           s1x4,     s1x4,     8,  0, 0, 0};
  82. static cm_thing oddmap1x4_1x4 =     {{6, 7, 2, 3}, {0, 1, 4, 5},        4, 4, s_crosswave,    s1x4,     s1x4,     8,  1, 0, 0};
  83. static cm_thing map2x3_2x3 = {{8, 11, 1, 2, 5, 7}, {9, 10, 0, 3, 4, 6}, 6, 6, s3x4,           s_2x3,    s_2x3,    12, 1, 1, 1};
  84. static cm_thing map1x2_bone6 = {{1, 7, 6, 5, 3, 2}, {0, 4},             6, 2, s_ptpd,         s_bone6,  s_1x2,    8,  0, 0, 0};
  85. static cm_thing map1x6_1x2 = {{2, 6}, {0, 1, 3, 4, 5, 7},               2, 6, s1x8,           s_1x2,    s_1x6,    8,  0, 0, 0};
  86. static cm_thing mapbone6_1x2 = {{7, 3}, {0, 1, 2, 4, 5, 6},             2, 6, s_bone,         s_1x2,    s_bone6,  8,  0, 0, 0};
  87. static cm_thing map1x4_1x4_rc = {{0, 2, 4, 6}, {1, 3, 5, 7},            4, 4, s1x8,           s1x4,     s1x4,     8,  0, 0, 0};
  88. static cm_thing map1x2_bone6_rc = {{0, 1, 3, 4, 5, 7}, {6, 2},          6, 2, s_bone,         s_bone6,  s_1x2,    8,  0, 0, 0};
  89. static cm_thing map2x2_dmd_rc = {{7, 1, 3, 5}, {0, 2, 4, 6},            4, 4, s_spindle,      sdmd,     s2x2,     8,  0, 0, 0};
  90. static cm_thing map2x2_1x4_rc = {{0, 2, 4, 6}, {1, 7, 5, 3},            4, 4, s_ptpd,         s1x4,     s2x2,     8,  0, 0, 0};
  91. static cm_thing oddmap2x2_1x4_rc = {{0, 2, 4, 6}, {3, 1, 7, 5},         4, 4, s_ptpd,         s1x4,     s2x2,     8,  0, 1, 9};
  92. static cm_thing map1x2_2x3 = {{0, 1, 2, 4, 5, 6}, {7, 3},               6, 2, s_spindle,      s_2x3,    s_1x2,    8,  0, 0, 0};
  93. static cm_thing map1x2_short6 = {{1, 2, 3, 5, 6, 7}, {0, 4},            6, 2, s_galaxy,       s_short6, s_1x2,    8,  0, 0, 0};
  94. static cm_thing mapshort6_1x2h = {{5, 1}, {6, 7, 0, 2, 3, 4},           2, 6, s_spindle,      s_1x2,    s_short6, 8,  1, 1, 1};
  95. static cm_thing mapshort6_1x2v = {{7, 3}, {5, 6, 0, 1, 2, 4},           2, 6, s_hrglass,      s_1x2,    s_short6, 8,  1, 1, 0};
  96. static cm_thing mapstar_2x2 = {{1, 3, 5, 7}, {0, 2, 4, 6},              4, 4, s_galaxy,       s2x2,     s_star,   8,  0, 0, 0};
  97. static cm_thing map1x2_1x6 = {{1, 3, 2, 5, 7, 6}, {0, 4},               6, 2, s1x8,           s_1x6,    s_1x2,    8,  0, 0, 0};
  98. static cm_thing oddmap1x2_1x6 = {{0, 1, 2, 4, 5, 6}, {7, 3},            6, 2, s_3x1dmd,       s_1x6,    s_1x2,    12, 0, 1, 0};
  99. static cm_thing map1x4_2x2 = {{0, 1, 4, 5}, {6, 7, 2, 3},               4, 4, s_rigger,       s2x2,     s1x4,     8,  0, 0, 0};
  100. static cm_thing oddmap1x4_2x2 = {{5, 0, 1, 4}, {6, 7, 2, 3},            4, 4, s_rigger,       s2x2,     s1x4,     8,  1, 0, 0};
  101. static cm_thing map1x4_star = {{2, 3, 6, 7}, {0, 1, 4, 5},              4, 4, s_wingedstar,   s_star,   s1x4,     8,  0, 0, 0};
  102. static cm_thing oddmap1x4_star = {{7, 2, 3, 6}, {0, 1, 4, 5},           4, 4, s_wingedstar,   s_star,   s1x4,     8,  1, 0, 0};
  103. static cm_thing map2x2_dmd = {{6, 3, 2, 7}, {0, 1, 4, 5},               4, 4, s_hrglass,      sdmd,     s2x2,     8,  0, 0, 1};
  104. static cm_thing oddmap2x2_dmd = {{6, 3, 2, 7}, {5, 0, 1, 4},            4, 4, s_hrglass,      sdmd,     s2x2,     8,  0, 1, 9};
  105. static cm_thing map2x2_1x4h = {{6, 7, 2, 3}, {0, 1, 4, 5},              4, 4, s_qtag,         s1x4,     s2x2,     8,  0, 0, 1};
  106. static cm_thing oddmap2x2_1x4h = {{6, 7, 2, 3}, {5, 0, 1, 4},           4, 4, s_bone,         s1x4,     s2x2,     8,  0, 1, 9};
  107. static cm_thing mapstar_1x4 =    {{1, 2, 5, 6}, {0, 3, 4, 7},           4, 4, s_3x1dmd,       s1x4,     s_star,   12, 0, 0, 9};
  108. static cm_thing oddmapstar_1x4 = {{1, 2, 5, 6}, {7, 0, 3, 4},           4, 4, s_3x1dmd,       s1x4,     s_star,   12, 0, 1, 9};
  109. static cm_thing mapstar_dmd ={{1, 3, 5, 7}, {0, 2, 4, 6},               4, 4, s_crosswave,    sdmd,     s_star,   8,  0, 0, 9};
  110. static cm_thing oddmapstar_dmd =  {{1, 3, 5, 7}, {6, 0, 2, 4},          4, 4, s_crosswave,    sdmd,     s_star,   8,  0, 1, 9};
  111. static cm_thing map2x2_1x4v = {{6, 7, 2, 3}, {0, 1, 4, 5},              4, 4, s_bone,         s1x4,     s2x2,     8,  0, 0, 0};
  112. static cm_thing oddmap2x2_1x4v = {{6, 7, 2, 3}, {5, 0, 1, 4},           4, 4, s_qtag,         s1x4,     s2x2,     8,  0, 1, 9};
  113. static cm_thing map2x2_2x2v = {{1, 2, 5, 6}, {0, 3, 4, 7},              4, 4, s2x4,           s2x2,     s2x2,     8,  0, 0, 0};
  114. static cm_thing oddmap2x2_2x2h = {{1, 2, 5, 6}, {7, 0, 3, 4},           4, 4, s2x4,           s2x2,     s2x2,     8,  0, 1, 9};
  115. static cm_thing oddmap2x2_2x2v = {{6, 1, 2, 5}, {0, 3, 4, 7},           4, 4, s2x4,           s2x2,     s2x2,     8,  1, 0, 9};
  116. static cm_thing map2x2_2x2h = {{6, 1, 2, 5}, {7, 0, 3, 4},              4, 4, s2x4,           s2x2,     s2x2,     8,  1, 1, 9};
  117. static cm_thing maplatgal = {{7, 0, 1, 3, 4, 5}, {6, 2},                6, 2, s_galaxy,       s_short6, s_1x2,    8,  1, 1, 0};
  118. static cm_thing oddmap1x4_dmd = {{7, 2, 3, 6}, {0, 1, 4, 5},            4, 4, s_3x1dmd,       sdmd,     s1x4,     12, 1, 0, 0};
  119. static cm_thing oddmap1x2_bone6 = {{5, 0, 3, 1, 4, 7}, {6, 2},          6, 2, s_hrglass,      s_bone6,  s_1x2,    8,  1, 0, 0};
  120. static cm_thing oddmap1x2_2x3 = {{5, 7, 0, 1, 3, 4}, {6, 2},            6, 2, s_qtag,         s_2x3,    s_1x2,    8,  1, 0, 0};
  121. static cm_thing oddmap1x2_short6 = {{5, 7, 0, 1, 3, 4}, {6, 2},         6, 2, s_rigger,       s_short6, s_1x2,    8,  1, 0, 0};
  122. static cm_thing oddmap2x3_1x2 = {{11, 5}, {9, 10, 0, 3, 4, 6},          2, 6, s3x4,           s_1x2,    s_2x3,    12, 0, 1, 0};
  123. static cm_thing oddmapshort6_1x2h = {{2, 6}, {3, 0, 1, 7, 4, 5},        2, 6, s_ptpd,         s_1x2,    s_short6, 8,  0, 1, 1};
  124. static cm_thing oddmapshort6_1x2v = {{7, 3}, {5, 6, 0, 1, 2, 4},        2, 6, s_qtag,         s_1x2,    s_short6, 8,  0, 1, 0};
  125. static cm_thing oddmap1x2_short6_rc = {{5, 6, 0, 1, 2, 4}, {7, 3},      6, 2, s_rigger,       s_short6, s_1x2,    8,  1, 0, 0};
  126. static cm_thing map2x4_2x2 = {{2, 3, 8, 9}, {0, 1, 4, 5, 6, 7, 10, 11}, 4, 8, s2x6,           s2x2,     s2x4,     12, 0, 0, 9};
  127. static cm_thing oddmap2x4_2x2 = {{9, 2, 3, 8},
  128.                                        {0, 1, 4, 5, 6, 7, 10, 11},      4, 8, s2x6,           s2x2,     s2x4,     12, 1, 0, 9};
  129. static cm_thing mapdmd_line = {{1, 2, 5, 6}, {0, 3, 4, 7},              4, 4, s_3x1dmd,       s1x4,     sdmd,     8,  0, 0, 0};
  130. static cm_thing map_s_dmd_line = {{1, 2, 5, 6}, {0, 3, 4, 7},           4, 4, s_wingedstar,   s1x4,     sdmd,     8,  0, 0, 0};
  131. static cm_thing map_12_dmd_line = {{1, 2, 4, 7, 8, 10},
  132.                                                {11, 0, 3, 5, 6, 9},     6, 6, s_wingedstar12, s_1x6,    s_short6, 12,  0, 1, 0};
  133.  
  134.  
  135. static cm_thing *concmap1x2_1x2[4]       = {&map1x2_1x2,          &oddmap1x2_1x2,       &map1x2_1x2,      &oddmap1x2_1x2};
  136. static cm_thing *concmapdmd_dmd[4]       = {&mapdmd_dmd,          0,                    &mapdmd_dmd,      0};
  137. static cm_thing *concmapdmd_1x4[4]       = {&mapdmd_1x4,          &oddmapdmd_1x4,       &mapdmd_1x4,      &oddmapdmd_1x4};
  138. static cm_thing *concmap_s_dmd_1x4[4]    = {&map_s_dmd_1x4,       &oddmap_s_dmd_1x4,    &map_s_dmd_1x4,   &oddmap_s_dmd_1x4};
  139. static cm_thing *concmap_cs_1x4_dmd[4]   = {&map_cs_1x4_dmd,      0,                    &map_cs_1x4_dmd,  0};
  140. static cm_thing *concmap_s_star_1x4[4]   = {&map_s_star_1x4,      &oddmap_s_star_1x4,   &map_s_star_1x4,  &oddmap_s_star_1x4};
  141. static cm_thing *concmap_s_short_1x6[4]  = {0,                    &oddmap_s_short_1x6,  0,                0};
  142. static cm_thing *concmapdmd_2x2[4]       = {&mapdmd_2x2h,         &mapdmd_2x2v,         &mapdmd_2x2h,     &mapdmd_2x2v};
  143. static cm_thing *concmap2x2_2x2[4]       = {&map2x2_2x2v,         &oddmap2x2_2x2v,      &map2x2_2x2h,     &oddmap2x2_2x2h};
  144. static cm_thing *concmap2x2_1x4[4]       = {&map2x2_1x4v,         &oddmap2x2_1x4v,      &map2x2_1x4h,     &oddmap2x2_1x4h};
  145. static cm_thing *concmap2x2_dmd[4]       = {0,                    &oddmap2x2_dmd,       &map2x2_dmd,      0};
  146. static cm_thing *concmapshort6_1x2[4]    = {&mapshort6_1x2v,      &oddmapshort6_1x2v,   &mapshort6_1x2h,  &oddmapshort6_1x2h};
  147. static cm_thing *concmap1x2_1x6[4]       = {&map1x2_1x6,          &oddmap1x2_1x6,       &map1x2_1x6,      &oddmap1x2_1x6};
  148. static cm_thing *concmap1x2_bone6[4]     = {&map1x2_bone6,        &oddmap1x2_bone6,     &map1x2_bone6,    &oddmap1x2_bone6};
  149. static cm_thing *concmap1x2_2x3[4]       = {&map1x2_2x3,          &oddmap1x2_2x3,       &map1x2_2x3,      &oddmap1x2_2x3};
  150. static cm_thing *concmap1x2_short6[4]    = {&map1x2_short6,       &oddmap1x2_short6,    &map1x2_short6,   &oddmap1x2_short6};
  151. static cm_thing *concmap2x4_2x2[4]       = {&map2x4_2x2,          &oddmap2x4_2x2,       &map2x4_2x2,      &oddmap2x4_2x2};
  152. static cm_thing *concmap1x4_2x2[4]       = {&map1x4_2x2,          &oddmap1x4_2x2,       &map1x4_2x2,      &oddmap1x4_2x2};
  153. static cm_thing *concmap1x4_star[4]      = {&map1x4_star,         &oddmap1x4_star,      &map1x4_star,     &oddmap1x4_star};
  154. static cm_thing *concmap1x4_dmd[4]       = {0,                    &oddmap1x4_dmd,       0,                &oddmap1x4_dmd};
  155. static cm_thing *concmap1x4_1x4[4]       = {&map1x4_1x4,          &oddmap1x4_1x4,       &map1x4_1x4,      &oddmap1x4_1x4};
  156. static cm_thing *concmapstar_2x2[4]      = {&mapstar_2x2,         0,                    &mapstar_2x2,     0};
  157. static cm_thing *concmapstar_1x4[4]      = {&mapstar_1x4,         &oddmapstar_1x4,      &mapstar_1x4,     &oddmapstar_1x4};
  158. static cm_thing *concmapstar_dmd[4]      = {&mapstar_dmd,         &oddmapstar_dmd,      &mapstar_dmd,     &oddmapstar_dmd};
  159. static cm_thing *concmap2x3_1x2[4]       = {&map2x3_1x2,          &oddmap2x3_1x2,       &map2x3_1x2,      &oddmap2x3_1x2};
  160. static cm_thing *concmap2x3_2x3[4]       = {&map2x3_2x3,          0,                    &map2x3_2x3,      0};
  161. static cm_thing *concmapbone6_1x2[4]     = {&mapbone6_1x2,        0,                    &mapbone6_1x2,    0};
  162. static cm_thing *concmap1x6_1x2[4]       = {&map1x6_1x2,          0,                    &map1x6_1x2,      0};
  163. static cm_thing *concmap1x4_1x4_rc[4]    = {&map1x4_1x4_rc,       0,                    &map1x4_1x4_rc,   0};
  164. static cm_thing *concmap2x2_dmd_rc[4]    = {&map2x2_dmd_rc,       0,                    &map2x2_dmd_rc,   0};
  165. static cm_thing *concmap2x2_1x4_rc[4]    = {&map2x2_1x4_rc,       &oddmap2x2_1x4_rc,    &map2x2_1x4_rc,   &oddmap2x2_1x4_rc};
  166.  
  167.  
  168.  
  169. /* This overwrites its "inners" and "outers argument setups. */
  170. extern void normalize_concentric(
  171.    calldef_schema synthesizer,
  172.    int center_arity,
  173.    setup inners[],
  174.    setup *outers,
  175.    int outer_elongation,
  176.    setup *result)
  177. {
  178.    /* If "outer_elongation" < 0, the outsides can't deduce their ending spots on
  179.       the basis of the starting formation.  In this case, it is an error unless
  180.       they go to some setup for which their elongation is obvious, like a 1x4. */
  181.  
  182.    int i, j, q, rot;
  183.    cm_thing **map_ptr;
  184.    cm_thing *lmap_ptr;
  185.  
  186.    clear_people(result);
  187.  
  188.    /* If a call was being done "piecewise" or "random", we demand that both
  189.       calls run out of parts at the same time, and, when that happens, we
  190.       report it to the higher level in the recursion. */
  191.  
  192.    if ((inners[0].setupflags ^ outers->setupflags) & RESULTFLAG__DID_LAST_PART)
  193.       fail("Centers and ends parts must use the same number of fractions.");
  194.  
  195.    result->setupflags = inners[0].setupflags | outers->setupflags;
  196.  
  197.    if (inners[0].kind == nothing && outers->kind == nothing) {
  198.       result->kind = nothing;
  199.       return;
  200.    }
  201.  
  202.    compute_rotation_again:
  203.  
  204.    i = (inners[0].rotation - outers->rotation) & 3;
  205.  
  206.    map_ptr = 0;
  207.  
  208.    if (center_arity != 1) {
  209.       if (synthesizer != schema_conc_star12 || outers->kind != s1x4 || inners[0].kind != s_star || inners[1].kind != s_star)
  210.          fail("Can't do this with 12 matrix stars.");
  211.  
  212.       if (i&1)
  213.          lmap_ptr = &map_spec_star12v;
  214.       else
  215.          lmap_ptr = &map_spec_star12;
  216.  
  217.       goto gotit;
  218.    }
  219.  
  220.    if (synthesizer == schema_rev_checkpoint) {
  221.       /* Fix up nonexistent centers or ends, in a rather inept way. */
  222.       if (inners[0].kind == nothing) {
  223.          inners[0].kind = outers->kind;
  224.          inners[0].rotation = outers->rotation;
  225.          inners[0].setupflags = outers->setupflags;
  226.          clear_people(&inners[0]);
  227.          i = 0;
  228.       }
  229.       else if (outers->kind == nothing) {
  230.          outers->kind = inners[0].kind;
  231.          outers->rotation = inners[0].rotation;
  232.          outers->setupflags = inners[0].setupflags;
  233.          clear_people(outers);
  234.          i = 0;
  235.       }
  236.  
  237.       switch (outers->kind) {
  238.          case s2x2:
  239.             switch (inners[0].kind) {
  240.                case s1x4: map_ptr = concmap2x2_1x4_rc; break;
  241.                case sdmd: map_ptr = concmap2x2_dmd_rc; break;
  242.             }
  243.             break;
  244.          case s1x4:
  245.             switch (inners[0].kind) {
  246.                case s1x4: map_ptr = concmap1x4_1x4_rc; break;
  247.                case sdmd:
  248.                   /* This is a diamond inside a 1x4, oriented the bad way.
  249.                      Leave it as a concentric setup. */
  250.                   if (!(i&1)) {
  251.                      result->inner.skind = inners[0].kind;
  252.                      result->inner.srotation = inners[0].rotation;
  253.                      result->outer.skind = outers->kind;
  254.                      result->outer.srotation = outers->rotation;
  255.                      result->outer_elongation = 0;
  256.                      result->kind = s_normal_concentric;
  257.                      if (i == 0) {
  258.                         install_person(result, 0, outers, 1);
  259.                         install_person(result, 2, outers, 3);
  260.                         install_person(result, 1, &inners[0], 1);
  261.                         install_person(result, 3, &inners[0], 3);
  262.                         install_person(result, 12, &inners[0], 0);
  263.                         install_person(result, 14, &inners[0], 2);
  264.                         install_person(result, 13, outers, 0);
  265.                         install_person(result, 15, outers, 2);
  266.                      }
  267.                      else
  268.                         fail("Sorry, code is broken at line 581 of sdconc.c.");
  269.  
  270.                      canonicalize_rotation(result);
  271.                      return;
  272.                   }
  273.             }
  274.             break;
  275.       }
  276.    }
  277.    else if (synthesizer == schema_ckpt_star) {
  278.       /* There are a few cases of centers or ends being phantoms, in which
  279.          we nevertheless know what to do, since we know that the setup should
  280.          be some kind of "winged star". */
  281.       if (inners[0].kind == nothing && outers->kind == s1x4) {
  282.          inners[0].kind = s_star;
  283.          inners[0].rotation = 0;
  284.          inners[0].setupflags = outers->setupflags;
  285.          clear_people(&inners[0]);
  286.          goto compute_rotation_again;
  287.       }
  288.       else if (inners[0].kind == sdmd && outers->kind == nothing) {
  289.          /* The test case for this is: RWV:intlkphanbox relay top;splitphanbox flip reaction. */
  290.          outers->kind = s1x4;
  291.          outers->rotation = inners[0].rotation;
  292.          outers->setupflags = inners[0].setupflags;
  293.          clear_people(outers);
  294.          goto compute_rotation_again;
  295.       }
  296.  
  297.       switch (outers->kind) {
  298.          case s1x4:
  299.             switch (inners[0].kind) {
  300.                case sdmd: map_ptr = concmap_cs_1x4_dmd; break;
  301.             }
  302.             break;
  303.       }
  304.    }
  305.    else if (synthesizer == schema_conc_star) {
  306.       /* There are a few cases of centers or ends being phantoms, in which
  307.          we nevertheless know what to do, since we know that the setup should
  308.          be some kind of "winged star". */
  309.       if (outers->kind == nothing && inners[0].kind == s1x4) {
  310.          outers->kind = s_star;
  311.          outers->rotation = 0;
  312.          outers->setupflags = inners[0].setupflags;
  313.          clear_people(outers);
  314.          goto compute_rotation_again;
  315.       }
  316.       else if (outers->kind == nothing && inners[0].kind == s_star) {
  317.          outers->kind = s1x4;
  318.          outers->rotation = outer_elongation;
  319.          outers->setupflags = inners[0].setupflags;
  320.          clear_people(outers);
  321.          goto compute_rotation_again;
  322.       }
  323.       else if (outers->kind == s1x4 && inners[0].kind == nothing) {
  324.          inners[0].kind = s_star;
  325.          inners[0].rotation = 0;
  326.          inners[0].setupflags = outers->setupflags;
  327.          clear_people(&inners[0]);
  328.          goto compute_rotation_again;
  329.       }
  330.  
  331.       switch (outers->kind) {
  332.          case sdmd:
  333.             switch (inners[0].kind) {
  334.                case s1x4: map_ptr = concmap_s_dmd_1x4; break;
  335.             }
  336.             break;
  337.          case s_star:
  338.             switch (inners[0].kind) {
  339.                case s1x4: map_ptr = concmap_s_star_1x4; break;
  340.             }
  341.             break;
  342.          case s1x4:
  343.             switch (inners[0].kind) {
  344.                case s_star: map_ptr = concmap1x4_star; break;
  345.                case s1x4:
  346.                   /* In certain phantom cases, what should have been a diamond
  347.                      around the outside, resulting from a 1/2 circulate, will be
  348.                      a line with the two centers missing, since the basic_move
  349.                      routine gives preference to a line when it is ambiguous.
  350.                      If this happens, we have to turn it back into a diamond. */
  351.                   if (!(outers->people[1].id1 | outers->people[3].id1)) {
  352.                      outers->kind = sdmd;  /* That's all that it takes to fix it. */
  353.                      goto compute_rotation_again;
  354.                   }
  355.                   /* Or the two ends missing. */
  356.                   else if (!(outers->people[0].id1 | outers->people[2].id1)) {
  357.                      outers->kind = sdmd;
  358.                      outers->rotation = (outers->rotation-1) & 3;
  359.                      (void) copy_rot(outers, 1, outers, 1, 011);
  360.                      (void) copy_rot(outers, 3, outers, 3, 011);
  361.                      canonicalize_rotation(outers);
  362.                      goto compute_rotation_again;
  363.                   }
  364.             }
  365.             break;
  366.       }
  367.    }
  368.    else if (synthesizer == schema_conc_star12) {
  369.       switch (outers->kind) {
  370.          case s_short6:
  371.             switch (inners[0].kind) {
  372.                case s_1x6: map_ptr = concmap_s_short_1x6; break;
  373.             }
  374.             break;
  375.       }
  376.    }
  377.    else {
  378.       /* Fix up nonexistent centers or ends, in a rather inept way. */
  379.       if (inners[0].kind == nothing) {
  380.          inners[0].kind = outers->kind;
  381.          inners[0].rotation = outers->rotation;
  382.          inners[0].setupflags = outers->setupflags;
  383.          clear_people(&inners[0]);
  384.          i = 0;
  385.       }
  386.       else if (outers->kind == nothing) {
  387.          outers->kind = inners[0].kind;
  388.          outers->rotation = inners[0].rotation;
  389.          outers->setupflags = inners[0].setupflags;
  390.          clear_people(outers);
  391.          i = 0;
  392.       }
  393.  
  394.       /* Nonexistent center or ends have been taken care of.  Now figure out how to put
  395.          the setups together. */
  396.  
  397.       switch (outers->kind) {
  398.          case s_1x6:
  399.             switch (inners[0].kind) {
  400.                case s_1x2: map_ptr = concmap1x6_1x2; break;
  401.             }
  402.             break;
  403.          case s_bone6:
  404.             switch (inners[0].kind) {
  405.                case s_1x2: map_ptr = concmapbone6_1x2; break;
  406.             }
  407.             break;
  408.          case s_2x3:
  409.             switch (inners[0].kind) {
  410.                case s_1x2: map_ptr = concmap2x3_1x2; break;
  411.                case s_2x3: map_ptr = concmap2x3_2x3; break;
  412.             }
  413.             break;
  414.          case s2x4:
  415.             switch (inners[0].kind) {
  416.                case s2x2: map_ptr = concmap2x4_2x2; break;
  417.             }
  418.             break;
  419.          case s1x4:
  420.             switch (inners[0].kind) {
  421.                case s1x4: map_ptr = concmap1x4_1x4; break;
  422.                case sdmd: map_ptr = concmap1x4_dmd; break;
  423.                case s_star: map_ptr = concmap1x4_star; break;
  424.                case s2x2: map_ptr = concmap1x4_2x2; break;
  425.             }
  426.             break;
  427.          case s_1x2:
  428.             switch (inners[0].kind) {
  429.                case s_1x2:    map_ptr = concmap1x2_1x2; break;
  430.                case s_2x3:    map_ptr = concmap1x2_2x3; break;
  431.                case s_bone6 : map_ptr = concmap1x2_bone6; break;
  432.                case s_short6: map_ptr = concmap1x2_short6; break;
  433.                case s_1x6:    map_ptr = concmap1x2_1x6; break;
  434.             }
  435.             break;
  436.          case s_short6:
  437.             switch (inners[0].kind) {
  438.                case s_1x2: map_ptr = concmapshort6_1x2; break;
  439.             }
  440.             break;
  441.          case s2x2:
  442.             switch (inners[0].kind) {
  443.                case s2x2: map_ptr = concmap2x2_2x2; break;
  444.                case s1x4: map_ptr = concmap2x2_1x4; break;
  445.                case sdmd: map_ptr = concmap2x2_dmd; break;
  446.             }
  447.             break;
  448.          case sdmd:
  449.             switch (inners[0].kind) {
  450.                case sdmd: map_ptr = concmapdmd_dmd; break;
  451.                case s1x4: map_ptr = concmapdmd_1x4; break;
  452.                case s2x2: map_ptr = concmapdmd_2x2; break;
  453.             }
  454.             break;
  455.          case s_star:
  456.             switch (inners[0].kind) {
  457.                case sdmd: map_ptr = concmapstar_dmd; break;
  458.                case s1x4: map_ptr = concmapstar_1x4; break;
  459.                case s2x2: map_ptr = concmapstar_2x2; break;
  460.             }
  461.             break;
  462.       }
  463.    }
  464.  
  465.    if (!map_ptr) goto anomalize_it;
  466.  
  467.    if (outer_elongation < 0) {
  468.       /* We need to find out whether it would have made a difference
  469.          when picking out the map. */
  470.  
  471.       if (map_ptr[(i&1)] != map_ptr[(i&1) + 2]) goto elongation_loss;
  472.    }
  473.  
  474.    lmap_ptr = map_ptr[(i&1) + (((outer_elongation ^ outers->rotation) & 1) << 1)];
  475.  
  476. gotit:
  477.  
  478.    if (!lmap_ptr) goto anomalize_it;
  479.  
  480.    result->kind = lmap_ptr->bigsetup;
  481.    result->rotation = outers->rotation + lmap_ptr->outer_rot;
  482.  
  483.    rot = ((-lmap_ptr->outer_rot) & 3) * 011;
  484.    for (j=0; j<lmap_ptr->outlimit; j++)
  485.       (void) copy_rot(result, lmap_ptr->mapout[j], outers, j, rot);
  486.  
  487.    /* Find out whether inners need to be flipped around. */
  488.    q = i + lmap_ptr->inner_rot - lmap_ptr->outer_rot;
  489.  
  490.    if (q & 1)
  491.       fail("Sorry, there is a bug in normalize_concentric.");
  492.  
  493.    if (q & 2) {
  494.       inners[0].rotation += 2;
  495.       canonicalize_rotation(&inners[0]);
  496.    }
  497.  
  498.    rot = ((-lmap_ptr->inner_rot) & 3) * 011;
  499.    for (j=0; j<lmap_ptr->inlimit; j++)
  500.       (void) copy_rot(result, lmap_ptr->mapin[j], &inners[0], j, rot);
  501.  
  502.    if (lmap_ptr == &map_spec_star12) {
  503.       if (q & 2) {
  504.          inners[1].rotation += 2;
  505.          canonicalize_rotation(&inners[1]);
  506.       }
  507.       (void) copy_rot(result, 10, &inners[1], 0, rot);
  508.       (void) copy_rot(result, 5,  &inners[1], 1, rot);
  509.       (void) copy_rot(result, 8,  &inners[1], 2, rot);
  510.       (void) copy_rot(result, 9,  &inners[1], 3, rot);
  511.    }
  512.    else if (lmap_ptr == &map_spec_star12v) {
  513.       if (q & 2) {
  514.          inners[1].rotation += 2;
  515.          canonicalize_rotation(&inners[1]);
  516.       }
  517.       (void) copy_rot(result, 9,  &inners[1], 0, rot);
  518.       (void) copy_rot(result, 10, &inners[1], 1, rot);
  519.       (void) copy_rot(result, 5,  &inners[1], 2, rot);
  520.       (void) copy_rot(result, 8,  &inners[1], 3, rot);
  521.    }
  522.  
  523.    canonicalize_rotation(result);
  524.    return;
  525.  
  526.    anomalize_it:            /* Failed, just leave it as it is. */
  527.  
  528.    switch (synthesizer) {
  529.       case schema_rev_checkpoint:
  530.          fail("Sorry, can't figure out this reverse checkpoint result.");
  531.       case schema_single_concentric:
  532.       case schema_single_cross_concentric:
  533.          fail("Can't figure out this single concentric result.");
  534.       case schema_conc_star:
  535.       case schema_conc_star12:
  536.          fail("Can't figure out this concentric result.");
  537.    }
  538.  
  539.    if (outer_elongation < 0) goto elongation_loss;
  540.  
  541.    result->kind = s_normal_concentric;
  542.    result->inner.skind = inners[0].kind;
  543.    result->inner.srotation = inners[0].rotation;
  544.    result->outer.skind = outers->kind;
  545.    result->outer.srotation = outers->rotation;
  546.    result->outer_elongation = outer_elongation ^ outers->rotation;
  547.    for (j=0; j<12; j++) {
  548.       (void) copy_person(result, j, &inners[0], j);
  549.       (void) copy_person(result, j+12, outers, j);
  550.    }
  551.    canonicalize_rotation(result);
  552.    return;
  553.  
  554.    elongation_loss:
  555.    fail("Ends can't figure out what spots to finish on.");
  556. }
  557.  
  558.  
  559.  
  560. /* BEWARE!!  This list is keyed to the definition of "setup_kind" in database.h . */
  561. /* The horizontal structure is keyed to the enumeration "analyzer_kind" :
  562.    normal      checkpt                   2x6                 6x2             star12             single       vertical6          lateral6     diamond_line */
  563.  
  564. static cm_thing *bigconctab[][9] = {
  565.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* nothing */
  566.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_1x1 */
  567.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_1x2 */
  568.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_1x3 */
  569.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s2x2 */
  570.    {0,              0,                    0,                  0,                 0,                &oddmap1x2_1x2, 0,                0,          0},               /* sdmd */
  571.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_star */
  572.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_trngl */
  573.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_bone6 */
  574.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_short6 */
  575.    {&map2x2_1x4h,   0,                    &oddmapshort6_1x2v, &oddmap1x2_2x3,    0,                0,              0,                0,          0},               /* s_qtag */
  576.    {&map2x2_1x4v,   &map1x2_bone6_rc,     &mapbone6_1x2,      0,                 0,                0,              0,                0,          0},               /* s_bone */
  577.    {&map1x4_2x2,    &oddmap1x2_short6_rc, 0,                  &oddmap1x2_short6, 0,                0,              0,                0,          0},               /* s_rigger */
  578.    {0,              &map2x2_dmd_rc,       &mapshort6_1x2h,    &map1x2_2x3,       0,                0,              0,                0,          0},               /* s_spindle */
  579.    {&map2x2_dmd,    0,                    &mapshort6_1x2v,    0,                 0,                0,              &oddmap1x2_bone6, 0,          0},               /* s_hrglass */
  580.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_hyperglass */
  581.    {&oddmap1x4_1x4, 0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_crosswave */
  582.    {0,              0,                    0,                  0,                 0,                &map1x2_1x2,    0,                0,          0},               /* s1x4 */
  583.    {&map1x4_1x4,    &map1x4_1x4_rc,       &map1x6_1x2,        &map1x2_1x6,       0,                0,              0,                0,          0},               /* s1x8 */
  584.    {&map2x2_2x2v,   0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s2x4 */
  585.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_2x3 */
  586.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_1x6 */
  587.    {0,              0,                    &oddmap2x3_1x2,     0,                 &map2x3_2x3,      0,              0,                0,          0},               /* s3x4 */
  588.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s2x6 */
  589.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s2x8 */
  590.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s4x4 */
  591.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s1x10 */
  592.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s1x12 */
  593.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s1x14 */
  594.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s1x16 */
  595.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_c1phan */
  596.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_bigblob */
  597.    {0,              &map2x2_1x4_rc,       &oddmapshort6_1x2h, &map1x2_bone6,     0,                0,              0,                0,          0},               /* s_ptpd */
  598.    {&oddmap1x4_dmd, 0,                    0,                  &oddmap1x2_1x6,    0,                0,              0,                0,          &mapdmd_line},    /* s_3x1dmd */
  599.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_3dmd */
  600.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_4dmd */
  601.    {&map1x4_star,   0,                    0,                  0,                 0,                0,              0,                0,          &map_s_dmd_line}, /* s_wingedstar */
  602.    {0,              0,                    0,                  0,                 &map_spec_star12, 0,              0,                0,          &map_12_dmd_line},/* s_wingedstar12 */
  603.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_wingedstar16 */
  604.    {&mapstar_2x2,   0,                    0,                  0,                 0,                0,              &map1x2_short6,   &maplatgal, 0},               /* s_galaxy */
  605.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s4x6 */
  606.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0},               /* s_thar */
  607.    {0,              0,                    0,                  0,                 0,                0,              0,                0,          0}};              /* s_normal_concentric */
  608.  
  609.  
  610.  
  611.  
  612.  
  613. /* This is keyed to the enumeration "analyzer_kind". */
  614. static char *conc_error_messages[] = {
  615.    "Can't find centers and ends in this formation.",                   /* analyzer_NORMAL */
  616.    "Can't find checkpoint people in this formation.",                  /* analyzer_CHECKPT */
  617.    "Can't find 2 centers and 6 ends in this formation.",               /* analyzer_2X6 */
  618.    "Can't find 6 centers and 2 ends in this formation.",               /* analyzer_6X2 */
  619.    "Can't find 12 matrix centers and ends in this formation.",         /* analyzer_STAR12 */
  620.    "Can't find single concentric centers and ends in this formation.", /* analyzer_SINGLE */
  621.    "Wrong formation.",                                                 /* analyzer_VERTICAL6 */
  622.    "Wrong formation.",                                                 /* analyzer_LATERAL6 */
  623.    "Can't find center line and outer diamond."                         /* analyzer_DIAMOND_LINE */
  624. };
  625.  
  626.  
  627.  
  628.  
  629. /* This sets "outer_elongation" to the absolute elongation of the
  630.    outsides.  If the outsides are in a 2x2, this, along with individual
  631.    facing directions, will permit enforcement of the "lines-to-lines/
  632.    columns-to-columns" rule.  Otherwise, this will permit enforcement
  633.    of the Hodson checkpoint rule.
  634.    
  635.    There are a few cases in which this result may seem wrong:
  636.       (1) If we have triple diamonds with points in only the center
  637.          diamond (that is, a line of 6 with some points hanging off
  638.          the center 2), and we ask for the center 6/outer 2, the
  639.          lonesome points become the ends, and "outer_elongation"
  640.          reflects their elongation, even though the line of 6 is longer.
  641.          This doesn't seem to affect any checkpoint or concentric cases.
  642.          Perhaps the phrases "center 6" and "outer 2" aren't really
  643.          correct here.
  644.       (2) If we have a quarter tag, and we ask for the center 6/outer 2,
  645.          the center 6 are, of course, a 2x3, and the ends of the line
  646.          are the outer 2.  We set "outer_elongation" to reflect
  647.          the elongation of the outer 2, which may not be what people
  648.          would think.  Once again, this does not arise in any actual
  649.          checkpoint or concentric case.
  650.       (3) If we have an "H", and we ask for the center 2/outer 6, the
  651.          outer 6 are the 2x3, and "outer_elongation" will show
  652.          their elongation, even though that is not the elongation of
  653.          the 3x4 matrix.  Once again, this does not arise in any actual
  654.          checkpoint or concentric case. */
  655.  
  656. static void concentrify(
  657.    setup *ss,
  658.    calldef_schema analyzer,
  659.    setup inners[],
  660.    setup *outers,
  661.    int *center_arity,
  662.    int *outer_elongation,    /* Set to elongation of original outers. */
  663.    int *xconc_elongation)    /* If cross concentric, set to elongation of original ends. */
  664.  
  665. {
  666.    int i, rot, analyzer_index;
  667.    cm_thing *lmap_ptr;   
  668.  
  669.    clear_people(outers);
  670.    clear_people(&inners[0]);
  671.  
  672.    outers->setupflags = ss->setupflags;
  673.    inners[0].setupflags = ss->setupflags;
  674.  
  675.    *center_arity = 1;
  676.  
  677.    /* First, translate the analyzer into a form that encodes only what we need to know. */
  678.  
  679.    switch (analyzer) {
  680.       case schema_lateral_6:
  681.          analyzer_index = analyzer_LATERAL6; break;
  682.       case schema_vertical_6:
  683.          analyzer_index = analyzer_VERTICAL6; break;
  684.       case schema_checkpoint:
  685.       case schema_ckpt_star:
  686.          analyzer_index = analyzer_CHECKPT; break;
  687.       case schema_single_concentric:
  688.       case schema_single_cross_concentric:
  689.          analyzer_index = analyzer_SINGLE; break;
  690.       case schema_conc_star12:
  691.          analyzer_index = analyzer_STAR12; break;
  692.       case schema_concentric_diamond_line:
  693.          analyzer_index = analyzer_DIAMOND_LINE; break;
  694.       case schema_concentric_6_2:
  695.          analyzer_index = analyzer_6X2; break;
  696.       case schema_concentric_2_6:
  697.          if (ss->kind == s3x4 && ((ss->people[1].id1 | ss->people[2].id1 | ss->people[7].id1 | ss->people[8].id1) ||
  698.                      (!(ss->people[0].id1 & ss->people[3].id1 & ss->people[4].id1 & ss->people[5].id1 &
  699.                      ss->people[6].id1 & ss->people[9].id1 & ss->people[10].id1 & ss->people[11].id1))))
  700.             fail("Can't find centers and ends in this formation.");
  701.          analyzer_index = analyzer_2X6;
  702.          break;
  703.       case schema_rev_checkpoint:
  704.       case schema_concentric:
  705.       case schema_conc_star:
  706.       case schema_cross_concentric:
  707.          analyzer_index = analyzer_NORMAL; break;
  708.       case schema_maybe_single_concentric:
  709.          fail("Can't figure out whether concentric is single -- this shouldn't happen.");
  710.       case schema_maybe_matrix_conc_star:
  711.          fail("Can't figure out whether concentric is 12 or 16 matrix -- this shouldn't happen.");
  712.       default:
  713.          fail("Don't understand this concentricity type???.");
  714.    }
  715.  
  716.    /* Next, deal with the "normal_concentric" special case.
  717.       We need to be careful here.  The setup was not able to be normalized, but
  718.       we are being asked to pick out centers and ends.  There are very few
  719.       non-normal concentric setups for which we can do that correctly.  For example,
  720.       if we have concentric diamonds whose points are along different axes from each
  721.       other, who are the 4 centers of the total setup?  (If the axes of the diamonds
  722.       had been consistent, the setup would have been normalized to crossed lines,
  723.       and we wouldn't be here.)
  724.       If we don't take action here and the setup is normal_concentric, an error will
  725.       be raised, since the "bigconctab" entries are zero. */
  726.  
  727.    if (ss->kind == s_normal_concentric) {
  728.       outers->rotation = ss->outer.srotation;
  729.       inners[0].rotation = ss->outer.srotation;
  730.  
  731.       switch (analyzer_index) {
  732.          case analyzer_DIAMOND_LINE:
  733.             if (ss->inner.skind == sdmd && ss->inner.srotation == ss->outer.srotation) {
  734.                inners[0].kind = s1x4;
  735.                outers->kind = sdmd;
  736.                (void) copy_person(&inners[0], 0, ss, 13);
  737.                (void) copy_person(&inners[0], 1, ss, 0);
  738.                (void) copy_person(&inners[0], 2, ss, 15);
  739.                (void) copy_person(&inners[0], 3, ss, 2);
  740.                (void) copy_person(outers, 0, ss, 12);
  741.                (void) copy_person(outers, 1, ss, 1);
  742.                (void) copy_person(outers, 2, ss, 14);
  743.                (void) copy_person(outers, 3, ss, 3);
  744.                if (ss->outer.skind == s1x4) {
  745.                   *outer_elongation = ss->outer.srotation & 1;
  746.                   goto finish;
  747.                }
  748.             }
  749.             break;
  750.          case analyzer_NORMAL:
  751.             if (ss->inner.skind == sdmd && ss->inner.srotation == ss->outer.srotation) {
  752.                inners[0].kind = sdmd;
  753.                outers->kind = ss->outer.skind;
  754.                for (i=0; i<4; i++) {
  755.                   (void) copy_person(&inners[0], i, ss, i);
  756.                   (void) copy_person(outers, i, ss, i+12);
  757.                }
  758.  
  759.                /* We allow a diamond inside a box with wrong elongation (if elongation were good, it would be an hourglass.) */
  760.                if (ss->outer.skind == s2x2) {
  761.                   *outer_elongation = (ss->outer.srotation ^ ss->outer_elongation) & 1;
  762.                   goto finish;
  763.                }
  764.                /* And a diamond inside a line with wrong elongation (if elongation were good, it would be a 3x1 diamond.) */
  765.                if (ss->outer.skind == s1x4) {
  766.                   *outer_elongation = ss->outer.srotation & 1;
  767.                   goto finish;
  768.                }
  769.             }
  770.             else if (ss->inner.skind == s_1x2 && ss->outer.skind == s_1x6 && ss->inner.srotation != ss->outer.srotation) {
  771.                inners[0].kind = sdmd;
  772.                outers->kind = s1x4;
  773.  
  774.                if ((ss->inner.srotation - ss->outer.srotation) & 2) {
  775.                   (void) copy_rot(&inners[0], 1, ss, 1, 033);
  776.                   (void) copy_rot(&inners[0], 3, ss, 0, 033);
  777.                }
  778.                else {
  779.                   (void) copy_rot(&inners[0], 1, ss, 0, 011);
  780.                   (void) copy_rot(&inners[0], 3, ss, 1, 011);
  781.                }
  782.  
  783.                (void) copy_person(&inners[0], 0, ss, 14);
  784.                (void) copy_person(&inners[0], 2, ss, 17);
  785.                (void) copy_person(outers, 0, ss, 12);
  786.                (void) copy_person(outers, 1, ss, 13);
  787.                (void) copy_person(outers, 2, ss, 15);
  788.                (void) copy_person(outers, 3, ss, 16);
  789.  
  790.                goto finish;
  791.             }
  792.             break;
  793.       }
  794.    }
  795.  
  796.    /* Next, do the 3x4 -> qtag fudging.  Don't ask permission, just do it. **** maybe that isn't right for Z calls. */
  797.  
  798.    if (analyzer_index == analyzer_NORMAL && ss->kind == s3x4) {
  799.       inners[0].kind = s1x4;
  800.       inners[0].rotation = ss->rotation;
  801.       outers->kind = s2x2;
  802.       outers->rotation = ss->rotation;
  803.       *outer_elongation = (outers->rotation^1) & 1;
  804.       (void) copy_person(&inners[0], 0, ss, 10);
  805.       (void) copy_person(&inners[0], 1, ss, 11);
  806.       (void) copy_person(&inners[0], 2, ss, 4);
  807.       (void) copy_person(&inners[0], 3, ss, 5);
  808.  
  809.       if (!ss->people[0].id1 && ss->people[1].id1)
  810.          (void) copy_person(outers, 0, ss, 1);
  811.       else if (!ss->people[1].id1 && !ss->people[0].id1)
  812.          (void) copy_person(outers, 0, ss, 0);
  813.       else fail("Can't find centers and ends in this formation.");
  814.  
  815.       if (!ss->people[2].id1 && ss->people[3].id1)
  816.          (void) copy_person(outers, 1, ss, 3);
  817.       else if (!ss->people[3].id1 && ss->people[2].id1)
  818.          (void) copy_person(outers, 1, ss, 2);
  819.       else fail("Can't find centers and ends in this formation.");
  820.  
  821.       if (!ss->people[6].id1 && ss->people[7].id1)
  822.          (void) copy_person(outers, 2, ss, 7);
  823.       else if (!ss->people[7].id1 && ss->people[6].id1)
  824.          (void) copy_person(outers, 2, ss, 6);
  825.       else fail("Can't find centers and ends in this formation.");
  826.  
  827.       if (!ss->people[8].id1 && ss->people[9].id1)
  828.          (void) copy_person(outers, 3, ss, 9);
  829.       else if (!ss->people[9].id1 && ss->people[8].id1)
  830.          (void) copy_person(outers, 3, ss, 8);
  831.       else fail("Can't find centers and ends in this formation.");
  832.       goto finish;
  833.    }
  834.  
  835.    lmap_ptr = bigconctab[ss->kind][analyzer_index];
  836.    if (!lmap_ptr) fail(conc_error_messages[analyzer_index]);
  837.  
  838.    inners[0].kind = lmap_ptr->insetup;
  839.    inners[0].rotation = ss->rotation;
  840.    outers->kind = lmap_ptr->outsetup;
  841.    outers->rotation = ss->rotation;
  842.  
  843.    rot = 0;
  844.  
  845.    if (lmap_ptr->outer_rot) {
  846.       outers->rotation--;
  847.       rot = 011;
  848.    }
  849.  
  850.    for (i=0; i<lmap_ptr->outlimit; i++) (void) copy_rot(outers, i, ss, lmap_ptr->mapout[i], rot);
  851.  
  852.    rot = 0;
  853.  
  854.    if (lmap_ptr->inner_rot) {
  855.       inners[0].rotation--;
  856.       rot = 011;
  857.    }
  858.  
  859.    for (i=0; i<lmap_ptr->inlimit; i++) (void) copy_rot(&inners[0], i, ss, lmap_ptr->mapin[i], rot);
  860.  
  861.    if (lmap_ptr == &map_spec_star12) {
  862.       *center_arity = 2;
  863.       clear_people(&inners[1]);
  864.       inners[1].setupflags = ss->setupflags;
  865.       inners[1].kind = lmap_ptr->insetup;
  866.       inners[1].rotation = ss->rotation;
  867.       (void) copy_person(&inners[1], 0, ss, 10);
  868.       (void) copy_person(&inners[1], 1, ss, 5);
  869.       (void) copy_person(&inners[1], 2, ss, 8);
  870.       (void) copy_person(&inners[1], 3, ss, 9);
  871.    }
  872.  
  873.    /* Set the outer elongation to whatever elongation the outsides really had, as indicated
  874.       by the map. */
  875.  
  876.    *outer_elongation = (lmap_ptr->mapelong + outers->rotation) & 1;
  877.  
  878.    /* If the concept is cross-concentric, we have to set the elongation to what
  879.          the centers (who will, of course, be going to the outside) had.
  880.       If the original centers are in a 2x2, we set it according to the orientation
  881.          of the entire 2x4 they were in, so that they can think about whether they were
  882.          in lines or columns and act accordingly.  If they were not in a 2x4, that is,
  883.          the setup was a wing or galaxy, we set the elongation to -1 to indicate an
  884.          error.  In such a case the centers won't be able to decide whether they were
  885.          in lines or columns. */
  886.  
  887.    if (analyzer == schema_cross_concentric) {
  888.       *xconc_elongation = *outer_elongation;
  889.       switch (ss->kind) {
  890.          case s_galaxy:
  891.          case s_rigger:
  892.          case s_3dmd:
  893.          case s_3x1dmd:
  894.             *xconc_elongation = -1;    /* Can't do this! */
  895.             break;
  896.          case s_crosswave:
  897.          case s_qtag:
  898.          case s_hrglass:
  899.          case s3x4:
  900.             *xconc_elongation ^= 1;
  901.             break;
  902.       }
  903.    }
  904.  
  905.    finish:
  906.  
  907.    canonicalize_rotation(outers);
  908.    canonicalize_rotation(&inners[0]);
  909.    if (*center_arity == 2)
  910.       canonicalize_rotation(&inners[1]);
  911. }
  912.  
  913.  
  914.  
  915.  
  916. int concwarn1x4table[] = {warn__xclineconc_perp, warn__lineconc_perp, warn__lineconc_par};
  917. int concwarndmdtable[] = {warn__xcdmdconc_perp, warn__dmdconc_perp, warn__dmdconc_par};
  918.  
  919.  
  920.  
  921. extern void concentric_move(
  922.    setup *ss,
  923.    parse_block *parsein,
  924.    parse_block *parseout,
  925.    callspec_block *callspecin,
  926.    callspec_block *callspecout,
  927.    final_set final_conceptsin,
  928.    final_set final_conceptsout,
  929.    calldef_schema analyzer,
  930.    defmodset modifiersin,
  931.    defmodset modifiersout,
  932.    setup *result)
  933.  
  934. {
  935.    defmodset localmods, localmodsin, localmodsout;
  936.    setup begin_inner[3];
  937.    setup begin_outer;
  938.    int begin_outer_elongation;
  939.    int begin_xconc_elongation;
  940.    int final_elongation;
  941.    int center_arity;
  942.    setup result_inner[3];
  943.    setup result_outer;
  944.    int i, k;
  945.  
  946.    setup_kind orig_inners_start_kind;    /* The original info about the people who STARTED on the inside. */
  947.    int orig_inners_start_dirs;           /* We don't need rotation, since we will only use this if 2x2. */
  948.    int orig_inners_start_directions[8];
  949.  
  950.    setup_kind orig_outers_start_kind;    /* The original info about the people who STARTED on the outside. */
  951.    int orig_outers_start_dirs;           /* We don't need rotation, since we will only use this if 2x2. */
  952.    int orig_outers_start_directions[8];
  953.  
  954.    setup_kind final_outers_start_kind;   /* The original info about the people who will FINISH on the outside. */
  955.    int *final_outers_start_directions;
  956.  
  957.    int final_outers_finish_dirs;         /* The final info about the people who FINISHED on the outside. */
  958.    int final_outers_finish_directions[8];
  959.  
  960.    /* It is clearly too late to expand the matrix -- that can't be what is wanted. */
  961.    ss->setupflags |= SETUPFLAG__NO_EXPAND_MATRIX;
  962.  
  963.    for (i=0; i<8; i++) {
  964.       orig_inners_start_directions[i] =
  965.       orig_outers_start_directions[i] =
  966.       final_outers_finish_directions[i] = 0;
  967.    }
  968.  
  969.    localmodsin = modifiersin;
  970.    localmodsout = modifiersout;
  971.  
  972.    concentrify(ss, analyzer, begin_inner, &begin_outer, ¢er_arity, &begin_outer_elongation, &begin_xconc_elongation);
  973.  
  974.    /* Get initial info for the original ends. */
  975.    orig_outers_start_dirs = 0;
  976.    for (i=0; i<=setup_limits[begin_outer.kind]; i++) {
  977.       int q = begin_outer.people[i].id1;
  978.       orig_outers_start_dirs |= q;
  979.       orig_outers_start_directions[(q >> 6) & 07] = q;
  980.    }
  981.    orig_outers_start_kind = begin_outer.kind;
  982.  
  983.    /* Get initial info for the original centers. */
  984.    orig_inners_start_dirs = 0;
  985.    for (i=0; i<=setup_limits[begin_inner[0].kind]; i++) {
  986.       int q = begin_inner[0].people[i].id1;
  987.       orig_inners_start_dirs |= q;
  988.       orig_inners_start_directions[(q >> 6) & 07] = q;
  989.    }
  990.    orig_inners_start_kind = begin_inner[0].kind;
  991.  
  992.    if ((analyzer == schema_cross_concentric) || (analyzer == schema_single_cross_concentric)) {
  993.       setup temptemp = begin_inner[0];
  994.       begin_inner[0] = begin_outer;
  995.       begin_outer = temptemp;
  996.  
  997.       final_outers_start_kind = orig_inners_start_kind;
  998.       final_outers_start_directions = orig_inners_start_directions;
  999.    }
  1000.    else {
  1001.       final_outers_start_kind = orig_outers_start_kind;
  1002.       final_outers_start_directions = orig_outers_start_directions;
  1003.    }
  1004.  
  1005.    begin_inner[0].setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1006.    begin_inner[1].setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1007.    begin_inner[2].setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1008.  
  1009.    /* If the call turns out to be "detour", this will make it do just the ends part. */
  1010.    begin_outer.setupflags = ss->setupflags | SETUPFLAG__DISTORTED | SETUPFLAG__DOING_ENDS;
  1011.  
  1012.    /* There are two special pieces of information we now have that will help us decide where to
  1013.       put the outsides.  "Orig_outers_kind" tells what setup the outsides were originally in,
  1014.       and "begin_outer_elongation" is odd if the outsides were oriented vertically.
  1015.       "begin_outer_elongation" refers to absolute orientation, that is, "our" view of the
  1016.       setups, taking all rotations into account.  "Final_outers_start_dir" gives the individual
  1017.       orientations (absolute) of the people who are finishing on the outside.  Later, we will compute
  1018.       "final_outers_finish_dirs", telling how the individual people were oriented.  How we use all this
  1019.       information depends on many things that we will attend to below. */
  1020.  
  1021.    /* Giving one of the concept descriptor pointers as nil indicates that we don't want those people to do anything. */
  1022.  
  1023.    if (parsein) {
  1024.       for (k=0; k<center_arity; k++) {
  1025.          update_id_bits(&begin_inner[k]);
  1026.          move(&begin_inner[k], parsein, callspecin, final_conceptsin, FALSE, &result_inner[k]);
  1027.       }
  1028.    }
  1029.    else {
  1030.       for (k=0; k<center_arity; k++) {
  1031.          result_inner[k] = begin_inner[k];
  1032.          result_inner[k].setupflags = 0;
  1033.          /* Strip out the roll bits -- people who didn't move can't roll. */
  1034.          if (setup_limits[result_inner[k].kind] >= 0) {
  1035.             for (i=0; i<=setup_limits[result_inner[k].kind]; i++) {
  1036.                if (result_inner[k].people[i].id1) result_inner[k].people[i].id1 = (result_inner[k].people[i].id1 & (~ROLL_MASK)) | ROLLBITM;
  1037.             }
  1038.          }
  1039.       }
  1040.    }
  1041.  
  1042.    if (parseout) {
  1043.       /* If the ends' starting setup is a 2x2, and we did not say "concentric" (indicated by
  1044.          the "concentric rules" flag being off), we mark the setup as elongated.  If the call
  1045.          turns out to be a 2-person call, the elongation will be checked against the pairings
  1046.          of people, and an error will be given if it isn't right.  This is what makes "cy-kick"
  1047.          illegal from diamonds, and "ends hinge" illegal from waves.  The reason this is turned
  1048.          off when the "concentric" concept is given is so that "concentric hinge" from waves,
  1049.          obnoxious as it may be, will be legal.
  1050.       We also turn it off if this is reverse checkpoint.  In that case, the ends know exactly
  1051.          where they should go.  This is what makes "reverse checkpoint recycle by star thru"
  1052.          work from a DPT setup. */
  1053.  
  1054.       if (begin_outer.kind == s2x2 && analyzer != schema_rev_checkpoint &&
  1055.             !(begin_outer_elongation & ~1)) {      /* We demand elongation be 0 or 1. */
  1056.          begin_outer.setupflags |= ((begin_outer_elongation+1) * SETUPFLAG__ELONGATE_BIT);
  1057.  
  1058.          /* If "demand lines" or "demand columns" has been given, we suppress elongation
  1059.             checking.  In that case,
  1060.             the database author knows what elongation is required and is taking responsibility
  1061.             for it.  This is what makes "scamper" and "divvy up" work. */
  1062.  
  1063.          if ((dfm_conc_concentric_rules | dfm_conc_demand_lines | dfm_conc_demand_columns) & modifiersout)
  1064.             begin_outer.setupflags |= SETUPFLAG__NO_CHK_ELONG;
  1065.       }
  1066.  
  1067.       update_id_bits(&begin_outer);
  1068.       move(&begin_outer, parseout, callspecout, final_conceptsout, FALSE, &result_outer);
  1069.    }
  1070.    else {
  1071.       result_outer = begin_outer;
  1072.       result_outer.setupflags = 0;
  1073.       localmodsout |= dfm_conc_force_spots;      /* Make sure these people go to the same spots. */
  1074.       /* Strip out the roll bits -- people who didn't move can't roll. */
  1075.       if (setup_limits[result_outer.kind] >= 0) {
  1076.          for (i=0; i<=setup_limits[result_outer.kind]; i++) {
  1077.             if (result_outer.people[i].id1) result_outer.people[i].id1 = (result_outer.people[i].id1 & (~ROLL_MASK)) | ROLLBITM;
  1078.          }
  1079.       }
  1080.    }
  1081.  
  1082.    /* If the call was something like "ends detour", the concentricity info was left in the
  1083.       setupflags during the execution of the call, so we have to pick it up to make sure
  1084.       that the necessary "demand" and "force" bits are honored. */
  1085.    localmodsout |= (begin_outer.setupflags & DFM_CONCENTRICITY_FLAG_MASK);
  1086.  
  1087.    /* Check whether the necessary "demand" conditions are met.  First, set "localmods"
  1088.       to the demand info for the call that the original ends did.  Where this comes from
  1089.       depends on whether the schema is cross concentric. */
  1090.  
  1091.    if ((analyzer == schema_cross_concentric) || (analyzer == schema_single_cross_concentric)) {
  1092.       localmods = localmodsin;      /* Yes!  "In" describes the call for the original ends. */
  1093.    }
  1094.    else {
  1095.       localmods = localmodsout;
  1096.    }
  1097.  
  1098.    if ((dfm_conc_demand_lines & localmods) && (orig_outers_start_kind == s2x2)) {
  1099.       /* We make use of the fact that the setup, being a 2x2, is canonicalized. */
  1100.       if ((begin_outer_elongation < 0) ||
  1101.             (orig_outers_start_dirs & (1 << 3*(begin_outer_elongation & 1))))
  1102.          fail("Outsides must be as if in lines at start of this call.");
  1103.    }
  1104.    
  1105.    if ((dfm_conc_demand_columns & localmods) && (orig_outers_start_kind == s2x2)) {
  1106.       if ((begin_outer_elongation < 0) ||
  1107.             (orig_outers_start_dirs & (8 >> 3*(begin_outer_elongation & 1))))
  1108.          fail("Outsides must be as if in columns at start of this call.");
  1109.    }
  1110.  
  1111.    /* Now check whether there are any demands on the original centers.  The interpretation
  1112.       of "lines" and "columns" is slightly different in this case.  We apply the test only if
  1113.       the centers are in a 2x2, but we don't care about the outsides' setup, as long as it
  1114.       has a measurable elongation.  If the outsides are also in a 2x2, so that the whole setup
  1115.       is a 2x4, these tests will do just what they say -- they will check whether the centers
  1116.       believe they are in lines or columns.  However, if the outsides are in a 1x4, so the
  1117.       overall setup is a "rigger", we simply test the outsides' elongation.  In such a case
  1118.       "demand lines" means "demand outsides lateral to me". */
  1119.  
  1120.    if ((analyzer == schema_cross_concentric) || (analyzer == schema_single_cross_concentric)) {
  1121.       localmods = localmodsout;
  1122.    }
  1123.    else {
  1124.       localmods = localmodsin;
  1125.    }
  1126.  
  1127.    if ((dfm_conc_demand_lines & localmods) && (orig_inners_start_kind == s2x2)) {
  1128.       if ((begin_outer_elongation < 0) ||
  1129.             (orig_inners_start_dirs & (1 << 3*(begin_outer_elongation & 1))))
  1130.          fail("Centers must be as if in lines at start of this call.");
  1131.    }
  1132.    
  1133.    if ((dfm_conc_demand_columns & localmods) && (orig_inners_start_kind == s2x2)) {
  1134.       if ((begin_outer_elongation < 0) ||
  1135.             (orig_inners_start_dirs & (8 >> 3*(begin_outer_elongation & 1))))
  1136.          fail("Centers must be as if in columns at start of this call.");
  1137.    }
  1138.  
  1139.    localmods = localmodsout;
  1140.  
  1141.    final_outers_finish_dirs = 0;
  1142.    for (i=0; i<=setup_limits[result_outer.kind]; i++) {
  1143.       int q = result_outer.people[i].id1;
  1144.       final_outers_finish_dirs |= q;
  1145.       final_outers_finish_directions[(q >> 6) & 07] = q;
  1146.    }
  1147.  
  1148.    /* Now final_outers_finish_dirs tells whether outer peoples' orientations changed.
  1149.       This is only meaningful if outer setup is 2x2.  Note that, if the setups
  1150.       are 2x2's, canonicalization sets their rotation to zero, so the
  1151.       tbonetest quantities refer to absolute orientation. */
  1152.    
  1153.    /* The time has come to compute the elongation of the outsides in the final setup.
  1154.       This gets complicated if the outsides' final setup is a 2x2.  Among the
  1155.       procedures we could use are:
  1156.          (1) if the call is "checkpoint", go to spots with opposite elongation
  1157.             from the original outsides' elongation.  This is the "Hodson checkpoint
  1158.             rule", named after the caller who first used a consistent, methodical,
  1159.             and universal rule for the checkpoint concept.
  1160.          (2) if the call is "concentric", use the Hodson rule if the original setup
  1161.             was a 1x4 or diamond, or the "lines-to-lines, columns-to-columns" rule
  1162.             if the original setup was a 2x2.
  1163.          (3) if we have various definition flags, such as "force_lines" or
  1164.             "force_otherway", obey them.
  1165.       We will use information from several sources in carrying out these rules.
  1166.       The concentric concept will signify itself by turning on the "lines_lines"
  1167.       flag.  The checkpoint concept will signify itself by turning on the
  1168.       "force_otherway" flag.  The "parallel_conc_end" flag in the outsides' setup
  1169.       indicates that, if "concentric" or "checkpoint" are NOT being used, the call
  1170.       wants the outsides to maintain the same elongation as they had at the beginning.
  1171.       This is what makes "ends hinge" and "ends recycle" do their respective
  1172.       right things when called from a grand wave. */
  1173.  
  1174.    /* Default: the ends just keep their original elongation.  This will often
  1175.       mean that they stay on their spots. */
  1176.  
  1177.    if ((analyzer == schema_cross_concentric) || (analyzer == schema_single_cross_concentric))
  1178.       final_elongation = begin_xconc_elongation;
  1179.    else
  1180.       final_elongation = begin_outer_elongation;
  1181.  
  1182.    /* Note: final_elongation might be -1 now, meaning that the people on the outside
  1183.       cannot determine their elongation from the original setup.  Unless their
  1184.       final setup is one that does not require knowing the value of final_elongation,
  1185.       it is an error. */
  1186.  
  1187.    if (result_outer.kind == nothing) {
  1188.       if (result_inner[0].kind == nothing) {
  1189.          result->kind = nothing;    /* If everyone is a phantom, it's simple. */
  1190.          return;
  1191.       }
  1192.  
  1193.       /* If the schema is one of the special ones, we will know what to do. */
  1194.       if (  analyzer == schema_conc_star ||
  1195.             analyzer == schema_ckpt_star ||
  1196.             analyzer == schema_conc_star12 ||
  1197.             analyzer == schema_conc_star16) {
  1198.  
  1199.          /* This is what makes 12 matrix relay the top work when everyone is
  1200.             in the stars. */
  1201.  
  1202.          result_outer.kind = s1x4;
  1203.          clear_people(&result_outer);
  1204.          result_outer.setupflags = 0;
  1205.          result_outer.rotation = ss->rotation;
  1206.       }
  1207.       else if (analyzer == schema_concentric_diamond_line) {
  1208.          if (ss->kind == s_wingedstar || ss->kind == s_wingedstar12 || ss->kind == s_wingedstar16) {
  1209.             result_outer.kind = s2x2;
  1210.             result_outer.rotation = 0;
  1211.             clear_people(&result_outer);
  1212.             /* Set their "natural" elongation perpendicular to their original diamond.
  1213.                The test for this is 1P2P; touch 1/4; column circ; boys truck; split phantom
  1214.                lines tag chain thru reaction.  They should finish in outer triple boxes,
  1215.                not a 2x4. */
  1216.             result_outer.setupflags = (result_inner[0].setupflags & ~RESULTFLAG__ELONGATE_MASK) |
  1217.                   (((~ss->rotation & 1) + 1) * RESULTFLAG__ELONGATE_BIT);
  1218.          }
  1219.          else
  1220.             goto no_end_err;
  1221.       }
  1222.       else {
  1223.          /* We may be in serious trouble -- we have to figure out what setup the ends
  1224.             finish in, and they are all phantoms.  We can save the day only if we
  1225.             can convince ourselves that they did the call "nothing".  We make use
  1226.             of the fact that "concentrify" did NOT flush them, so we still know
  1227.             what their starting setup was.
  1228.          This is what makes split phantom diamonds diamond chain through work
  1229.             from columns far apart. */
  1230.    
  1231.          result_outer = begin_outer;               /* Restore the original bunch of phantoms. */
  1232.          /* Make sure these people go to the same spots, and remove possibly misleading info. */
  1233.          localmods |= dfm_conc_force_spots;
  1234.          localmods &= ~(dfm_conc_force_lines | dfm_conc_force_columns | dfm_conc_force_otherway);
  1235.    
  1236.          if (parseout && callspecout && (callspecout->schema == schema_nothing))
  1237.             ;        /* It's OK. */
  1238.          else if (center_arity > 1)
  1239.             ;        /* It's OK. */
  1240.          else {
  1241.             /* We simply have no idea where the outsides should be.  We
  1242.                simply contract the setup to a 4-person setup (or whatever),
  1243.                throwing away the outsides completely.  If this was an
  1244.                "on your own", it may be possible to put things back together.
  1245.                This is what makes "1P2P; pass thru; ENDS leads latch on;
  1246.                ON YOUR OWN disband & snap the lock" work.  But if we try to glue
  1247.                these setups together, "fix_n_results" will raise an error, since
  1248.                it won't know whether to leave room for the phantoms. */
  1249.  
  1250.             *result = result_inner[0];   /* This gets all the inner people. */
  1251.             result->kind = s_normal_concentric;
  1252.             result->inner.skind = result_inner[0].kind;
  1253.             result->inner.srotation = result_inner[0].rotation;
  1254.             result->outer.skind = nothing;
  1255.             result->outer.srotation = 0;
  1256.             result->outer_elongation = 0;
  1257.             canonicalize_rotation(result);
  1258.             return;
  1259.          }
  1260.       }
  1261.    }
  1262.    else if (result_inner[0].kind == nothing) {
  1263.       /* If the schema is one of the special ones, we will know what to do. */
  1264.       if (  analyzer == schema_conc_star ||
  1265.             analyzer == schema_ckpt_star ||
  1266.             analyzer == schema_conc_star12 ||
  1267.             analyzer == schema_conc_star16) {
  1268.                   ;        /* Take no action. */
  1269.       }
  1270.       /* If the ends are a 2x2, we just set the missing centers to a 2x2.
  1271.          The ends had better know their elongation, of course.  It shouldn't
  1272.          matter to the ends whether the phantoms in the center did something
  1273.          that leaves the whole setup as diamonds or as a 2x4.  (Some callers
  1274.          might think it matters (Hi, Clark!) but it doesn't matter to this program.)
  1275.          This is what makes split phantom diamonds diamond chain through work
  1276.          from a grand wave. */
  1277.       else if (result_outer.kind == s2x2 && center_arity == 1) {
  1278.          result_inner[0].kind = s2x2;
  1279.          clear_people(&result_inner[0]);
  1280.          result_inner[0].setupflags = 0;
  1281.          result_inner[0].rotation = 0;
  1282.       }
  1283.       /* If the ends are a 1x4, we just set the missing centers to a 1x4,
  1284.          so the entire setup is a 1x8.  Maybe the phantoms went to a 2x2,
  1285.          so the setup is really a rigger, but we don't care.  See the comment
  1286.          just above.  This is what makes "1P2P; pass thru; ENDS leads latch on;
  1287.          ON YOUR OWN disband & snap the lock" work. */
  1288.       else if (result_outer.kind == s1x4 && center_arity == 1) {
  1289.          result_inner[0].kind = s2x2;
  1290.          clear_people(&result_inner[0]);
  1291.          result_inner[0].setupflags = 0;
  1292.          result_inner[0].rotation = result_outer.rotation;
  1293.       }
  1294.       else {
  1295.          /* The centers are just gone!  It is quite possible that "fix_n_results"
  1296.             may be able to repair this damage by copying some info from another setup.
  1297.             Missing centers are not as serious as missing ends, because they won't
  1298.             lead to indecision about whether to leave space for the phantoms. */
  1299.  
  1300.          int j;
  1301.          result->kind = s_normal_concentric;
  1302.          result->outer.skind = result_outer.kind;
  1303.          result->outer.srotation = result_outer.rotation;
  1304.          result->inner.skind = nothing;
  1305.          result->inner.srotation = 0;
  1306.          result->outer_elongation = 0;
  1307.  
  1308.          for (j=0; j<12; j++) (void) copy_person(result, j+12, &result_outer, j);
  1309.          canonicalize_rotation(result);
  1310.          return;
  1311.       }
  1312.    }
  1313.  
  1314. /* ***** We used to have this:
  1315.    if (result_outer.kind == s_short6) {
  1316.       switch (final_outers_start_kind) {
  1317.          case s_bone6:
  1318.             final_elongation ^= 1;     Natural elongation is wrong way!!
  1319.             break;
  1320.       }
  1321.    }
  1322. which is wrong.  The fact that short6 has a funny definition is taken care of in
  1323. normalize_concentric.  This code was making "outer 6 convert the triangle" fail
  1324. from a bone (heads left swing thru, side girl turn back).
  1325. ***** */
  1326.  
  1327.    /* At this point, "final_elongation" actually has the INITIAL elongation of the
  1328.       people who finished on the outside.  That is, if they went from a wave or diamond
  1329.       to a 2x2, it has the elongation of their initial wave or diamond points.
  1330.       
  1331.       The elongation bits in their setup tells how they "naturally" wanted to end,
  1332.       based on the call they did, how it got divided up, whether it had the "parallel_conc_end"
  1333.       flag on, etc.
  1334.       
  1335.       We will use both pieces of information to figure out how to elongate the outsides at
  1336.       the conclusion of the call.  For example, if the word "concentric" was not spoken,
  1337.       we will just use their "natural" elongation from the setup.  This is what makes
  1338.       "ends hinge" work from a grand wave.  If the word "concentric" was spoken, their
  1339.       natural elongation is discarded, and we will set them perpendicular to their
  1340.       original 1x4 or diamond, using the value in "final_elongation"  If invocation
  1341.       flags like "force lines" or "force columns" are present, we will use those.
  1342.       
  1343.       When we are done, our final judgement will be put back into the variable
  1344.       "final_elongation". */
  1345.  
  1346.    if (result_outer.kind == s2x2) {
  1347.       int *concwarntable = (final_outers_start_kind == s1x4) ? concwarn1x4table : concwarndmdtable;
  1348.  
  1349.       switch (final_outers_start_kind) {
  1350.          case s1x4: case sdmd:
  1351.  
  1352.             /* Outers' call has gone from a 1x4 or diamond to a 2x2.  The rules are:
  1353.                (1) The "force_columns" or "force_lines" flag in the invocation takes precedence
  1354.                   over anything else.
  1355.                (2) If the "concentric rules" flag is on (that flag is a euphemism for "the
  1356.                   concentric or checkpoint concept is explicitly in use here"), we set the
  1357.                   elongation perpendicular to the original 1x4 or diamond.
  1358.                (3) If the "force_otherway" invocation flag is on, meaning the database
  1359.                   really wants us to, we set the elongation perpendicular to the original
  1360.                   1x4 or diamond.  *** Actually, it appears that this flag is meaningless
  1361.                   for 1x4/dmd -> 2x2 calls, and the "par_conc_end" does this function
  1362.                (4) Otherwise, we set the elongation to the natural elongation that the people
  1363.                   went to.  This uses the result of the "par_conc_end" flag for 1x4/dmd -> 2x2
  1364.                   calls, or the manner in which the setup was divided for calls that were put
  1365.                   together from 2-person calls, or whatever.  (For 1x4->2x2 calls, the "par_conc_end"
  1366.                   flag means the call prefers the SAME elongation in the resulting 2x2.  The default,
  1367.                   absent this flag, is to change the elongation.  In any case, the result of all that
  1368.                   has been encoded into the elongation of the 2x2 setup that the people went to;
  1369.                   we just have to obey. */
  1370.  
  1371.             if (dfm_conc_force_lines & localmods) {
  1372.                if ((final_outers_finish_dirs & 011) == 011)
  1373.                   fail("Can't force ends to be as in lines - they are T-boned.");
  1374.                final_elongation = final_outers_finish_dirs & 1;
  1375.             }
  1376.             else if (dfm_conc_force_columns & localmods) {
  1377.                if ((final_outers_finish_dirs & 011) == 011)
  1378.                   fail("Can't force ends to be as in columns - they are T-boned.");
  1379.                final_elongation = (final_outers_finish_dirs+1) & 1;
  1380.             }
  1381.             else if ((dfm_conc_concentric_rules | dfm_conc_force_otherway) & localmods) {
  1382.                if (analyzer == schema_cross_concentric)
  1383.                   warn(concwarntable[0]);
  1384.                else
  1385.                   warn(concwarntable[1]);
  1386.  
  1387.                final_elongation ^= 1;
  1388.             }
  1389.             else {
  1390.                /* Get the elongation from the result setup, if possible. */
  1391.                unsigned long int newelong = ((result_outer.setupflags & RESULTFLAG__ELONGATE_MASK) / RESULTFLAG__ELONGATE_BIT) - 1;
  1392.  
  1393.                if (result_outer.setupflags & RESULTFLAG__ELONGATE_MASK) {
  1394.                   if (final_elongation == newelong) {
  1395.                      warn(concwarntable[2]);
  1396.                   }
  1397.                   else {
  1398.                      if (analyzer == schema_cross_concentric)
  1399.                         warn(concwarntable[0]);
  1400.                      else
  1401.                         warn(concwarntable[1]);
  1402.                   }
  1403.                }
  1404.  
  1405.                final_elongation = newelong;
  1406.             }
  1407.  
  1408.             break;
  1409.          case s2x2:
  1410.             /* If call went from 2x2 to 2x2, the rules are:
  1411.                First, check for "force_columns" or "force_lines" in the invocation.  This is not
  1412.                   a property of the call that we did, but of the way its parent (or the concept) invoked it.
  1413.                Second, check for "force_spots" or "force_otherway" in the invocation.  This is not
  1414.                   a property of the call that we did, but of the way its parent (or the concept) invoked it.
  1415.                Third, check for "lines_lines" in the invocation.  This is not
  1416.                   a property of the call that we did, but of the way its parent (or the concept) invoked it.
  1417.                   If the concept was "concentric", it will be on, of course.
  1418.                Finally, check the elongation bits in the result flags left over from the call.  These tell
  1419.                   whether to work to spots, or antispots, or whatever, based what the call was, and whether
  1420.                   it, or various sequential parts of it, had the "parallel_conc_end" flag on.
  1421.                If there are no elongation bits, we simply don't know waht to do.
  1422.  
  1423.                Note that the "ends do thus-and-so" concept does NOT set the lines_lines flag in the
  1424.                   invocation, so we work to spots unless the call says "parallel_conc_end".  Counter-rotate,
  1425.                   for example, says "parallel_conc_end", so it works to antispots. */
  1426.  
  1427.             if (dfm_conc_force_lines & localmods) {
  1428.                if ((final_outers_finish_dirs & 011) == 011)
  1429.                   fail("Can't force ends to be as in lines - they are T-boned.");
  1430.                final_elongation = final_outers_finish_dirs & 1;
  1431.             }
  1432.             else if (dfm_conc_force_columns & localmods) {
  1433.                if ((final_outers_finish_dirs & 011) == 011)
  1434.                   fail("Can't force ends to be as in columns - they are T-boned.");
  1435.                final_elongation = (final_outers_finish_dirs+1) & 1;
  1436.             }
  1437.             else if (dfm_conc_force_otherway & localmods)
  1438.                final_elongation ^= 1;
  1439.             else if (dfm_conc_force_spots & localmods)
  1440.                ;           /* It's OK the way it is. */
  1441.             else if (dfm_conc_concentric_rules & localmods) {       /* do "lines-to-lines / columns-to-columns" */
  1442.                int new_elongation = -1;
  1443.  
  1444.                for (i=0; i<8; i++) {
  1445.                   if (final_outers_finish_directions[i]) {
  1446.                      int t = (final_outers_start_directions[i] ^ final_outers_finish_directions[i] ^ final_elongation) & 1;
  1447.                      if (t != new_elongation) {
  1448.                         if (new_elongation >= 0)
  1449.                            fail("Sorry, outsides would have to go to a 'pinwheel', can't handle that.");
  1450.                         new_elongation = t;
  1451.                      }
  1452.                   }
  1453.                }
  1454.  
  1455.                /* The warning "warn__ends_work_to_spots" is now obsolete. */
  1456.  
  1457.                final_elongation = new_elongation;
  1458.             }
  1459.             else
  1460.                final_elongation = ((result_outer.setupflags & RESULTFLAG__ELONGATE_MASK) / RESULTFLAG__ELONGATE_BIT) - 1;
  1461.  
  1462.             break;
  1463.          default:
  1464.             fail("Don't recognize starting setup.");
  1465.       }
  1466.    }
  1467.  
  1468.    /* Now lossage in "final_elongation" may have been repaired.  If it is still
  1469.       negative, there may be trouble ahead. */
  1470.  
  1471.    normalize_concentric(analyzer, center_arity, result_inner, &result_outer, final_elongation, result);
  1472.    return;
  1473.  
  1474.    no_end_err:
  1475.    fail("Can't figure out ending setup for concentric call -- no ends.");
  1476. }
  1477.  
  1478.  
  1479. /* This overwrites its first argument setup. */
  1480. extern void merge_setups(setup *ss, setup *result)
  1481. {
  1482.    int i, r, rot, offs, limit, lim1, limhalf;
  1483.    setup res2copy;
  1484.    setup *res1, *res2;
  1485.  
  1486.    res2copy = *result;
  1487.    res1 = ss;
  1488.    res2 = &res2copy;
  1489.  
  1490.    canonicalize_rotation(res1);    /* Do we really need to do this before normalize_setup? */
  1491.    normalize_setup(res1, normalize_before_merge);
  1492.    canonicalize_rotation(res1);    /* We definitely need to do it now -- a 2x2 might have been created. */
  1493.  
  1494.    tryagain:
  1495.  
  1496.    canonicalize_rotation(res2);
  1497.    normalize_setup(res2, normalize_before_merge);
  1498.    canonicalize_rotation(res2);
  1499.  
  1500.    /* Canonicalize the setups according to their kind.  This is a bit sleazy, since
  1501.       the enumeration order of setup kinds is supposed to be insignificant.  We depend in
  1502.       general on small setups being before larger ones.  In particular, we seem to require:
  1503.          s2x2 < s2x4
  1504.          s2x2 < s2x6
  1505.          s2x2 < s1x8
  1506.          s1x4 < s1x8
  1507.          s1x4 < s2x4
  1508.          s2x4 < s_c1phan
  1509.          s2x4 < s2x6
  1510.       You get the idea. */
  1511.  
  1512.    if (res2->kind < res1->kind) {
  1513.       setup *temp = res2;
  1514.       res2 = res1;
  1515.       res1 = temp;
  1516.    }
  1517.  
  1518.    /* If one of the setups was a "concentric" setup in which there are no ends, we can still handle it. */
  1519.  
  1520.    if (res2->kind == s_normal_concentric) {
  1521.       res2->kind = res2->inner.skind;
  1522.       res2->rotation = res2->inner.srotation;
  1523.       goto tryagain;    /* Need to recanonicalize setup order. */
  1524.    }
  1525.  
  1526.    result->rotation = res2->rotation;
  1527.  
  1528.    r = (res1->rotation - res2->rotation) & 3;
  1529.    rot = r * 011;
  1530.    
  1531.    if (res1->kind == nothing) {
  1532.       *result = *res2;
  1533.       return;
  1534.    }
  1535.    else if ((res1->kind == s2x4) && (res2->kind == s2x4) && (r&1)) {
  1536.       offs = r * 2;
  1537.       if ((((res1->people[0].id1 & res1->people[1].id1 & res1->people[4].id1 & res1->people[5].id1) |
  1538.                (res1->people[2].id1 & res1->people[3].id1 & res1->people[6].id1 & res1->people[7].id1)) & BIT_PERSON) &&
  1539.          (((res2->people[0].id1 & res2->people[1].id1 & res2->people[4].id1 & res2->people[5].id1) |
  1540.                (res2->people[2].id1 & res2->people[3].id1 & res2->people[6].id1 & res2->people[7].id1)) & BIT_PERSON)) {
  1541.          result->kind = s_c1phan;
  1542.          (void) copy_person(result, 10, res2, 5);
  1543.          (void) copy_person(result, 5, res2, 3);
  1544.          (void) copy_person(result, 13, res2, 7);
  1545.          (void) copy_person(result, 7, res2, 2);
  1546.          (void) copy_person(result, 2, res2, 1);
  1547.          (void) copy_person(result, 8, res2, 4);
  1548.          (void) copy_person(result, 15, res2, 6);
  1549.          clear_person(result, 1);
  1550.          clear_person(result, 3);
  1551.          clear_person(result, 4);
  1552.          clear_person(result, 6);
  1553.          clear_person(result, 9);
  1554.          clear_person(result, 11);
  1555.          clear_person(result, 12);
  1556.          clear_person(result, 14);
  1557.          install_rot(result, 11, res1, 0^offs, rot);
  1558.          install_rot(result, 9, res1, 1^offs, rot);
  1559.          install_rot(result, 4, res1, 2^offs, rot);
  1560.          install_rot(result, 6, res1, 3^offs, rot);
  1561.          install_rot(result, 3, res1, 4^offs, rot);
  1562.          install_rot(result, 1, res1, 5^offs, rot);
  1563.          install_rot(result, 12, res1, 6^offs, rot);
  1564.          install_rot(result, 14, res1, 7^offs, rot);
  1565.       }
  1566.       else {
  1567.          result->kind = s4x4;
  1568.          clear_person(result, 12);
  1569.          clear_person(result, 13);
  1570.          clear_person(result, 14);
  1571.          clear_person(result, 0);
  1572.          clear_person(result, 4);
  1573.          clear_person(result, 5);
  1574.          clear_person(result, 6);
  1575.          clear_person(result, 8);
  1576.          (void) copy_person(result, 10, res2, 0);
  1577.          (void) copy_person(result, 15, res2, 1);
  1578.          (void) copy_person(result, 3, res2, 2);
  1579.          (void) copy_person(result, 1, res2, 3);
  1580.          (void) copy_person(result, 2, res2, 4);
  1581.          (void) copy_person(result, 7, res2, 5);
  1582.          (void) copy_person(result, 11, res2, 6);
  1583.          (void) copy_person(result, 9, res2, 7);
  1584.  
  1585.          install_rot(result, 7, res1, 0^offs, rot);
  1586.          install_rot(result, 5, res1, 1^offs, rot);
  1587.          install_rot(result, 14, res1, 2^offs, rot);
  1588.          install_rot(result, 3, res1, 3^offs, rot);
  1589.          install_rot(result, 15, res1, 4^offs, rot);
  1590.          install_rot(result, 13, res1, 5^offs, rot);
  1591.          install_rot(result, 6, res1, 6^offs, rot);
  1592.          install_rot(result, 11, res1, 7^offs, rot);
  1593.       }
  1594.       return;
  1595.    }
  1596.    else if (res2->kind == s_c1phan && res1->kind == s2x4) {
  1597.       result->kind = s_c1phan;
  1598.       for (i=0; i<16; i++)
  1599.          (void) copy_person(result, i, res2, i);
  1600.  
  1601.       result->rotation -= r;
  1602.       canonicalize_rotation(result);
  1603.  
  1604.       install_person(result, 0, res1, 0);
  1605.       install_person(result, 2, res1, 1);
  1606.       install_person(result, 7, res1, 2);
  1607.       install_person(result, 5, res1, 3);
  1608.       install_person(result, 8, res1, 4);
  1609.       install_person(result, 10, res1, 5);
  1610.       install_person(result, 15, res1, 6);
  1611.       install_person(result, 13, res1, 7);
  1612.  
  1613.       result->rotation += r;
  1614.       canonicalize_rotation(result);
  1615.       return;
  1616.    }
  1617.    else if (res2->kind == s2x4 && res1->kind == s2x2) {
  1618.       result->kind = s2x4;
  1619.       for (i=0; i<8; i++)
  1620.          (void) copy_person(result, i, res2, i);
  1621.  
  1622.       res1->rotation += r;
  1623.       canonicalize_rotation(res1);
  1624.  
  1625.       install_person(result, 1, res1, 0);
  1626.       install_person(result, 2, res1, 1);
  1627.       install_person(result, 5, res1, 2);
  1628.       install_person(result, 6, res1, 3);
  1629.  
  1630.       canonicalize_rotation(result);
  1631.       return;
  1632.    }
  1633.    else if (res2->kind == s2x6 && res1->kind == s2x2) {
  1634.       result->kind = s2x6;
  1635.       for (i=0; i<12; i++)
  1636.          (void) copy_person(result, i, res2, i);
  1637.  
  1638.       res1->rotation += r;
  1639.       canonicalize_rotation(res1);
  1640.  
  1641.       install_person(result, 2, res1, 0);
  1642.       install_person(result, 3, res1, 1);
  1643.       install_person(result, 8, res1, 2);
  1644.       install_person(result, 9, res1, 3);
  1645.  
  1646.       canonicalize_rotation(result);
  1647.       return;
  1648.    }
  1649.    else if (res2->kind == s1x8 && res1->kind == s2x2 && (!(res2->people[2].id1 | res2->people[3].id1 | res2->people[6].id1 | res2->people[7].id1))) {
  1650.       res2->kind = s1x4;
  1651.       (void) copy_person(res2, 2, res2, 4);
  1652.       (void) copy_person(res2, 3, res2, 5);
  1653.       normalize_concentric(schema_concentric, 1, res1, res2, 0, result);
  1654.       return;
  1655.    }
  1656.    else if (res2->kind == s1x8 && res1->kind == s1x4 && (!(res2->people[2].id1 | res2->people[3].id1 | res2->people[6].id1 | res2->people[7].id1))) {
  1657.       res2->kind = s1x4;
  1658.       (void) copy_person(res2, 2, res2, 4);
  1659.       (void) copy_person(res2, 3, res2, 5);
  1660.       normalize_concentric(schema_concentric, 1, res1, res2, 0, result);
  1661.       return;
  1662.    }
  1663.    else if (res2->kind == s2x4 && res1->kind == s1x4 && (!(res2->people[1].id1 | res2->people[2].id1 | res2->people[5].id1 | res2->people[6].id1))) {
  1664.       int outer_elongation = res2->rotation & 1;
  1665.       res2->kind = s2x2;
  1666.       (void) copy_person(res2, 1, res2, 3);
  1667.       (void) copy_person(res2, 2, res2, 4);
  1668.       (void) copy_person(res2, 3, res2, 7);
  1669.       canonicalize_rotation(res2);
  1670.       normalize_concentric(schema_concentric, 1, res1, res2, outer_elongation, result);
  1671.       return;
  1672.    }
  1673.    else if (res2->kind == s2x6 && res1->kind == s2x4 && (r == 0)) {
  1674.       /* Because of canonicalization, we know that r = 0 unless
  1675.          they are 90 degrees from each other. */
  1676.       result->kind = s2x6;
  1677.       for (i=0; i<12; i++)
  1678.          (void) copy_person(result, i, res2, i);
  1679.  
  1680.       install_person(result, 1, res1, 0);
  1681.       install_person(result, 2, res1, 1);
  1682.       install_person(result, 3, res1, 2);
  1683.       install_person(result, 4, res1, 3);
  1684.       install_person(result, 7, res1, 4);
  1685.       install_person(result, 8, res1, 5);
  1686.       install_person(result, 9, res1, 6);
  1687.       install_person(result, 10, res1, 7);
  1688.       return;
  1689.    }
  1690.    
  1691.    /* This is sleazy. */
  1692.  
  1693.    limit = setup_limits[res1->kind];
  1694.    lim1 = limit+1;
  1695.    limhalf = lim1 >> 1;
  1696.  
  1697.    /* The only remaining hope is that the setups match and we can blindly combine them.  We require
  1698.       lim1 even because our 180 degree rotation wouldn't work for triangles. */
  1699.  
  1700.    if (res1->kind != res2->kind || r & 1 || limit < 0 || lim1 & 1)
  1701.       fail("Can't figure out result setup.");
  1702.    
  1703.    *result = *res2;
  1704.  
  1705.    if (r) {
  1706.       for (i=0; i<limit+1; i++)
  1707.          install_rot(result, i, res1, (i+limhalf) % lim1, rot);
  1708.    }
  1709.    else {
  1710.       for (i=0; i<limit+1; i++)
  1711.          install_person(result, i, res1, i);
  1712.    }
  1713. }
  1714.  
  1715.  
  1716. extern void on_your_own_move(
  1717.    setup *ss,
  1718.    parse_block *parseptr,
  1719.    setup *result)
  1720.  
  1721. {
  1722.    setup setup1, setup2, res1;
  1723.  
  1724.    if (ss->kind != s2x4) fail("Must have 2x4 setup for 'on your own'.");
  1725.    
  1726.    setup1 = *ss;              /* Get outers only. */
  1727.    clear_person(&setup1, 1);
  1728.    clear_person(&setup1, 2);
  1729.    clear_person(&setup1, 5);
  1730.    clear_person(&setup1, 6);
  1731.    setup1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1732.    move(&setup1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  1733.    
  1734.    setup2 = *ss;              /* Get inners only. */
  1735.    clear_person(&setup2, 0);
  1736.    clear_person(&setup2, 3);
  1737.    clear_person(&setup2, 4);
  1738.    clear_person(&setup2, 7);
  1739.    setup2.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  1740.    move(&setup2, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, result);
  1741.    
  1742.    merge_setups(&res1, result);
  1743. }
  1744.  
  1745.  
  1746.  
  1747. extern void so_and_so_only_move(
  1748.    setup *ss,
  1749.    parse_block *parseptr,
  1750.    setup *result)
  1751.  
  1752. {
  1753.    selector_kind saved_selector;
  1754.    int i;
  1755.    long_boolean others;
  1756.    setup setup1, setup2, res1;
  1757.  
  1758.    saved_selector = current_selector;
  1759.    others = parseptr->concept->value.arg1;
  1760.    current_selector = parseptr->selector;
  1761.  
  1762.    setup1 = *ss;              /* designees */
  1763.    setup2 = *ss;              /* non-designees */
  1764.    
  1765.    if (setup_limits[ss->kind] < 0) fail("Can't identify people in this setup.");
  1766.    for (i=0; i<setup_limits[ss->kind]+1; i++) {
  1767.       if (ss->people[i].id1) {
  1768.          if (selectp(ss, i))
  1769.             clear_person(&setup2, i);
  1770.          else
  1771.             clear_person(&setup1, i);
  1772.       }
  1773.    }
  1774.    
  1775.    current_selector = saved_selector;
  1776.    
  1777.    normalize_setup(&setup1, normalize_before_isolated_call);
  1778.    normalize_setup(&setup2, normalize_before_isolated_call);
  1779.    setup1.setupflags = ss->setupflags;
  1780.    setup2.setupflags = ss->setupflags;
  1781.    
  1782.    move(&setup1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  1783.    
  1784.    if (others) {
  1785.       move(&setup2, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, result);
  1786.  
  1787.       if ((res1.setupflags ^ result->setupflags) & RESULTFLAG__DID_LAST_PART)
  1788.          fail("Two calls must use the same number of fractions.");
  1789.    
  1790.       result->setupflags |= res1.setupflags;
  1791.    }
  1792.    else {
  1793.       *result = setup2;
  1794.       result->setupflags = res1.setupflags;
  1795.    }
  1796.  
  1797.    merge_setups(&res1, result);
  1798. }
  1799.