improve anaconda.c

make some changes to anaconda:
  -> fix memory leaks
  -> add tabs instead of spaces
  -> show score on screen
  -> adapt to different screen sizes
This commit is contained in:
randomuser 2022-08-15 18:42:26 -05:00
parent d37e632bd8
commit 6b5d621820
1 changed files with 171 additions and 126 deletions

View File

@ -8,15 +8,15 @@
#include <X11/Xlib.h> #include <X11/Xlib.h>
typedef struct point { typedef struct point {
double x; double x;
double y; double y;
struct point *next; struct point *next;
} point; } point;
typedef struct anaconda { typedef struct anaconda {
int score; int score;
double rot; double rot;
struct point *chain; struct point *chain;
} anaconda; } anaconda;
Display *d; Display *d;
@ -26,13 +26,13 @@ int s;
GC gc; GC gc;
void xinit(void) { void xinit(void) {
d = XOpenDisplay(NULL); d = XOpenDisplay(NULL);
s = DefaultScreen(d); s = DefaultScreen(d);
w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1, w = XCreateSimpleWindow(d, RootWindow(d, s), 10, 10, 100, 100, 1,
BlackPixel(d, s), WhitePixel(d, s)); BlackPixel(d, s), WhitePixel(d, s));
XSelectInput(d, w, ExposureMask | KeyPressMask | PointerMotionMask); XSelectInput(d, w, ExposureMask | KeyPressMask | PointerMotionMask);
XMapWindow(d, w); XMapWindow(d, w);
gc = XCreateGC(d, w, 0, NULL); gc = XCreateGC(d, w, 0, NULL);
} }
/* thanks to /* thanks to
@ -41,162 +41,207 @@ void xinit(void) {
*/ */
int ccw(point *a, point *b, point *c) { int ccw(point *a, point *b, point *c) {
return (c->y - a->y) * (b->x - a->x) > return (c->y - a->y) * (b->x - a->x) >
(b->y - a->y) * (c->x - a->x); (b->y - a->y) * (c->x - a->x);
} }
int intersect(point *a, point *b, point *c, point *d) { int intersect(point *a, point *b, point *c, point *d) {
return (ccw(a, c, d) != ccw(b, c, d)) && (ccw(a, b, c) != ccw(a, b, d)); return (ccw(a, c, d) != ccw(b, c, d)) && (ccw(a, b, c) != ccw(a, b, d));
} }
int randrange(int b, int s) { int randrange(int b, int s) {
return rand() % (b - s + 1) + s; return rand() % (b - s + 1) + s;
} }
int eucliddist(point *a, point *b) { int eucliddist(point *a, point *b) {
return sqrt(pow(a->x - b->x, 2) + pow(a->y - b->y, 2)); return sqrt(pow(a->x - b->x, 2) + pow(a->y - b->y, 2));
} }
point *mkPoint(double x, double y) { point *mkPoint(double x, double y) {
point *ret = malloc(sizeof *ret); point *ret = malloc(sizeof *ret);
ret->x = x; ret->x = x;
ret->y = y; ret->y = y;
ret->next = NULL; ret->next = NULL;
return ret; return ret;
} }
point *rotate(point *p, double rot) { point *rotate(point *p, double rot) {
double rad = rot * M_PI/180; double rad = rot * M_PI/180;
return mkPoint( return mkPoint(
p->x * cos(rad) - p->y * sin(rad), p->x * cos(rad) - p->y * sin(rad),
p->x * sin(rad) + p->y * cos(rad) p->x * sin(rad) + p->y * cos(rad)
); );
} }
void appendPoint(point *dest, point *origin) { void appendPoint(point *dest, point *origin) {
while(dest->next) dest = dest->next; while(dest->next) dest = dest->next;
dest->next = origin; dest->next = origin;
} }
int updateAnaconda(anaconda *anaconda, int w, int h, point *apple) { int updateAnaconda(anaconda *anaconda, point *basepoint, int w, int h, point *apple) {
point *temp, *new, *ptr; point *temp, *new, *ptr;
new = anaconda->chain; new = anaconda->chain;
temp = rotate(mkPoint(10, 0), anaconda->rot);
new = mkPoint(
new->x + temp->x,
new->y + temp->y
);
new->next = anaconda->chain;
anaconda->chain = new;
free(temp); temp = rotate(basepoint, anaconda->rot);
new = mkPoint(
new->x + temp->x,
new->y + temp->y
);
new->next = anaconda->chain;
anaconda->chain = new;
if(eucliddist(new, apple) <= 30) { free(temp);
anaconda->score += 30;
apple->x = randrange(20, w / 2);
apple->y = randrange(20, h / 2);
} else {
ptr = new;
while(1) { if(eucliddist(new, apple) <= 30) {
if(ptr->next) { anaconda->score += 30;
if(ptr->next->next) ptr = ptr->next; apple->x = randrange(20, w / 2);
else break; apple->y = randrange(20, h / 2);
} else break; } else {
} ptr = new;
free(ptr->next);
ptr->next = NULL;
}
ptr = anaconda->chain; while(1) {
for(int i = 0; i < 3; i++) { if(ptr->next) {
if(ptr->next) ptr = ptr->next; if(ptr->next->next) ptr = ptr->next;
else return 1; /* we're fine, the snake is too short to intersect itself */ else break;
} } else break;
}
free(ptr->next);
ptr->next = NULL;
}
while(ptr->next) { ptr = anaconda->chain;
if(intersect(new, new->next, ptr, ptr->next)) return 0; for(int i = 0; i < 3; i++) {
ptr = ptr->next; if(ptr->next) ptr = ptr->next;
} else return 1; /* we're fine, the snake is too short to intersect itself */
}
if( while(ptr->next) {
new->x >= w || new->x <= 0 || if(intersect(new, new->next, ptr, ptr->next)) return 0;
new->y >= h || new->y <= 0 ptr = ptr->next;
) return 0; }
if(eucliddist(new, apple) <= 30) { if(
anaconda->score += 30; new->x >= w || new->x <= 0 ||
apple->x = randrange(20, w / 2); new->y >= h || new->y <= 0
apple->y = randrange(20, h / 2); ) return 0;
}
return 1; if(eucliddist(new, apple) <= 30) {
anaconda->score += 30;
apple->x = randrange(20, w / 2);
apple->y = randrange(20, h / 2);
}
return 1;
}
void freeAnaconda(anaconda *anaconda) {
point *current = anaconda->chain;
point *next = NULL;
for(;;) {
if(!current) break;
next = current->next;
free(current);
current = next;
}
free(anaconda);
return;
} }
point *generateChain(int length) { point *generateChain(int length) {
point *ret = mkPoint(100, 100); point *ret = mkPoint(100, 100);
point *head = ret; point *head = ret;
for(int i = 1; i < length - 1; i++) { for(int i = 1; i < length - 1; i++) {
ret->next = mkPoint( ret->next = mkPoint(
10 * i + 100, 10 * i + 100,
5 * i + 100 5 * i + 100
); );
ret = ret->next; ret = ret->next;
} }
return head; return head;
} }
anaconda *mkAnaconda(point *point, double rot) { anaconda *mkAnaconda(point *point, double rot) {
anaconda *ret = malloc(sizeof *ret); anaconda *ret = malloc(sizeof *ret);
ret->chain = point; ret->chain = point;
ret->rot = rot; ret->rot = rot;
ret->score = 0; ret->score = 0;
return ret; return ret;
} }
int main(void) { int main(void) {
anaconda *anaconda = mkAnaconda(generateChain(30), 0); anaconda *anaconda = mkAnaconda(generateChain(30), 0);
xinit(); point *basepoint = mkPoint(10, 0);
srand(time(0)); char scorebuffer[30];
int width = DisplayWidth(d, s); xinit();
int height = DisplayHeight(d, s); srand(time(0));
point *apple = mkPoint(randrange(20, width / 2 - 20), randrange(20, height / 2 - 20)); int width = DisplayWidth(d, s);
while(1) { int height = DisplayHeight(d, s);
if(!updateAnaconda(anaconda, width, height, apple)) { point *apple = mkPoint(randrange(20, width / 2 - 20), randrange(20, height / 2 - 20));
return 0; int exposed = 0;
} while(1) {
XClearWindow(d, w); if(exposed) {
point *ptr = anaconda->chain; if(!updateAnaconda(anaconda, basepoint, width, height, apple)) {
while(ptr->next) { freeAnaconda(anaconda);
XDrawLine(d, w, gc, ptr->x, ptr->y, ptr->next->x, ptr->next->y); free(apple);
ptr = ptr->next; free(basepoint);
} return 0;
printf("%f %f\n", apple->x, apple->y); }
XDrawArc(d, w, gc, apple->x - (5/2), apple->y - (5/2), 5, 5, 0, 360*64); XClearWindow(d, w);
while(XPending(d)) { point *ptr = anaconda->chain;
XNextEvent(d, &e); while(ptr->next) {
switch(e.type) { XDrawLine(d, w, gc, ptr->x, ptr->y, ptr->next->x, ptr->next->y);
case KeyPress: ptr = ptr->next;
switch(e.xkey.keycode) { }
case 113: /* left arrow key */ XDrawArc(d, w, gc, apple->x - (5/2), apple->y - (5/2), 5, 5, 0, 360*64);
anaconda->rot += 10; int len = snprintf(&scorebuffer, 30, "%i", anaconda->score);
break; XDrawString(d, w, gc, 25, 25, &scorebuffer, len);
case 114: /* right arrow key */ }
anaconda->rot -= 10; while(XPending(d)) {
break; XNextEvent(d, &e);
} switch(e.type) {
break; case KeyPress:
} switch(e.xkey.keycode) {
} case 113: /* left arrow key */
usleep(100000); anaconda->rot += 10;
} break;
case 114: /* right arrow key */
anaconda->rot -= 10;
break;
}
break;
case Expose:
/* hold off drawing until we get an expose event */
exposed = 1;
return 0; width = e.xexpose.width;
height = e.xexpose.height;
if(apple->x > width) {
free(apple);
apple = mkPoint(randrange(20, width / 2 - 20), randrange(20, height / 2 - 20));
} else if (apple->y > height) {
free(apple);
apple = mkPoint(randrange(20, width / 2 - 20), randrange(20, height / 2 - 20));
}
break;
}
}
usleep(100000);
}
freeAnaconda(anaconda);
free(apple);
free(basepoint);
return 0;
} }