/*
**  gp_strct
**
**   genetic programming structure stuff
**
*/

/* 
**   Scott "Jerry" Lawrence
**   2000 January 24,25
**   j@absynth.com
*/

/*
** $Id: gp_strct.c,v 1.6 2000/02/08 01:13:48 sdlpci Exp sdlpci $
**
** $Log: gp_strct.c,v $
 * Revision 1.6  2000/02/08  01:13:48  sdlpci
 * moved enumerate line into here
 *
 * Revision 1.5  2000/02/07  22:21:02  sdlpci
 * removed the conditional structure -- it was not needed.
 *
 * Revision 1.4  2000/01/25  17:38:49  sdlpci
 * added code to free the structs.
 *
 * Revision 1.3  2000/01/25  17:08:36  sdlpci
 * added indent & commented code
 *
 * Revision 1.2  2000/01/25  05:18:39  sdlpci
 * added line creation & dump tools.
 *
 * Revision 1.1  2000/01/24  16:38:31  sdlpci
 * Initial revision
 *
*/

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


/*******************************************************************************
** creation / alloc features
*/

GP_LINE * gp_line_new(void)
{
    GP_LINE * l = (GP_LINE *) malloc(sizeof(GP_LINE));
    if (!l) return NULL;

    l->cond_type  = -1;
    l->cond_value = 0;
    l->direction  = DIR_0;
    l->line_then  = NULL;
    l->line_else  = NULL;

    return l;
}


/*******************************************************************************
** deletion / free features
*/

void gp_line_free(GP_LINE * l)
{
    if (!l) return;
    if (l->line_then)  gp_line_free(l->line_then);
    if (l->line_else)  gp_line_free(l->line_else);
    free(l);
    /* well... that was easy.  */
}


/*******************************************************************************
** generation features
*/
GP_LINE * gp_line_gen(void)
{
    int r = random_int(0, 100);
    GP_LINE * g = gp_line_new();
    
    if (r < 50)
    {
	// conditional
	g->type = LINE_TYPE_COND;

	g->cond_type  = random_int(0, 5);
	g->cond_value = random_int(1, 6);

	g->line_then  = gp_line_gen();
	g->line_else  = gp_line_gen();
	g->direction  = random_int(1, 4);

    } else if (r < 95)
    {
	// move
	g->type = LINE_TYPE_MOVE;

	g->direction = random_int(0, 4);

    } else 
    {
	// noop
	g->type = LINE_TYPE_NOOP;
    }

    return g;
}


GP_LINE * gp_line_clone(GP_LINE * src)
{
    GP_LINE * temp;
    if (!src) return NULL;

    temp = gp_line_new();

    temp->type       = src->type;
    temp->cond_type  = src->cond_type;
    temp->cond_value = src->cond_value;
    temp->direction  = src->direction;
    temp->line_then  = gp_line_clone(src->line_then);
    temp->line_else  = gp_line_clone(src->line_else);

    return temp;
}

/*******************************************************************************
** misc util features
*/


// enumerate the id's of the line.  (pass it in 0 or some other number)
int gp_enumerate_line(GP_LINE * node, int i)
{
    if (!node) return i;
    node->id = i++;

    i = gp_enumerate_line(node->line_then, i);
    i = gp_enumerate_line(node->line_else, i);

    return i;
}


/*******************************************************************************
** dump features
*/
char *move_dirs[] = {
    "zero",
    "north",
    "south",
    "east",
    "west"
};


void gp_line_indent(int indent)
{
    while(indent--)  printf(" ");
}


void gp_line_dump(GP_LINE * l, int indent)
{
    if (!l) return;

    if (l->type == LINE_TYPE_NOOP)
    {
	gp_line_indent(indent);
	printf("nop;\n");

    } else if (l->type == LINE_TYPE_MOVE)
    {
	gp_line_indent(indent);
	printf("move %s;\n", move_dirs[l->direction]);

    } else 
    {
	// it's a conditional
	gp_line_indent(indent);
	printf ("if ");
	switch (l->cond_type)
	{
	    case(CONDITIONAL_TYPE_FALSE):
		printf("(never)");
		break;

	    case(CONDITIONAL_TYPE_TRUE):
		printf("(always)");
		break;

	    case(CONDITIONAL_TYPE_TRAV):
		printf("(%s has been travelled lt %d times)",
			move_dirs[l->direction], l->cond_value );
		break;

	    case(CONDITIONAL_TYPE_GT):
		printf("(%s gt this)", move_dirs[l->direction]);
		break;

	    case(CONDITIONAL_TYPE_LT):
		printf("(%s lt this)", move_dirs[l->direction]);
		break;

	    case(CONDITIONAL_TYPE_EQ):
		printf("(%s eq this)", move_dirs[l->direction]);
		break;
	}
	printf(" \n");
	gp_line_indent(indent);
	printf("{\n");
	gp_line_dump(l->line_then, indent+GP_LINE_INDENT_SW);

	gp_line_indent(indent);
	printf("} else {\n");
	gp_line_dump(l->line_else, indent+GP_LINE_INDENT_SW);

	gp_line_indent(indent);
	printf("}\n");
    }
}
