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 / sdistort.c < prev    next >
C/C++ Source or Header  |  1992-10-10  |  31KB  |  819 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 version 24.0. */
  20.  
  21. /* This defines the following functions:
  22.    distorted_2x2s_move
  23.    distorted_move
  24.    triple_twin_move
  25.    do_concept_rigger
  26.    do_concept_callrigger
  27. */
  28.  
  29.  
  30. #include "sd.h"
  31.  
  32.  
  33.  
  34. static int list_10_6_5_4[4] = {8, 6, 5, 4};
  35. static int list_11_13_7_2[4] = {9, 11, 7, 2};
  36. static int list_12_17_3_1[4] = {10, 15, 3, 1};
  37. static int list_14_15_16_0[4] = {12, 13, 14, 0};
  38. static int list_14_12_11_10[4] = {12, 10, 9, 8};
  39. static int list_15_17_13_6[4] = {13, 15, 11, 6};
  40. static int list_16_3_7_5[4] = {14, 3, 7, 5};
  41. static int list_0_1_2_4[4] = {0, 1, 2, 4};
  42.  
  43.  
  44. extern void distorted_2x2s_move(
  45.    setup *ss,
  46.    parse_block *parseptr,
  47.    setup *result)
  48.  
  49. {
  50.    /* maps for 4x4 Z's */
  51.    static int map1[16] = {12, 15, 11, 10, 3, 2, 4, 7, 12, 3, 7, 10, 15, 2, 4, 11};
  52.    static int map2[16] = {12, 13, 3, 15, 11, 7, 4, 5, 12, 13, 7, 11, 15, 3, 4, 5};
  53.    static int map3[16] = {14, 1, 2, 3, 10, 11, 6, 9, 11, 1, 2, 6, 10, 14, 3, 9};
  54.    static int map4[16] = {13, 14, 1, 3, 9, 11, 5, 6, 13, 14, 11, 9, 3, 1, 5, 6};
  55.    static int map5[16] = {10, 13, 15, 9, 7, 1, 2, 5, 10, 7, 5, 9, 13, 1, 2, 15};
  56.    static int map6[16] = {13, 14, 15, 10, 7, 2, 5, 6, 13, 14, 2, 7, 10, 15, 5, 6};
  57.    static int map7[16] = {3, 0, 1, 7, 9, 15, 11, 8, 15, 0, 1, 11, 9, 3, 7, 8};
  58.    static int map8[16] = {14, 0, 3, 15, 11, 7, 6, 8, 14, 0, 7, 11, 15, 3, 6, 8};
  59.  
  60.    /* maps for 3x4 Z's */
  61.    static int mapa[16] = {10, 1, 11, 9, 5, 3, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1};
  62.    static int mapb[16] = {-1, -1, -1, -1, -1, -1, -1, -1, 10, 2, 5, 9, 11, 3, 4, 8};
  63.    static int mapc[16] = {-1, -1, -1, -1, -1, -1, -1, -1, 0, 5, 7, 10, 1, 4, 6, 11};
  64.    static int mapd[16] = {0, 11, 8, 10, 2, 4, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1};
  65.  
  66.    /* maps for 2x6 Z's */
  67.    static int mape[16] = {0, 1, 9, 10, 3, 4, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1};
  68.    static int mapf[16] = {1, 2, 10, 11, 4, 5, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1};
  69.  
  70.    /* maps for twin parallelograms */
  71.    static int map_p1[16] = {2, 3, 11, 10, 5, 4, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1};
  72.    static int map_p2[16] = {0, 1, 4, 5, 10, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1};
  73.  
  74.    /* maps for interlocked boxes/interlocked parallelograms */
  75.    static int map_b1[16] = {1, 3, 4, 11, 10, 5, 7, 9, 1, 3, 5, 10, 11, 4, 7, 9};
  76.    static int map_b2[16] = {0, 2, 5, 10, 11, 4, 6, 8, 0, 2, 4, 11, 10, 5, 6, 8};
  77.  
  78.    /* maps for jays */
  79.  
  80.    static int mapj1[24] = {
  81.                7, 2, 4, 5, 0, 1, 3, 6,
  82.                6, 3, 4, 5, 0, 1, 2, 7,
  83.                -1, -1, -1, -1, -1, -1, -1, -1};
  84.    static int mapj2[24] = {
  85.                6, 3, 4, 5, 0, 1, 2, 7,
  86.                7, 2, 4, 5, 0, 1, 3, 6,
  87.                -1, -1, -1, -1, -1, -1, -1, -1};
  88.    static int mapj3[24] = {
  89.                -1, -1, -1, -1, -1, -1, -1, -1,
  90.                7, 2, 4, 5, 0, 1, 3, 6,
  91.                6, 3, 4, 5, 0, 1, 2, 7};
  92.    static int mapj4[24] = {
  93.                -1, -1, -1, -1, -1, -1, -1, -1,
  94.                6, 3, 4, 5, 0, 1, 2, 7,
  95.                7, 2, 4, 5, 0, 1, 3, 6};
  96.  
  97.    /* maps for facing/back-to-front/back-to-back parallelograms */
  98.  
  99.    static int mapk1[24] = {
  100.                3, 2, 4, 5, 0, 1, 7, 6,
  101.                6, 7, 4, 5, 0, 1, 2, 3,
  102.                -1, -1, -1, -1, -1, -1, -1, -1};
  103.    static int mapk2[24] = {
  104.                6, 7, 4, 5, 0, 1, 2, 3,
  105.                3, 2, 4, 5, 0, 1, 7, 6,
  106.                -1, -1, -1, -1, -1, -1, -1, -1};
  107.    static int mapk3[24] = {
  108.                -1, -1, -1, -1, -1, -1, -1, -1,
  109.                3, 2, 4, 5, 0, 1, 7, 6,
  110.                6, 7, 4, 5, 0, 1, 2, 3};
  111.    static int mapk4[24] = {
  112.                -1, -1, -1, -1, -1, -1, -1, -1,
  113.                6, 7, 4, 5, 0, 1, 2, 3,
  114.                3, 2, 4, 5, 0, 1, 7, 6};
  115.  
  116.    int i;
  117.    int table_offset;
  118.    int misc_indicator;
  119.    setup a1, a2;
  120.    setup res1, res2;
  121.    int *map_ptr;
  122.  
  123.    /* Check for special case of "interlocked parallelogram", which doesn't look like the
  124.       kind of concept we are expecting. */
  125.    
  126.    if (parseptr->concept->kind == concept_do_both_boxes) {
  127.       table_offset = 8;
  128.       misc_indicator = 3;
  129.    }
  130.    else {
  131.       table_offset = parseptr->concept->value.arg2;
  132.       misc_indicator = parseptr->concept->value.arg1;
  133.    }
  134.    
  135.    /* misc_indicator    concept                                                      */
  136.    /*      0         some kind of "Z"                                                */
  137.    /*      1         some kind of "Jay"                                              */
  138.    /*      2       twin parallelograms (the physical setup is like offset lines)     */
  139.    /*      3       interlocked boxes/Pgrams (the physical setup is like Z's)         */
  140.    /*      4         some kind of parallelogram (as from "heads travel thru")        */
  141.    /* Concept is Jay, "Z", or offset parallelogram/interlocked boxes.                */
  142.    
  143.    /* table_offset is 0, 8, or 12.  It selects the appropriate part of the maps. */
  144.    /* For "Z"      :   0 == normal, 8 == interlocked. */
  145.    /* For Jay/Pgram:   0 == normal, 8 == back-to-front, 16 == back-to-back. */
  146.    
  147.    switch (misc_indicator) {
  148.       case 0:
  149.          switch (ss->kind) {   /* The concept is some variety of "Z" */
  150.             case s4x4:
  151.                if (!(ss->people[0].id1 | ss->people[8].id1)) {
  152.                   if (!(ss->people[1].id1 | ss->people[14].id1 | ss->people[6].id1 | ss->people[9].id1)) {
  153.                      if (!(ss->people[5].id1 | ss->people[13].id1))
  154.                          map_ptr = map1;
  155.                      else if (!(ss->people[2].id1 | ss->people[10].id1))
  156.                          map_ptr = map2;
  157.                      else goto lose;
  158.                   }
  159.                   else if (!(ss->people[4].id1 | ss->people[7].id1 | ss->people[12].id1 | ss->people[15].id1)) {
  160.                      if (!(ss->people[5].id1 | ss->people[13].id1))
  161.                          map_ptr = map3;
  162.                      else if (!(ss->people[2].id1 | ss->people[10].id1))
  163.                          map_ptr = map4;
  164.                      else goto lose;
  165.                   }
  166.                   else if (!(ss->people[3].id1 | ss->people[4].id1 | ss->people[11].id1 | ss->people[12].id1)) {
  167.                      if (!(ss->people[6].id1 | ss->people[14].id1))
  168.                          map_ptr = map5;
  169.                      else if (!(ss->people[1].id1 | ss->people[9].id1))
  170.                          map_ptr = map6;
  171.                      else goto lose;
  172.                   }
  173.                   else goto lose;
  174.                }
  175.                else if (!(ss->people[4].id1 | ss->people[2].id1 | ss->people[5].id1 | ss->people[12].id1 | ss->people[10].id1 | ss->people[13].id1)) {
  176.                   if (!(ss->people[6].id1 | ss->people[14].id1))
  177.                      map_ptr = map7;
  178.                   else if (!(ss->people[1].id1 | ss->people[9].id1))
  179.                      map_ptr = map8;
  180.                   else goto lose;
  181.                }
  182.                else goto lose;
  183.                break;
  184.             case s3x4:
  185.                if (!(ss->people[0].id1 | ss->people[6].id1)) {
  186.                   if (!(ss->people[2].id1 | ss->people[8].id1))
  187.                      map_ptr = mapa;
  188.                   else if (!(ss->people[1].id1 | ss->people[7].id1))
  189.                      map_ptr = mapb;
  190.                   else goto lose;
  191.                }
  192.                else if (!(ss->people[3].id1 | ss->people[9].id1)) {
  193.                   if (!(ss->people[2].id1 | ss->people[8].id1))
  194.                      map_ptr = mapc;
  195.                   else if (!(ss->people[1].id1 | ss->people[7].id1))
  196.                      map_ptr = mapd;
  197.                   else goto lose;
  198.                }
  199.                else goto lose;
  200.                break;
  201.             case s2x6:
  202.                if (!(ss->people[2].id1 | ss->people[5].id1 | ss->people[8].id1 | ss->people[11].id1))
  203.                   map_ptr = mape;
  204.                else if (!(ss->people[0].id1 | ss->people[3].id1 | ss->people[6].id1 | ss->people[9].id1))
  205.                   map_ptr = mapf;
  206.                else goto lose;
  207.                break;
  208.             default:
  209.                fail("Must have 3x4, 2x6, or 4x4 setup for this concept.");
  210.          }
  211.          break;
  212.       case 1:
  213.          {               
  214.          switch (ss->kind)  /* The concept is some variety of jay */
  215.             {
  216.             case s_qtag:
  217.                if (((ss->people[0].id1&d_mask) == d_south && (ss->people[1].id1&d_mask) == d_south &&
  218.                   (ss->people[4].id1&d_mask) == d_north && (ss->people[5].id1&d_mask) == d_north)
  219.                                  || table_offset == 0)
  220.                   {
  221.                   if ((ss->people[6].id1&d_mask) == d_north && (ss->people[7].id1&d_mask) == d_south &&
  222.                         (ss->people[3].id1&d_mask) == d_north && (ss->people[2].id1&d_mask) == d_south)
  223.                      map_ptr = mapj1;
  224.                   else if ((ss->people[6].id1&d_mask) == d_south && (ss->people[7].id1&d_mask) == d_north &&
  225.                         (ss->people[3].id1&d_mask) == d_south && (ss->people[2].id1&d_mask) == d_north)
  226.                      map_ptr = mapj2;
  227.                   else goto lose;
  228.                   }
  229.                else if ((ss->people[0].id1&d_mask) == d_north && (ss->people[1].id1&d_mask) == d_north &&
  230.                      (ss->people[4].id1&d_mask) == d_south && (ss->people[5].id1&d_mask) == d_south)
  231.                   {
  232.                   if ((ss->people[6].id1&d_mask) == d_north && (ss->people[7].id1&d_mask) == d_south &&
  233.                         (ss->people[3].id1&d_mask) == d_north && (ss->people[2].id1&d_mask) == d_south)
  234.                      map_ptr = mapj3;
  235.                   else if ((ss->people[6].id1&d_mask) == d_south && (ss->people[7].id1&d_mask) == d_north &&
  236.                         (ss->people[3].id1&d_mask) == d_south && (ss->people[2].id1&d_mask) == d_north)
  237.                      map_ptr = mapj4;
  238.                   else goto lose;
  239.                   }
  240.                else goto lose;
  241.                break;
  242.             default:
  243.                fail("Must have quarter-tag setup for this concept.");
  244.             }
  245.          break;
  246.          }
  247.       case 2:
  248.          switch (ss->kind)     /* The concept is twin parallelograms */
  249.             {
  250.             case s3x4:
  251.                if (!(ss->people[0].id1 | ss->people[6].id1 | ss->people[1].id1 | ss->people[7].id1))
  252.                   map_ptr = map_p1;
  253.                else if (!(ss->people[3].id1 | ss->people[9].id1 | ss->people[2].id1 | ss->people[8].id1))
  254.                   map_ptr = map_p2;
  255.                else goto lose;
  256.                break;
  257.             default:
  258.                fail("Must have 3x4 setup for this concept.");
  259.             }
  260.          break;
  261.       case 3:
  262.          switch (ss->kind) {   /* The concept is interlocked boxes or interlocked parallelograms */
  263.             case s3x4:
  264.                if (!(ss->people[0].id1 | ss->people[6].id1 | ss->people[2].id1 | ss->people[8].id1))
  265.                   map_ptr = map_b1;
  266.                else if (!(ss->people[3].id1 | ss->people[9].id1 | ss->people[1].id1 | ss->people[7].id1))
  267.                   map_ptr = map_b2;
  268.                else goto lose;
  269.                break;
  270.             default:
  271.                fail("Must have 3x4 setup for this concept.");
  272.          }
  273.          break;
  274.       case 4:
  275.          switch (ss->kind) {  /* The concept is facing (or back-to-back, or front-to-back) Pgram */
  276.             case s_qtag:
  277.                if ((ss->people[0].id1&d_mask) == d_south && (ss->people[1].id1&d_mask) == d_south &&
  278.                            (ss->people[4].id1&d_mask) == d_north && (ss->people[5].id1&d_mask) == d_north) {
  279.                   if ((ss->people[6].id1&d_mask) == d_north && (ss->people[7].id1&d_mask) == d_north &&
  280.                               (ss->people[3].id1&d_mask) == d_south && (ss->people[2].id1&d_mask) == d_south)
  281.                      map_ptr = mapk1;
  282.                   else if ((ss->people[6].id1&d_mask) == d_south && (ss->people[7].id1&d_mask) == d_south &&
  283.                            (ss->people[3].id1&d_mask) == d_north && (ss->people[2].id1&d_mask) == d_north)
  284.                      map_ptr = mapk2;
  285.                   else goto lose;
  286.                }
  287.                else if ((ss->people[0].id1&d_mask) == d_north && (ss->people[1].id1&d_mask) == d_north &&
  288.                         (ss->people[4].id1&d_mask) == d_south && (ss->people[5].id1&d_mask) == d_south) {
  289.                   if ((ss->people[6].id1&d_mask) == d_north && (ss->people[7].id1&d_mask) == d_north &&
  290.                            (ss->people[3].id1&d_mask) == d_south && (ss->people[2].id1&d_mask) == d_south)
  291.                      map_ptr = mapk3;
  292.                   else if ((ss->people[6].id1&d_mask) == d_south && (ss->people[7].id1&d_mask) == d_south &&
  293.                            (ss->people[3].id1&d_mask) == d_north && (ss->people[2].id1&d_mask) == d_north)
  294.                      map_ptr = mapk4;
  295.                   else goto lose;
  296.                }
  297.                else goto lose;
  298.                break;
  299.             default:
  300.                fail("Must have quarter-line setup for this concept.");
  301.          }
  302.          break;
  303.    }
  304.    
  305.    if (map_ptr[table_offset] < 0) goto lose;
  306.    
  307.    result->kind = ss->kind;
  308.    result->rotation = 0;
  309.    
  310.    for (i=0; i<4; i++) {
  311.       (void) copy_person(&a1, i, ss, map_ptr[i+table_offset]);
  312.       (void) copy_person(&a2, i, ss, map_ptr[i+table_offset+4]);
  313.    }
  314.    
  315.    a1.kind = s2x2;
  316.    a1.rotation = 0;
  317.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  318.    move(&a1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  319.    
  320.    a2.kind = s2x2;
  321.    a2.rotation = 0;
  322.    a2.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  323.    move(&a2, parseptr->next, NULLCALLSPEC, 0, FALSE, &res2);
  324.    
  325.    if (res1.kind != s2x2 || res2.kind != s2x2) fail("Can't do shape-changer with this concept.");
  326.    
  327.    for (i=0; i<4; i++) {
  328.       (void) copy_person(result, map_ptr[i+table_offset], &res1, i);
  329.       (void) copy_person(result, map_ptr[i+table_offset+4], &res2, i);
  330.    }
  331.    
  332.    result->setupflags = res1.setupflags | res2.setupflags;
  333.    return;
  334.    
  335.    lose: fail("Can't find the indicated formation.");
  336. }
  337.  
  338.  
  339.  
  340. static long_boolean search_row(
  341.    int n,
  342.    int *x1,
  343.    int *x2,
  344.    int row[8],
  345.    setup *s)
  346.  
  347.    /* This returns true if the two live people were consecutive, meaning this is a true Z line/column. */
  348.  
  349.    {
  350.    int i, z, fill_count;
  351.    long_boolean win;
  352.    
  353.    fill_count = 0;
  354.    z = 2;                       /* counts downward as we see consecutive people */
  355.    win = FALSE;
  356.    for (i=0; i<n; i++)
  357.       if (!s->people[row[i]].id1)           /* live person here? */
  358.          z = 2;                 /* no, reset the consecutivity counter */
  359.       else
  360.          {
  361.          --z;                   /* yes, count -- if get two in a row, turn "win" on */
  362.          if (!z) win = TRUE;
  363.          /* then push this index onto the map, check for no more than 2 */
  364.          fill_count++;
  365.          switch (fill_count)
  366.             {
  367.             case 1: *x1 = row[i]; break;
  368.             case 2: *x2 = row[i]; break;
  369.             default: fail("Can't identify distorted line or column.");
  370.             }
  371.          }
  372.    
  373.    /* Now check that the map has exactly 2 people. */
  374.    
  375.    if (fill_count != 2) fail("Can't identify distorted line or column.");
  376.    
  377.    /* And return this. */
  378.    
  379.    return(win);
  380.    }
  381.  
  382.  
  383. extern void distorted_move(
  384.    setup *ss,
  385.    parse_block *parseptr,
  386.    setup *result)
  387.  
  388. {
  389.  
  390. /*
  391.    Args from the concept are as follows:
  392.    arg1 =
  393.       0 - user claims this is some kind of columns
  394.       1 - user claims this is some kind of lines
  395.    arg2 =
  396.       disttest_offset - user claims this is offset lines/columns
  397.       disttest_z      - user claims this is Z lines/columns
  398.       disttest_any    - user claims this is distorted lines/columns
  399.  
  400.    Tbonetest has the OR of all the people, or all the standard people if
  401.       this is "standard", so it is what we look at to interpret the
  402.       lines vs. columns nature of the concept.
  403. */
  404.  
  405.    static int list_0_12_11[3] = {0, 10, 9};
  406.    static int list_1_13_10[3] = {1, 11, 8};
  407.    static int list_2_5_7[3] = {2, 5, 7};
  408.    static int list_3_4_6[3] = {3, 4, 6};
  409.  
  410.    int tbonetest;
  411.    int livemask;
  412.    int the_map[8];
  413.    int linesp;
  414.    long_boolean zlines;
  415.    disttest_kind disttest;
  416.    int i, rot, rotz;
  417.    setup a1;
  418.    setup res1;
  419.    map_thing *map_ptr;
  420.  
  421.    tbonetest = global_tbonetest;
  422.    livemask = global_livemask;
  423.  
  424.    linesp = parseptr->concept->value.arg1;
  425.    disttest = (disttest_kind) parseptr->concept->value.arg2;
  426.    zlines = TRUE;
  427.  
  428.    if (ss->kind == s4x4) {
  429.       int vertical = (linesp ^ tbonetest) & 1;
  430.  
  431.       /* **** This is all sort of a crock.  Here we are picking out the "winning" method for
  432.         doing distorted/offset/Z lines and columns.  Below, we do it by the old way, which allows
  433.         T-bone setups. */
  434.    
  435.       /* If any people are T-boned, we must invoke the other method and hope for the best.
  436.          ***** We will someday do it right. */
  437.          
  438.       if ((tbonetest & 011) == 011) {
  439.          if (disttest != disttest_offset)
  440.             fail("Sorry, can't apply this concept when people are T-boned.");
  441.    
  442.          phantom_2x4_move(ss, linesp, phantest_only_one, &(map_offset), parseptr->next, result);
  443.          return;
  444.       }
  445.    
  446.       /* Check for special case of offset lines/columns, and do it the elegant way (handling shape-changers) if so. */
  447.  
  448.       /* Search for the live people.
  449.          Vertical == 0 if must scan sideways for each Y value, looking for exactly 2 people
  450.          Vertical == 1 if must scan vertically for each X value, looking for exactly 2 people.
  451.          If any of the scans returns false, meaning that the 2 people are not adjacent,
  452.          set zlines to false. */
  453.       
  454.       if (vertical) {
  455.          if (livemask == 0xB4B4) { map_ptr = &map_rf_s2x4_r; goto do_divided_call; }
  456.          else if (livemask == 0x4B4B) { map_ptr = &map_lf_s2x4_r; goto do_divided_call; }
  457.          else {
  458.             if (!search_row(4, &the_map[0], &the_map[7], list_14_12_11_10, ss)) zlines = FALSE;
  459.             if (!search_row(4, &the_map[1], &the_map[6], list_15_17_13_6, ss)) zlines = FALSE;
  460.             if (!search_row(4, &the_map[2], &the_map[5], list_16_3_7_5, ss)) zlines = FALSE;
  461.             if (!search_row(4, &the_map[3], &the_map[4], list_0_1_2_4, ss)) zlines = FALSE;
  462.          }
  463.       }
  464.       else {
  465.          if (livemask == 0xB4B4) { map_ptr = (*map_lists[s2x4][0])[MPKIND__OFFS_L_FULL][1]; goto do_divided_call; }
  466.          else if (livemask == 0x4B4B) { map_ptr = (*map_lists[s2x4][0])[MPKIND__OFFS_R_FULL][1]; goto do_divided_call; }
  467.          else {
  468.             if (!search_row(4, &the_map[0], &the_map[7], list_10_6_5_4, ss)) zlines = FALSE;
  469.             if (!search_row(4, &the_map[1], &the_map[6], list_11_13_7_2, ss)) zlines = FALSE;
  470.             if (!search_row(4, &the_map[2], &the_map[5], list_12_17_3_1, ss)) zlines = FALSE;
  471.             if (!search_row(4, &the_map[3], &the_map[4], list_14_15_16_0, ss)) zlines = FALSE;
  472.          }
  473.       }
  474.    
  475.       rot = (1 - vertical) * 011;
  476.       result->kind = s4x4;
  477.       rotz = (1 - vertical) * 033;
  478.    }
  479.    else if (ss->kind == s3x4) {
  480.       if (linesp & 1) {
  481.          if (tbonetest & 1) fail("There are no lines of 4 here.");
  482.       }
  483.       else {
  484.          if (tbonetest & 010) fail("There are no columns of 4 here.");
  485.       }
  486.  
  487.       /* Check for special case of offset lines/columns, and do it the elegant way (handling shape-changers) if so. */
  488.       
  489.       if (livemask == 07474) { map_ptr = (*map_lists[s2x4][0])[MPKIND__OFFS_L_HALF][1]; goto do_divided_call; }
  490.       else if (livemask == 06363) { map_ptr = (*map_lists[s2x4][0])[MPKIND__OFFS_R_HALF][1]; goto do_divided_call; }
  491.  
  492.       /* Search for the live people. */
  493.       /* Minor loss!!!  Search row should use symmetry, and refuse to do its job on unsymmetrical stuff.
  494.          Why?  Because, if it turns out that the result of "move" flips the whole thing over,
  495.          so that res1.rot = 2, we just set result->rot = 2 and proceed.  This would violate the
  496.          true shape of the result setup. */
  497.       
  498.       if (!search_row(3, &the_map[0], &the_map[7], list_0_12_11, ss)) zlines = FALSE;
  499.       if (!search_row(3, &the_map[1], &the_map[6], list_1_13_10, ss)) zlines = FALSE;
  500.       if (!search_row(3, &the_map[2], &the_map[5], list_2_5_7, ss)) zlines = FALSE;
  501.       if (!search_row(3, &the_map[3], &the_map[4], list_3_4_6, ss)) zlines = FALSE;
  502.       
  503.       rot = 0;
  504.       result->kind = s3x4;      
  505.       rotz = 0;
  506.    }
  507.    else
  508.       fail("Must have 3x4 or 4x4 setup for this concept.");
  509.  
  510.    /* Now see if the concept was correctly named. */
  511.  
  512.    if (zlines) {
  513.       if (disttest != disttest_z)
  514.          fail("You must specify Z lines/columns when in this setup.");
  515.    }
  516.    else {
  517.       switch (disttest) {
  518.          case disttest_z:
  519.             fail("Can't find Z lines/columns, perhaps you mean distorted.");
  520.          case disttest_offset:
  521.             fail("Can't find offset lines/columns, perhaps you mean distorted.");
  522.       }
  523.    }
  524.  
  525.    for (i=0; i<8; i++) (void) copy_rot(&a1, i, ss, the_map[i], rot);
  526.  
  527.    a1.kind = s2x4;
  528.    a1.rotation = 0;
  529.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  530.    move(&a1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  531.  
  532.    if (res1.kind != s2x4 || (res1.rotation & 1)) fail("Can only do non-shape-changing 2x4 -> 2x4 calls in Z or distorted setups.");
  533.    result->rotation = res1.rotation;
  534.    for (i=0; i<8; i++) (void) copy_rot(result, the_map[i], &res1, i, rotz);
  535.    result->setupflags = res1.setupflags;
  536.  
  537.    reinstate_rotation(ss, result);
  538.    return;
  539.    
  540.    do_divided_call:
  541.  
  542.    if (disttest != disttest_offset)
  543.       fail("You must specify offset lines/columns when in this setup.");
  544.  
  545.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  546.       map_ptr, phantest_ok, TRUE, result);
  547. }
  548.  
  549.  
  550. extern void triple_twin_move(
  551.    setup *ss,
  552.    parse_block *parseptr,
  553.    setup *result)
  554. {
  555.    int tbonetest;
  556.    int i;
  557.    static short source_indices[16]  = {4, 7, 22, 8, 13, 14, 15, 21, 16, 19, 10, 20, 1, 2, 3, 9};
  558.  
  559.    /* Arg1 = 1 for triple twin columns, 0 for triple twin lines. */
  560.  
  561.    /* The setup has not necessarily been expanded to a 4x6.  It has only been
  562.       expanded to a 4x4.  Why?  Because the stuff in toplevelmove that does
  563.       the expansion didn't know which way to orient the 4x6.  (It might have
  564.       depended on "standard" information.)  So why is the expansion supposed
  565.       to be done there rather than at the point where the concept is executed?
  566.       It is to prevent monstrosities like "in your split phantom line you
  567.       have a split phantom column".  Expansion takes place only at the top
  568.       level.  When the concept "in your split phantom line" is executed,
  569.       toplevelmove expands the setup to a 4x4, the concept routine splits
  570.       it into 2x4's, and then the second concept is applied without further
  571.       expansion.  Since we now have 2x4's and the you have a split phantom
  572.       column" concept requires a 4x4, it will raise an error.  If the
  573.       expansion were done wherever a concept is performed, this monstrosity
  574.       would by permitted to occur.  So the remaining question is "What
  575.       safety are we sacrificing (or what monstrosities are we permitting)
  576.       by doing the expansion here?"  The answer is that, if there were a
  577.       concept that divided the setup into 4x4's, we could legally do
  578.       something like "in your split phantom 4x4's you have triple twin
  579.       columns".  It would expand each 4x4 into a 4x6 and go the call.
  580.       Horrors.  Fortunately, there are no such concepts.  Of course
  581.       the really right way to do this is to have a setupflag called
  582.       NOEXPAND, and do the expansion when the concept is acted upon.
  583.       Anyway, here goes. */
  584.  
  585.    tbonetest = global_tbonetest;
  586.  
  587.    if ((tbonetest & 011) == 011) fail("Can't do this from T-bone setup.");
  588.  
  589.    tbonetest ^= parseptr->concept->value.arg1;
  590.  
  591.    if (ss->kind == s4x4) {
  592.       setup stemp;
  593.       stemp = *ss;
  594.       clear_people(ss);
  595.  
  596.       if (tbonetest & 1) {
  597.          for (i=0; i<16; i++) copy_person(ss, source_indices[i], &stemp, i);
  598.       }
  599.       else {
  600.          for (i=0; i<16; i++) (void) copy_rot(ss, source_indices[i], &stemp, (i+4) & 0xF, 033);
  601.          ss->rotation++;
  602.          tbonetest ^= 1;    /* Fix it. */
  603.       }
  604.    
  605.       ss->kind = s4x6;
  606.  
  607.    }
  608.    else if (ss->kind != s4x6) fail("Must have a 4x6 setup for this concept.");
  609.    
  610.    if (!(tbonetest & 1)) {
  611.       if (parseptr->concept->value.arg1) fail("Can't find triple twin columns.");
  612.       else fail("Can't find triple twin lines.");
  613.    }
  614.    
  615.    divided_setup_move(ss, parseptr->next, NULLCALLSPEC, 0,
  616.          (*map_lists[s2x4][2])[MPKIND__SPLIT][1], phantest_not_just_centers, TRUE, result);
  617. }
  618.  
  619.  
  620.  
  621. extern void do_concept_rigger(
  622.    setup *ss,
  623.    parse_block *parseptr,
  624.    setup *result)
  625.  
  626. {
  627.    /* First half is for wing; second half is for 1/4-tag. */
  628.    /* A huge coincidence is at work here -- the two halves of the maps are the same. */
  629.    static int map1[16] = {0, 1, 3, 2, 4, 5, 7, 6, 0, 1, 3, 2, 4, 5, 7, 6};
  630.    static int map2[16] = {6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5};
  631.  
  632.    int rstuff, i, indicator;
  633.    setup a1;
  634.    setup res1;
  635.    int *map_ptr;
  636.  
  637.    rstuff = parseptr->concept->value.arg1;
  638.    /* rstuff =
  639.       outrigger   : 0
  640.       leftrigger  : 1
  641.       inrigger    : 2
  642.       rightrigger : 3 */
  643.  
  644.    if (ss->kind != s_rigger) fail("Must have a 'rigger' setup to do this concept.");
  645.  
  646.    if (!(ss->people[2].id1 & ss->people[6].id1 & BIT_PERSON))
  647.       fail("Can't tell which way 'rigger' people are facing.");
  648.  
  649.    if (((ss->people[2].id1 ^ ss->people[6].id1) & 3) != 2)
  650.       fail("'Rigger' people are not facing consistently!");
  651.  
  652.    indicator = (ss->people[6].id1 ^ rstuff) & 3;
  653.  
  654.    if (indicator & 1)
  655.       fail("'Rigger' direction is inappropriate.");
  656.  
  657.    if (indicator)
  658.        map_ptr = map1;
  659.    else
  660.        map_ptr = map2;
  661.  
  662.    for (i=0; i<8; i++) (void) copy_person(&a1, i, ss, map_ptr[i]);
  663.    
  664.    a1.kind = s2x4;
  665.    a1.rotation = 0;
  666.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  667.    move(&a1, parseptr->next, NULLCALLSPEC, 0, FALSE, &res1);
  668.    
  669.    if (res1.kind != s2x4) fail("Can only do 2x4 -> 2x4 calls.");
  670.  
  671.    if ((res1.rotation) & 1) {
  672.       result->rotation = res1.rotation;
  673.       for (i=0; i<8; i++) (void) copy_person(result, map_ptr[i+8], &res1, i);
  674.       result->kind = s_qtag;
  675.    }
  676.    else {
  677.       result->rotation = res1.rotation;
  678.       for (i=0; i<8; i++) (void) copy_person(result, map_ptr[i], &res1, i);
  679.       result->kind = s_rigger;
  680.    }
  681.    
  682.    result->setupflags = res1.setupflags;
  683.    reinstate_rotation(ss, result);
  684. }
  685.  
  686.  
  687.  
  688. typedef struct {
  689.    int map_a1[4];
  690.    int map_a2[4];
  691.    setup_kind start_kind;
  692.    setup_kind end_kind;
  693.    int outrot;
  694.    int parity;
  695.    int bigmap1[8];
  696.    int bigmap2[8];
  697.    } rig_thing;
  698.  
  699. static rig_thing rig_wing = {{3, 2, -1, -1}, {-1, -1, 7, 6}, s1x4, s2x2, 0, 0, {0, 1, 8, 9, 4, 5, 14, 15}, {12, 13, 0, 1, 10, 11, 4, 5}};
  700. static rig_thing rig_2x4 =  {{3, -1, -1, 4}, {-1, 0, 7, -1}, s2x2, s2x2, 0, 0, {1, 2, 8, 9, 5, 6, 14, 15}, {12, 13, 1, 2, 10, 11, 5, 6}};
  701. static rig_thing rig_xwv =  {{5, 4, -1, -1}, {-1, -1, 1, 0}, s1x4, s1x4, 1, 0, {8, 9, 7, 6, 14, 15, 3, 2}, {2, 3, 11, 10, 6, 7, 13, 12}};
  702. static rig_thing rig_qtag=  {{-1, -1, 1, 0}, {5, 4, -1, -1}, s2x2, s1x4, 0, 1, {8, 9, 3, 2, 14, 15, 7, 6}, {6, 7, 11, 10, 2, 3, 13, 12}};
  703.  
  704.  
  705.  
  706. extern void do_concept_callrigger(
  707.    setup *ss,
  708.    parse_block *parseptr,
  709.    setup *result)
  710.  
  711. {
  712.    /* First half is for wing; second half is for 1/4-tag. */
  713.    /* A huge coincidence is at work here -- the two halves of the maps are the same. */
  714.    static int map1[16] = {0, 1, 3, 2, 4, 5, 7, 6, 0, 1, 3, 2, 4, 5, 7, 6};
  715.    static int map2[16] = {6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5};
  716.  
  717.    int i, j, signature;
  718.    setup a1, a2;
  719.    rig_thing *rig_map;
  720.    int *map_ptr;
  721.    setup z[2];
  722.  
  723.    switch (ss->kind) {
  724.       case s_rigger: rig_map = &rig_wing; break;
  725.       case s2x4: rig_map = &rig_2x4; break;
  726.       case s_crosswave: rig_map = &rig_xwv; break;
  727.       case s_qtag: rig_map = &rig_qtag; break;
  728.       default: fail("Must have a 'rigger' setup to do this concept.");
  729.    }
  730.  
  731.    clear_people(&a1);
  732.    clear_people(&a2);
  733.  
  734.    /* Pull out the wings and have them do the call. */
  735.  
  736.    for (i=0; i<4; i++) {
  737.       if (rig_map->map_a1[i] >= 0)
  738.          (void) copy_person(&a1, i, ss, rig_map->map_a1[i]);
  739.  
  740.       if (rig_map->map_a2[i] >= 0)
  741.          (void) copy_person(&a2, i, ss, rig_map->map_a2[i]);
  742.    }
  743.  
  744.  
  745.    a1.rotation = 0;
  746.    a1.kind = rig_map->start_kind;
  747.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  748.  
  749.    a2.rotation = 0;
  750.    a2.kind = rig_map->start_kind;
  751.    a2.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  752.  
  753.    move(&a1, parseptr->next, NULLCALLSPEC, 0, FALSE, &z[0]);
  754.    move(&a2, parseptr->next, NULLCALLSPEC, 0, FALSE, &z[1]);
  755.    result->setupflags = z[0].setupflags | z[1].setupflags;
  756.  
  757.    if (fix_n_results(2, z))
  758.       fail("There are no wings???");
  759.  
  760.    if (z[0].kind != rig_map->end_kind) fail("Can't figure out result of rigging call.");
  761.  
  762.    if (z[0].rotation != rig_map->outrot) fail("Sorry, can't handle this rotation from rigging call.");
  763.  
  764.    signature = 0;
  765.  
  766.    for (i=0, j=1; i<=4; i++, j<<=1) {
  767.       if (z[0].people[i].id1) {
  768.          signature |= j;
  769.       }
  770.       if (z[1].people[i].id1) {
  771.          signature |= (j<<4);
  772.       }
  773.    }
  774.  
  775.    /* Copy the people from the various sources into one place (a2) for easier indexing. */
  776.  
  777.    for (i=0; i<8; i++) {
  778.       if (rig_map->outrot)
  779.          (void) copy_rot(&a2, i, ss, i, 033);
  780.       else
  781.          (void) copy_person(&a2, i, ss, i);
  782.    }
  783.  
  784.    for (i=0; i<4; i++) {
  785.       (void) copy_person(&a2, i+8, &z[0], i);
  786.       (void) copy_person(&a2, i+12, &z[1], i);
  787.    }
  788.  
  789.    if (signature == 0xC3) {
  790.       for (i=0; i<8; i++) (void) copy_person(&a1, i, &a2, rig_map->bigmap1[i]);
  791.       map_ptr = map1;
  792.    }
  793.    else if (signature == 0x3C) {
  794.       for (i=0; i<8; i++) (void) copy_person(&a1, i, &a2, rig_map->bigmap2[i]);
  795.       map_ptr = map2;
  796.    }
  797.    else fail("Can't figure out which way to rig.");
  798.  
  799.    a1.kind = s2x4;
  800.    a1.rotation = rig_map->outrot;
  801.    a1.setupflags = ss->setupflags | SETUPFLAG__DISTORTED;
  802.    move(&a1, parseptr->subsidiary_root, NULLCALLSPEC, 0, FALSE, &z[0]);
  803.    
  804.    if (z[0].kind != s2x4) fail("Can only do 2x4 -> 2x4 calls.");
  805.    result->rotation = z[0].rotation;
  806.  
  807.    if ((z[0].rotation ^ rig_map->parity) & 1) {
  808.       for (i=0; i<8; i++) (void) copy_person(result, map_ptr[i+8], &z[0], i);
  809.       result->kind = s_qtag;
  810.    }
  811.    else {
  812.       for (i=0; i<8; i++) (void) copy_person(result, map_ptr[i], &z[0], i);
  813.       result->kind = s_rigger;
  814.    }
  815.    
  816.    result->setupflags |= z[0].setupflags;
  817.    reinstate_rotation(ss, result);
  818. }
  819.