/* PANDAMAT file PAND4.CPP by Jeff Whitledge Fall 1995 Pandemonium controlling an animat. */ #include #include #include #include #include #include #include #include #define MAXX 58 //defines the width and highth of the landscape #define MAXY 19 #define N 50 // the number of problems to display the average of #define GRAPH_SIZE_X 8000L // the number of problems to graph #define GRAPH_SIZE_Y 20L // the maximum problem time to graph #define GRANULARITY 5 // the width of each graph item in pixels int graph_mode=0; // 0 is text mode, 1 is graphics int speed=0; // 0 is fast, 1 is slow /*-------------------------- Landscape (the ANIMAT portion)---------------*/ typedef enum { north, ne, east, se, south, sw, west, nw } direction_type; #define FIRST_DIRECTION north #define MAX_DIRECTION nw typedef enum { none_f=' ', tree_f='T', food_f='F' } feature_type; typedef char sense_vector[9]; // "gain" and "senses" are passed from // the environment (animat) to the control structure (pandemonium) float gain; sense_vector senses; // these variables keep statistics int problem_time; int last_time; unsigned long int problem_number; int last_N[N]; int current; int graph_data[GRAPH_SIZE_X]; long int max_x,max_y; // the land_c class is the environment class land_c { private: char field[MAXY][MAXX+1]; int animatx,animaty; void erase_animat(); void draw_animat(); void move_animat_randomly(); void print_data(); void eat_food(int newx,int newy); public: land_c(); void draw_field(); void move_animat(direction_type d); }; land_c::land_c() { // the environment is WOODS07 strcpy(field[ 0]," T TT T "); strcpy(field[ 1],"TFT F F T F FT "); strcpy(field[ 2]," T TT F "); strcpy(field[ 3]," T T F T "); strcpy(field[ 4]," TFT TFT F TT F "); strcpy(field[ 5]," F T T "); strcpy(field[ 6]," TT TT T "); strcpy(field[ 7]," TT T F TFT F "); strcpy(field[ 8],"TFT F TF T "); strcpy(field[ 9]," T TT T "); strcpy(field[10]," TT T FT F TF TFT "); strcpy(field[11]," F F T "); strcpy(field[12]," T TF T T T "); strcpy(field[13]," T T FT F TF "); strcpy(field[14]," F F F T "); strcpy(field[15]," T TT T "); strcpy(field[16]," T T "); strcpy(field[17]," F TFT F F F TF "); strcpy(field[18]," TT T TT T T "); animatx=1; animaty=1; move_animat_randomly(); problem_time=0; } void land_c::draw_field() { int index; clrscr(); for (index=0;indexN) { gotoxy(50,22); printf ("average over last %d: %2.2f ",N,average); } } else { // in graphics mode. Draw nothing. } } void land_c::move_animat_randomly() { erase_animat(); do { animatx=random(MAXX); animaty=random(MAXY); } while (field[animaty][animatx]!=none_f); draw_animat(); } void land_c::eat_food(int newy,int newx) { if (speed==0) return; gotoxy(newx+1,newy+1); textcolor(YELLOW); putch('X'); delay(500); gotoxy(newx+1,newy+1); textcolor(LIGHTGRAY); putch('F'); } void land_c::move_animat(direction_type d) { int newx,newy; problem_time++; switch(d) { case nw: case north: case ne: newy=animaty-1; break; case west: case east: newy=animaty; break; case sw: case south: case se: newy=animaty+1; break; } switch(d) { case nw: case west: case sw: newx=animatx-1; break; case north: case south: newx=animatx; break; case ne: case east: case se: newx=animatx+1; break; } if (newx>MAXX-1) newx=0; if (newx<0) newx=MAXX-1; if (newy>MAXY-1) newy=0; if (newy<0) newy=MAXY-1; switch(field[newy][newx]) { case none_f: erase_animat(); animatx=newx; animaty=newy; draw_animat(); gain=-0.25; //-0.01 -0.25 break; case tree_f: gain=-1.0; //-0.1 -1.0 break; case food_f: eat_food(newy,newx); gain=2.25; // 0.2 2.0 move_animat_randomly(); print_data(); break; } senses[0]=field[(MAXY+animaty-1) % MAXY][ animatx ]; senses[1]=field[(MAXY+animaty-1) % MAXY][(animatx+1) % MAXX ]; senses[2]=field[ animaty ][(animatx+1) % MAXX ]; senses[3]=field[(animaty+1) % MAXY ][(animatx+1) % MAXX ]; senses[4]=field[(animaty+1) % MAXY ][ animatx ]; senses[5]=field[(animaty+1) % MAXY ][(MAXX+animatx-1) % MAXX]; senses[6]=field[ animaty ][(MAXX+animatx-1) % MAXX]; senses[7]=field[(MAXY+animaty-1) % MAXY][(MAXX+animatx-1) % MAXX]; return; } land_c land; /*---------------------- Control Structure (PANDEMONIUM) ---------------*/ /* There are three types of demons: sense, action, and other. The sense demons get their volumes from the environment. The action demons effect the environment. The other demons don't do anything in particular. */ #define NUM_SENSE 24 #define NUM_OTHER 10 #define NUM_ACTION 8 #define NUM_DEMONS NUM_SENSE+NUM_OTHER+NUM_ACTION #define ARENA_SENSE 8 #define ARENA_OTHER 2 #define ARENA_ACTION 1 #define SIZE_ARENA ARENA_SENSE+ARENA_OTHER+ARENA_ACTION int arena[SIZE_ARENA]; float connections[NUM_DEMONS][NUM_DEMONS]; // the class demon is the base class for all of the demons class demon { protected: float volume; // how load the demon is shouting float built_in_volume; // default base volume for this demon int my_number; public: demon(); float get_volume() {return volume;} virtual void calc_volume(); void get_number(int num); void adjust_strengths(); // adjusts the volume connections // according to the gain virtual void print_stuff(); //used for debugging }; demon::demon() { } void demon::calc_volume() { int index; volume=built_in_volume; for (index=0;indexget_volume(); for (arena_index=0;arena_indexarena_volumes[arena_index]) { temp_vol=arena_volumes[arena_index]; temp_demon=arena[arena_index]; arena_volumes[arena_index]=current_volume; arena[arena_index]=current_demon; current_volume=temp_vol; current_demon=temp_demon; } } } //calculate volumes for the other demons for (index=0;indexget_volume(); for (arena_index=ARENA_SENSE;arena_indexarena_volumes[arena_index]) { temp_vol=arena_volumes[arena_index]; temp_demon=arena[arena_index]; arena_volumes[arena_index]=current_volume; arena[arena_index]=current_demon; current_volume=temp_vol; current_demon=temp_demon; } } } //calculate volumes for action demons for (index=0;indexget_volume(); arena_index=ARENA_SENSE+ARENA_OTHER; if (current_volume>arena_volumes[arena_index]) { temp_vol=arena_volumes[arena_index]; temp_demon=arena[arena_index]; arena_volumes[arena_index]=current_volume; arena[arena_index]=current_demon; current_volume=temp_vol; current_demon=temp_demon; } } //take action action_demons[arena[ARENA_SENSE+ARENA_OTHER]-NUM_SENSE-NUM_OTHER].take_action(); //gotoxy(1,21); // used for debugging //for (index=0;indexadjust_strengths(); return; } void initialize_pandemonium() { int index1,index2; for (index1=0;index1get_number(index1); } /*---------------------- main ------------------------------------------*/ void make_graphics() { int index,current_x,count; float average; int gdriver = DETECT, gmode, errorcode; initgraph(&gdriver, &gmode, ""); errorcode = graphresult(); if (errorcode != grOk) /* an error occurred */ { gotoxy(1,23); printf("Graphics error: %s\n", grapherrormsg(errorcode)); graph_mode=0; return; } max_x=getmaxx(); max_y=getmaxy(); line(0,0,0,max_y); line(0,max_y,max_x,max_y); for (index=0;indexGRAPH_SIZE_X) break; average+=graph_data[index]; } if (count==0) continue; if (index>GRAPH_SIZE_X) break; average/=count; lineto(current_x,max_y-max_y/(float)GRAPH_SIZE_Y*average); } /* for (index=2;indexprint_stuff(); key=0; while (key!=27) { if (speed==1) delay(100); iterate_pandemonium(); key=0; if (kbhit()) key=getch(); if ((key=='G') || (key=='g')) switch (graph_mode) { case 0: graph_mode=1; make_graphics(); break; case 1: graph_mode=0; make_text(); break; } if ((key=='s') || (key=='S')) speed = 1-speed; } if (graph_mode) make_text(); gotoxy(1,24); _setcursortype(_NORMALCURSOR); return 0; }