/*
**  gp_run
**
**   the genetic program interpreter
**
*/

/* 
**   Scott "Jerry" Lawrence
**   2000 February 10
**   j@absynth.com
*/

/*
** $Id: gp_run.c,v 1.1 2000/02/12 02:00:52 sdlpci Exp sdlpci $
**
** $Log: gp_run.c,v $
 * Revision 1.1  2000/02/12  02:00:52  sdlpci
 * Initial revision
 *
*/

#include <stdio.h>
#include <stdlib.h>   /* for malloc/free */
#include <string.h>   /* for memset      */
#include "map.h"
#include "gp_strct.h"
#include "gp.h"
#include "util.h"


int gpr_attempt_move(INTMAP * map, int direction)
{
    int startpos;

    if (!map) return -9999;
    if (!map->trav || !map->data) return -9999;

    startpos = map->data[map->y][map->x];

    // note that "direction" is abstracted into this function, so
    // that i can add more directions later or something...

    //     N
    //   W   E
    //     S

    switch (direction)
    {
	case(DIR_N):
	    //printf("N");
	    map->y--;
	    break;
	case(DIR_S):
	    //printf("S");
	    map->y++;
	    break;

	case(DIR_W):
	    //printf("W");
	    map->x--;
	    break;
	case(DIR_E):
	    //printf("E");
	    map->x++;
	    break;

	default:
	    //printf("-");
	    return 0;
	    break;
    }

    // now clip it.  (i've never done it this way... it's kinda neat)
    map->x = MAX(0, map->x);
    map->x = MIN(map->w-1, map->x);
    map->y = MAX(0, map->y);
    map->y = MIN(map->h-1, map->y);

    map->trav[map->y][map->x]++;

    map->max = MAX(map->max, map->trav[map->y][map->x]);

    return (2 - (2 << (map->trav[map->y][map->x]) ) 
              - ( (map->data[map->y][map->x] > startpos)?5:0 )
           );
}



int gpr_get_datatrav_at_direction(INTMAP * map, int direction, int data)
{
    int nx = map->x;
    int ny = map->y;

    switch(direction)
    {
	case(DIR_N):
	    ny--;
	    break;

	case(DIR_S):
	    ny++;
	    break;

	case(DIR_E):
	    nx--;
	    break;

	case(DIR_W):
	    nx++;
	    break;
    }

    if (data)
    {
	if (nx < 0 || ny < 0)
	    return 'z';   // something greater than normal
	else 
	    return map->data[ny][nx];

    } else {

	if (nx < 0 || ny < 0)
	    return 5000;   // something greater than normal
	else 
	    return map->trav[ny][nx];
    }
}


int gpr_run_step(GP_LINE * dna, INTMAP * map)
{
    int np, nt;
    int run_then = 0;
    int run_else = 0;

    if (!dna) return 0;
    switch (dna->type)
    {
	case(LINE_TYPE_MOVE):
//printf ("move %d\n", dna->direction);
	    return gpr_attempt_move(map, dna->direction);
	    break;

	case(LINE_TYPE_COND):
//printf ("cond %d\n", dna->cond_type);
	    switch(dna->cond_type)
	    {
		case(CONDITIONAL_TYPE_FALSE):
		    run_else = 1;
		    break;

		case(CONDITIONAL_TYPE_TRUE):
		    run_then = 1;
		    return gpr_run_step(dna->line_then, map);
		    break;

		case(CONDITIONAL_TYPE_TRAV):
		    nt = gpr_get_datatrav_at_direction(map, dna->direction, 0);
		    if (nt <= dna->cond_value)
			run_then = 1;
		    else
			run_else = 1;
		    break;

		case(CONDITIONAL_TYPE_LT):
		    np = gpr_get_datatrav_at_direction(map, dna->direction, 1);
		    if (np < map->data[map->y][map->x])
			run_then = 1;
		    else
			run_else = 1;
		    break;

		case(CONDITIONAL_TYPE_GT):
		    np = gpr_get_datatrav_at_direction(map, dna->direction, 1);
		    if (np > map->data[map->y][map->x])
			run_then = 1;
		    else
			run_else = 1;
		    break;

		case(CONDITIONAL_TYPE_EQ):
		    np = gpr_get_datatrav_at_direction(map, dna->direction, 1);
		    if (np == map->data[map->y][map->x])
			run_then = 1;
		    else
			run_else = 1;
		    break;
	    }
	    break;

	case(LINE_TYPE_NOOP):
	default:
//printf ("noop\n");
	    return 0;
	    break;
    }

    if (run_then)
	return gpr_run_step(dna->line_then, map);
    return gpr_run_step(dna->line_else, map);
}


// setup the initial population
void gpr_run(GP_INDIVIDUAL * i, INTMAP * map)
{
    int steps = 0;

    if (!i) return;
    if (!i->dna) return;

    if (!map) return;
    if (!map->w || !map->h) return;
    if (!map->trav) return;

    map_reset_trav(map);

    // ending conditions: 
    // steps = size_of_array *2
    // end at ending
    while (    (steps < (map->w * map->h * 2))
            && !(    (map->x == map->w-1)
                  && (map->y == map->h-1)
               )
	    && (map->max < 5)
          )
    {
	//printf ("%d \n", steps);
	steps++;
	i->fitness = gpr_run_step(i->dna, map);
    }
}
