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:
parent
d37e632bd8
commit
6b5d621820
297
c/anaconda.c
297
c/anaconda.c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue