Exemplo n.º 1
0
Arquivo: bs.c Projeto: a565109863/src
/* Checks to see if there's room for a ship of a given length in a given
 * direction.  If direction is negative, check in all directions.  Note
 * that North and South are equivalent, as are East and West.
 */
static bool
cpushipcanfit(int x, int y, int length, int direction)
{
	int len = 1;
	int x1, y1;

	if (direction >= 0)
	{
		direction %= 4;
		while (direction < 8)
		{
			x1 = x + xincr[direction];
			y1 = y + yincr[direction];
			while (POSSIBLE(x1,y1))
			{
			    len++;
			    x1 += xincr[direction];
			    y1 += yincr[direction];
			}
			direction += 4;
		}
		return (len >= length);
	}
	else
	{
		return ((cpushipcanfit(x,y,length,E)) ||
			    (cpushipcanfit(x,y,length,S)));
	}
}
Exemplo n.º 2
0
/*
 * This code implements a fairly irregular FSM, so please forgive the rampant
 * unstructuredness below. The five labels are states which need to be held
 * between computer turns.
 *
 * The FSM is not externally reset to RANDOM_FIRE if the player wins. Instead,
 * the other states check for "impossible" conditions which signify a new
 * game, then if found transition to RANDOM_FIRE.
 */
static bool
cputurn(void)
{
#define POSSIBLE(x, y)	(ONBOARD(x, y) && !hits[COMPUTER][x][y])
#define RANDOM_FIRE	0
#define RANDOM_HIT	1
#define HUNT_DIRECT	2
#define FIRST_PASS	3
#define REVERSE_JUMP	4
#define SECOND_PASS	5
    static int next = RANDOM_FIRE;
    static bool used[4];
    static ship_t ts;
    int navail, x, y, d, n;
    int hit = S_MISS;

    switch (next) {
    case RANDOM_FIRE:		/* last shot was random and missed */
      refire:
	randomfire(&x, &y);
	if (!(hit = cpufire(x, y)))
	    next = RANDOM_FIRE;
	else {
	    ts.x = x;
	    ts.y = y;
	    ts.hits = 1;
	    next = (hit == S_SUNK) ? RANDOM_FIRE : RANDOM_HIT;
	}
	break;

    case RANDOM_HIT:		/* last shot was random and hit */
	used[E / 2] = used[S / 2] = used[W / 2] = used[N / 2] = FALSE;
	/* FALLTHROUGH */

    case HUNT_DIRECT:		/* last shot hit, we're looking for ship's long axis */
	for (d = navail = 0; d < 4; d++) {
	    x = ts.x + xincr[d * 2];
	    y = ts.y + yincr[d * 2];
	    if (!used[d] && POSSIBLE(x, y))
		navail++;
	    else
		used[d] = TRUE;
	}
	if (navail == 0)	/* no valid places for shots adjacent... */
	    goto refire;	/* ...so we must random-fire */
	else {
	    n = rnd(navail) + 1;
	    for (d = 0; used[d]; d++) ;
	    /* used[d] is first that == 0 */
	    for (; n > 1; n--)
		while (used[++d]) ;
	    /* used[d] is next that == 0 */

	    assert(d < 4);
	    assert(used[d] == FALSE);

	    used[d] = TRUE;
	    x = ts.x + xincr[d * 2];
	    y = ts.y + yincr[d * 2];

	    assert(POSSIBLE(x, y));

	    if (!(hit = cpufire(x, y)))
		next = HUNT_DIRECT;
	    else {
		ts.x = x;
		ts.y = y;
		ts.dir = d * 2;
		ts.hits++;
		next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS;
	    }
	}
	break;

    case FIRST_PASS:		/* we have a start and a direction now */
	x = ts.x + xincr[ts.dir];
	y = ts.y + yincr[ts.dir];
	if (POSSIBLE(x, y) && (hit = cpufire(x, y))) {
	    ts.x = x;
	    ts.y = y;
	    ts.hits++;
	    next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS;
	} else
	    next = REVERSE_JUMP;
	break;

    case REVERSE_JUMP:		/* nail down the ship's other end */
	d = (ts.dir + 4) % 8;
	x = ts.x + ts.hits * xincr[d];
	y = ts.y + ts.hits * yincr[d];
	if (POSSIBLE(x, y) && (hit = cpufire(x, y))) {
	    ts.x = x;
	    ts.y = y;
	    ts.dir = d;
	    ts.hits++;
	    next = (hit == S_SUNK) ? RANDOM_FIRE : SECOND_PASS;
	} else
	    next = RANDOM_FIRE;
	break;

    case SECOND_PASS:		/* continue shooting after reversing */
	x = ts.x + xincr[ts.dir];
	y = ts.y + yincr[ts.dir];
	if (POSSIBLE(x, y) && (hit = cpufire(x, y))) {
	    ts.x = x;
	    ts.y = y;
	    ts.hits++;
	    next = (hit == S_SUNK) ? RANDOM_FIRE : SECOND_PASS;
	    break;
	} else
	    next = RANDOM_FIRE;
	break;
    }

    /* pause between shots in salvo */
    if (salvo) {
	(void) refresh();
	(void) sleep(1);
    }
#ifdef DEBUG
    (void) mvprintw(PROMPTLINE + 2, 0,
		    "New state %d, x=%d, y=%d, d=%d",
		    next, x, y, d);
#endif /* DEBUG */
    return ((hit) ? TRUE : FALSE);
}
Exemplo n.º 3
0
/*
 * This code implements a fairly irregular FSM, so please forgive the rampant
 * unstructuredness below. The five labels are states which need to be held
 * between computer turns.
 */
static bool
cputurn(void)
{
#define POSSIBLE(x, y)	(ONBOARD(x, y) && !hits[COMPUTER][x][y])
#define RANDOM_FIRE	0
#define RANDOM_HIT	1
#define HUNT_DIRECT	2
#define FIRST_PASS	3
#define REVERSE_JUMP	4
#define SECOND_PASS	5
    static int next = RANDOM_FIRE;
    static bool used[4];
    static ship_t ts;
    int navail, x, y, d, n, hit = S_MISS;

    switch(next)
    {
    case RANDOM_FIRE:	/* last shot was random and missed */
    refire:
	randomfire(&x, &y);
	if (!(hit = cpufire(x, y)))
	    next = RANDOM_FIRE;
	else
	{
	    ts.x = x; ts.y = y;
	    ts.hits = 1;
	    next = (hit == S_SUNK) ? RANDOM_FIRE : RANDOM_HIT;
	}
	break;

    case RANDOM_HIT:	/* last shot was random and hit */
	used[E/2] = used[S/2] = used[W/2] = used[N/2] = FALSE;
	/* FALLTHROUGH */

    case HUNT_DIRECT:	/* last shot hit, we're looking for ship's long axis */
	for (d = navail = 0; d < 4; d++)
	{
	    x = ts.x + xincr[d*2]; y = ts.y + yincr[d*2];
	    if (!used[d] && POSSIBLE(x, y))
		navail++;
	    else
		used[d] = TRUE;
	}
	if (navail == 0)	/* no valid places for shots adjacent... */
	    goto refire;	/* ...so we must random-fire */
	else
	{
	    for (d = 0, n = rnd(navail) + 1; n; n--)
		while (used[d])
		    d++;

	    assert(d <= 4);

	    used[d] = FALSE;
	    x = ts.x + xincr[d*2];
	    y = ts.y + yincr[d*2];

	    assert(POSSIBLE(x, y));

	    if (!(hit = cpufire(x, y)))
		next = HUNT_DIRECT;
	    else
	    {
		ts.x = x; ts.y = y; ts.dir = d*2; ts.hits++;
		next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS;
	    }
	}
	break;

    case FIRST_PASS:	/* we have a start and a direction now */
	x = ts.x + xincr[ts.dir];
	y = ts.y + yincr[ts.dir];
	if (POSSIBLE(x, y) && (hit = cpufire(x, y)))
	{
	    ts.x = x; ts.y = y; ts.hits++;
	    next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS;
	}
	else
	    next = REVERSE_JUMP;
	break;

    case REVERSE_JUMP:	/* nail down the ship's other end */
	d = ts.dir + 4;
	x = ts.x + ts.hits * xincr[d];
	y = ts.y + ts.hits * yincr[d];
	if (POSSIBLE(x, y) && (hit = cpufire(x, y)))
	{
	    ts.x = x; ts.y = y; ts.dir = d; ts.hits++;
	    next = (hit == S_SUNK) ? RANDOM_FIRE : SECOND_PASS;
	}
	else
	    next = RANDOM_FIRE;
	break;

    case SECOND_PASS:	/* kill squares not caught on first pass */
	x = ts.x + xincr[ts.dir];
	y = ts.y + yincr[ts.dir];
	if (POSSIBLE(x, y) && (hit = cpufire(x, y)))
	{
	    ts.x = x; ts.y = y; ts.hits++;
	    next = (hit == S_SUNK) ? RANDOM_FIRE: SECOND_PASS;
	    break;
	}
	else
	    next = RANDOM_FIRE;
	break;
    }

    /* check for continuation and/or winner */
    if (salvo)
    {
	refresh();
	sleep(1);
    }
    if (awinna() != -1)
	return(FALSE);

#ifdef DEBUG
    mvprintw(PROMPTLINE + 2, 0,
		    "New state %d, x=%d, y=%d, d=%d",
		    next, x, y, d);
#endif /* DEBUG */
    return(hit);
}
Exemplo n.º 4
0
Arquivo: bs.c Projeto: a565109863/src
/*
 * This code implements a fairly irregular FSM, so please forgive the rampant
 * unstructuredness below. The five labels are states which need to be held
 * between computer turns.
 */
static int
cputurn(void)
{
    static bool used[4];
    static ship_t ts;
    int navail, x, y, d, n, hit = S_MISS;
    bool closenoshot = FALSE;

    switch(next)
    {
    case RANDOM_FIRE:	/* last shot was random and missed */
    refire:
	randomfire(&x, &y);
	if (!(hit = cpufire(x, y)))
	    next = RANDOM_FIRE;
	else
	{
	    ts.x = x; ts.y = y;
	    ts.hits = 1;
	    next = (hit == S_SUNK) ? RANDOM_FIRE : RANDOM_HIT;
	}
	break;

    case RANDOM_HIT:	/* last shot was random and hit */
	used[E/2] = used[W/2] = (!(cpushipcanfit(ts.x,ts.y,cpushortest,E)));
	used[S/2] = used[N/2] = (!(cpushipcanfit(ts.x,ts.y,cpushortest,S)));
	/* FALLTHROUGH */

    case HUNT_DIRECT:	/* last shot hit, we're looking for ship's long axis */
	for (d = navail = 0; d < 4; d++)
	{
	    x = ts.x + xincr[d*2]; y = ts.y + yincr[d*2];
	    if (!used[d] && POSSIBLE(x, y))
		navail++;
	    else
		used[d] = TRUE;
	}
	if (navail == 0)	/* no valid places for shots adjacent... */
	    goto refire;	/* ...so we must random-fire */
	else
	{
	    for (d = 0, n = rnd(navail) + 1; n; n--,d++)
		while (used[d])
		    d++;
	    d--;

	    x = ts.x + xincr[d*2];
	    y = ts.y + yincr[d*2];

	    if (!(hit = cpufire(x, y)))
		next = HUNT_DIRECT;
	    else
	    {
		ts.x = x; ts.y = y; ts.dir = d*2; ts.hits++;
		next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS;
	    }
	}
	break;

    case FIRST_PASS:	/* we have a start and a direction now */
	x = ts.x + xincr[ts.dir];
	y = ts.y + yincr[ts.dir];
	if (POSSIBLE(x, y))
	{
	    if ((hit = cpufire(x, y)))
	    {
		    ts.x = x; ts.y = y; ts.hits++;
		    next = (hit == S_SUNK) ? RANDOM_FIRE : FIRST_PASS;
	    }
	    else
	         next = REVERSE_JUMP;
	    break;
	}
	else
	    next = REVERSE_JUMP;
	/* FALL THROUGH */

    case REVERSE_JUMP:	/* nail down the ship's other end */
	ts.dir = (ts.dir + 4) % 8;
	ts.x += (ts.hits-1) * xincr[ts.dir];
	ts.y += (ts.hits-1) * yincr[ts.dir];
	/* FALL THROUGH */

    case SECOND_PASS:	/* kill squares not caught on first pass */
	x = ts.x + xincr[ts.dir];
	y = ts.y + yincr[ts.dir];
	if (POSSIBLE(x, y))
	{
	    if ((hit = cpufire(x, y)))
	    {
		    ts.x = x; ts.y = y; ts.hits++;
		    next = (hit == S_SUNK) ? RANDOM_FIRE : SECOND_PASS;
	    }
	    else
	    {
	    /* The only way to get here is if closepack is on; otherwise,
	     * we _have_ sunk the ship.  I set hit to S_SUNK just to get
	     * the additional closepack logic at the end of the switch.
	     */
/*assert closepack*/
if (!closepack)  error("Assertion failed: not closepack 1");
		    hit = S_SUNK;
		    next = RANDOM_FIRE;
	    }
	}
	else
	{
/*assert closepack*/
if (!closepack)  error("Assertion failed: not closepack 2");
	    hit = S_SUNK;
	    closenoshot = TRUE;  /* Didn't shoot yet! */
	    next = RANDOM_FIRE;
	}
	break;
    }   /* switch(next) */

    if (hit == S_SUNK)
    {
	   /* Update cpulongest and cpushortest.  We could increase srchstep
	    * if it's smaller than cpushortest but that makes strategic sense
	    * only if we've been doing continuous diagonal stripes, and that's
	    * less interesting to watch.
	    */
	    ship_t *sp = plyship;

	    cpushortest = cpulongest;
	    cpulongest  = 0;
	    for (d=0 ; d < SHIPTYPES; d++, sp++)
	    {
		   if (sp->hits < sp->length)
		   {
		cpushortest = (cpushortest < sp->length) ? cpushortest : sp->length;
		cpulongest  = (cpulongest  > sp->length) ? cpulongest  : sp->length;
		   }
	    }
	    /* Now, if we're in closepack mode, we may have knocked off part of
	     * another ship, in which case we shouldn't do RANDOM_FIRE.  A
		* more robust implementation would probably do this check regardless
		* of whether closepack was set or not.
		* Note that MARK_HIT is set only for ships that aren't sunk;
		* hitship() changes the marker to the ship's character when the
		* ship is sunk.
	     */
	    if (closepack)
	    {
		  ts.hits = 0;
		  for (x = 0; x < BWIDTH; x++)
			for (y = 0; y < BDEPTH; y++)
			{
				if (hits[COMPUTER][x][y] == MARK_HIT)
				{
				/* So we found part of another ship.  It may have more
				 * than one hit on it.  Check to see if it does.  If no
				 * hit does, take the last MARK_HIT and be RANDOM_HIT.
				 */
	ts.x = x; ts.y = y; ts.hits = 1;
	for (d = 0; d < 8; d += 2)
	{
	    while ((ONBOARD(ts.x, ts.y)) && 
			(hits[COMPUTER][(int)ts.x][(int)ts.y] == MARK_HIT))
	    {
		    ts.x += xincr[d]; ts.y += yincr[d]; ts.hits++;
	    }
	    if ((--ts.hits > 1) && (ONBOARD(ts.x, ts.y)) &&
		    (hits[COMPUTER][(int)ts.x][(int)ts.y] == 0))
	    {
		    ts.dir = d;
		    ts.x -= xincr[d]; ts.y -= yincr[d];
		    d = 100;                  /* use as a flag */
		    x = BWIDTH; y = BDEPTH;   /* end the loop */
	    } else {
	         ts.x = x; ts.y = y; ts.hits = 1;
	    }
	
	}
				}
				if (ts.hits)
				{
					next = (d >= 100) ? FIRST_PASS : RANDOM_HIT;
				} else
					next = RANDOM_FIRE;
				}
	    }
	    if (closenoshot)
	    {
		   return(cputurn());
	    }
    }

    /* check for continuation and/or winner */
    if (salvo)
    {
	(void)refresh();
	(void)sleep(1);
    }

    return(hit);
}