/*
   File:        pgco.c
   Author:      Andrew W. Moore
   Created:     Mon Sep 21 17:00:12 EDT 1992
   Description: The Parti-Game Control Algorithm & Environment

   Copyright (C) 1992, Andrew W. Moore
*/

#include <stdio.h>
#include <math.h>
#include "ambs.h"      /* Very basic operations */
#include "amma.h"      /* Fast, non-fragmenting, memory management */
#include "amar.h"      /* Obvious operations on 1-d arrays */
#include "amgr.h"      /* Basic (0,512)x(0,512) Graphics window */
#include "maxdim.h"    /* The MAX_DIM declaration */
#include "gpro.h"      /* Graphics projections kd->2d space */
#include "hype.h"      /* Hyper-rectangles from ../kdtr */
#include "region.h"    /* K-d region Data Structure */
#include "wrld.h"      /* Spec. of the World Control problem */
#include "whis.h"      /* History of worsts */
#include "part.h"      /* PARTitions and TESSalations */
#include "diar.h"      /* The diary data-structure */
#include "pgco.h"      /* PartiGame Control and env definition */

/*
#define ALWAYS_SAME
*/

char *partition_name_from_args(argc,argv)
int argc;
char *argv[];
{
  char *result;
  int index = index_of_arg("-pt",argc,argv);

  if ( index >= 0 && index < argc-1 )
    result = argv[index+1];
  else
    result = "allelig";

  return(result);
}

void env_add_goal_everywhere(e)
env *e;
{
  part_list *ptl;
  part *goal_pt = 
    part_search(&e->tess,e->world.goal->mode,e->world.goal->nstate);

  if ( Verbosity > 20.0 )
    printf("Adding goal evrywhere\n");

  for ( ptl = e->tess.all_parts ; ptl != NULL ; ptl = ptl -> next )  
    if ( ptl->part->tess_id == e->running_mode )
      add_extra_neigh(ptl->part,goal_pt);
}
      
void env_refresh_game(e)
env *e;
{
  part *goal_pt = 
    part_search(&e->tess,e->world.goal->mode,e->world.goal->nstate);

  if ( Verbosity > 20.0 )
    printf("env_refresh_game\n");

  if ( !e->tess.game_tree_valid )
  {
    int mode;
    if ( Verbosity > 20.0 )
    {
      printf("** Game Tree Not Valid **\n");
      wait_for_key();
    }

    for ( mode = 0 ; mode < e->world.number_modes ; mode++ )
    {
      mtrans *mts;
      mode_spec *msp = mode_ref(&e->world,mode);
      for ( mts = msp -> mode_transitions ; mts != NULL ; mts = mts -> next )
      {
        worst mid_wst;
        part *src,*dst;

        mid_wst.mode = mode;
        middle_of_region(mts->region,mid_wst.nstate);
        src = part_search(&e->tess,mode,mid_wst.nstate);
        dst = part_search(&e->tess,mts->next_worst->mode,
                          mts->next_worst->nstate
                         );
        add_extra_neigh(src,dst);
      }
    }

    add_extra_neigh(goal_pt,goal_pt);
    if ( Verbosity > 20.0 )
      fprintf_part(stdout,"stupid-goal_pt",goal_pt,&e->tess);

    if ( e->all_goal_oriented )
      env_add_goal_everywhere(e);

    free_game_structure(&e->tess);
    build_game_structure(&e->tess);
  }
  
  if ( !e->tess.game_scores_valid )
  {
    solve_game(&e->tess,goal_pt);

    if ( Verbosity > 20.0 )
      fprintf_part(stdout,"solved-goal_pt",goal_pt,&e->tess);

    if ( Verbosity > 20.0 )
      gp_clear(&e->gproj);

    gp_draw_geom_data(&e->gproj,&e->tess,e->running_mode);

    if ( Verbosity > 20.0 )
    {
      printf("Drawn geom data\n");
      if ( e->world.draw_structure != NULL )
        e->world.draw_structure(&e->gproj,&e->world,e->world.goal);
      printf("Drawn world\n");
    }
  }
}
  
void init_env(e,argc,argv)
env *e;
int argc;
char *argv[];
/*
   PRE:   e not initted before.
   POST:  e legal, but worst, wac and local_goal undefined
*/
{
  int i;
  mode_spec *msp;
  char *exp_name;

  if ( argc < 2 || eq_string(argv[1],"help") )
  {
    printf("Usage partigame <world-name> [world-options] [options]\n");
    printf("<world-name> can be smaze or hill\n");
    printf("[world-options] for smaze is a lines file (usual *-smaze.txt)\n");
    printf("There are no [world-options] for hill\n");
    printf("[options] include\n");
    printf("-pt <part-type>, manual,allelig(default),nearest or everything\n");
    printf("-verbose <verbosity>. 0 no messages, 50 lots, 200 masses\n");
    printf("-start <s1> <s2> .. <sN>: Default start state\n");
    printf("-name <experiment-name>: results filename. Default 'test'\n");
    exit(-1);
  }

  i = index_of_arg("-verbose",argc,argv);
  if ( i >= 0 && i < argc-1 )
    Verbosity = atof(argv[i+1]);

  load_world(&e->world,argv[1],argc,argv);
  if ( Verbosity > 20.0 )
    fprint_world(stdout,"world",&e->world);
  
  e -> running_mode = mode_number_called(&e->world,"running");
  msp = mode_ref(&e->world,e->running_mode);

  if ( eq_string(e->world.name,"arm") )
  {
    float xxx[MAX_DIM];
    set_floats_constant(xxx,msp->state.dim,0.5);
    gproj_from_m_and_s(&e->gproj,xxx,xxx,msp->state.dim,0,1);
  }
  else
    gproj_from_m_and_s(&e->gproj,msp->middle,msp->scales,msp->state.dim,0,1);
 
  if ( Verbosity > 20.0 )
    printf("Will init_tess\n");
  init_tess(&e->tess,e->world.number_modes);

  for ( i = 0 ; i < e->world.number_modes ; i++ )
  {
    mode_spec *mspi = mode_ref(&e->world,i);
    make_geom_data(&e->tess,i,mspi->state.dim,mspi->middle,mspi->scales);
    if ( Verbosity > 20.0 )
      printf("Made geom_data[%d]\n",i);
  }

  start_worst_from_args(&e->world,&e->start_worst,argc,argv);

  init_diary(&e->diary);

  e->partition_style = partition_name_from_args(argc,argv);

  init_state_sequence(&e->state_sequence);
  e -> reap_epsilon = DEFAULT_REAP_EPSILON;

  e->all_goal_oriented = index_of_arg("-allgoal",argc,argv) >= 0;

  i = index_of_arg("-schedule",argc,argv);
  if ( i >= 0 && i < argc-1 )
  {
    if ( strlen(argv[i+1]) >= MAX_SCHEDULE_LENGTH )
      my_error("isvbd");
    else
      sprintf(e->schedule,"%s",argv[i+1]);
  }
  else if ( state_dim(&e->world,e->running_mode) >= MAX_SCHEDULE_LENGTH )
    my_error("ovfbiowe");
  else
  {
    for ( i = 0 ; i < state_dim(&e->world,e->running_mode) ; i++ )
      e->schedule[i] = (char) ('0' + i);
    e->schedule[i] = '\0';
  }

  env_refresh_game(e);
  
  if ( e->world.draw_structure != NULL )
  {
    gp_clear(&e->gproj);
    e->world.draw_structure(&e->gproj,&e->world,e->world.goal);
  }

  i = index_of_arg("-name",argc,argv);
  if ( i >= 0 && i < argc-1 )
    exp_name = argv[i+1];
  else
    exp_name = "test";
  
  init_profile(&e->profile,exp_name,&e->tess,&e->world,
               &e->state_sequence,&e->gproj
              );
}

void env_cli(e)
env *e;
{
  char command[100];
  sprintf(command,"he");

  while ( !eq_string(command,"co") )
  {
    if ( eq_string(command,"he") )
    {
      printf("he: help\n");
      printf("pr: Do profile files for this run\n");
      printf("go: Graphics On (send to PostScript)\n");
      printf("gf: Graphics Finish (complete PostScript)\n");
      printf("dt: Draw tree, dw: draw world\n");
      printf("ma: malloc report\n");
      printf("ga: print current game structure\n");
      printf("ds: draw sequence of all states and local goals\n");
      printf("ps: print sequence of all states and local goals\n");
      printf("tj: draw and or print trajes from a selected partition\n");
      printf("hs: draw and or print histos from a selected partition\n");
      printf("co: continue with the partigame\n");
    }
    else if ( eq_string(command,"pr") )
      produce_profile(&e->profile,&e->start_worst);
    else if ( eq_string(command,"go") )
    {
      char fname[100];
      ag_on(input_string("Graphics PostScript Filename>",fname,100));
    }
    else if ( eq_string(command,"gf") )
      ag_off();
    else if ( eq_string(command,"dt") )
      gp_draw_geom_data(&e->gproj,&e->tess,e->running_mode);
    else if ( eq_string(command,"dw") )
    {
      if ( e->world.draw_structure != NULL )
        e->world.draw_structure(&e->gproj,&e->world,e->world.goal);
    }
    else if ( eq_string(command,"ma") )
      am_malloc_report();
    else if ( eq_string(command,"ga") )
      fprint_game(stdout,&e->tess);
    else if ( eq_string(command,"tj") )
    {
      int button = 1;

      while ( button != 2 )
      {
        float farr[MAX_DIM];
        part *pt;
        printf("LEFT: click on the partition whose TRAJES you want to draw\n");
        printf("MIDDLE: Go back to debug partigame\n");
        printf("RIGHT: click on partition whose TRAJES you want to print\n");
        button = gp_use_mouse(&e->gproj,farr);
        gp_clear(&e->gproj);
        gp_draw_geom_data(&e->gproj,&e->tess,e->running_mode);
        if ( e->world.draw_structure != NULL )
          e->world.draw_structure(&e->gproj,&e->world,e->world.goal);
        pt = part_search(&e->tess,e->running_mode,farr);
        if ( button == 1 ) draw_trajes(&e->gproj,&e->world,pt);
        if ( button == 3 ) print_trajes(&e->world,pt);
      }
    }
    else if ( eq_string(command,"hs") )
    {
      int button = 1;

      while ( button != 2 )
      {
        float farr[MAX_DIM];
        part *pt;
        printf("LEFT: click on the partition whose HISTOS you want to draw\n");
        printf("MIDDLE: Go back to debug partigame\n");
        printf("RIGHT: click on partition whose HISTOS you want to print\n");
        button = gp_use_mouse(&e->gproj,farr);
        gp_clear(&e->gproj);
        gp_draw_geom_data(&e->gproj,&e->tess,e->running_mode);
        if ( e->world.draw_structure != NULL )
          e->world.draw_structure(&e->gproj,&e->world,e->world.goal);
        pt = part_search(&e->tess,e->running_mode,farr);
        if ( button == 1 ) draw_histos(&e->gproj,&e->world,e->running_mode,
                                       (histos *) pt -> histos_data
                                      );
        if ( button == 3 ) print_histos(&e->world,e->running_mode,
                                        (histos *) pt -> histos_data
                                       );
      }
    }
    else if ( eq_string(command,"ds") )
    {
/*      gp_clear(&e->gproj);
      if ( e->world.draw_structure != NULL )
        e->world.draw_structure(&e->gproj,&e->world,e->world.goal);
*/
      draw_state_sequence(&e->gproj,&e->state_sequence,e->running_mode);
    }
    else if ( eq_string(command,"ps") )
    {
      print_seq_nodes(&e->world,e->state_sequence.start,e->running_mode);
    }
    (void) input_string("partigame debug> ",command,100);
  }

  printf("..back to partigame..\n");
}

void env_choose_start(e)
env *e;
/*
    PRE:  e->worst, wac and local_goal undefined.
          e->start_worst defined.
    POST: e->worst defined wac and local_goal undefined
          e->worst not yet recorded in diary.
*/
{
  int button = 2;

  if ( e -> state_sequence.start != NULL )
    add_to_profile(&e->profile);

  e->worst.mode = e->running_mode;

  while ( button == 2 )
  {
    extern int Number_backups;
    printf("Number of partitions  : %d\n",number_partitions(&e->tess));
    printf("Number backups so far : %d\n",Number_backups);
    printf("\n*** Click Mouse on Start State ***\n");
    fprintf_worst(stdout,"  LEFT = start at ",&e->start_worst,&e->world,"\n");
    printf("MIDDLE = Go to debug/display data mode\n");
    printf(" RIGHT = Run from new start position\n");
    button= gp_worst_from_mouse(&e->gproj,&e->world,&e->start_worst,&e->worst);

    if ( button == 2 )
      env_cli(e);
  }

  gp_clear(&e->gproj);
  if ( e->world.draw_structure != NULL )
    e->world.draw_structure(&e->gproj,&e->world,e->world.goal);
  gp_draw_geom_data(&e->gproj,&e->tess,e->running_mode);

  fprintf_worst(stdout,"start-worst = ",&e->worst,&e->world,"\n");
  world_draw_worst(&e->gproj,&e->world,&e->worst);
  if ( Verbosity > 20.0 )
    printf("Chosen start\n");
}

bool env_needs_resetting(e)
env *e;
/*
   PRE: e -> worst is defined

   We need resetting if we're in an absorbing state. We detect if we're
   in an absorbing state by seeing if this mode of operation has a defined
   next-state function. Simple but not-effective (except in our initial
   test worlds, in which this'll be fine).
*/
{
  bool result;
  if ( Verbosity > 20.0 )
    printf("e->worst.mode = %d\n",e->worst.mode);
  result = mode_ref(&e->world,e->worst.mode)->next_worst == NULL;
  if ( Verbosity > 20.0 )
    printf("env %s need resetting\n",(result) ? "does" : "doesn't");
  return(result);
}

bool env_choice_happy(e)
env *e;
/*
   PRE:  e->worst defined, e->local_goal and e->wac undefined, all parts undef
   POST: IF there's a promosing local goal
            e->worst defined and e->local_goal defined as the most promising
            e->aim part defined
            and returns TRUE
         ELSE
            return FALSE
*/
{
  part *p;
  neighs *ne;
  bool result;

  if ( Verbosity > 20.0 )
    printf("happy? Will pary search\n");
  p = part_search(&e->tess,e->worst.mode,e->worst.nstate);
  if ( Verbosity > 20.0 )
    fprintf_part(stdout,"this-part",p,&e->tess);
  ne = best_neigh(p);
  if ( Verbosity > 20.0 )
    printf("found best neighbor\n");

  if ( ne == NULL )
  {
    if ( Verbosity > 20.0 )
      printf("We have no working neighbours! Lawks a Lordy!\n");
    result = FALSE;
  }
  else
  {
    int i;
    int dim;
    if ( Verbosity > 20.0 )
      fprintf_part(stdout,"best_neigh",ne->neigh,&e->tess);
    e->local_goal.mode = ne -> neigh -> tess_id;
    dim = state_dim(&e->world,e->local_goal.mode);
    for ( i = 0 ; i < dim ; i++ )
      e->local_goal.nstate[i] = middle_pivot(&e->tess,ne->neigh,i);
    if ( Verbosity > 20.0 )
    {
      printf("e->local_goal.mode = X%X\n",e->local_goal.mode);
      fprintf_worst(stdout,"e->local_goal = ",&e->local_goal,&e->world,"\n");
    }
    e->aim = ne -> neigh;
    result = TRUE;
  }

  if ( Verbosity > 20.0 )
    printf("env choice %shappy\n",(result) ? "" : "not ");
  return(result);
}

split_spec *allelig_repartition(gp,ts,tess_id,farr_now,sched)
gproj *gp;
tess *ts;
int tess_id;
float *farr_now;
char *sched;
/*
    Far now is just something to tell us the current state within
    tess[tess_id]. It may be NULL in which case it's ignored. It's only
    used for drawing things.
*/
{
  part_list *ptl = get_biggest_eligables(gp,ts,tess_id);
  split_spec *result = split_spec_from_schedule(ts,ptl,sched);

  if ( Verbosity > 20.0 )
    printf("Got split spec\n");
    
  free_part_list(ptl);

  if ( Verbosity > 20.0 )
    printf("Will return result\n");

  return(result);
}

split_spec *nearest_repartition(gp,ts,tess_id,farr_now,sched)
gproj *gp;
tess *ts;
int tess_id;
float *farr_now;
char *sched;
/*
    Far now is just something to tell us the current state within
    tess[tess_id]. It must not be NULL. It is NOT just for drawing.
*/
{
  part_list *ptl = get_biggest_eligables(gp,ts,tess_id);
  part *close = find_closest_part(ts,ptl,farr_now);
  part_list *one_ptl = add_to_part_list(close,(part_list *) NULL);
  split_spec *result = split_spec_from_schedule(ts,one_ptl,sched);

  if ( Verbosity > 20.0 )
    printf("Got split spec\n");
    
  free_part_list(ptl);
  free_part_list(one_ptl);

  if ( Verbosity > 20.0 )
    printf("Will return result\n");

  return(result);
}

split_spec *everything_repartition(gp,ts,tess_id,farr_now)
gproj *gp;
tess *ts;
int tess_id;
float *farr_now;
/*
    Far now is just something to tell us the current state within
    tess[tess_id]. It must not be NULL. It is NOT just for drawing.
*/
{
  split_spec *result = NULL;
  part_list *ptl;

  for ( ptl = ts->all_parts ; ptl != NULL ; ptl = ptl -> next )
  {
    if ( ptl->part->tess_id == tess_id )
    {
      int split;
      float pivot;
      split_middle_of_longest(ts,ptl->part,&split,&pivot);
      result = add_to_split_spec(ptl->part,split,pivot,result);
    }
  }

  return(result);
}

split_spec *manual_repartition(gp,ts,tess_id,farr_now)
gproj *gp;
tess *ts;
int tess_id;
float *farr_now;
/*
    Far now is just something to tell us the current state within
    tess[tess_id]. It may be NULL in which case it's ignored. It's only
    used for drawing things.
*/
{
  split_spec *sps = NULL;
  int button = 1;

  while ( button != 2 )
  {
    float farr[MAX_DIM];
    gp_draw_floats_disc(gp,farr_now,6.0);
    printf("Click LEFT   in partition to be split with a vertical\n");
    printf("Click MIDDLE when satisfied\n");
    printf("Click RIGHT  in partition to be split with a horizontal\n");
    button = gp_use_mouse(gp,farr);
    printf("button = %d\n",button);
    if ( button != 2 )
    {
      part *p = part_search(ts,tess_id,farr);
      if ( is_in_split_spec(sps,p) )
        printf("*** NO! You have already included that partition ***\n");
      else
      {
        int split = (button==1) ? gp->x.comp : gp->y.comp;
        draw_filled_part(gp,ts,tess_id,p);
        sps = add_to_split_spec(p,split,middle_pivot(ts,p,split),sps);
      }
    }
    printf("button = %d\n",button);
  }
  return(sps);
}

void env_maybe_remove_neighs(e)
env *e;
/*
   If running_mode -> should_remove_trans is non null, we run through
   all running mode partitions, and look at the neighbors. We are
   interested in the "default" neighs... those with no real outcome.
   Should they really be there? We ask running_mode -> should_remove_neighs
   and it tells us. If it wants them toasted, they are toasted.
*/
{
  mode_spec *msp = mode_ref(&e->world,e->running_mode);
  if ( msp -> should_remove_trans != NULL )
  {
    tess *ts = &e->tess;
    hype *hy_me = create_hype(msp->state.dim);
    hype *hy_neigh = create_hype(msp->state.dim);
    part_list *ptl;
    for ( ptl = ts -> all_parts ; ptl != NULL ; ptl = ptl -> next )
    {
      if ( ptl -> part -> tess_id == e -> running_mode )
      {
        part *pt = ptl -> part;
        neighs *ne = pt -> neighs;
        neighs *last = NULL;
        pt -> neighs = NULL;

        while ( ne != NULL )
        {
          neighs *next = ne -> next;
          bool remove = ne -> outcomes == NULL;
          ne -> next = NULL;
         
          if ( remove )
          {
            hype_of_part(pt,hy_me);
            hype_of_part(ne->neigh,hy_neigh);
            remove = msp->should_remove_trans(&e->world,msp,hy_me,hy_neigh);
          }

          if ( remove )
            free_neighs_node(ne);
          else
          {
            if ( last == NULL )
              pt -> neighs = ne;
            else
              last -> next = ne;
            
            last = ne;
          }
    
          ne = next;
        }
      }
    }

    free_hype(hy_me);
    free_hype(hy_neigh);
  }
}

void env_repartition(e)
env *e;
/*
   POST: e->all parts are undefined, e->local_goal undefined. e->worst defined
*/
{
  split_spec *sps,*x_sps;
  float *farr_now = (e->worst.mode == e->running_mode) ?
        e->worst.nstate :
        NULL;
  trajes *saved_trajes = NULL;
  part_list *ptl;

  if ( eq_string(e->partition_style,"manual") )
    sps=manual_repartition(&e->gproj,&e->tess,e->running_mode,farr_now);
  else if ( eq_string(e->partition_style,"allelig") )
    sps=allelig_repartition(&e->gproj,&e->tess,e->running_mode,farr_now,e->schedule);
  else if ( eq_string(e->partition_style,"nearest") )
    sps=nearest_repartition(&e->gproj,&e->tess,e->running_mode,farr_now,e->schedule);
  else if ( eq_string(e->partition_style,"everything") )
    sps=everything_repartition(&e->gproj,&e->tess,e->running_mode,farr_now);
  else
  {
    printf("Unknown repartition method: %s\n",e->partition_style);
    my_error("env_repartition()");
  }

  if ( Verbosity > 20.0 ) printf("Will remember trajes of 2bsplitted parts\n");
  for ( x_sps = sps ; x_sps != NULL ; x_sps = x_sps -> next )
  {
    saved_trajes = append_trajes(part_trajes(x_sps->part),saved_trajes);
    free_histos_of_part(x_sps->part);
  }

  if ( Verbosity > 200.0 )
  {
    trajes *tjs;
    for ( tjs = saved_trajes ; tjs != NULL ; tjs = tjs -> next )
    {
      if ( tjs -> seq_node == NULL )
        printf("One of the trajes has a null seq node\n");
      else if ( tjs -> seq_node -> nstate == NULL )
        printf("One of the trajes has a null seq node nstate\n");
      else
        print_trajes(&e->world,
                    part_search(&e->tess,e->running_mode,tjs->seq_node->nstate)
                    );
    }
  }

  if ( Verbosity > 20.0 ) printf("Will perform splits\n");
  perform_splits(&e->tess,sps);
  if ( Verbosity > 20.0 ) printf("Will free split spec\n");
  free_split_spec(sps);
  if ( Verbosity > 20.0 ) printf("Will perhaps remove neighs\n");
  env_maybe_remove_neighs(e);
  if ( Verbosity > 20.0 ) printf("Will insert trajes\n");
  insert_trajes(&e->tess,&e->world,e->running_mode,saved_trajes);
  if ( Verbosity > 20.0 ) printf("Will get histos from new trajes\n");
  for ( ptl = e->tess.all_parts ; ptl != NULL ; ptl = ptl -> next )
  {
    part *pt = ptl -> part;
    if ( pt->experience_data != NULL && 
         pt->histos_data==NULL && 
         pt->tess_id==e->running_mode
       )
    {
      histos_from_trajes(&e->tess,&e->world,e->running_mode,
                         part_trajes(pt),e->reap_epsilon
                        );
    }
  }
  if ( Verbosity > 20.0 ) printf("Will free trajes\n");
  free_all_traj_nodes(saved_trajes);
  if ( Verbosity > 20.0 ) printf("Will refresh game\n");
  env_refresh_game(e);
  if ( Verbosity > 20.0 )
    printf("finished repartition\n");

  print_partition_info(&e->tess,e->running_mode);
}

void run_env_until_transition(e)
env *e;
/*
   PRE:   e->worst, local_goal, aim all defined
   POST:  those suckers still defined, but now also e->source and actual
*/
{
  seq_node *old_seq_node = (e->state_sequence.end);
  trajes *new_trajes;

  empty_diary(&e->diary);
  add_to_diary(&e->world,&e->tess,&e->diary,&e->worst);
  while ( !is_diary_transition(&e->world,&e->tess,&e->diary,
                               &e->source,&e->actual
                              )
        )
  {
    step_world(&e->world,&e->worst,&e->local_goal);
    if ( Verbosity > 20.0 )
      fprintf_worst(stdout,"run-wst = ",&e->worst,&e->world,"\n");

    world_draw_worst(&e->gproj,&e->world,&e->worst);

    add_to_diary(&e->world,&e->tess,&e->diary,&e->worst);
    if ( Verbosity > 20.0 )
      wait_for_key();
  }

  if ( Verbosity > 20.0 )
  {
    fprintf_part(stdout,"source",e->source,&e->tess);
    fprintf_part(stdout,"aim",e->aim,&e->tess);
    fprintf_part(stdout,"actual",e->actual,&e->tess);
    printf("Okay, we gotta transition!\n");
    wait_for_key();
  }

  if( Verbosity > 25.0 ) printf("Will augment state sequence\n");
  augment_state_sequence_from_history(&e->world,
                                      &e->diary.worst_hist,
                                      e->running_mode,
                                      &e->local_goal,
                                      &e->state_sequence
                                     );

  if( Verbosity > 25.0 ) printf("Will add experience data\n");
  new_trajes = add_experience_data(&e->tess,
                                   &e->world,
                                   e->running_mode,
                                   ( (old_seq_node==NULL) ? 
                                     e->state_sequence.start : 
                                     old_seq_node
                                   ),
                                   old_seq_node != NULL
                                  );
  if( Verbosity > 25.0 ) printf("Will get new histos\n");
  histos_from_trajes(&e->tess,&e->world,e->running_mode,
                     new_trajes,e->reap_epsilon
                    );
  free_all_traj_nodes(new_trajes);
}

void incorporate_transition(e)
env *e;
/*
   PRE:   e -> all parts are defined as well as e->worst
   POST:  e -> local_goal NOT well defined
*/
{
  part_and_game_observe(&e->tess,e->source,e->aim,e->actual);
  env_refresh_game(e);  
  if ( Verbosity > 20.0 )
    printf("incorporated transition\n");
}

/*
#define VAR_GOAL
*/

void env_choose_goal(e)
env *e;
{
  int button = 2;
  worst goal;
  mode_spec *msp = mode_ref(&e->world,e->running_mode);
  hype *hy = create_hype(2);
  part_list *ptl;

  goal.mode = e->running_mode;
  goal.nstate[0] = 0.5;
  goal.nstate[1] = 0.5;

  while ( button != 3 )
  {
    printf("\n*** Click RIGHT button of Mouse on Goal State ***\n");
    button= gp_worst_from_mouse(&e->gproj,&e->world,&e->start_worst,&goal);
  }

  hype_update(hy,0,LO,goal.nstate[0] - 0.05);
  hype_update(hy,0,HI,goal.nstate[0] + 0.05);

  hype_update(hy,1,LO,goal.nstate[1] - 0.05);
  hype_update(hy,1,HI,goal.nstate[1] + 0.05);

  msp->mode_transitions->region = create_in_hype_region(hy);

  for ( ptl = e->tess.all_parts ; ptl != NULL ; ptl = ptl -> next )
  {
    neighs *ns = ptl->part->neighs;
    bool goes_to_goal = FALSE;
    for ( ; ns != NULL ; ns = ns -> next )
      goes_to_goal = goes_to_goal || ns->neigh->tess_id != e->running_mode;

    if ( goes_to_goal )
    {
      printf("Found a part leading to a goal\n");
      ptl->part->neighs_valid = FALSE;
      ptl->part->neighs = NULL;
    }
  }

  e->tess.game_tree_valid = FALSE;
  e->tess.game_scores_valid = FALSE;

  gp_clear(&e->gproj);
  if ( e->world.draw_structure != NULL )
    e->world.draw_structure(&e->gproj,&e->world,e->world.goal);
  gp_draw_geom_data(&e->gproj,&e->tess,e->running_mode);
}

void partigame_algorithm(argc,argv)
int argc;
char *argv[];
{
  env e;

  init_env(&e,argc,argv);
  while ( TRUE )
  {
    env_choose_start(&e);
#ifdef VAR_GOAL
    env_choose_goal(&e);
    perform_splits(&e.tess,(split_spec *)NULL);
    env_refresh_game(&e);  
#endif
    while ( !env_needs_resetting(&e) )
    {
      while ( !env_choice_happy(&e) )
        env_repartition(&e);
      run_env_until_transition(&e);
      incorporate_transition(&e);
    }
  }
}
