ref: 961c08f468a543948e8855d62ce017f61b04fda8
dir: /andy.c/
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <geometry.h>
#include "dat.h"
#include "fns.h"
/* Nexus-9 technology from The Rosen Association */
static char *nametab[] = {
"hannibal",
"luba",
"roy",
"irmgard",
"buster",
"rachael",
"phil",
"pris",
"polokov",
"zhora",
"kowalski",
"luv",
"sapper",
"freysa",
"mariette",
};
Point2 nwes[] = {
{0,-1,0},
{-1,0,0}, {1,0,0},
{0,1,0},
};
static char *
getaname(void)
{
return nametab[getrand(nelem(nametab))];
}
static void
turnaround(Andy *a)
{
if(--a->passes > 0){
a->passdir = mulpt2(a->passdir, -1);
a->lastshot = a->firsthit;
}else
a->disengage(a);
}
static int
between(double n, double min, double max)
{
return n >= min && n < max;
}
static int
lineXline(Point2 min0, Point2 max0, Point2 min1, Point2 max1)
{
double a₁, b₁;
double a₂, b₂;
double det;
a₁ = max0.y - min0.y;
b₁ = min0.x - max0.x;
a₂ = max1.y - min1.y;
b₂ = min1.x - max1.x;
det = a₁*b₂ - a₂*b₁;
if(det == 0){
/* do they overlap? */
if((min0.x == min1.x && (between(min0.y, min1.y, max1.y) || between(max0.y, min1.y, max1.y))) ||
(min0.y == min1.y && (between(min0.x, min1.x, max1.x) || between(max0.x, min1.x, max1.x))))
return 1;
return 0;
}
return 1;
}
static void
andy_layout(Andy *a, Msg *m)
{
Point2 cells[NSHIPS], sv[NSHIPS];
char buf[NSHIPS*(1+3+1)+1];
int i, j, o[NSHIPS], n;
for(i = 0; i < NSHIPS; i++){
Retry:
cells[i] = Pt2(getrand(MAPW-shiplen(i)), getrand(MAPH-shiplen(i)), 1);
o[i] = getrand(1<<20)&1? OH: OV;
sv[i] = o[i] == OH? Vec2(1,0): Vec2(0,1);
fprint(2, "%d%c ", i, o[i] == OH? 'h': 'v');
for(j = 0; j < i; j++)
if(lineXline(cells[i], addpt2(cells[i], mulpt2(sv[i], shiplen(i))),
cells[j], addpt2(cells[j], mulpt2(sv[j], shiplen(j)))))
goto Retry;
}
fprint(2, "\n");
n = 0;
for(i = 0; i < nelem(cells); i++){
assert(sizeof buf - n > 1+3+1);
if(i != 0)
buf[n++] = ',';
n += cell2coords(buf+n, sizeof buf - n, cells[i]);
buf[n++] = o[i] == OH? 'h': 'v';
}
buf[n] = 0;
m->body = smprint("layout %s", buf);
sendp(a->ego->battle->data, m);
}
static void
andy_shoot(Andy *a, Msg *m)
{
Point2 cell;
char buf[3+1];
Retry:
switch(a->state){
case ASearching:
do
cell = Pt2(getrand(MAPW), getrand(MAPH), 1);
while(gettile(a, cell) != Twater);
break;
case ACalibrating:
do
cell = addpt2(a->firsthit, nwes[--a->ntries&3]);
while((gettile(a, cell) != Twater || isoob(cell)) && a->ntries > 1);
if(gettile(a, cell) != Twater || isoob(cell)){
a->disengage(a);
goto Retry;
}
break;
case ABombing:
cell = addpt2(a->lastshot, a->passdir);
if(gettile(a, cell) != Twater || isoob(cell)){
turnaround(a);
goto Retry;
}
break;
}
cell2coords(buf, sizeof buf, cell);
m->body = smprint("shoot %s", buf);
sendp(a->ego->battle->data, m);
a->lastshot = cell;
}
static void
andy_engage(Andy *a)
{
a->firsthit = a->lastshot;
a->state = ACalibrating;
a->ntries = nelem(nwes);
a->passes = 2;
}
static void
andy_disengage(Andy *a)
{
a->state = ASearching;
}
static void
andy_registerhit(Andy *a)
{
settile(a, a->lastshot, Thit);
if(a->state == ASearching)
a->engage(a);
else if(a->state == ACalibrating){
a->passdir = subpt2(a->lastshot, a->firsthit);
a->state = ABombing;
}
}
static void
andy_registermiss(Andy *a)
{
settile(a, a->lastshot, Tmiss);
if(a->state == ACalibrating && a->ntries < 1)
a->disengage(a);
else if(a->state == ABombing)
turnaround(a);
}
Andy *
newandy(Player *p)
{
Andy *a;
a = emalloc(sizeof *a);
a->ego = p;
snprint(p->name, sizeof p->name, "%s", getaname());
a->state = ASearching;
a->layout = andy_layout;
a->shoot = andy_shoot;
a->engage = andy_engage;
a->disengage = andy_disengage;
a->registerhit = andy_registerhit;
a->registermiss = andy_registermiss;
return a;
}
void
freeandy(Andy *a)
{
free(a);
}