NEAT C main

#ifdef _WIN32

#include <windows.h>

#endif

#include <stdlib.h>

#include <stdio.h>

#include <stdarg.h>

#include <signal.h>

#include <time.h>

#include <math.h>

#include <GL/glut.h>

#include "neat.h"

#include "map.h"

#include "unit.h"

#include "avg.h"

#include "list.h"

#include "error.h"

#define _PI 3.14159265358979323846

#define _2PI (2 * _PI)

#define _NDIST 6

#define _MDIST 1000

#define _NPOPS 4

#define _NUNITS 50

#define _TIME_ALIVE_MIN 2000

#define _TIME_ALIVE_MAX 40000

#define _NINPUTS (5 + _NDIST)

#define _NOUTPUTS 2

#define _GENEPROB 1

#define _NTRACES 100

#define _UNIT_ANGLE     (16 * _PI / 180)

#define _LIGHT_MOVERAYS 16

#define _MAPW (16 * 16)

#define _MAPH (16 * 10)

#define _FILENAME_MAP   "world.map"

#define _FILENAME_POPS  "pops.gnm"

#define _MAX(A, B) ((A) > (B) ? (A) : (B))

#define _MIN(A, B) ((A) < (B) ? (A) : (B))

#define _COL(C) ((C) >> 16 & 0xFF) / 255.,\

((C) >> 8 & 0xFF) / 255., \

((C) & 0xFF) / 255. 

#define _DBGSTRLEN 1024

int time_alive_min = _TIME_ALIVE_MIN;

int time_evolve_step = _MAX(1, _TIME_ALIVE_MIN / (.5 * _NUNITS));

int oclock = 0, tickspersecs = 0, ticks = 0;

int clear = 0;

int spawno = 0, spawnr = 0, pause = 0, wolf = 1;

int plot_champ = 1, plot_traces = 1, plot_radar = 0, plot_dbg = 1;

struct avg *avgcrash;

int mapx, mapy, mapu, mapv, tx, ty, move;

double width, height, mapz = 1;

double lightx = _MAPW / 2;

double lighty = _MAPH / 2;

double langle = 0;

int lightmove = 0, lightauto = 0;

char dbgstr[_DBGSTRLEN];

int nests[] = { 24, 24, _MAPW - 24, 24,

_MAPW - 24, _MAPH - 24, 24, _MAPH - 24 };

int cols[] = { 0x00FFFF, 0xFF00FF, 0x00FF00, 0xFFFF00 };

struct unit *units[_NPOPS][_NUNITS];

struct map *map;

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _free_world(void);

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _signal(int sig)

{

if (sig == SIGINT) {

_free_world();

exit(0);

}

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _screen_to_map(int x, int y, double *mx, double *my)

{

double min, dx, dy;

min = _MIN(width / map->width, height / map->height);

dx = x - width / 2 - mapx;

dy = y - height / 2 - mapy;

dx = dx / (mapz * width);

dy = dy / (mapz * height);

dx = (dx * (width / map->width) / min + .5) * map->width;

dy = (dy * (height / map->height) / min + .5) * map->height;

*mx = dx;

*my = dy;

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _cartesian_to_polar(double x, double y, double *angle, double *radius)

{

*angle = atan2(y, x);

*radius = sqrt(x * x + y * y);

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

int _get_champ(int pop)

{

int u, champ = -1;

double fit, maxfit = -1;

for (u = 0; u < _NUNITS; u++) {

fit = neat_fitness_get(pop, u);

if (fit >= maxfit) {

maxfit = fit;

champ = u;

}

}

return champ;

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _eval_light(void)

{

int i, n;

double dx, dy;

if (lightauto && (ticks % 100 == 0)) {

for (n = 0; n < 100; n++) {

langle += ((rand() % 8) - 4) * _PI / 180;

if (langle < 0)

langle += _2PI;

if (langle > _2PI)

langle -= _2PI;

dx = lightx + .2 * cos(langle);

dy = lighty + .2 * sin(langle);

for (i = 0; i < _LIGHT_MOVERAYS; i++)

if (map_collisioni(map, NULL, 3, dx, dy,

  i * _2PI / _LIGHT_MOVERAYS))

break;

if (i == _LIGHT_MOVERAYS) {

lightx = dx;

lighty = dy;

break;

}

}

}

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _eval_unit(int pop, int org, int *ncrashes)

{

int i, nturns, nest;

double dist, fit, inputs[_NINPUTS], fx, fy, ox, oy, movedist;

double lightdist, lightangle, dx, dy;

const double *outputs;

struct unit *unit;

unit = units[pop][org];

fit = neat_fitness_get(pop, org);

if (unit->age++ == _TIME_ALIVE_MAX)

goto _spawn;

_cartesian_to_polar(unit->xpos - lightx, unit->ypos - lighty,

   &lightangle, &lightdist);

inputs[0] = 1;

inputs[1] = unit->tangle;

inputs[2] = unit->tangle - unit->mangle;

inputs[3] = unit->tangle - lightangle;

inputs[4] = unit->mspeed;

for (i = 0; i < _NDIST; i++)

map_collisioni(map, &inputs[5 + i], _MDIST,

      unit->xpos, unit->ypos,

      unit->tangle + _2PI * i / _NDIST);

outputs = neat_activate(pop, org, inputs);

unit->thrust = outputs[0];

unit->tangle += (outputs[1] - .5) * _UNIT_ANGLE;

if (unit->tangle >= _PI)

unit->tangle -= _2PI;

if (unit->tangle < - _PI)

unit->tangle += _2PI;

fx = unit->mspeed * cos(unit->mangle) +

    .03 * unit->thrust * cos(unit->tangle);

fy = unit->mspeed * sin(unit->mangle) +

    .03 * unit->thrust * sin(unit->tangle) + .01;

_cartesian_to_polar(fx, fy, &unit->mangle, &unit->mspeed);

/*unit->mspeed -= unit->mspeed * unit->mspeed / 100;

unit->mspeed = _MAX(0, unit->mspeed);*/

if (map_collisioni(map, &dist, unit->mspeed,

  unit->xpos, unit->ypos, unit->mangle)) {

(*ncrashes)++;

fit *= .1;

_spawn:

nest = (pop + spawno + spawnr * rand()) % _NPOPS;

unit_spawn(unit, nests[2 * nest], nests[2 * nest + 1]);

neat_flush(pop, org);

goto _done;

}

ox = unit->xpos;

oy = unit->ypos;

unit_move(unit);

movedist = sqrt((unit->xpos - ox) * (unit->xpos - ox) +

(unit->ypos - oy) * (unit->ypos - oy));

fit *= .999;

fit += 1 + movedist + 100 * exp(-lightdist / 5);

_done:

neat_fitness_set(pop, org, fit);

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _eval(void)

{

static int oticks = 0;

int ncrashes, clock;

struct unit *unit;

int w, t, u, i, n, worstid, nest, champ, dbgoff;

double fit, dx, dy, dist;

for (w = 0; w < wolf; w++) {

ticks++;

ncrashes = 0;

for (t = 0; t < _NPOPS; t++) {

for (u = 0; u < _NUNITS; u++)

_eval_unit(t, u, &ncrashes);

if ((ticks % time_evolve_step) == 0) {

worstid = neat_evolve(t);

if (worstid >= 0) {

unit = units[t][worstid];

nest = (t + spawno + spawnr * rand()) %

_NPOPS;

unit_spawn(unit, nests[2 * nest],

  nests[2 * nest + 1]);

}

}

}

clock = time(NULL);

if (clock - oclock >= 5) {

tickspersecs = (ticks - oticks) / (clock - oclock);

oclock = clock;

oticks = ticks;

}

/* debug info */

avg_add(avgcrash, ncrashes, ticks);

snprintf(dbgstr, _DBGSTRLEN, "%8d  %4d    %.2f : %.2f : %.2f\n",

ticks, tickspersecs,

avgcrash->savg0, avgcrash->savg1, avgcrash->savg2);

_eval_light();

}

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _gl_eval(void)

{

_eval();

if (pause)

glutIdleFunc(NULL);

glutPostRedisplay();

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _draw_light(void)

{

glPushMatrix();

glTranslatef(lightx, lighty, 0);

glColor3f(0, 0, 1);

glBegin(GL_QUADS);

       glVertex2f(-1, -1);

glVertex2f(1, -1);

glVertex2f(1, 1);

glVertex2f(-1, 1);

glEnd();

glPopMatrix();

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _draw_dbg(void)

{

int i = 0;

int slen = strlen(dbgstr);

glRasterPos2d(0, 0);

while (i++ < slen)

glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, dbgstr[i]);

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _draw_champ(void)

{

int i, t, champ;

struct unit *unit;

double xpos, ypos, dist, angle;

for (t = 0; t < _NPOPS; t++) {

champ = _get_champ(t);

ASSERT(champ >= 0);

unit = units[t][champ];

ASSERT(unit);

xpos = unit->xpos;

ypos = unit->ypos;

/* circle */

glColor3f(_COL(cols[t]));

glBegin(GL_LINE_LOOP);

for (i = 0; i < 16; i++) {

angle = _2PI * i / 16;

glVertex2d(xpos + 6 * cos(angle),

  ypos + 6 * sin(angle));

}

glEnd();

/* radar */

if (plot_radar) {

for (i = 0; i < _NDIST; i++) {

angle = unit->tangle + _2PI * i / _NDIST;

map_collisioni(map, &dist, _MDIST,

      xpos, ypos, angle);

glBegin(GL_LINES);

glVertex2d(xpos + 6 * cos(angle),

  ypos + 6 * sin(angle));

glVertex2d(xpos + dist * cos(angle),

  ypos + dist * sin(angle));

glEnd();

}

}

}

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _display(void)

{

int u, t;

double min;

if (clear) {

clear = 0;

glClearColor(0, 0, 0, 0);

glClear(GL_COLOR_BUFFER_BIT);

}

min = _MIN(width / map->width, height / map->height);

glMatrixMode(GL_TEXTURE);

glPushMatrix();

glScalef((double)map->width / map->texw,

(double)map->height / map->texh, 1);

glTranslatef(.5, .5, 0);

glScalef(width / (mapz * min * map->width),

height / (mapz * min * map->height), 1);

glTranslatef(-.5 - (double)mapx / width,

    -.5 + (double)mapy / height, 0);

glMatrixMode(GL_MODELVIEW);

glPushMatrix();

glTranslatef(-1, -1, 0);

glScalef(2, 2, 1);

map_draw(map);

if (plot_dbg)

_draw_dbg();

glPopMatrix();

glPushMatrix();

glTranslatef(2 * (double)mapx / width, -2 * (double)mapy / height, 0);

glScalef(2 * mapz * min / width, -2 * mapz * min / height, 1);

glTranslatef(-map->width / 2, -map->height / 2, 0);

_draw_light();

for (t = 0; t < _NPOPS; t++)

for (u = 0; u < _NUNITS; u++)

unit_draw(units[t][u], plot_traces, _COL(cols[t]));

if (plot_champ)

_draw_champ();

if (map->wall)

map_wall(map);

glPopMatrix();

glMatrixMode(GL_TEXTURE);

glPopMatrix();

glutSwapBuffers();

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _reshape(int w, int h)

{

width = w;

height = h;

glViewport(0, 0, width, height);

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _motion(int x, int y)

{

double mx, my;

if (map->wall) {

_screen_to_map(x, y, &mx, &my);

_cartesian_to_polar(mx - map->wx, my - map->wy,

   &map->wa, &map->wr);

} else if (move) {

mapx = mapu + x - tx;

mapy = mapv + y - ty;

} else if (lightmove)

_screen_to_map(x, y, &lightx, &lighty);

glutPostRedisplay();

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _mouse(int button, int state, int x, int y)

{

int mod;

mod = glutGetModifiers();

if (state == GLUT_UP) {

switch (button) {

case GLUT_MIDDLE_BUTTON:

break;

case GLUT_RIGHT_BUTTON:

if (!(mod & GLUT_ACTIVE_SHIFT)) {

lightmove = 0;

break;

}

/* FALL */

case GLUT_LEFT_BUTTON:

if (mod & GLUT_ACTIVE_SHIFT) {

map->wall = 2;

glutPostRedisplay();

} else {

mapu = mapx;

mapv = mapy;

move = 0;

}

break;

}

}

if (state == GLUT_DOWN) {

switch (button) {

case GLUT_MIDDLE_BUTTON:

break;

case GLUT_RIGHT_BUTTON:

if (mod & GLUT_ACTIVE_SHIFT)

map->erase = 1;

else {

_screen_to_map(x, y, &lightx, &lighty);

lightmove = 1;

glutPostRedisplay();

break;

}

/* FALL */

case GLUT_LEFT_BUTTON:

if (mod & GLUT_ACTIVE_SHIFT) {

map->wall = 1;

_screen_to_map(x, y, &map->wx, &map->wy);

map->wa = 0;

map->wr = 0;

glutPostRedisplay();

} else {

tx = x;

ty = y;

move = 1;

}

break;

case 3:

/* WHEEL_UP */

mapz = _MIN(5, mapz + .1);

glutPostRedisplay();

break;

case 4:

/* WHEEL_DOWN */

clear = 1;

mapz = _MAX(.3, mapz - .1);

glutPostRedisplay();

break;

default:

TRACE("%x", button);

break;

}

}

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _keyboard(unsigned char key, int x, int y)

{

FILE *file;

int t, u;

switch (key) {

case ' ':

if (pause)

glutIdleFunc(_gl_eval);

break;

case '+':

mapz = _MIN(5, mapz + .1);

glutPostRedisplay();

break;

case '-':

clear = 1;

mapz = _MAX(.3, mapz - .1);

glutPostRedisplay();

break;

case 'c':

plot_champ = !plot_champ;

glutPostRedisplay();

break;

case 'd':

plot_dbg = !plot_dbg;

glutPostRedisplay();

break;

case 'f':

mapz = 1;

mapx = 0;

mapy = 0;

mapu = 0;

mapv = 0;

glutPostRedisplay();

break;

case 'm':

lightauto = !lightauto;

break;

case 'p':

pause = !pause;

if (pause)

glutIdleFunc(NULL);

else

glutIdleFunc(_gl_eval);

break;

case 'q':

_free_world();

exit(0);

break;

case 'r':

plot_radar = !plot_radar;

glutPostRedisplay();

break;

case 's':

INFO("Saving %s", _FILENAME_MAP);

file = fopen(_FILENAME_MAP, "w");

ASSERT(file);

map_write(map, file);

fclose(file);

INFO("Saving %s", _FILENAME_POPS);

file = fopen(_FILENAME_POPS, "w");

ASSERT(file);

for (t = 0; t < _NPOPS; t++) {

for (u = 0; u < _NUNITS; u++)

neat_print(t, u, file);

}

fclose(file);

break;

case 't':

plot_traces = !plot_traces;

glutPostRedisplay();

break;

case 'u':

map->erase = 1;

map->wall = 2;

map->dirty = 1;

glutPostRedisplay();

break;

case 'v':

spawnr = !spawnr;

break;

case 'w':

switch (wolf) {

case 100:

wolf = 10;

break;

case 10:

wolf = 1;

break;

case 1:

wolf = 100;

break;

}

break;

case 'x':

spawno = (spawno + 1) % _NPOPS;

break;

case 'z':

spawno = (spawno - 1 + _NPOPS) % _NPOPS;

break;

}

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _free_world(void)

{

int t, u;

for (t = 0; t < _NPOPS; t++) {

for (u = 0; u < _NUNITS; u++)

unit_destroy(units[t][u]);

neat_destroy(t);

}

avg_destroy(avgcrash);

map_destroy(map);

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

void _init_world(void)

{

int i, x, y, u, t;

FILE *file;

map = map_create(_MAPW, _MAPH);

if ((file = fopen(_FILENAME_MAP, "r"))) {

INFO("Loading %s", _FILENAME_MAP);

map_read(map, file);

fclose(file);

}

if ((file = fopen(_FILENAME_POPS, "r"))) {

INFO("Loading %s", _FILENAME_POPS);

for (t = 0; t < _NPOPS; t++)

neat_create_from_file(_NUNITS, _NINPUTS, _NOUTPUTS,

     file);

fclose(file);

} else {

for (t = 0; t < _NPOPS; t++)

neat_create(_NUNITS, _NINPUTS, _NOUTPUTS, _GENEPROB);

}

for (t = 0; t < _NPOPS; t++) {

for (u = 0; u < _NUNITS; u++) {

units[t][u] = unit_create(_NTRACES);

unit_spawn(units[t][u], nests[2 * t], nests[2 * t + 1]);

}

}

avgcrash = avg_create(1000, 5000, 15000);

}

//+------------------------------------------------------------------+

//|

//+------------------------------------------------------------------+

int main(int argc, char **argv)

{

signal(SIGINT, _signal);

if (argc == 2) {

wolf = atoi(argv[1]);

_init_world();

_eval();

_free_world();

exit(0);

}

srand(time(NULL));

_init_world();

glutInit(&argc, argv);

glutInitWindowSize(800, 600);

glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);

glutCreateWindow("eco");

glutDisplayFunc(_display);

glutReshapeFunc(_reshape);

glutKeyboardFunc(_keyboard);

glutMouseFunc(_mouse);

glutMotionFunc(_motion);

glutIdleFunc(_gl_eval);

glutMainLoop();

return 0;

}