#include #include #include #include #include #include #include #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); }