home *** CD-ROM | disk | FTP | other *** search
/ Kinjite Games 1996 November / SENTINEL.img / dosgames / sports / apool098 / src / computer.c < prev    next >
C/C++ Source or Header  |  1995-05-26  |  24KB  |  677 lines

  1. /* This is "computer.c", a part of the pool (billiards)-program
  2.                    
  3.                      "ANOTHER POOL".
  4.  
  5.    "computer.c" includes the procedures needed for the computer-
  6.    player of ANOTHER POOL. "computer.c" also uses CBGRX 2.0.
  7.  
  8.    Copyright (C) 1995 by Gerrit Jahn (email: ub1g@rz.uni-karlsruhe.de)
  9.  
  10.    "ANOTHER POOL" is free software; you can redistribute it 
  11.    and/or modify it under the terms of the GNU General Public License 
  12.    as published by the Free Software Foundation; either version 2 of 
  13.    the License, or (at your option) any later version.
  14.  
  15.    This program is distributed in the hope that it will be useful,
  16.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.    GNU General Public License for more details.
  19.  
  20.    You should have received a copy of the GNU General Public License
  21.    along with GNU CC; see the file COPYING.  If not, write to
  22.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  23.  
  24. /* ------------------------------ computer.c ----------------------------- */
  25.  
  26. #include <math.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include "c:/djgpp/contrib.20/libgrx/include/grx20.h"
  30. #include <time.h>
  31. #include <pc.h>
  32. #include "apool.h"
  33.  
  34. struct target t; /* Kopf der 'target'-Liste ... (s.u.) */
  35.  
  36. int in_line_c( int b,int b2,struct vect x0,struct vect x1,int color,int grx)
  37. /* diese wichtigste Funktion überhaupt, testet, ähnlich wie in_line() in 
  38.    graphics.c, ob im Abstand RADIUS der Verbindungslinie x0--> x1 eine Kugel
  39.    liegt, welche dann natürlich einen Stoß in diese Richtung verbieten muß !*/
  40.  {
  41.  struct vect kk, c;
  42.  double t, dummy;
  43.  int i;
  44.  kk.x = x1.x - x0.x;
  45.  kk.y = x1.y - x0.y;
  46.  /* unten: der Weg der Kugel muß noch um 2*RADIUS weiter überprüft werden ! */
  47.  if( (dummy = BETR( kk )) ) 
  48.   {
  49.    kk.x /= dummy;
  50.    kk.y /= dummy;
  51.    x1.x += (2*RADIUS)/DIFFX * kk.x; 
  52.    x1.y += (2*RADIUS)/DIFFX * kk.y;
  53.   }
  54.  c.x = x1.x - x0.x; c.y = x1.y - x0.y;
  55.  if( grx ) 
  56.   {
  57.   GrLine( x0.x*DIFFX+LEFT, x0.y*DIFFX+UP, x1.x*DIFFX+LEFT, 
  58.    x1.y*DIFFX+UP, color | GrXOR );
  59.   }
  60.  for( i=0;i<WHITE;i++ )
  61.   if( (i != b) && ( i!= b2) && !(k[i].stat) )
  62.    {
  63.     t = -(c.x*(x0.x-k[i].p.x)+c.y*(x0.y-k[i].p.y)) / (SKALP(c,c));
  64.     kk.x = x0.x + c.x * t;
  65.     kk.y = x0.y + c.y * t;
  66.     if( (c.x * (kk.x-x0.x) >= 0) && (c.y * (kk.y-x0.y) >= 0) &&
  67.      (c.x * (kk.x-x1.x) <= 0) && (c.y * (kk.y-x1.y) <= 0) )
  68.      {
  69.       if( grx ) GrLine(k[i].p.x*DIFFX+LEFT,k[i].p.y*DIFFX+UP,kk.x*DIFFX+LEFT,
  70.        kk.y*DIFFX+UP,  color | GrXOR );
  71.       if( sqrt( DIFF(k[i].p.x-kk.x, k[i].p.y-kk.y) ) <= (2*RADIUS)/DIFFX )
  72.        { if( grx ) GrCircle( k[i].p.x*DIFFX+LEFT, k[i].p.y*DIFFX+UP, 5, 
  73.         color | GrXOR); return 1; }
  74.     /* Abstand (Verbind.linie -> Kugel) zu klein --> Kugel liegt im Weg */
  75.      }
  76.    }
  77.   return 0;
  78.  }
  79.  
  80. /*#define HOLE_INLINE 1 */ 
  81.  
  82. #ifdef HOLE_INLINE
  83. int hole_inline( struct vect v, struct vect x0 )
  84.  /* es wird berechnet, ob sich ein Loch in der Bahn des jeweiligen
  85.     Abstandsvektors befindet. */
  86.  {
  87.  struct vect kk, c, x1;
  88.  double t;
  89.  int i;
  90.  x1.x = x0.x + v.x;
  91.  x1.y = x0.y + v.y;    /* alles ein bißchen doppelt gemoppelt !!! !!! !!! */
  92.  c.x = x1.x - x0.x; 
  93.  c.y = x1.y - x0.y;
  94.  for( i=0;i<6;i++ )
  95.   {
  96.    t = -(c.x*(x0.x-posl[i].m.x)+c.y*(x0.y-posl[i].m.y)) / (SKALP(c, c));
  97.    kk.x = x0.x + c.x * t;
  98.    kk.y = x0.y + c.y * t;
  99.    if( (c.x * (kk.x-x0.x) >= 0) && (c.y * (kk.y-x0.y) >= 0) &&
  100.     (c.x * (kk.x-x1.x) <= 0) && (c.y * (kk.y-x1.y) <= 0) )
  101.     {
  102.      if( sqrt( DIFF(posl[i].m.x-kk.x, posl[i].m.y-kk.y) ) 
  103.       <= (5*RADIUS)/DIFFX ) return 1;
  104.     }
  105.   }
  106.   return 0;
  107.  }
  108. #endif
  109.  
  110. struct vect calc_tp( struct vect a, struct vect b )
  111. /* berechnet den Punkt, an den die Kugel ball getroffen werden muß, damit
  112.    sie in Richtung h rollt... ! !!! !!! !!! stimmt SO nicht mehr */
  113.  {
  114.   struct vect c;
  115.   double dummy;
  116.   c.x = b.x - a.x; c.y = b.y - a.y;
  117.   if( (dummy=BETR( c )) ) { c.x /= dummy; c.y /= dummy; }
  118.   a.x -= 2.0*RADIUS/DIFFX * c.x;
  119.   a.y -= 2.0*RADIUS/DIFFX * c.y;
  120.   return a;
  121.  }
  122.  
  123. void set_c_speed( double v0, struct vect v )
  124.  { /* berechnet die Geschwindigkeit, mit der der Computer stoßen muß; in 
  125.       Richtung v, Streckenlänge strecke */
  126.   double dummy; /* v : zeigt in Richtung der Geschwindigkeit */
  127.   char out[80];
  128.   if( (dummy=BETR( v )) ) { v.x/=dummy; v.y/=dummy; }
  129.   spd = DIFFX * v0;
  130.   if( spd > 1.0 ) 
  131.    { 
  132.     sprintf(out, "sorry, %s I'm to weak... (only %3.0f%%)",
  133.     (1/spd > 0.94) ? "maybe" : "", 100.0/spd);
  134.     debug(out);
  135.     spd = 1.0; 
  136.    }
  137.   k[WHITE].v.x = spd/DIFFX * v.x;
  138.   k[WHITE].v.y = spd/DIFFX * v.y;
  139.   speed( spd );
  140.  }         
  141.  
  142. #ifdef BANDEN
  143. struct ball ball_copy( int nr, int xl, int yl, int xr, int yr )
  144. /* je nach Aufruf wird der Tisch nach oben, unten links, rechts gespiegelt,
  145.    womit sich Bandenstöße (allerdings nur, falls Einfallswinkel=Ausfallswinkel
  146.    gilt) leichter berechnen lassen */
  147.  {
  148.   struct ball ret;
  149.   ret.p.x = k[nr].p.x + xl * k[nr].p.x + xr * (1.0 - k[nr].p.x);
  150.   ret.p.y = k[nr].p.y + yl * k[nr].p.y + yr * (0.5 - k[nr].p.y);
  151.   ret.col = k[nr].col;
  152.   ret.stat = k[nr].stat; /* Rest: Masse, Geschw. nicht nötig */
  153.   return ret;
  154.  }
  155. #endif
  156.  
  157. #ifdef BANDEN
  158. void plot_sides(  struct ball *kb, struct hole *poslb )
  159. /* malt auf den normalen Tisch die mit ball_copy() kopierten Tische auf 
  160.     wird wohl eher zum graphischen Debuggen dienen ... !!! !!! !!!*/
  161.  {
  162.  int i, j;
  163.  GrLine( LEFT+200, UP+0, LEFT+200, UP+300, 6 | GrXOR);
  164.  GrLine( LEFT+400, UP+0, LEFT+400, UP+300, 6 | GrXOR);
  165.  GrLine( LEFT+0, UP+100, LEFT+600, UP+100, 6 | GrXOR);
  166.  GrLine( LEFT+0, UP+200, LEFT+600, UP+200, 6 | GrXOR);
  167.  for( i=0;i<BANDEN;i++ )
  168.   for( j=0;j<WHITE;j++ )
  169.   { 
  170.    GrFilledCircle( LEFT + 200+kb[i*BALLS+j].p.x*200,  
  171.     UP + 100 + kb[i*BALLS+j].p.y*200, 2, (3*kb[i*BALLS+j].col + 3) | GrXOR );
  172.   }
  173.  for( i=0;i<BANDEN;i++ )
  174.   for( j=0;j<6;j++ )
  175.    GrFilledCircle( LEFT+200+poslb[i*6+j].m.x*200, UP+100+200*poslb[i*6+j].m.y,
  176.     1, 15 | GrXOR);
  177.  }
  178.  
  179. struct hole hole_copy( int x, int y, int n )
  180. /* analog ball_copy werden hier für die Bandenstöße die Löcher gespiegelt,
  181.    wobei man natürlich aufgrund der Symmetrie nicht "richtig" spiegeln 
  182.    muß, einfach verschieben genügt hierbei auch */
  183.  {
  184.  struct hole ret;
  185.  ret.p.x = posl[n].p.x + x*1.0;
  186.  ret.p.y = posl[n].p.y + y*0.5;
  187.  ret.m.x = posl[n].m.x + x*1.0;
  188.  ret.m.y = posl[n].m.y + y*0.5;
  189.  return ret; 
  190.  }
  191.  
  192. int banden_stoss( void )
  193. /* berechnet den Stoß über eine bzw., falls eine Kugel über Eck rollt,
  194.    zwei Banden ... da gibt's noch etwas Arbeit !!! !!! !!!*/
  195.  {
  196.  int ret = 0, i, j;
  197.  struct ball kb[BALLS*9];
  198.  struct hole poslb[9*6];
  199.  /* zuerst: nur 1.5 (1 hoch/runter, 2 mit "übereck") Banden !!! !!! !!!*/
  200.  /* 1, Aktion: Kugeln in alle 8 Richtungen spiegeln: */
  201.  for( j=0;j<6;j++ )
  202.   {
  203.   poslb[0*6+j] = hole_copy( -1, -1, j );
  204.   poslb[1*6+j] = hole_copy(  0, -1, j );
  205.   poslb[2*6+j] = hole_copy(  1, -1, j );
  206.   poslb[3*6+j] = hole_copy( -1,  0, j );
  207.   poslb[4*6+j] = hole_copy(  0,  0, j );
  208.   poslb[5*6+j] = hole_copy(  1,  0, j );
  209.   poslb[6*6+j] = hole_copy( -1,  1, j );
  210.   poslb[7*6+j] = hole_copy(  0,  1, j );
  211.   poslb[8*6+j] = hole_copy(  1,  1, j );
  212.   }
  213.  for( i=0;i<WHITE;i++ )
  214.   {
  215.   kb[0*BALLS+i] = ball_copy( i, -2, -2, 0, 0 );        /* links oben */
  216.   kb[1*BALLS+i] = ball_copy( i, 0, -2, 0, 0 );        /* oben */
  217.   kb[2*BALLS+i] = ball_copy( i, 0, -2, 2, 0 );        /* oben rechts */
  218.   kb[3*BALLS+i] = ball_copy( i, -2, 0, 0, 0 );        /* links */
  219.   kb[4*BALLS+i] = ball_copy( i, 0, 0, 0, 0 );        /* mitte */
  220.   kb[4*BALLS+WHITE].p.x = k[WHITE].p.x;
  221.   kb[4*BALLS+WHITE].p.y = k[WHITE].p.y;
  222.   kb[5*BALLS+i] = ball_copy( i, 0, 0, 2, 0 );        /* rechts */
  223.   kb[6*BALLS+i] = ball_copy( i, -2, 0, 0, 2 );        /* links unten */
  224.   kb[7*BALLS+i] = ball_copy( i, 0, 0, 0, 2 );        /* unten */
  225.   kb[8*BALLS+i] = ball_copy( i, 0, 0, 2, 2 );        /* unten rechts */
  226.   }
  227. plot_sides( kb, poslb );
  228. if( (c_player == -1) || (act != c_player) ) 
  229.  if( getkey() == 27 ) stop_it();
  230. plot_sides( kb, poslb );
  231. return ret;
  232. }
  233. #endif
  234.  
  235. int out_of_bounds( struct vect p )
  236. /* Es wird überprüft, ob der Treffpunkt, der bei calc_tp berechnet wurde,
  237.    innerhalb des spielbaren Bereichs des Tisches, also nicht in den Banden
  238.    liegt. Könnte man mit calc_tp evtl. kombinieren ... !!! !!! !!! */
  239. /* ACHTUNG !!! !!! !!! Fehlerquelle, könnte sein, daß die Treffpunkte, die
  240.    in der Nähe eines Lochs liegen so ebenfalls herausgefiltert werden ! */
  241.  {
  242.  if( (p.x > (DIFFX-RADIUS)/DIFFX) || (p.x < RADIUS/DIFFX) ||
  243.   (p.y > (DIFFX/2-RADIUS)/DIFFX) || (p.y < RADIUS/DIFFX) )
  244.   return 1;
  245.  return 0;
  246.  }
  247.  
  248. struct target *mark_higher_combies( struct target *last,int ordnung,int egal,
  249.  double max_angle )
  250. /* es werden die Treffpunkte an den Kugeln berechnet, die, wenn sie angespielt
  251.    werden, dazu "führen", daß eine ander Kugel entweder ins Loch geht oder
  252.    wiederum eine andere trifft, ... */
  253.  {
  254.  int i;
  255.  double dummy;
  256.  struct target *end, *actual, *dum;
  257.  struct vect b, c, d, e;
  258.  end = last;
  259.  if( t.next != NULL )
  260.   for( i=0;i<WHITE;i++ )
  261.    {
  262.     actual = t.next;
  263.     while( (actual->ord) < ordnung-1 ) actual = actual->next;
  264.     if( !k[i].stat && ( (k[i].col == ply[act].col) ||
  265.     (!ply[act].col && (i != BLACK)) || egal ) )
  266.     while( (actual->ord == (ordnung-1) ) && (actual != NULL) )
  267.      {
  268.       b.x = k[i].p.x; b.y = k[i].p.y;
  269.       if( !in_line_c( i, actual->kno, b, actual->pos, 0, 0 ) )
  270.        {
  271.        c = calc_tp( b, actual->pos );
  272.        if( !out_of_bounds( c ) )
  273.         {
  274.         d.x = k[actual->kno].p.x - actual->pos.x; 
  275.         d.y = k[actual->kno].p.y - actual->pos.y;
  276.         e.x = actual->pos.x - c.x;
  277.     e.y = actual->pos.y - c.y;
  278.         if( (dummy = COSV( d, e )) > max_angle )
  279.          {
  280.       /* Zirkelschlüsse vermeiden !!! !!! !!! */
  281.           dum = malloc( sizeof( struct target ) );
  282.           dum->pos.x = c.x;
  283.           dum->pos.y = c.y;
  284.       dum->test = actual;
  285.       /* unten: es dürfen nicht ALLE (auch die vorherigen) Strecken durch
  286.          den cos geteilt werden, nur die letzte !!! !!! !!! */
  287.       dum->spd = SET_V( BETR(e), actual->spd / dummy );
  288.       dum->angle = (actual->angle) * dummy;
  289.           dum->kno = i;
  290.           dum->ord = ordnung;
  291.           dum->next = end->next;
  292.           end->next = dum;
  293.           end = end->next; /* = dum */          
  294.          }
  295.     }
  296.        }
  297.       actual = actual->next;
  298.      }
  299.    }
  300.  return end;
  301. }
  302.  
  303. int plot_targets( void )
  304. /* Malt die mit mark_combi, mark_higher_combies berechneten Punkte */
  305.  {
  306.  int i = 0, x, y;
  307.  struct target *actt;
  308.  actt = t.next;
  309.  while( actt != NULL )
  310.   {
  311.   x = actt->pos.x*DIFFX+LEFT;
  312.   y = actt->pos.y*DIFFX+UP;
  313.   GrLine( x-2, y-2, x+2, y+2, 7 | GrXOR );
  314.   GrLine( x-2, y+2, x-1, y+1, 7 | GrXOR );
  315.   GrLine( x+1, y-1, x+2, y-2, 7 | GrXOR );
  316.   actt = actt->next;
  317.   i++;
  318.   }
  319.  return i; 
  320.  }
  321.  
  322. void mark_combi( void )
  323. /* markiert die "targets", also die Punkte, die, wenn man sie mit der Weißen
  324.    anspielt, entweder direkt, oder über einige andere Kugeln (Kombie), eine
  325.    Kugel versenken ... !, s. auch mark_higher_combies() */
  326.  {
  327.  int i, j, next;
  328.  double dummy;
  329.  struct vect a, b, c, d, e;
  330.  struct target *dum, *actt;
  331.  actt = &t;
  332.  /* Es folgen die "targets" 0. Ordnung, also eigentlich keine Kombies,
  333.     sondern einfach Kugeln, die direkt ins Loch gespielt werden können */
  334.  for( i=0;i<WHITE;i++ )
  335.   if( !k[i].stat && ( (k[i].col == ply[act].col) ||
  336.   (!ply[act].col && (i != BLACK)) ) )
  337.    {
  338.    for( j=0;j<6;j++ )
  339.     {
  340.      b.x = posl[j].p.x-posl[j].m.x; /*ersteinmal alles so lassen !!! !!! !!!*/
  341.      b.y = posl[j].p.y-posl[j].m.y;
  342.      /* u: dieses if fragt ab, ob sich eine Kugel schon fast im Loch befindet,
  343.         ob sie also so liegt, daß man sie einfach nur in Richutung Loch 
  344.     (irgendwie) anstoßen muß, damit sie ins Loch rollt; die "14" ergibt
  345.     sich (bei den Ecklöchern aus sqrt(2)*Bandendicke... */
  346.      if( DIFF( posl[j].p.x-k[i].p.x, posl[j].p.y-k[i].p.y ) <= 
  347.       ((RADIUSL+14)*(RADIUSL+14)/(DIFFX*DIFFX)) )
  348.        { c.x = posl[j].p.x - k[i].p.x; c.y = posl[j].p.y - k[i].p.y; }
  349.      else /* d.h., Kugel liegt noch nicht fast im Loch */
  350.       { c.x = posl[j].m.x - k[i].p.x; c.y = posl[j].m.y - k[i].p.y; }
  351.      if( ( ((j == 2) || (j == 5)) && (COSV(b, c) > COS(e_winkel)) ) 
  352.       || ( (j != 2)  && (j != 5 )) )
  353.       {
  354.        d.x = k[i].p.x; d.y = k[i].p.y;
  355.        if( DIFF( posl[j].p.x-k[i].p.x, posl[j].p.y-k[i].p.y ) <= 
  356.         ((RADIUSL+14)*(RADIUSL+14)/(DIFFX*DIFFX)) )
  357.         {  
  358.         /* "unsaubere" Lösung: Wenn eine Kugel schon fast im Loch liegt,
  359.        wird hier einfach der Treffpunkt in Richtung Mittelpunkt des Lochs
  360.        verschoben, da dieser besser zu treffen ist !!! */
  361.         b.x = posl[j].p.x - posl[j].m.x;
  362.     b.y = posl[j].p.y - posl[j].m.y; 
  363.     if( (dummy = BETR( b )) ) { b.x /= dummy; b.y /= dummy; }
  364.     c.x = d.x - b.x * 2.0*RADIUS/DIFFX; 
  365.     c.y = d.y - b.y * 2.0*RADIUS/DIFFX;
  366.     next = 1;
  367.     }
  368.        else /* d.h., Kugel liegt noch nicht fast im Loch */
  369.         { 
  370.      b.x = posl[j].m.x; b.y = posl[j].m.y; next = 0; 
  371.          c = calc_tp( d, b );
  372.         }
  373.        if( next || !out_of_bounds( c ) )
  374.         {
  375.         d.x = c.x - k[WHITE].p.x;
  376.         d.y = c.y - k[WHITE].p.y;
  377.         e.x = k[i].p.x - c.x;
  378.         e.y = k[i].p.y - c.y;
  379.     a.x = k[i].p.x;
  380.     a.y = k[i].p.y;    /* -0.95 ? */
  381.         if( (COSV( d, e ) > -0.95) && (!in_line_c( i, i, a, b, 6, 0) ) )
  382.          {
  383.           dum = malloc( sizeof( struct target ) );
  384.           dum->pos.x = c.x;
  385.           dum->pos.y = c.y;
  386.           b.x = posl[j].m.x - c.x;
  387.           b.y = posl[j].m.y - c.y;   /* u: letzteres, da nicht IM Loch ..! */
  388.       dum->spd = SET_V( BETR(b), 0 );
  389.       dum->angle = 1.0;
  390.           dum->kno = i;
  391.           dum->ord = 0;
  392.       dum->test = NULL;
  393.           dum->next = actt->next;
  394.           actt->next = dum;
  395.           actt = actt->next; /* = dum */    
  396.      }
  397.        }
  398.       }
  399.     }
  400.    }
  401. /* jetzt: Kombies höherer Ordnung, also "echte" Mehrfachstöße .... */
  402.  for( i=1;i<CLEV;i++ )
  403.   actt = mark_higher_combies( actt, i, 1, 0.05 + 0.05*i );
  404.  mark_higher_combies( actt, CLEV, 0, 0.05 + 0.05*i ); /*f.CLEV=0 geht's auch*/
  405.  }
  406.  
  407. void delete_targets( struct target *dum )
  408. /* Löscht am Ende alle mit mark_combi() erstellten targets aus der Liste */
  409.  {
  410.  if( dum->next != NULL ) delete_targets( dum->next );
  411.  free( dum );
  412.  }
  413.  
  414. void plot_line( struct target *head ) 
  415. /* malt den Weg, von der Weißen ausgehend bis ins Loch, evtl über alle 
  416.    Kombies, den die Kugeln nehmen sollen (!), nachdem der Computer mit 
  417.    mark_... diesen Weg indirekt berechnet hat */
  418.  {
  419.   struct target *actual;
  420.   int oldx, oldy, x, y, i;
  421.   struct vect a, b;
  422.   actual = head;
  423.   oldx = k[WHITE].p.x*DIFFX+LEFT;
  424.   oldy = k[WHITE].p.y*DIFFX+UP;
  425.   while( actual->test != NULL )
  426.    {
  427.     x = (actual->pos.x)*DIFFX+LEFT;
  428.     y = (actual->pos.y)*DIFFX+UP;
  429.     GrLine( oldx, oldy, x, y, 6 | GrXOR );    
  430.     oldx = x;
  431.     oldy = y;
  432.     actual = actual->test;
  433.    }
  434.   x = (actual->pos.x)*DIFFX+LEFT;
  435.   y = (actual->pos.y)*DIFFX+UP;
  436.   GrLine( oldx, oldy, x, y, 6 | GrXOR );    
  437.   /* letzter Weg muß "geraten" werden (!?) */
  438.   for( i=0;i<6;i++ )
  439.    {
  440.     a.x = posl[i].m.x - actual->pos.x;
  441.     a.y = posl[i].m.y - actual->pos.y;
  442.     b.x = k[actual->kno].p.x - actual->pos.x;
  443.     b.y = k[actual->kno].p.y - actual->pos.y;
  444.     if( (COSV( a, b ) > 0.99) || (sqrt(DIFF( posl[i].p.x - k[actual->kno].p.x,
  445.      posl[i].p.y - k[actual->kno].p.y )) < (RADIUSL+2.0*RADIUS)/DIFFX) )
  446.      {
  447.       GrLine( x, y, posl[i].m.x*DIFFX+LEFT, posl[i].m.y*DIFFX+UP, 6 | GrXOR );
  448.       break;
  449.      }
  450.    }
  451.  }
  452.  
  453. void wait_user_time( double time )
  454.  { /* wartet time Sekunden */
  455.  clock_t old_t = clock();
  456.  if( demo ) time /= 2.0;
  457.  if( kbhit() ) 
  458.   { 
  459.   msg("computer-play stopped..."); 
  460.   if( getkey() == 27 ) stop_it(); 
  461.   demo = 0; 
  462.   c_player = -1;
  463.   }
  464.  while( (clock() - old_t)/CLOCKS_PER_SEC < time );
  465.  }
  466.  
  467. void computer_stoss( void )
  468. /* Der eigentliche Computer-"Spieler", hier werden die obigen Prozeduren
  469.    benötigt... */
  470.  {
  471.  struct vect v, v1, v2;
  472.  int j, ende=0, color=0, ok = -10;
  473.  double dummy, dummy2;
  474.  struct target *dum, *best_dum = NULL;
  475.  char out[80];
  476.  set_spin( 0.0, 0.0, 0.0 );
  477.  wink( alph=0.0 );
  478.  old_ball = -1;
  479.  old_hole = -1;
  480.  old_min = 0.0001;
  481.  t.next = NULL; /* t: Kopf der "target-Liste" */
  482.  if( anstoss )
  483.   {
  484.   mouse_off();
  485.   plot_one_ball( WHITE );
  486.   k[WHITE].p.x = 0.25;
  487.   k[WHITE].p.y = 0.5 - (RADIUS+1)/DIFFX;
  488.   v.x = k[2].p.x - k[WHITE].p.x;
  489.   v.y = k[2].p.y - k[WHITE].p.y;
  490.   dummy = BETR( v );
  491.   k[WHITE].v.x = v.x / (dummy * DIFFX);
  492.   k[WHITE].v.y = v.y / (dummy * DIFFX);
  493.   speed( spd = 1 );
  494.   set_spin( 0.0, -k[WHITE].v.x*DIFFX, -k[WHITE].v.y );
  495.   wink( alph = 0 );
  496.   plot_one_ball( WHITE );
  497.   debug("full-power first one...");
  498.   wait_user_time( 2.0/3.0 );
  499.   return;
  500.   }
  501.  mark_combi();
  502.  if( t.next != NULL ) /* d.h., es gibt anspielbare Kugeln ! */
  503.   {
  504.    dum = t.next;
  505.    do
  506.     {
  507.      v.x = k[WHITE].p.x;
  508.      v.y = k[WHITE].p.y;
  509.      color = k[dum->kno].col;
  510.      if( ( (color == ply[act].col) || (!ply[act].col && ( color != 3 )) ) )
  511.       if( !in_line_c( dum->kno, dum->kno, v, dum->pos, 0, 0 ) )
  512.        {
  513.         v1.x = dum->pos.x - v.x;
  514.         v1.y = dum->pos.y - v.y;
  515.         v2.x = k[dum->kno].p.x - dum->pos.x;
  516.         v2.y = k[dum->kno].p.y - dum->pos.y;
  517.     if( ((dummy2=COSV( v1, v2 )) > 0.1) && ( old_min < ( dummy2 *
  518.      (dum->angle) ) ) )
  519.          {
  520. #ifdef HOLE_INLINE
  521.       Abfrage, ob Weiße ins Loch fällt !!! !!! !!! ist noch arg
  522.       verbesserungsbedürftig, muß noch die Rest-Geschw. der Weißen nach
  523.       dem Stoß miteinbeziehen !!!  
  524.       struct vect v3, v4, v5;
  525.       v3.x = k[dum->kno].p.x - dum->pos.x;
  526.       v3.y = k[dum->kno].p.y - dum->pos.y;
  527.       dummy = BETR( v3 ); / if != 0, (naja) /
  528.       v3.x /= dummy; v3.y /= dummy;
  529.       v4.x = dum->pos.x - k[WHITE].p.x; v4.y = dum->pos.y - k[WHITE].p.y;
  530.       dummy = BETR( v4 );
  531.       v4.x /= dummy; v4.y /= dummy;
  532.       v5.x = (dummy3=SKALP( v3, v4 )) * v3.x; 
  533.       v5.y = dummy3 * v3.y;
  534.       v4.x -= v5.x; v4.y -= v5.y;
  535.       dummy = BETR( v4 );
  536.       v4.x /= dummy; v4.y /= dummy;
  537.       if( !(hole_inline( v4, dum->pos ) && dummy2 < 0.85 ) )
  538. #endif
  539.            {
  540.         old_min = dummy2 * (dum->angle);
  541.             best_dum = dum;
  542.            }
  543. #ifdef HOLE_INLINE
  544.           else /*"Weiße wäre reingegegangen !!!" */ {}
  545. #endif
  546.          }
  547.        }
  548.      if( dum->next == NULL ) ende = 1;
  549.      else dum = dum->next;
  550.     }
  551.    while( !ende );
  552.   }
  553.  /* So... der beste Stoß verläuft nun in Richtung best_dum ..... */   
  554.  if( best_dum != NULL )
  555.  /* Man müßte noch testen, ob sich eine der Konigs-Kugelbanden im Weg einer
  556.     Kugel befindet ... !!! !!! !!! */
  557.   {
  558.    if( best_dum->ord == 0) sprintf(out,"will be a normal shot...");
  559.    else sprintf(out, "o.k., this will be a 'Combi' %d. Ord.",best_dum->ord);
  560.    debug(out);
  561.    v1.x = best_dum->pos.x - v.x;
  562.    v1.y = best_dum->pos.y - v.y;
  563.    v2.x = k[best_dum->kno].p.x - best_dum->pos.x;
  564.    v2.y = k[best_dum->kno].p.y - best_dum->pos.y;
  565.    /* Hier wird's viel zuviel, da die GESAMTE bisherige Strecke durch den
  566.       Kosinus geteilt wird !!! !!! !!! */
  567.    if( (dummy2 = COSV( v1, v2 )) )
  568.     dummy = SET_V( BETR(v1), best_dum->spd / dummy2);
  569.    else dummy = 100000.0;
  570.    set_c_speed( dummy, v1 );
  571.    plot_line( best_dum );
  572.    if( (c_player == -1) || (act != c_player) ) 
  573.     { 
  574.      plot_targets(); 
  575.      if( getkey() == 27 ) stop_it();
  576.      plot_targets();
  577.     }
  578.    else wait_user_time( 2.0/3.0 );
  579.    plot_line( best_dum );
  580.   }
  581.  else
  582.   {
  583.    for( j=0;j<WHITE;j++)
  584.     if( !k[j].stat && ( (k[j].col == ply[act].col) 
  585.      || ( !ply[act].col && (j != BLACK) ) ) )
  586.       {
  587.        /* 1. Fall: einen Ball der akt.Farbe zentral treffen (safety-shot) */
  588.        v.x = k[WHITE].p.x; v.y = k[WHITE].p.y; 
  589.        v1.x = k[j].p.x - v.x; v1.y = k[j].p.y - v.y;
  590.        if( (dummy = BETR( v1 )) ) { v2.x = v1.x/dummy; v2.y = v1.y/dummy; }
  591.        else v2.x = v2.y = 0;
  592.        v1.x = k[j].p.x - v2.x * 2.0*RADIUS/DIFFX;
  593.        v1.y = k[j].p.y - v2.y * 2.0*RADIUS/DIFFX;
  594.        /* obiges, da in in_line_c() wieder verlängert wird ... !! */
  595.        if( !in_line_c( j, j, v, v1, 6, 0 ) ) { ok = 0; }
  596.        if( ok == -10 ) /* 2. Fall, links am Rand ... */
  597.         {
  598.          v1.x = k[j].p.x; v1.y = k[j].p.y;
  599.      v2.x = v1.x - v.x; v2.y = v1.y - v.y;
  600.      if( (dummy = BETR( v2 )) ) { v2.x /= dummy; v2.y /= dummy; }
  601.      dummy = v2.x;
  602.      v1.x -= (2*RADIUS-1.0)/DIFFX * v2.y;
  603.      v1.y += (2*RADIUS-1.0)/DIFFX * v2.x;
  604.          if( !in_line_c( j, j, v, v1, 6, 0 ) )  { ok = 1; }
  605.     }
  606.        if( ok == -10 ) /* 3. Fall: rechts am Rand... */
  607.         {
  608.          v1.x = k[j].p.x; v1.y = k[j].p.y;
  609.      v1.x += (2*RADIUS-1.0)/DIFFX * v2.y;
  610.      v1.y -= (2*RADIUS-1.0)/DIFFX * v2.x;
  611.          if( !in_line_c( j, j, v, v1, 6, 0 ) )  { ok = -1; }
  612.     }
  613.        if( ok != -10 ) j = BALLS; /* ---> eigentlich break; */
  614.       }
  615.      if( ( ok == -10 ) && !freeball ) 
  616.       {
  617.        debug("I've no idea..."); /* Kein Ball "stoßbar" */
  618.        /* Wenn der Computer schon foult, dann so, daß die Weiße hinter
  619.        irgendeiner Kugel liegen bleibt ... */
  620.        /* zuerst überprüfen, ob Weg zur Schwarzen frei! */
  621.        v.x = k[BLACK].p.x - k[WHITE].p.x;
  622.        v.y = k[BLACK].p.y - k[WHITE].p.y;
  623.        if( (dummy = BETR( v )) ) { v2.x = v.x/dummy; v2.y = v.y/dummy; }
  624.        else v2.x = v2.y = 0;
  625.        v1.x = k[BLACK].p.x - v2.x * 2*RADIUS/DIFFX; 
  626.        v1.y = k[BLACK].p.y - v2.y * 2*RADIUS/DIFFX;
  627.        if( in_line_c( BLACK, BLACK, k[WHITE].p, v1, 0, 0 ) )
  628.         { /* d.h., Weg zur Schwarzen ist nicht frei ! ... */
  629.          dummy = 100000;
  630.          for( j=0;j<WHITE;j++ )
  631.       if( !k[j].stat 
  632.        && (DIFF( k[j].p.x-k[WHITE].p.x, k[j].p.y-k[WHITE].p.y ) < dummy) )
  633.         { dummy = DIFF( k[j].p.x-k[WHITE].p.x, k[j].p.y-k[WHITE].p.y ); 
  634.          color=j; }
  635.          v.x = k[color].p.x - k[WHITE].p.x;
  636.          v.y = k[color].p.y - k[WHITE].p.y;
  637.         }
  638.        set_c_speed( SET_V(BETR( v ) - (2.0*RADIUS)/DIFFX,0), v );
  639.       }
  640.      else /* if( ok ==-1,0,1), d.h. Ball kann getroffen werden */
  641.       {
  642.        if( ok == 0 ) debug("'safety-shot' <c>");
  643.        else if( ok == -1 ) debug("'safety-shot' <l>");
  644.        else if( ok == 1 ) debug("'safety-shot' <r>");
  645.        v.x = v1.x - k[WHITE].p.x;  v.y = v1.y - k[WHITE].p.y;
  646.        /* Geschwindigkeit wird bisher noch so gesetzt, daß in die aktuelle 
  647.           Richtung einfach die Strecke 1 dazugezählt wird, was meistens einen
  648.         viel zu festen "safety-shot" zur Folge hat, ÄNDERN !!! !!! !!! 
  649.       (ist inzwischen schon viel besser, prinz. aber verbessern) */
  650.        set_c_speed(SET_V(BETR(v)+1.0+4.0*(ply[1-act].wait!=0),0),v);
  651.       }
  652.      if( (c_player == -1) || (act != c_player) )
  653.       {
  654.       char c = getkey();
  655.       if( c == 27 ) stop_it();
  656.       }
  657.      else wait_user_time( 2.0/3.0 );
  658.   }
  659.  if( t.next != NULL ) delete_targets( t.next );
  660.  }
  661.  
  662. void calc_hot_spot( void )
  663.  { /* Mittelpunkte der Löcher, zum Zielen für den Computer-Gegner */
  664.  posl[0].m.x = (ban[1].p0.x+RADIUS-1)/DIFFX;        /* Loch l. unten */
  665.  posl[0].m.y = (ban[10].p0.y-RADIUS+1)/DIFFX; 
  666.  posl[1].m.x = (ban[1].p0.x+RADIUS)/DIFFX;        /* links oben */
  667.  posl[1].m.y = (ban[7].p0.y+RADIUS+0.5)/DIFFX;
  668.  posl[2].m.x = (ban[8].p1.x+ban[12].p0.x)/(2.0*DIFFX);    /* Mitte oben */
  669.  posl[2].m.y = posl[2].p.y + (RADIUSL-1.5)/DIFFX;
  670.  posl[3].m.x = (ban[4].p1.x-RADIUS)/DIFFX;        /* rechts oben */
  671.  posl[3].m.y = (ban[13].p1.y+RADIUS+0.5)/DIFFX;
  672.  posl[4].m.x = (ban[4].p0.x-RADIUS+1)/DIFFX;        /* rechts unten */
  673.  posl[4].m.y = (ban[16].p0.y-RADIUS+1)/DIFFX;
  674.  posl[5].m.x = (ban[9].p0.x+ban[17].p1.x)/(2.0*DIFFX);    /* Mitte unten */
  675.  posl[5].m.y = posl[5].p.y - (RADIUSL-1.5)/DIFFX;
  676.  }
  677.