/* * Seven Kingdoms: Ancient Adversaries * * Copyright 1997,1998 Enlight Software Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ //Filename : OSPATHS2.CPP //Description : Object SeekPathS2 //Owner : Alex #include #include #include #include #include #include #include #include #include //----------- Define static variables -----------// static Location* world_loc_matrix; static int cur_stack_pos_s2 = 0; static NodeS2* stack_array[MAX_STACK_NUM]; static DWORD group_id_s2; static short search_mode_s2; static char mobile_type_s2; static short target_recno_s2; static short building_id_s2; // used in search_mode = SEARCH_MODE_TO_FIRM or SEARCH_MODE_TO_TOWN, get from miscNo static int building_x1_s2, building_y1_s2, building_x2_s2, building_y2_s2; // the building upper-left to lower-right positions // if search_mode = SEARCH_MODE_TO_FIRM or SEARCH_MODE_TO_TOWN static FirmInfo *searchFirmInfo_s2; static short x_shift_array[8] = { 1, 1, 0, -1, -1, -1, 0, 1}; static short y_shift_array[8] = { 0, -1, -1, -1, 0, 1, 1, 1}; //---- used in determining the return nodes in the starting node -----// static char source_blocked_exit_direction[8]; // indicate which exit direction of starting node is impossible static char source_locate_type; // indicate the upper left position of the unit located in the 2x2 node //---- used to decide which path is return in a node -------// static short prefer_upper_s2; // if upper and lower paths are available, true if the upper path is preferred static short prefer_lower_s2; // if upper and lower paths are available, true if the lower path is preferred static short prefer_left_s2; // if left and right paths are available, true if the left path is preferred static short prefer_right_s2; // if left and right paths are available, true if the right path is preferred //--- show whether shift-map method is used the direction shifted ---// static short use_shift_map_method_s2;// is 0 or 1, 1 for using this method static short shift_map_x_offset_s2; // useful only as shift-map-method is applied static short shift_map_y_offset_s2; // useful only as shift-map-method is applied //static short reverse_direction_result_node; //-- store the orginal and the finalized starting and destination location --// static short source_x_s2; // starting x location in 2x2 node format static short source_y_s2; // starting y location in 2x2 node format static int vir_start_x_s2; // store the start x loc after applying shift-map-method static int vir_start_y_s2; // store the start y loc after applying shift-map-method static int final_dest_x_s2; // store the finalize x loc after applying shift-map-method, path-reuse, and etc static int final_dest_y_s2; // store the finalize y loc after applying shift-map-method, path-reuse, and etc //------------------- used in path-reuse -----------------------// static int max_node_num_s2; static short *reuse_node_matrix_ptr_s2; static NodeS2 *reuse_result_node_ptr_s2; static int final_dx; static int final_dy; //------- aliasing class member vars for fast access ------// static SeekPathS2* cur_seek_path_s2; static short cur_dest_x_s2, cur_dest_y_s2; static short* cur_node_matrix_s2; static NodeS2* cur_node_array_s2; static short cur_border_x1_s2, cur_border_y1_s2, cur_border_x2_s2, cur_border_y2_s2; #ifdef DEBUG static ResultNode *debugPtr1, *debugPtr2; static short debugVX, debugVY; static int debugCount; void debug_checks2(ResultNode *nodeArray, int count) { debugPtr1 = nodeArray; debugPtr2 = nodeArray+1; for(debugCount=1; debugCountnode_x<0 || debugPtr1->node_x>=MAX_WORLD_X_LOC-1 || debugPtr1->node_y<0 || debugPtr1->node_y>=MAX_WORLD_Y_LOC-1); debugVX = debugPtr1->node_x - debugPtr2->node_x; debugVY = debugPtr1->node_y - debugPtr2->node_y; err_when(debugVX!=0 && debugVY!=0 && (abs(debugVX)!=abs(debugVY))); } err_when(debugPtr1->node_x<0 || debugPtr1->node_x>=MAX_WORLD_X_LOC-1 || debugPtr1->node_y<0 || debugPtr1->node_y>=MAX_WORLD_Y_LOC-1); } #endif #ifdef DEBUG #define debug_check_paths2(nodeArray, count) debug_checks2((nodeArray), (count)) #else #define debug_check_paths2(nodeArray, count) #endif //----------- Define static functions -----------// static void stack_push(NodeS2 *nodePtr); static NodeS2* stack_pop(); //------- Begin of static function sys_yield ----------// static void sys_yield() { //sys.yield(); } //------- End of static function sys_yield ----------// //------- Begin of static function can_move_to ----------// static int can_move_to(int xLoc, int yLoc) // xLoc, yLoc is location after applying shift-map-method { //-------------------------------------------------------// // note : return value should be 0 (false) or 1 (true) //-------------------------------------------------------// int x, y; //-------------------- boundary checking -----------------// if(shift_map_x_offset_s2==0) { if(xLoc<0 || xLoc>=MAX_WORLD_X_LOC) return 0; else x = xLoc; } else // shifted { if(xLoc<1 || xLoc>MAX_WORLD_X_LOC) return 0; else x = xLoc+shift_map_x_offset_s2; } if(shift_map_y_offset_s2==0) { if(yLoc<0 || yLoc>=MAX_WORLD_Y_LOC) return 0; else y = yLoc; } else // shifted { if(yLoc<1 || yLoc>MAX_WORLD_Y_LOC) return 0; else y = yLoc+shift_map_y_offset_s2; } Location* locPtr = world_loc_matrix+y*MAX_WORLD_X_LOC+x; Unit* unitPtr; //---------- checking whether the location is walkable ----------// switch(mobile_type_s2) { case UNIT_LAND: if(!locPtr->walkable() && search_mode_s2=SEARCH_MODE_TO_FIRM return 0; switch(search_mode_s2) { case SEARCH_MODE_IN_A_GROUP: // group move case SEARCH_MODE_REUSE: // path-reuse if(!locPtr->cargo_recno) return 1; else { unitPtr = unit_array[locPtr->cargo_recno]; return (unitPtr->unit_group_id==group_id_s2 && unitPtr->cur_action!=SPRITE_ATTACK) || unitPtr->cur_action==SPRITE_MOVE; } case SEARCH_MODE_A_UNIT_IN_GROUP: // a unit in a group return locPtr->cargo_recno==0 || unit_array[locPtr->cargo_recno]->cur_action==SPRITE_MOVE; case SEARCH_MODE_TO_ATTACK: // to attack target if(!locPtr->cargo_recno) return 1; else { unitPtr = unit_array[locPtr->cargo_recno]; return (unitPtr->unit_group_id==group_id_s2 && unitPtr->cur_action!=SPRITE_ATTACK) || locPtr->cargo_recno==target_recno_s2 || unitPtr->cur_action==SPRITE_MOVE; } case SEARCH_MODE_BLOCKING: // 2x2 unit blocking if(locPtr->cargo_recno) unitPtr = unit_array[locPtr->cargo_recno]; return locPtr->cargo_recno==0 || (unitPtr->unit_group_id==group_id_s2 && (unitPtr->cur_action==SPRITE_MOVE || unitPtr->cur_action==SPRITE_READY_TO_MOVE)); case SEARCH_MODE_TO_VEHICLE: err_here(); //** error return 0; //-----------------------------------------------------------------------// // for the following search_mode, location may be treated as walkable // although it is not. //-----------------------------------------------------------------------// case SEARCH_MODE_TO_FIRM: // move to a firm, (location may be not walkable) case SEARCH_MODE_TO_TOWN: // move to a town zone, (location may be not walkable) return (locPtr->walkable() && (locPtr->cargo_recno==0 || (unit_array[locPtr->cargo_recno]->unit_group_id==group_id_s2 && unit_array[locPtr->cargo_recno]->cur_action!=SPRITE_ATTACK) )) || (xLoc>=building_x1_s2 && xLoc<=building_x2_s2 && yLoc>=building_y1_s2 && yLoc<=building_y2_s2); case SEARCH_MODE_TO_WALL_FOR_GROUP: // move to wall for a group, (location may be not walkable) return (locPtr->walkable() && (locPtr->cargo_recno==0 || (unit_array[locPtr->cargo_recno]->unit_group_id==group_id_s2 && unit_array[locPtr->cargo_recno]->cur_action!=SPRITE_ATTACK) )) || (xLoc==final_dest_x_s2 && yLoc==final_dest_y_s2); case SEARCH_MODE_TO_WALL_FOR_UNIT: // move to wall for a unit only, (location may be not walkable) return (locPtr->walkable() && locPtr->cargo_recno==0) || (xLoc==final_dest_x_s2 && yLoc==final_dest_y_s2); } break; case UNIT_SEA: if( !locPtr->sailable() ) return 0; if( search_mode_s2== SEARCH_MODE_A_UNIT_IN_GROUP) return locPtr->cargo_recno==0; else return locPtr->cargo_recno==0 || unit_array[locPtr->cargo_recno]->unit_group_id==group_id_s2 || (search_mode_s2==SEARCH_MODE_TO_ATTACK && locPtr->cargo_recno==target_recno_s2); break; case UNIT_AIR: if( search_mode_s2== SEARCH_MODE_A_UNIT_IN_GROUP) return locPtr->air_cargo_recno==0; else return locPtr->air_cargo_recno==0 || unit_array[locPtr->air_cargo_recno]->unit_group_id==group_id_s2 || (search_mode_s2==SEARCH_MODE_TO_ATTACK && locPtr->air_cargo_recno==target_recno_s2); break; default: err_here(); break; } return 0; } //------- End of static function can_move_to ----------// //------- Begin of static function can_move_to_s2 ----------// static int can_move_to_s2(int xLoc, int yLoc) // xLoc, yLoc is location after applying shift-map-method { //------------------------------------------------// // note: return value should be 0 or 1 //------------------------------------------------// if(can_move_to(xLoc,yLoc) && can_move_to(xLoc+1,yLoc) && can_move_to(xLoc,yLoc+1) && can_move_to(xLoc+1,yLoc+1)) return 1; // is walkable else return 0; // is not walkable as one point is not walkable } //------- End of static function can_move_to_s2 ----------// //-------- Begin of function SeekPathS2::init ---------// void SeekPathS2::init(int maxNode) { max_node = maxNode; node_array = (NodeS2*) mem_add( max_node * sizeof(NodeS2) ); node_matrix = (short*) mem_add(sizeof(short)*(MAX_WORLD_X_LOC/2+1)*(MAX_WORLD_Y_LOC/2+1)); path_status = PATH_WAIT; open_node_list = NULL; closed_node_list = NULL; } //--------- End of function SeekPathS2::init ---------// //-------- Begin of function SeekPathS2::deinit ---------// void SeekPathS2::deinit() { if( node_array ) { mem_del(node_array); node_array = NULL; } if( node_matrix ) { mem_del(node_matrix); node_matrix = NULL; } } //--------- End of function SeekPathS2::deinit ---------// //-------- Begin of function SeekPathS2::set_node_matrix ---------// void SeekPathS2::set_node_matrix(short reuseNodeMatrix[]) { reuse_node_matrix_ptr_s2 = reuseNodeMatrix; } //--------- End of function SeekPathS2::set_node_matrix ---------// //-------- Begin of function SeekPathS2::reset ---------// void SeekPathS2::reset() { path_status=PATH_WAIT; open_node_list=NULL; closed_node_list=NULL; } //--------- End of function SeekPathS2::reset ---------// //-------- Begin of function SeekPathS2::add_result_node ---------// inline void SeekPathS2::add_result_node(ResultNode** curPtr, ResultNode** prePtr, int& count) { err_when(abs((*curPtr)->node_x-(*prePtr)->node_x)>1 || abs((*curPtr)->node_y-(*prePtr)->node_y)>1); *prePtr = *curPtr; (*curPtr)++; count++; } //--------- End of function SeekPathS2::add_result_node ---------// //-------- Begin of function SeekPathS2::seek ---------// // // sx, sy - the starting world location. // dx, dy - the destination world location. // groupId - unit group id. // mobileType - mobile type, can be UNIT_AIR, UNIT_LAND or UNIT_SEA // // [int] searchMode - 1, SEARCH_MODE_IN_A_GROUP for one group with an unique group id (default) // 2, SEARCH_MODE_A_UNIT_IN_GROUP for one sprite in a group // 3, SEARCH_MODE_TO_ATTACK for attacking // 4, SEARCH_MODE_REUSE for path reuse // 5, SEARCH_MODE_BLOCKING for 2x2 unit blocked searching // 6, SEARCH_MODE_TO_FIRM for moving to a firm // 7, SEARCH_MODE_TO_TOWN for moving to a town zone // 8, SEARCH_MODE_TO_VEHICLE for moving to a vehicle // (default : 1) // // [int] miscNo - target record no if searchMode=SEARCH_MODE_TO_ATTACK // - firm ID if searchMode=SEARCH_MODE_TO_FIRM // // [int] maxTries - maximum no. of tries in the first seek action. // this refer to the maximum no. of nodes created. // (default : max_node) // // [int] borderX1, borderY1, - borders of the seek area in the world map // borderX2, borderY2 (default: the whole map) // // Note: if maxTries==max_node, incremental seek (PATH_SEEKING) won't happen. // // return : seekStatus - PATH_FOUND, PATH_SEEKING, PATH_NODE_USED_UP, or PATH_IMPOSSIBLE // if PATH_FOUND, or PATH_NODE_USED_UP, can call get_result() to retrieve the result. // int SeekPathS2::seek(int sx,int sy,int dx,int dy,DWORD groupId,char mobileType,short searchMode,short miscNo, int maxTries,int borderX1,int borderY1,int borderX2,int borderY2) { //-------- initialize vars --------------// path_status = PATH_SEEKING; world_loc_matrix = world.loc_matrix; // alias for fast access open_node_list = NULL; closed_node_list = NULL; search_mode_s2 = searchMode; group_id_s2 = groupId; mobile_type_s2 = mobileType; //------------------------------------------------------------------------------// // extract informaton from the parameter "miscNo" //------------------------------------------------------------------------------// target_recno_s2 = building_id_s2 = 0; building_x1_s2 = building_y1_s2 = building_x2_s2 = building_y2_s2 = -1; err_when(search_mode_s2==SEARCH_MODE_TO_VEHICLE); if(search_mode_s2==SEARCH_MODE_TO_ATTACK) target_recno_s2 = miscNo; else { building_id_s2 = miscNo; building_x1_s2 = dx; // upper left corner location building_y1_s2 = dy; //------- calculate the lower right corner location -------// if(search_mode_s2==SEARCH_MODE_TO_FIRM) { searchFirmInfo_s2 = firm_res[building_id_s2]; building_x2_s2 = dx+searchFirmInfo_s2->loc_width-1; building_y2_s2 = dy+searchFirmInfo_s2->loc_height-1; } else if(search_mode_s2==SEARCH_MODE_TO_TOWN) { if(miscNo != -1) { Location* buildPtr = world.get_loc(dx, dy); Town* targetTown = town_array[buildPtr->town_recno()]; building_x2_s2 = targetTown->loc_x2; building_y2_s2 = targetTown->loc_y2; } else // searching to settle. Detail explained in function set_move_to_surround() { building_x2_s2 = building_x1_s2+STD_TOWN_LOC_WIDTH-1; building_y2_s2 = building_y1_s2+STD_TOWN_LOC_HEIGHT-1; } } } //------------------------------------------------------------------------------// // set start location and destination location //------------------------------------------------------------------------------// real_sour_x = sx; real_sour_y = sy; //---------- adjust destination for some kind of searching ------------// if(search_mode_s2==SEARCH_MODE_TO_FIRM || search_mode_s2==SEARCH_MODE_TO_TOWN) { final_dx = (building_x1_s2+building_x2_s2)/2; // the destination is set to be the middle of the building final_dy = (building_y1_s2+building_y2_s2)/2; } else { //---------- no adjustment --------// final_dx = real_dest_x = dx; final_dy = real_dest_y = dy; } //------------------------------------------------------------------------------// // check whether applying shift-map-method //------------------------------------------------------------------------------// if(final_dx%2) // perform x-shift { use_shift_map_method_s2 = 1; shift_map_x_offset_s2 = -1; vir_start_x_s2 = sx+1; final_dest_x_s2 = final_dx+1; } else { use_shift_map_method_s2 = 0; shift_map_x_offset_s2 = 0; vir_start_x_s2 = sx; final_dest_x_s2 = final_dx; } if(final_dy%2) // perform y-shift { use_shift_map_method_s2 = 1; shift_map_y_offset_s2 = -1; vir_start_y_s2 = sy+1; final_dest_y_s2 = final_dy+1; } else { //use_shift_map_method_s2 = 0; // have been set to zero in the previous check shift_map_y_offset_s2 = 0; vir_start_y_s2 = sy; final_dest_y_s2 = final_dy; } //--------------------------------------------------------------// // change to 2x2 node format //--------------------------------------------------------------// border_x1 = short(borderX1/2); // change to 2x2 node format border_y1 = short(borderY1/2); border_x2 = short(borderX2/2); border_y2 = short(borderY2/2); if(shift_map_x_offset_s2!=0) // adjust if shift-map is used border_x2++; if(shift_map_y_offset_s2!=0) border_y2++; //-------------- initialize the array -----------------// memset(source_blocked_exit_direction, 0, sizeof(char)*8); //----- determine the blocked exit direction in starting point----------// // there are four cases the real source located in the 2x2 node // // -- -- the number in the 2x2 node representing where the // | 1| 2| upper_left location of the unit is // -- -- // | 3| 4| // -- -- if(vir_start_y_s2%2 != 1) { if(vir_start_x_s2%2 != 1) // case 1 source_locate_type = 1; else // case 2 { source_locate_type = 2; if(!can_move_to(vir_start_x_s2-1, vir_start_y_s2+1) && !can_move_to(vir_start_x_s2, vir_start_y_s2-1)) source_blocked_exit_direction[7] = 1; // direction 8 if(!can_move_to(vir_start_x_s2-1, vir_start_y_s2) && !can_move_to(vir_start_x_s2, vir_start_y_s2+2)) source_blocked_exit_direction[1] = 1; // direction 2 // other cases will not be checked as these cases do not crack the search } } else { if(vir_start_x_s2%2 != 1) // case 3 { source_locate_type = 3; if(!can_move_to(vir_start_x_s2, vir_start_y_s2-1) && !can_move_to(vir_start_x_s2+2, vir_start_y_s2)) source_blocked_exit_direction[5] = 1; // direction 6 if(!can_move_to(vir_start_x_s2-1, vir_start_y_s2) && !can_move_to(vir_start_x_s2+1, vir_start_y_s2-1)) source_blocked_exit_direction[7] = 1; // direction 8 // other cases will not be checked as these cases do not crack the search } else // case 4 { source_locate_type = 4; if(!can_move_to(vir_start_x_s2, vir_start_y_s2-1) || !can_move_to(vir_start_x_s2-1, vir_start_y_s2)) source_blocked_exit_direction[7] = 1; // direction 8 if(!can_move_to(vir_start_x_s2-1, vir_start_y_s2+1) && !can_move_to(vir_start_x_s2, vir_start_y_s2-1)) source_blocked_exit_direction[0] = 1; // direction 1 if(!can_move_to(vir_start_x_s2-1, vir_start_y_s2) && !can_move_to(vir_start_x_s2+1, vir_start_y_s2-1)) source_blocked_exit_direction[6] = 1; // direction 7 // other cases will not be checked as these cases do not crack the search } } source_x_s2 = short(vir_start_x_s2/2); // the upper left corner is used source_y_s2 = short(vir_start_y_s2/2); err_when(final_dest_x_s2%2 || final_dest_y_s2%2); dest_x = short(final_dest_x_s2/2); dest_y = short(final_dest_y_s2/2); if(search_mode_s2!=SEARCH_MODE_REUSE) { max_node_num_s2 = 0xFFFF; memset(node_matrix, 0, sizeof(short)*((MAX_WORLD_X_LOC/2+1)*(MAX_WORLD_Y_LOC/2+1))); } else { max_node_num_s2 = max_node; memcpy(node_matrix, reuse_node_matrix_ptr_s2, sizeof(short)*((MAX_WORLD_X_LOC/2+1)*(MAX_WORLD_Y_LOC/2+1))); } //--------- create the first node --------// node_count = 0; result_node_ptr = NULL; NodeS2 *nodePtr = node_array + node_count++; memset(nodePtr, 0, sizeof(NodeS2)); //-------- store the upper left coordinate of the node ----------// upper_left_x = source_x_s2<<1; upper_left_y = source_y_s2<<1; //---------- calculate the node type -----------// switch(source_locate_type) { case 1: nodePtr->node_type = 15; break; case 2: nodePtr->node_type = 10+can_move_to(vir_start_x_s2-1,vir_start_y_s2)+ can_move_to(vir_start_x_s2-1,vir_start_y_s2+1)*4; break; case 3: nodePtr->node_type = 12+can_move_to(vir_start_x_s2,vir_start_y_s2-1)+ can_move_to(vir_start_x_s2+1,vir_start_y_s2-1)*2; break; case 4: nodePtr->node_type = 8+can_move_to(vir_start_x_s2-1,vir_start_y_s2-1)+ can_move_to(vir_start_x_s2,vir_start_y_s2-1)*2+ can_move_to(vir_start_x_s2-1,vir_start_y_s2)*4; break; default: err_here(); break; } err_when(nodePtr->node_type>15 || nodePtr->node_type <0); is_dest_blocked = !can_move_to_s2(final_dest_x_s2, final_dest_y_s2); // whether the destination is blocked, if so, only search till the destination's neighbor locations nodePtr->node_g = 0; nodePtr->node_h = (source_x_s2-dest_x)*(source_x_s2-dest_x)+(source_y_s2-dest_y)*(source_y_s2-dest_y); // should really use sqrt(). nodePtr->node_f = nodePtr->node_g + nodePtr->node_h; nodePtr->node_x = source_x_s2; nodePtr->node_y = source_y_s2; nodePtr->enter_direction = 0; open_node_list=nodePtr; // make Open List point to first node //--- if the destination is the current postion or next to it & the dest is occupied ---// if(source_x_s2==dest_x && source_y_s2==dest_y) { path_status = PATH_FOUND; result_node_ptr = nodePtr; return path_status; } //------------ seek now ------------------// if( !maxTries ) maxTries = max_node; return continue_seek( maxTries, 1); // 1-first seek session of the current seek order } //-------- End of function SeekPathS2::seek ---------// //---- Begin of function SeekPathS2::continue_seek ---------// // // If the last seek operation does not find the whole path, // continue the search. // // maxTries - maximum path seeking tries // [char] firstSeek - whether it's the first seek session of the seek order. // (default: 0) // // return : seekStatus - PATH_FOUND, PATH_SEEKING, PATH_NODE_USED_UP, // or PATH_IMPOSSIBLE // // You can call get_result() to retrieve the result. // int SeekPathS2::continue_seek(int maxTries, char firstSeek) { if( path_status != PATH_SEEKING ) return path_status; //------- aliasing class member vars for fast access ------// cur_seek_path_s2 = this; cur_dest_x_s2 = dest_x; cur_dest_y_s2 = dest_y; cur_node_matrix_s2 = node_matrix; cur_node_array_s2 = node_array; cur_border_x1_s2 = border_x1; cur_border_y1_s2 = border_y1; cur_border_x2_s2 = border_x2; cur_border_y2_s2 = border_y2; //------ seek the path using the A star algorithm -----// NodeS2 *bestNodePtr; int maxNode = max_node-MAX_CHILD_NODE; // generate_successors() can generate a max of MAX_CHILD_NODE new nodes per call if(maxTries < maxNode) maxNode = maxTries-MAX_CHILD_NODE; // limit the nodes used in shortest path searching for(int i=0; i= maxNode ) { path_status = PATH_NODE_USED_UP; break; } //------------------------------------------// // If the path is found OR // // If the destination is blocked, // consider it done when we are next to it. //------------------------------------------// if((bestNodePtr->node_x==dest_x && bestNodePtr->node_y==dest_y) || (is_dest_blocked && abs(bestNodePtr->node_x-dest_x)<=0 && abs(bestNodePtr->node_y-dest_y)<=0)) { path_status = PATH_FOUND; result_node_ptr = bestNodePtr; break; } //--------- generate successors -------// if(bestNodePtr->generate_successors(bestNodePtr->enter_direction)) { path_status = PATH_REUSE_FOUND; result_node_ptr = reuse_result_node_ptr_s2; return path_status; } } err_when( cur_stack_pos_s2!=0 ); // it should be zero all the times, all pushes should have been poped return path_status; } //------ End of function SeekPathS2::continue_seek ---------// //---- Begin of function SeekPathS2::get_result ---------// // // Compile the seek result nodes using results processed by // seek() and continue_seek() and store the results in // an array of ResultNode. // // resultNodeCount - a reference var for returning the no. of result nodes. // // return : an array of ResultNode. // the caller function is responsible for // freeing the memory of the array. // ResultNode* SeekPathS2::get_result(int& resultNodeCount, short& pathDist) { resultNodeCount = pathDist = 0; short useClosestNode = 0;// indicate whether closest node is return instead of the actual node if( !result_node_ptr ) // if PATH_IMPOSSIBLE or PATH_NODE_USED_UP, result_node_ptr is NULL, we need to call get_closest_node() to get the closest node. { result_node_ptr = return_closest_node(); useClosestNode = 1; if( !result_node_ptr ) return NULL; } //--------------------------------------------------// // Trace backwards to the starting node, and rationalize // nodes (i.e. group nodes of the same direction into // single nodes.) //--------------------------------------------------// NodeS2* nodePtr = result_node_ptr; // the node current being processed NodeS2* baseNodePtr = result_node_ptr; // the first end node for connecting the other end node for the path in that direction. NodeS2* parentNode = nodePtr->parent_node; // the parent node of nodePtr NodeS2* childNodePtr = nodePtr; // it should point to the children node of nodePtr //------------------------------------------------------------------------ // there are only one node, source & destination within the same 2x2 node //------------------------------------------------------------------------ if( !parentNode ) // parentNode==0 when the source location is the desination already { if( (vir_start_x_s2!=final_dest_x_s2 || vir_start_y_s2!=final_dest_y_s2) && abs(vir_start_x_s2-final_dest_x_s2)<=1 && abs(vir_start_y_s2-final_dest_y_s2)<=1 && can_move_to_s2(vir_start_x_s2,vir_start_y_s2) && // for source can_move_to_s2(final_dest_x_s2,final_dest_y_s2)) // for destination { pathDist = 1; ResultNode* resultNodeArray1 = (ResultNode*) mem_add(sizeof(ResultNode)*2); ResultNode* resultNodePtr1 = resultNodeArray1; resultNodeCount=2; resultNodePtr1->node_x = vir_start_x_s2 + shift_map_x_offset_s2; resultNodePtr1->node_y = vir_start_y_s2 + shift_map_y_offset_s2; resultNodePtr1++; resultNodePtr1->node_x = final_dest_x_s2 + shift_map_x_offset_s2; resultNodePtr1->node_y = final_dest_y_s2 + shift_map_y_offset_s2; #ifdef DEBUG debugPtr1 = resultNodeArray1; debugPtr2 = resultNodeArray1+1; err_when(debugPtr1->node_x==debugPtr2->node_x && debugPtr1->node_y==debugPtr2->node_y); #endif return resultNodeArray1; } else return NULL; } resultNodeCount = 1; //----------------------------------- // count the number of 2x2 node //----------------------------------- int numOfNode=0; NodeS2* curPtr = result_node_ptr; while(curPtr != NULL) { curPtr = curPtr->parent_node; numOfNode++; } sys_yield(); // update cursor position //----------------------------------------- // otherwise, there are more than one node //----------------------------------------- ResultNode* maxSizeResultNodeArray; // store all the result node in the reverse order, the turning point will be extracted later int nodeAllocated, nodeCount=0; int preNodeCount = nodeCount; nodeAllocated = numOfNode*2+2; maxSizeResultNodeArray = (ResultNode*) mem_add(nodeAllocated*sizeof(ResultNode)); max_size_result_node_ptr = maxSizeResultNodeArray; parent_result_node_ptr = maxSizeResultNodeArray; //---------------------------------- // start from the destination //---------------------------------- memset(max_size_result_node_ptr, 0, sizeof(ResultNode)*nodeAllocated); int upper_left_x = nodePtr->node_x<<1; int upper_left_y = nodePtr->node_y<<1; if(!useClosestNode && (search_mode_s2==SEARCH_MODE_TO_ATTACK || can_move_to_s2(final_dest_x_s2, final_dest_y_s2))) { max_size_result_node_ptr->node_x = final_dest_x_s2; max_size_result_node_ptr->node_y = final_dest_y_s2; max_size_result_node_ptr++; // note: parent_result_node_ptr don't change here nodeCount++; //--------------------------------------------------- // process the end node, may pass through two points //--------------------------------------------------- if(search_mode_s2==SEARCH_MODE_REUSE) process_end_node(upper_left_x, upper_left_y, nodePtr->node_type, nodePtr->enter_direction, nodeCount); } else // closest node is used { //------------------------------------------------------------------------// // may generate duplicated node for the destination if closet node is used. //------------------------------------------------------------------------// switch(nodePtr->enter_direction) { case 1: max_size_result_node_ptr->node_x = upper_left_x-1; max_size_result_node_ptr->node_y = upper_left_y; break; case 2: max_size_result_node_ptr->node_x = upper_left_x-1; max_size_result_node_ptr->node_y = upper_left_y+1; break; case 3: max_size_result_node_ptr->node_x = upper_left_x; max_size_result_node_ptr->node_y = upper_left_y+1; break; case 4: max_size_result_node_ptr->node_x = upper_left_x+1; max_size_result_node_ptr->node_y = upper_left_y+1; break; case 5: max_size_result_node_ptr->node_x = upper_left_x+1; max_size_result_node_ptr->node_y = upper_left_y; break; case 6: max_size_result_node_ptr->node_x = upper_left_x+1; max_size_result_node_ptr->node_y = upper_left_y-1; break; case 7: max_size_result_node_ptr->node_x = upper_left_x; max_size_result_node_ptr->node_y = upper_left_y-1; break; case 8: max_size_result_node_ptr->node_x = upper_left_x-1; max_size_result_node_ptr->node_y = upper_left_y-1; break; default: err_here(); break; } max_size_result_node_ptr++; // note: parent_result_node_ptr don't change here nodeCount++; } nodePtr = nodePtr->parent_node; // next 2x2 node //-------------------------------------------------- // get the actual path, process from the second node //-------------------------------------------------- int yieldCount = 0; while( (parentNode=nodePtr->parent_node) != NULL ) { upper_left_x = nodePtr->node_x<<1; upper_left_y = nodePtr->node_y<<1; err_when(nodePtr->enter_direction==(childNodePtr->enter_direction+3)%8+1); get_real_result_node(nodeCount, nodePtr->enter_direction, (childNodePtr->enter_direction+3)%8+1, nodePtr->node_type, upper_left_x, upper_left_y); childNodePtr = nodePtr; nodePtr = parentNode; //err_when(nodeCount+nodePtr->node_g+2 > nodeAllocated); yieldCount++; if(yieldCount%20==0) sys_yield(); // update cursor position } sys_yield(); // update cursor position debug_check_paths2(maxSizeResultNodeArray, nodeCount); /*#ifdef DEBUG debugPtr1 = maxSizeResultNodeArray; debugPtr2 = maxSizeResultNodeArray+1; for(debugCount=1; debugCountnode_x - debugPtr1->node_x; debugVY = debugPtr2->node_y - debugPtr1->node_y; err_when(debugVX!=0 && debugVY!=0 && abs(debugVX)!=abs(debugVY)); debugPtr1++; debugPtr2++; } #endif*/ //---------------------------------------------------- // process the starting node // nodePtr points at the starting node now //---------------------------------------------------- err_when(nodePtr->enter_direction); // it should be zero upper_left_x = nodePtr->node_x<<1; upper_left_y = nodePtr->node_y<<1; //------------------------------------------------------------------------------------------// // process the starting node //------------------------------------------------------------------------------------------// process_start_node(upper_left_x, upper_left_y, nodePtr->node_type, (childNodePtr->enter_direction+3)%8+1, nodeCount); max_size_result_node_ptr->node_x = vir_start_x_s2; max_size_result_node_ptr->node_y = vir_start_y_s2; err_when((abs(max_size_result_node_ptr->node_x-parent_result_node_ptr->node_x)>1) || (abs(max_size_result_node_ptr->node_y-parent_result_node_ptr->node_y)>1)); nodeCount++; sys_yield(); // update cursor position debug_check_paths2(maxSizeResultNodeArray, nodeCount); /*#ifdef DEBUG debugPtr1 = maxSizeResultNodeArray; debugPtr2 = maxSizeResultNodeArray+1; for(debugCount=1; debugCountnode_x - debugPtr1->node_x; debugVY = debugPtr2->node_y - debugPtr1->node_y; err_when(debugVX!=0 && debugVY!=0 && (abs(debugVX)!=abs(debugVY))); debugPtr1++; debugPtr2++; } #endif*/ //--------------------------------------------------// // smooth the path //--------------------------------------------------// maxSizeResultNodeArray = smooth_the_path(maxSizeResultNodeArray, nodeCount); sys_yield(); // update cursor position parent_result_node_ptr = maxSizeResultNodeArray; max_size_result_node_ptr = maxSizeResultNodeArray+1; ResultNode* result_node_pointer = max_size_result_node_ptr; //---------------------------------- // get the turning point //---------------------------------- short vectorX = max_size_result_node_ptr->node_x - parent_result_node_ptr->node_x; short vectorY = max_size_result_node_ptr->node_y - parent_result_node_ptr->node_y; short newVectorX, newVectorY; for(int i=1; inode_x-parent_result_node_ptr->node_x); newVectorY=(max_size_result_node_ptr->node_y-parent_result_node_ptr->node_y); err_when(newVectorY!=0 && newVectorX!=0 && abs(newVectorX)!=abs(newVectorY)); //------ turning to another direction at this point ------// if(vectorX!=newVectorX || vectorY!=newVectorY) { if(newVectorX!=0 || newVectorY!=0) { result_node_pointer->node_x = parent_result_node_ptr->node_x; result_node_pointer->node_y = parent_result_node_ptr->node_y; result_node_pointer++; resultNodeCount++; vectorX = newVectorX; vectorY = newVectorY; } } if(i%20==0) sys_yield(); // update cursor position } result_node_pointer->node_x = vir_start_x_s2; result_node_pointer->node_y = vir_start_y_s2; result_node_pointer++; resultNodeCount++; //------------------------------------------------// // After the above process, here we will have a // link of rationalize nodes. Retrieve them in the // backwards order //------------------------------------------------// ResultNode *resultNodeArray = (ResultNode*) mem_add( sizeof(ResultNode) * resultNodeCount ); ResultNode *resultNodePtr = resultNodeArray+resultNodeCount-1; int processCount = 1; ResultNode *preNodePtr = maxSizeResultNodeArray; resultNodePtr->node_x = preNodePtr->node_x; resultNodePtr->node_y = preNodePtr->node_y; resultNodePtr--; result_node_pointer = maxSizeResultNodeArray+1; err_when(pathDist!=0); int xDist, yDist; while(processCount++ < resultNodeCount) { err_when(result_node_pointer->node_x<0 || result_node_pointer->node_x>=MAX_WORLD_X_LOC || result_node_pointer->node_y<0 || result_node_pointer->node_y>=MAX_WORLD_Y_LOC); resultNodePtr->node_x = result_node_pointer->node_x; resultNodePtr->node_y = result_node_pointer->node_y; resultNodePtr--; xDist = abs(result_node_pointer->node_x-preNodePtr->node_x); yDist = abs(result_node_pointer->node_y-preNodePtr->node_y); err_when((!xDist && !yDist) || (xDist && yDist && xDist!=yDist)); pathDist += (xDist) ? xDist : yDist; preNodePtr = result_node_pointer; result_node_pointer++; if(processCount%20==0) sys_yield(); // update cursor position } err_when(nodeAllocatednode_x += shift_map_x_offset_s2; adjustNode->node_y += shift_map_y_offset_s2; adjustNode++; } } debug_check_paths2(resultNodeArray, resultNodeCount); /*#ifdef DEBUG debugPtr1 = resultNodeArray; debugPtr2 = resultNodeArray+1; for(debugCount=1; debugCountnode_x - debugPtr1->node_x; debugVY = debugPtr2->node_y - debugPtr1->node_y; err_when(debugVX!=0 && debugVY!=0 && (abs(debugVX)!=abs(debugVY))); debugPtr1++; debugPtr2++; } #endif*/ //--------------------------------------------------// // return NULL if there are only two nodes and these // nodes are equal //--------------------------------------------------// if(resultNodeCount == 2) { ResultNode *curTestNode1 = resultNodeArray; ResultNode *curTestNode2 = resultNodeArray+1; if(curTestNode1->node_x==curTestNode2->node_x && curTestNode1->node_y==curTestNode2->node_y) { mem_del(resultNodeArray); resultNodeCount = 0; pathDist = 0; return NULL; } } #ifdef DEBUG if(resultNodeCount==2) { debugPtr1 = resultNodeArray; debugPtr2 = resultNodeArray+1; err_when(debugPtr1->node_x==debugPtr2->node_x && debugPtr1->node_y==debugPtr2->node_y); } #endif sys_yield(); // update cursor position return resultNodeArray; } //------ End of function SeekPathS2::get_result ---------// //---- Begin of function SeekPathS2::process_end_node ---------// void SeekPathS2::process_end_node(int xLoc, int yLoc, char nodeType, char enterDirection, int &nodeCount) { short usePathSuccess = 0; // if failure, use the last path in the checking short destType = 1 + (final_dest_x_s2%2) + 2*(final_dest_y_s2%2); switch(destType) { case 1: break; case 2: switch(enterDirection) { case 1: max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 2: err_when(!(nodeType&0x1) && !can_move_to(xLoc+1,yLoc+2)); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+!(nodeType&0x1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 3: case 4: case 6: case 7: break; case 5: break; case 8: err_when(!(nodeType&0x4) && !can_move_to(xLoc+1,yLoc-1)); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-!(nodeType&0x4); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; default: err_here(); break; } break; case 3: switch(enterDirection) { case 1: case 2: case 4: case 5: break; case 3: break; case 6: err_when(!(nodeType&0x1) && !can_move_to(xLoc+2,yLoc+1)); max_size_result_node_ptr->node_x = xLoc+!(nodeType&0x1); max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 7: max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 8: err_when(!(nodeType&0x2) && !can_move_to(xLoc-1,yLoc+1)); max_size_result_node_ptr->node_x = xLoc-!(nodeType&0x2); max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; default: err_here(); break; } break; case 4: switch(enterDirection) { case 1: err_when(!(nodeType&0x2) && !can_move_to(xLoc,yLoc+2)); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+can_move_to(xLoc,yLoc+2); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 2: max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 3: case 4: case 5: break; case 6: max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 7: err_when(!(nodeType&0x4) && !can_move_to(xLoc+2,yLoc)); max_size_result_node_ptr->node_x = xLoc+can_move_to(xLoc+2,yLoc); max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 8: max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; default: err_here(); break; } break; default: err_here(); break; } } //------ End of function SeekPathS2::process_end_node ---------// //---- Begin of function SeekPathS2::process_start_node ---------// void SeekPathS2::process_start_node(int xLoc, int yLoc, char nodeType, char exitDirection, int &nodeCount) { short usePathSuccess = 0; // if failure, use the last path in the checking switch(source_locate_type) { case 1: switch(exitDirection) { case 1: // 3 possible paths if(parent_result_node_ptr->node_ynode_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_y>yLoc && can_move_to(xLoc-1,yLoc+2) && can_move_to(xLoc,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 2: // 3 possible paths if(parent_result_node_ptr->node_x==xLoc && //can_move_to(xLoc+1,yLoc+1) && can_move_to(xLoc+1,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_y==yLoc && can_move_to(xLoc-1,yLoc)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc+1; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 3: if(parent_result_node_ptr->node_x>xLoc && can_move_to(xLoc+2,yLoc+1) && can_move_to(xLoc+2,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_xnode_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 4: if(parent_result_node_ptr->node_x==xLoc && //can_move_to(xLoc,yLoc+1) && can_move_to(xLoc,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_y==yLoc && //can_move_to(xLoc+1,yLoc) && can_move_to(xLoc+2,yLoc)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc+1; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 5: if(parent_result_node_ptr->node_ynode_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_y>yLoc && can_move_to(xLoc+1,yLoc+2) && can_move_to(xLoc+2,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 6: if(parent_result_node_ptr->node_y==yLoc && //can_move_to(xLoc+1,yLoc+1) && can_move_to(xLoc+2,yLoc+1)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_x==xLoc && can_move_to(xLoc,yLoc-1)) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc-1; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 7: if(parent_result_node_ptr->node_x>xLoc && can_move_to(xLoc+2,yLoc-1) && can_move_to(xLoc+2,yLoc)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_xnode_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 8: if(parent_result_node_ptr->node_x==xLoc && can_move_to(xLoc+1,yLoc-1)) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_y==yLoc && can_move_to(xLoc-1,yLoc+1)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc-1; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; default: err_here(); break; } break; case 2: switch(exitDirection) { case 1: if(parent_result_node_ptr->node_ynode_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_y>yLoc && can_move_to(xLoc-1,yLoc+2) && can_move_to(xLoc,yLoc+2) && can_move_to(xLoc+1,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 2: if(parent_result_node_ptr->node_y==yLoc+1 && can_move_to(xLoc+1,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess && can_move_to(xLoc+1,yLoc+2) && ( (vir_start_x_s2-parent_result_node_ptr->node_x==parent_result_node_ptr->node_y-vir_start_y_s2) || (parent_result_node_ptr->node_x==xLoc) ) ) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_y==yLoc && can_move_to(xLoc-1,yLoc) && can_move_to(xLoc,yLoc)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); err_when(!(nodeType&0x1) && !can_move_to(xLoc+1,yLoc+2)); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+(!(nodeType&0x1)); } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 3: if(parent_result_node_ptr->node_x>xLoc && //can_move_to(xLoc+2,yLoc+1) && can_move_to(xLoc+2,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 4: if(parent_result_node_ptr->node_x==xLoc && can_move_to(xLoc,yLoc+1) && can_move_to(xLoc,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess) { if(abs(parent_result_node_ptr->node_x-vir_start_x_s2)>1 || abs(parent_result_node_ptr->node_y-vir_start_y_s2)>1) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc+1; } else break; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 5: break; case 6: if(parent_result_node_ptr->node_x==xLoc && can_move_to(xLoc,yLoc-1) && can_move_to(xLoc,yLoc)) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess) { if(abs(parent_result_node_ptr->node_x-vir_start_x_s2)>1 || abs(parent_result_node_ptr->node_y-vir_start_y_s2)>1) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc-1; } else break; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 7: if(parent_result_node_ptr->node_x>xLoc && can_move_to(xLoc+2,yLoc-1) && can_move_to(xLoc+2,yLoc)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 8: if(parent_result_node_ptr->node_y==yLoc-1 && can_move_to(xLoc+1,yLoc-1)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess && can_move_to(xLoc+1,yLoc-1) && ( (vir_start_x_s2-parent_result_node_ptr->node_x==vir_start_y_s2-parent_result_node_ptr->node_y) || (parent_result_node_ptr->node_x==xLoc) ) ) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_y==yLoc && can_move_to(xLoc-1,yLoc+1) && can_move_to(xLoc,yLoc+1)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); err_when(!(nodeType&0x4) && !can_move_to(xLoc+1,yLoc-1)); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-(!(nodeType&0x4)); } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; default: err_here(); break; } break; case 3: switch(exitDirection) { case 1: if(parent_result_node_ptr->node_y>yLoc && can_move_to(xLoc-1,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 2: if(abs(parent_result_node_ptr->node_x-vir_start_x_s2)>1 || abs(parent_result_node_ptr->node_y-vir_start_y_s2)>1) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); } break; case 3: break; case 4: if(abs(parent_result_node_ptr->node_x-vir_start_x_s2)>1 || abs(parent_result_node_ptr->node_y-vir_start_y_s2)>1) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); } break; case 5: if(parent_result_node_ptr->node_y>yLoc && can_move_to(xLoc+2,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 6: if(parent_result_node_ptr->node_y==yLoc && can_move_to(xLoc+2,yLoc+1)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_x==xLoc && can_move_to(xLoc,yLoc-1) && can_move_to(xLoc,yLoc)) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); err_when(!(nodeType&0x1) && !can_move_to(xLoc+2, yLoc+1)); max_size_result_node_ptr->node_x = xLoc+!(nodeType&0x1); max_size_result_node_ptr->node_y = yLoc; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 7: if(parent_result_node_ptr->node_x>xLoc && can_move_to(xLoc+2,yLoc-1) && can_move_to(xLoc+2,yLoc)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_xnode_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 8: if(can_move_to(xLoc-1,yLoc+1) && ( (vir_start_x_s2-parent_result_node_ptr->node_x==vir_start_y_s2-parent_result_node_ptr->node_y)|| (parent_result_node_ptr->node_y==yLoc) ) ) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_x==xLoc && can_move_to(xLoc+1,yLoc-1) && can_move_to(xLoc+1,yLoc)) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); err_when(!(nodeType&0x2) && !can_move_to(xLoc-1, yLoc+1)); max_size_result_node_ptr->node_x = xLoc-!(nodeType&0x2); max_size_result_node_ptr->node_y = yLoc; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; default: err_here(); break; } break; case 4: switch(exitDirection) { case 1: if(parent_result_node_ptr->node_y>yLoc && can_move_to(xLoc-1,yLoc+2) && can_move_to(xLoc,yLoc+2)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess && can_move_to(xLoc,yLoc+2) && parent_result_node_ptr->node_y==yLoc-1) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); err_when(!(nodeType&0x2) && !can_move_to(xLoc, yLoc+2)); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+!(nodeType&0x2); } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 2: if(vir_start_x_s2-parent_result_node_ptr->node_x==parent_result_node_ptr->node_y+1-vir_start_y_s2) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; usePathSuccess++; } if(!usePathSuccess) { if(abs(parent_result_node_ptr->node_x-vir_start_x_s2)>1 || abs(parent_result_node_ptr->node_y-vir_start_y_s2)>1) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; } else break; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 3: if(abs(parent_result_node_ptr->node_x-vir_start_x_s2)>1 || abs(parent_result_node_ptr->node_y-vir_start_y_s2)>1) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); } break; case 4: break; case 5: if(abs(parent_result_node_ptr->node_x-vir_start_x_s2)>1 || abs(parent_result_node_ptr->node_y-vir_start_y_s2)>1) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); } break; case 6: if(parent_result_node_ptr->node_x+1-vir_start_x_s2==vir_start_y_s2-parent_result_node_ptr->node_y) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { if(abs(parent_result_node_ptr->node_x-vir_start_x_s2)>1 || abs(parent_result_node_ptr->node_y-vir_start_y_s2)>1) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; } else break; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 7: if(parent_result_node_ptr->node_x>xLoc && can_move_to(xLoc+2,yLoc-1) && can_move_to(xLoc+2,yLoc)) { max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_xnode_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); max_size_result_node_ptr->node_x = xLoc+1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); err_when(!(nodeType&0x4) && !can_move_to(xLoc+2, yLoc)); max_size_result_node_ptr->node_x = xLoc+!(nodeType&0x4); max_size_result_node_ptr->node_y = yLoc; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; case 8: if(parent_result_node_ptr->node_x==xLoc && can_move_to(xLoc+1,yLoc-1)) { max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc-1; usePathSuccess++; } if(!usePathSuccess && parent_result_node_ptr->node_y==yLoc && can_move_to(xLoc-1,yLoc+1)) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc; usePathSuccess++; } if(!usePathSuccess) { max_size_result_node_ptr->node_x = xLoc-1; max_size_result_node_ptr->node_y = yLoc-1; } add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); err_when(!can_move_to(xLoc+1, yLoc) || !can_move_to(xLoc, yLoc+1)); max_size_result_node_ptr->node_x = xLoc; max_size_result_node_ptr->node_y = yLoc; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, nodeCount); break; default: err_here(); break; } break; default: err_here(); break; } } //------ End of function SeekPathS2::process_start_node ---------// //---- Begin of function SeekPathS2::get_real_result_node ---------// // // called by get_result to extract the point in a 2x2 node that is // used in the shortest path // // count - a reference var for counting number of node in // max_size_result_node_ptr // void SeekPathS2::get_real_result_node(int &count, short enterDirection, short exitDirection, short nodeType, short xCoord, short yCoord) { prefer_upper_s2 = prefer_lower_s2 = prefer_left_s2 = prefer_right_s2 = 0; switch(enterDirection) { case 0: err_here(); break; case 1: switch(exitDirection) { case 2: // 2 possible paths if(parent_result_node_ptr->node_xnode_x = xCoord-prefer_left_s2; max_size_result_node_ptr->node_y = yCoord+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 3: // 2 possible paths if(parent_result_node_ptr->node_x>=xCoord) prefer_right_s2 = 1; else { if(can_move_to(xCoord-1,yCoord+2)) prefer_left_s2 = 1; else prefer_right_s2 = 1; } max_size_result_node_ptr->node_x = xCoord-prefer_left_s2; max_size_result_node_ptr->node_y = yCoord+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 4: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord+1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_lower_s2 = 1; else prefer_upper_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x2) && !can_move_to(xCoord, yCoord+2)); max_size_result_node_ptr->node_x = xCoord; if(prefer_upper_s2) max_size_result_node_ptr->node_y = yCoord + !(nodeType&0x2); else // prefer_lower_s2 max_size_result_node_ptr->node_y = yCoord + can_move_to(xCoord, yCoord+2); err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 5: // 2 points, 2 paths //----------- process path selection ---------------// if(parent_result_node_ptr->node_y<=yCoord) prefer_upper_s2 = 1; else { if(!can_move_to(xCoord,yCoord+2) || !can_move_to(xCoord+1,yCoord+2) || !can_move_to(xCoord+2,yCoord+2)) prefer_upper_s2 = 1; else prefer_lower_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord+prefer_lower_s2; err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord+prefer_lower_s2; err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 6: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord-1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_upper_s2 = 1; else prefer_lower_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x8) && !can_move_to(xCoord, yCoord-1)); max_size_result_node_ptr->node_x = xCoord; if(prefer_upper_s2) max_size_result_node_ptr->node_y = yCoord-can_move_to(xCoord, yCoord-1); else // prefer_lower_s2 max_size_result_node_ptr->node_y = yCoord-!(nodeType&0x8); err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord-1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 7: // 2 possible paths if(parent_result_node_ptr->node_x>=xCoord) prefer_right_s2 = 1; else { if(can_move_to(xCoord-1,yCoord-1)) prefer_left_s2 = 1; else prefer_right_s2 = 1; } max_size_result_node_ptr->node_x = xCoord-prefer_left_s2; max_size_result_node_ptr->node_y = yCoord-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 8: // 2 possible paths if(parent_result_node_ptr->node_xnode_x = xCoord-prefer_left_s2; max_size_result_node_ptr->node_y = yCoord-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; default: err_here(); break; } break; case 2: switch(exitDirection) { case 1: max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 3: max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 4: // 2 points, 2 possible paths if(parent_result_node_ptr->node_y<=yCoord+1) prefer_upper_s2 = 1; else { if(!can_move_to(xCoord, yCoord+3) || !can_move_to(xCoord+1, yCoord+3) || !can_move_to(xCoord+2, yCoord+3)) prefer_upper_s2 = 1; else prefer_lower_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord+1+prefer_lower_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord+1+prefer_lower_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 5: // 2 points, 2 paths if(parent_result_node_ptr->node_y<=yCoord) prefer_upper_s2 = 1; else { if(!can_move_to(xCoord+2,yCoord+2) || !can_move_to(xCoord+1,yCoord+2)) prefer_upper_s2 = 1; else prefer_lower_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord+prefer_lower_s2; err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x1) && !can_move_to(xCoord+1, yCoord+2)); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord+(prefer_lower_s2 || !(nodeType&0x1)); err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 6: // 2 points max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(nodeType != 15); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 7: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord-1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_right_s2 = 1; else prefer_left_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!can_move_to(xCoord-1,yCoord) && !(nodeType&0x8)); max_size_result_node_ptr->node_y = yCoord; if(prefer_left_s2) max_size_result_node_ptr->node_x = xCoord-can_move_to(xCoord-1,yCoord); else max_size_result_node_ptr->node_x = xCoord-!(nodeType&0x8); err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord-1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 8: // 2 points, 2 possible paths if(parent_result_node_ptr->node_x>=xCoord-1) prefer_right_s2 = 1; else { if(!can_move_to(xCoord-2,yCoord-1) || !can_move_to(xCoord-2,yCoord) || !can_move_to(xCoord-2,yCoord+1)) // must check for all 3 points to avoid problems in dummy node generated in path-reuse prefer_right_s2 = 1; else prefer_left_s2 = 1; } max_size_result_node_ptr->node_x = xCoord-1-prefer_left_s2; max_size_result_node_ptr->node_y = yCoord-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord-1-prefer_left_s2; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; default: err_here(); break; } break; case 3: switch(exitDirection) { case 1: // 2 possible paths if(parent_result_node_ptr->node_y<=yCoord) prefer_upper_s2 = 1; else { if(can_move_to(xCoord-1,yCoord+2)) prefer_lower_s2 = 1; else prefer_upper_s2 = 1; } max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord+prefer_lower_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 2: // 2 possible paths if(parent_result_node_ptr->node_y>yCoord) prefer_lower_s2 = 1; else { if(!can_move_to(xCoord, yCoord) || !can_move_to(xCoord-1,yCoord)) prefer_lower_s2 = 1; else prefer_upper_s2 = 1; } max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord+prefer_lower_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 4: // 2 possible paths if(parent_result_node_ptr->node_y>yCoord) prefer_lower_s2 = 1; else { if(!can_move_to(xCoord+1,yCoord) || !can_move_to(xCoord+2,yCoord)) prefer_lower_s2 = 1; else prefer_upper_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord+prefer_lower_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 5: // 2 possible paths if(parent_result_node_ptr->node_y<=yCoord) prefer_upper_s2 = 1; else { if(can_move_to(xCoord+2,yCoord+2)) prefer_lower_s2 = 1; else prefer_upper_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord+prefer_lower_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 6: // 2 points. 2 paths max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord-1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_right_s2 = 1; else prefer_left_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x1) && !can_move_to(xCoord+2, yCoord+1)); max_size_result_node_ptr->node_y = yCoord; if(prefer_left_s2) max_size_result_node_ptr->node_x = xCoord + !(nodeType&0x1); else // prefer_right_s2 max_size_result_node_ptr->node_x = xCoord + can_move_to(xCoord+2, yCoord+1); err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 7: // 2 points, 2 paths max_size_result_node_ptr->node_y = yCoord-1; //----------- process path selection ---------------// if(parent_result_node_ptr->node_x<=xCoord) prefer_left_s2 = 1; else { if(!can_move_to(xCoord+2,yCoord-1) || !can_move_to(xCoord+2,yCoord) || !can_move_to(xCoord+2,yCoord+1)) prefer_left_s2 = 1; else prefer_right_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+prefer_right_s2; err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord+prefer_right_s2; max_size_result_node_ptr->node_y = yCoord; err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 8: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord-1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_left_s2 = 1; else prefer_right_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x2) && !can_move_to(xCoord-1, yCoord+1)); max_size_result_node_ptr->node_y = yCoord; if(prefer_left_s2) max_size_result_node_ptr->node_x = xCoord - can_move_to(xCoord-1, yCoord+1); else // prefer_right_s2 max_size_result_node_ptr->node_x = xCoord - !(nodeType&0x2); err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord-1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; default: err_here(); break; } break; case 4: switch(exitDirection) { case 1: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord-1; //----------- process path selection ---------------// if(parent_result_node_ptr->node_y<=yCoord) prefer_upper_s2 = 1; else { if(!can_move_to(xCoord-1,yCoord+2) || !can_move_to(xCoord,yCoord+2)) prefer_upper_s2 = 1; else prefer_lower_s2 = 1; } max_size_result_node_ptr->node_y = yCoord+prefer_lower_s2; err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x2) && !can_move_to(xCoord, yCoord+2)); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord+(prefer_lower_s2 || !(nodeType&0x2)); err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 2: // 2 points, 2 possible paths if(parent_result_node_ptr->node_y<=yCoord+1) prefer_upper_s2 = 1; else { if(!can_move_to(xCoord-1, yCoord+3) || !can_move_to(xCoord, yCoord+3) || !can_move_to(xCoord+1, yCoord+3)) prefer_upper_s2 = 1; else prefer_lower_s2 = 1; } max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord+1+prefer_lower_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord+1+prefer_lower_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 3: max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 5: max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 6: // 2 points, 2 possible paths if(parent_result_node_ptr->node_x<=xCoord+1) prefer_left_s2 = 1; else { if(!can_move_to(xCoord+3,yCoord-1) || !can_move_to(xCoord+3,yCoord) || !can_move_to(xCoord+3,yCoord+1)) prefer_left_s2 = 1; else prefer_right_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+1+prefer_right_s2; max_size_result_node_ptr->node_y = yCoord-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord+1+prefer_right_s2; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 7: // 2 points, 2 paths max_size_result_node_ptr->node_y = yCoord-1; //----------- process path selection ---------------// if(parent_result_node_ptr->node_x<=xCoord) prefer_left_s2 = 1; else { if(!can_move_to(xCoord+2,yCoord-1) || !can_move_to(xCoord+2,yCoord)) prefer_left_s2 = 1; else prefer_right_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+prefer_right_s2; err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x4) && !can_move_to(xCoord+2, yCoord)); max_size_result_node_ptr->node_x = xCoord+(prefer_right_s2 || !(nodeType&0x4)); max_size_result_node_ptr->node_y = yCoord; err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 8: // 2 points max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(nodeType!=15); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; default: err_here(); break; } break; case 5: switch(exitDirection) { case 1: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord-1; //----------- process path selection ---------------// if(parent_result_node_ptr->node_y<=yCoord) prefer_upper_s2 = 1; else { if(!can_move_to(xCoord-1,yCoord+2) || !can_move_to(xCoord,yCoord+2) || !can_move_to(xCoord+1,yCoord+2)) prefer_upper_s2 = 1; else prefer_lower_s2 = 1; } max_size_result_node_ptr->node_y = yCoord+prefer_lower_s2; err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord+prefer_lower_s2; err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 2: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord+1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_lower_s2 = 1; else prefer_upper_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x1) && !can_move_to(xCoord+1, yCoord+2)); max_size_result_node_ptr->node_x = xCoord; if(prefer_upper_s2) max_size_result_node_ptr->node_y = yCoord + !(nodeType&0x1); else // prefer_lower_s2 max_size_result_node_ptr->node_y = yCoord + can_move_to(xCoord+1, yCoord+2); err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 3: // 2 possible paths if(parent_result_node_ptr->node_x<=xCoord) prefer_left_s2 = 1; else { if(can_move_to(xCoord+2,yCoord+2)) prefer_right_s2 = 1; else prefer_left_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+prefer_right_s2; max_size_result_node_ptr->node_y = yCoord+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 4: // 2 possible paths if(parent_result_node_ptr->node_x>xCoord) prefer_right_s2 = 1; else { if(!can_move_to(xCoord,yCoord+1) || !can_move_to(xCoord,yCoord+2)) prefer_right_s2 = 1; else prefer_left_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+prefer_right_s2; max_size_result_node_ptr->node_y = yCoord+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 6: // 2 possible paths if(parent_result_node_ptr->node_x>xCoord) prefer_right_s2 = 1; else { if(!can_move_to(xCoord,yCoord-1) || !can_move_to(xCoord,yCoord)) prefer_right_s2 = 1; else prefer_left_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+prefer_right_s2; max_size_result_node_ptr->node_y = yCoord-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 7: // 2 possible paths if(parent_result_node_ptr->node_x<=xCoord) prefer_left_s2 = 1; else { if(can_move_to(xCoord+2,yCoord-1)) prefer_right_s2 = 1; else prefer_left_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+prefer_right_s2; max_size_result_node_ptr->node_y = yCoord-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 8: // 2 points max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord-1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_upper_s2 = 1; else prefer_lower_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x4) && !can_move_to(xCoord+1, yCoord-1)); max_size_result_node_ptr->node_x = xCoord; if(prefer_upper_s2) max_size_result_node_ptr->node_y = yCoord - can_move_to(xCoord+1, yCoord-1); else // prefer_lower_s2 max_size_result_node_ptr->node_y = yCoord - !(nodeType&0x4); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; default: err_here(); break; } break; case 6: switch(exitDirection) { case 1: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_lower_s2 = 1; else prefer_upper_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x8) && !can_move_to(xCoord, yCoord-1)); max_size_result_node_ptr->node_x = xCoord; if(prefer_upper_s2) max_size_result_node_ptr->node_y = yCoord - can_move_to(xCoord, yCoord-1); else // prefer_lower_s2 max_size_result_node_ptr->node_y = yCoord - !(nodeType&0x8); err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord-1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 2: // 2 points max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(nodeType != 15); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 3: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord+1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_left_s2 = 1; else prefer_right_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x1) && !can_move_to(xCoord+2, yCoord+1)); max_size_result_node_ptr->node_y = yCoord; if(prefer_left_s2) max_size_result_node_ptr->node_x = xCoord + !(nodeType&0x1); else // prefer_right_s2 max_size_result_node_ptr->node_x = xCoord + can_move_to(xCoord+2, yCoord+1); err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord-1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 4: // 2 points, 2 possible paths if(parent_result_node_ptr->node_x<=xCoord+1) prefer_left_s2 = 1; else { if(!can_move_to(xCoord+3,yCoord) || !can_move_to(xCoord+3,yCoord+1) || !can_move_to(xCoord+3,yCoord+2)) prefer_left_s2 = 1; else prefer_right_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+1+prefer_right_s2; max_size_result_node_ptr->node_y = yCoord+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord+1+prefer_right_s2; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 5: max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 7: max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 8: // 2 points, 2 possible paths if(parent_result_node_ptr->node_y>=yCoord-1) prefer_lower_s2 = 1; else { if(!can_move_to(xCoord-1,yCoord-2) || !can_move_to(xCoord,yCoord-2) || !can_move_to(xCoord+1,yCoord-2)) // must check for all 3 points to avoid problems in dummy node generated in path-reuse prefer_lower_s2 = 1; else prefer_upper_s2 = 1; } max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord-1-prefer_upper_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord-1-prefer_upper_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; default: err_here(); break; } break; case 7: switch(exitDirection) { case 1: // 2 possible paths if(parent_result_node_ptr->node_y>=yCoord) prefer_lower_s2 = 1; else { if(can_move_to(xCoord-1,yCoord-1)) prefer_upper_s2 = 1; else prefer_lower_s2 = 1; } max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord-prefer_upper_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 2: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord+1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_left_s2 = 1; else prefer_right_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x8) && !can_move_to(xCoord-1, yCoord)); max_size_result_node_ptr->node_y = yCoord; if(prefer_left_s2) max_size_result_node_ptr->node_x = xCoord - can_move_to(xCoord-1, yCoord); else // prefer_right_s2 max_size_result_node_ptr->node_x = xCoord - !(nodeType&0x8); err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord-1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 3: // 2 points, 2 paths max_size_result_node_ptr->node_y = yCoord+1; //----------- process path selection ---------------// if(parent_result_node_ptr->node_x<=xCoord) prefer_left_s2 = 1; else { if(!can_move_to(xCoord+2,yCoord) || !can_move_to(xCoord+2,yCoord+1) || !can_move_to(xCoord+2,yCoord+2)) prefer_left_s2 = 1; else prefer_right_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+prefer_right_s2; err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord+prefer_right_s2; max_size_result_node_ptr->node_y = yCoord; err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 4: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord+1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_right_s2 = 1; else prefer_left_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x4) && !can_move_to(xCoord+2, yCoord)); max_size_result_node_ptr->node_y = yCoord; if(prefer_left_s2) max_size_result_node_ptr->node_x = xCoord + !(nodeType&0x4); else // prefer_right_s2 max_size_result_node_ptr->node_x = xCoord + can_move_to(xCoord+2, yCoord); err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord+1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 5: // 2 possible paths if(parent_result_node_ptr->node_y>=yCoord) prefer_lower_s2 = 1; else { if(can_move_to(xCoord+1,yCoord-1)) prefer_upper_s2 = 1; else prefer_lower_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord-prefer_upper_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 6: // 2 possible paths if(parent_result_node_ptr->node_ynode_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord-prefer_upper_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 8: // 2 possible paths if(parent_result_node_ptr->node_ynode_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord-prefer_upper_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; default: err_here(); break; } break; case 8: switch(exitDirection) { case 1: max_size_result_node_ptr->node_x = xCoord-1; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 2: // 2 points, 2 possible paths if(parent_result_node_ptr->node_x>=xCoord-1) prefer_right_s2 = 1; else { if(!can_move_to(xCoord-2,yCoord) || !can_move_to(xCoord-2,yCoord+1) || !can_move_to(xCoord-2,yCoord+2)) prefer_right_s2 = 1; else prefer_left_s2 = 1; } max_size_result_node_ptr->node_x = xCoord-1-prefer_left_s2; max_size_result_node_ptr->node_y = yCoord+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord-1-prefer_left_s2; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 3: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord+1; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_right_s2 = 1; else prefer_left_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x2) && !can_move_to(xCoord-1, yCoord+1)); max_size_result_node_ptr->node_y = yCoord; if(prefer_left_s2) max_size_result_node_ptr->node_x = xCoord - can_move_to(xCoord-1, yCoord+1); else // prefer_right_s2 max_size_result_node_ptr->node_x = xCoord - !(nodeType&0x2); err_when(max_size_result_node_ptr->node_x!=xCoord && max_size_result_node_ptr->node_x!=xCoord-1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 4: // 2 points max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord+1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(nodeType!=15); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 5: // 2 points, 2 paths max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord; //----------- process path selection ---------------// if( (parent_result_node_ptr->node_x-max_size_result_node_ptr->node_x==0) || (parent_result_node_ptr->node_y-max_size_result_node_ptr->node_y==0) ) prefer_lower_s2 = 1; else prefer_upper_s2 = 1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); err_when(!(nodeType&0x4) && !can_move_to(xCoord+1, yCoord-1)); max_size_result_node_ptr->node_x = xCoord; if(prefer_upper_s2) max_size_result_node_ptr->node_y = yCoord - can_move_to(xCoord+1, yCoord-1); else // prefer_lower_s2 max_size_result_node_ptr->node_y = yCoord - !(nodeType&0x4); err_when(max_size_result_node_ptr->node_y!=yCoord && max_size_result_node_ptr->node_y!=yCoord-1); add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 6: // 2 points, 2 possible paths if(parent_result_node_ptr->node_y>=yCoord-1) prefer_lower_s2 = 1; else { if(!can_move_to(xCoord,yCoord-2) || !can_move_to(xCoord+1,yCoord-2) || !can_move_to(xCoord+2,yCoord-2)) prefer_lower_s2 = 1; else prefer_upper_s2 = 1; } max_size_result_node_ptr->node_x = xCoord+1; max_size_result_node_ptr->node_y = yCoord-1-prefer_upper_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord-1-prefer_upper_s2; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; case 7: max_size_result_node_ptr->node_x = xCoord; max_size_result_node_ptr->node_y = yCoord-1; add_result_node(&max_size_result_node_ptr, &parent_result_node_ptr, count); break; default: err_here(); break; } break; default: err_here(); break; } } //------ End of function SeekPathS2::get_real_result_node ---------// //-------- Begin of function SeekPathS2::return_best_node -------// // // return : the best node. // NULL if no more node on the open node list. There is no // possible path between the starting and destination points. // NodeS2* SeekPathS2::return_best_node() { NodeS2 *tempNode; if( !open_node_list ) return NULL; //------------------------------------------------------------------// // Pick Node with lowest f, in this case it's the first node in list // Because we sort the open_node_list list wrt lowest f. Call it BESTNode. //------------------------------------------------------------------// tempNode=open_node_list; // point to first node on open_node_list open_node_list=tempNode->next_node; // Make open_node_list point to nextnode or NULL. //------------------------------------------------------------------// // Next take BESTNode (or temp in this case) and put it on closed_node_list //------------------------------------------------------------------// tempNode->next_node=closed_node_list; closed_node_list=tempNode; return tempNode; } //-------- End of function SeekPathS2::return_best_node ---------// //----- Begin of function SeekPathS2::return_closest_node -------// // // Return the node that is closest to the destination. // NodeS2* SeekPathS2::return_closest_node() { NodeS2* nodePtr; NodeS2* shortestNode=NULL; int nodeDistance, shortestDistance=0x7FFF; int disX, disY; //------------ search open_node_list ----------// nodePtr = open_node_list; int yieldCount = 0; while(nodePtr) { //--- the distance between this node and the destination node ----// nodeDistance = (disX=cur_dest_x_s2-nodePtr->node_x)*disX + (disY=cur_dest_y_s2-nodePtr->node_y)*disY; //--- if the distance is shorter than the current shortest distance ---// if( nodeDistance < shortestDistance ) { shortestDistance = nodeDistance; shortestNode = nodePtr; } nodePtr=nodePtr->next_node; yieldCount++; if(yieldCount%25==0) sys_yield(); } //------------ search closed_node_list ----------// nodePtr = closed_node_list; yieldCount = 0; while(nodePtr) { //--- the distance between this node and the destination node ----// nodeDistance = (disX=cur_dest_x_s2-nodePtr->node_x)*disX + (disY=cur_dest_y_s2-nodePtr->node_y)*disY; //--- if the distance is shorter than the current shortest distance ---// if( nodeDistance < shortestDistance ) { shortestDistance = nodeDistance; shortestNode = nodePtr; } nodePtr=nodePtr->next_node; yieldCount++; if(yieldCount%25==0) sys_yield(); } //------------------------------------------------------// // there may be some nodes with the same shortest Distance // from the destination node. However, one should be closer // to the starting node. The following is used to find // out the closer node. //------------------------------------------------------// nodePtr = shortestNode->parent_node; yieldCount = 0; while(nodePtr) { //--- the distance between the parent node and the destination node ----// nodeDistance = (disX=cur_dest_x_s2-nodePtr->node_x)*disX + (disY=cur_dest_y_s2-nodePtr->node_y)*disY; //--- if the distance is shorter than the current shortest distance ---// if( nodeDistance <= shortestDistance ) { shortestDistance = nodeDistance; shortestNode = nodePtr; } else break; nodePtr=nodePtr->parent_node; yieldCount++; if(yieldCount%25==0) sys_yield(); } return shortestNode; } //----- End of function SeekPathS2::return_closest_node -------// //----- Begin of function SeekPathS2::insert_open_node -------// void SeekPathS2::insert_open_node(NodeS2 *succNode) { if (open_node_list == NULL) { open_node_list=succNode; return; } //---- insert into open_node_list successor wrt f ----// register int f=succNode->node_f; if( open_node_list && open_node_list->node_f < f ) { NodeS2 *tempNode1, *tempNode2; tempNode1=open_node_list; tempNode2=tempNode1->next_node; int yieldCount = 0; while( tempNode2 && tempNode2->node_f < f ) { tempNode1=tempNode2; tempNode2=tempNode2->next_node; yieldCount++; if(yieldCount%200==0) sys_yield(); } err_when(succNode!=NULL && tempNode2!=NULL && succNode->node_x==tempNode2->node_x && succNode->node_y==tempNode2->node_y); // avoid pointer pointing back to itself succNode->next_node = tempNode2; tempNode1->next_node = succNode; } else { succNode->next_node = open_node_list; open_node_list = succNode; } } //----- End of function SeekPathS2::insert_open_node -------// //-------- Begin of function SeekPath::smooth_the_path ---------// ResultNode* SeekPathS2::smooth_the_path(ResultNode* nodeArray, int& nodeCount) { //--------------------------------------------------// // to remove duplicate or useless node //--------------------------------------------------// int i, j, curNodeCount = 1; parent_result_node_ptr = nodeArray; max_size_result_node_ptr = nodeArray+1; for(i=0; inode_x!=max_size_result_node_ptr->node_x || parent_result_node_ptr->node_y!=max_size_result_node_ptr->node_y) { parent_result_node_ptr++; parent_result_node_ptr->node_x = max_size_result_node_ptr->node_x; parent_result_node_ptr->node_y = max_size_result_node_ptr->node_y; curNodeCount++; } max_size_result_node_ptr++; if(i%50==0) sys_yield(); } nodeCount = curNodeCount; //return nodeArray; //---------- declare variables ---------------// int checkedNodeCount; short vectorX, vectorY, newVectorX, newVectorY, newVectorX2, newVectorY2; short changed, caseNum, processed; ResultNode *curUsefulNodePtr = nodeArray+1; ResultNode *ptr1; ResultNode *ptr2; ResultNode *ptr3; ResultNode *ptr4; //--------------------------------------------------// // smooth the path //--------------------------------------------------// parent_result_node_ptr = nodeArray; max_size_result_node_ptr = nodeArray+1; changed = 1; checkedNodeCount = 1; curNodeCount = nodeCount; ptr1 = parent_result_node_ptr; ptr2 = max_size_result_node_ptr; ptr3 = max_size_result_node_ptr+1; int yieldCount = 1; while(changed && curNodeCount>=3) { yieldCount++; if(yieldCount%20==0) sys_yield(); vectorX = ptr2->node_x - ptr1->node_x; vectorY = ptr2->node_y - ptr1->node_y; changed = 0; for(j=1; jnode_x - ptr2->node_x; newVectorY= ptr3->node_y - ptr2->node_y; //----------------------------------------------------------// // reverse direction //----------------------------------------------------------// if(vectorX==-newVectorX && vectorY==-newVectorY) { if(j+2node_x - ptr1->node_x; vectorY = ptr2->node_y - ptr1->node_y; processed = 1; j++; continue; } else //-------- already the end of the array ----------// { ptr3++; changed++; break; // break the for loop } } //----------------------------------------------------------// // turning 45 degree angle //----------------------------------------------------------// if(abs(vectorX+newVectorX)<=1 && abs(vectorY+newVectorY)<=1 && // if so, turning 45 or 90 degree vectorX*newVectorX+vectorY*newVectorY!=0) // reject turning 90 degree { ptr2=ptr3; ptr3++; vectorX = ptr2->node_x - ptr1->node_x; vectorY = ptr2->node_y - ptr1->node_y; processed = 1; continue; } //----------------------------------------------------------// // turning at 90 degree clockwise / anti-clockwise //----------------------------------------------------------// if((vectorX==0 && vectorY!=0 && newVectorX!=0 && newVectorY==0) || // + case (vectorX!=0 && vectorY==0 && newVectorX==0 && newVectorY!=0)) { ptr2=ptr3; ptr3++; vectorX = ptr2->node_x - ptr1->node_x; vectorY = ptr2->node_y - ptr1->node_y; processed = 1; continue; } if((vectorX!=0 && vectorY!=0 && newVectorX!=0 && newVectorY!=0) && // x case ((vectorX==newVectorX && vectorY==-newVectorY) || (vectorX==-newVectorX && vectorY==newVectorY))) { ptr2->node_x = (ptr1->node_x+ptr3->node_x)/2; ptr2->node_y = (ptr1->node_y+ptr3->node_y)/2; curUsefulNodePtr->node_x = ptr2->node_x; curUsefulNodePtr->node_y = ptr2->node_y; curUsefulNodePtr++; checkedNodeCount++; ptr1 = ptr2; ptr2 = ptr3; ptr3++; vectorX = ptr2->node_x - ptr1->node_x; vectorY = ptr2->node_y - ptr1->node_y; processed = 1; continue; } //----------------------------------------------------------// // check for the 4-point case //----------------------------------------------------------// if(jnode_x - ptr3->node_x; newVectorY2 = ptr4->node_y - ptr3->node_y; caseNum = 0; if(!caseNum && vectorX==-1 && vectorY==0 && newVectorX==-1 && newVectorX2==0) { if(newVectorY==1 && newVectorY2==1 && can_move_to(ptr1->node_x, ptr4->node_y)) caseNum = 1; if(!caseNum && newVectorY==-1 && newVectorY2==-1 && can_move_to(ptr1->node_x, ptr4->node_y-1)) caseNum = 5; } if(!caseNum && vectorX==1 && vectorY==0 && newVectorX==1 && newVectorX2==0) { if(newVectorY==1 && newVectorY2==1 && can_move_to(ptr1->node_x+1, ptr4->node_y)) caseNum = 3; if(!caseNum && newVectorY==-1 && newVectorY2==-1 && can_move_to(ptr1->node_x+1, ptr4->node_y-1)) caseNum = 7; } if(!caseNum && vectorX==0 && vectorY==-1 && newVectorY==-1 && newVectorY2==0) { if(newVectorX==1 && newVectorX2==1 && can_move_to(ptr4->node_x, ptr1->node_y)) caseNum = 2; if(!caseNum && newVectorX==-1 && newVectorX2==-1 && can_move_to(ptr4->node_x+1, ptr1->node_y)) caseNum = 4; } if(!caseNum && vectorX==0 && vectorY==1 && newVectorY==1 && newVectorY2==0) { if(newVectorX==1 && newVectorX2==1 && can_move_to(ptr4->node_x, ptr1->node_y+1)) caseNum = 6; if(!caseNum && newVectorX==-1 && newVectorX2==-1 && can_move_to(ptr4->node_x+1, ptr1->node_y+1)) caseNum = 8; } if(caseNum) { switch(caseNum) { case 1: if(can_move_to(ptr1->node_x, ptr4->node_y)) { //ptr2->node_x = ptr2->node_x; ptr2->node_y++; //ptr2->node_y = ptr3->node_y; processed = 1; } break; case 2: if(can_move_to(ptr4->node_x, ptr1->node_y)) { ptr2->node_x++; //ptr2->node_x = ptr3->node_x; //ptr2->node_y = ptr2->node_y; processed = 1; } break; case 3: if(can_move_to(ptr2->node_x, ptr4->node_y)) { //ptr2->node_x = ptr2->node_x; ptr2->node_y++; //ptr2->node_y = ptr3->node_y; processed = 1; } break; case 4: if(can_move_to(ptr3->node_x, ptr1->node_y)) { ptr2->node_x--; //ptr2->node_x = ptr3->node_x; //ptr2->node_y = ptr2->node_y; processed = 1; } break; case 5: if(can_move_to(ptr1->node_x, ptr3->node_y)) { //ptr2->node_x = ptr2->node_x; ptr2->node_y--; //ptr2->node_y = ptr3->node_y; processed = 1; } break; case 6: if(can_move_to(ptr4->node_x, ptr2->node_y)) { ptr2->node_x++; //ptr2->node_x = ptr3->node_x; //ptr2->node_y = ptr2->node_y; processed = 1; } break; case 7: if(can_move_to(ptr2->node_x, ptr3->node_y)) { //ptr2->node_x = ptr2->node_x; ptr2->node_y--; //ptr2->node_y = ptr3->node_y; processed = 1; } break; case 8: if(can_move_to(ptr3->node_x, ptr2->node_y)) { ptr2->node_x--; //ptr2->node_x = ptr3->node_x; //ptr2->node_y = ptr2->node_y; processed = 1; } break; default: err_here(); break; } if(processed) { ptr3 = ptr4; curUsefulNodePtr->node_x = ptr2->node_x; curUsefulNodePtr->node_y = ptr2->node_y; curUsefulNodePtr++; checkedNodeCount++; ptr1 = ptr2; ptr2 = ptr3; ptr3++; j++; vectorX = ptr2->node_x - ptr1->node_x; vectorY = ptr2->node_y - ptr1->node_y; continue; } } } //------ none of the above case ---------// if(!processed) { curUsefulNodePtr->node_x = ptr2->node_x; curUsefulNodePtr->node_y = ptr2->node_y; curUsefulNodePtr++; checkedNodeCount++; } else changed = 1; ptr1 = ptr2; ptr2 = ptr3; ptr3++; vectorX = ptr2->node_x - ptr1->node_x; vectorY = ptr2->node_y - ptr1->node_y; } //---- end checking and then reset parameters----// curUsefulNodePtr->node_x = ptr2->node_x; curUsefulNodePtr->node_y = ptr2->node_y; curUsefulNodePtr++; checkedNodeCount++; curNodeCount = checkedNodeCount; checkedNodeCount = 1; ptr1 = parent_result_node_ptr; ptr2 = ptr1+1; ptr3 = ptr2+1; } nodeCount = curNodeCount; return nodeArray; } //------- End of function SeekPathS2::smooth_the_path -------// //-------- Begin of function NodeS2::generate_successors ---------// // Note: In fact, the cost of the starting node should be 0 or 1 // and the parentEnterDirection is 0. Now the cost in this // case is set to 2. The difference can be ignored as it will // not affect the search after generating the second level // children. // The advantage to ignore this case is that less comparsion // effort in checking parentEnterDirection. // short NodeS2::generate_successors(short parentEnterDirection) { int hasLeft = node_x > cur_border_x1_s2; int hasRight = node_x < cur_border_x2_s2; int hasUp = node_y > cur_border_y1_s2; int hasDown = node_y < cur_border_y2_s2; int upperLeftX,upperLeftY; short cost; upperLeftX = node_x<<1; upperLeftY = node_y<<1; err_when(upperLeftX != node_x+node_x || upperLeftY != node_y+node_y); //------------------------------------------- // enter_direction = (exit_direction+3)%8+1 //------------------------------------------- if( hasLeft ) { //--------- Left, exit_direction=1 --------// if(can_move_to(upperLeftX-1, upperLeftY) && node_type&0x1 && can_move_to(upperLeftX-1, upperLeftY+1) && node_type&0x4 ) { if(parentEnterDirection==2 || parentEnterDirection==3 || parentEnterDirection==7 || parentEnterDirection==8) cost = 1; else { if((parentEnterDirection==4 && (node_type&0x2 || can_move_to(upperLeftX,upperLeftY+2))) || parentEnterDirection==5 || (parentEnterDirection==6 && (node_type&0x8 || can_move_to(upperLeftX,upperLeftY-1)))) cost = 2; else { if(parentEnterDirection==0 && !source_blocked_exit_direction[0]) // direction 1 { if(source_locate_type==1 || source_locate_type==3) cost = 1; else cost = 2; } else cost = 0; } } if(cost) { err_when(parentEnterDirection==1); if(generate_succ(node_x-1,node_y,5,cost)) return 1; } } if( hasUp ) { //------- Upper-Left, exit_direction=8 ---------// if(can_move_to(upperLeftX-1, upperLeftY-1) && can_move_to(upperLeftX, upperLeftY-1) && can_move_to(upperLeftX-1, upperLeftY) && node_type&0x1) { if(parentEnterDirection==1 || parentEnterDirection==2 || parentEnterDirection==6 || parentEnterDirection==7) cost = 1; else { if((parentEnterDirection==3 && (node_type&0x2 || can_move_to(upperLeftX-1, upperLeftY+1))) || (parentEnterDirection==4 && node_type==15) || (parentEnterDirection==5 && (node_type&0x4 || can_move_to(upperLeftX+1, upperLeftY-1)))) cost = 2; else { if(parentEnterDirection==0 && !source_blocked_exit_direction[7]) // direction 8 { if(source_locate_type==1) cost = 1; else cost = 2; } else cost = 0; } } if(cost) { err_when(parentEnterDirection==8); if(generate_succ(node_x-1,node_y-1,4,cost)) return 1; } } } if( hasDown ) { //--------- Lower-Left, exit_direction=2 ----------// if(can_move_to(upperLeftX-1,upperLeftY+1) && node_type&0x4 && can_move_to(upperLeftX-1,upperLeftY+2) && can_move_to(upperLeftX,upperLeftY+2)) { if(parentEnterDirection==1 || parentEnterDirection==3 || parentEnterDirection==4 || parentEnterDirection==8) cost = 1; else { if((parentEnterDirection==5 && (node_type&0x1 || can_move_to(upperLeftX+1,upperLeftY+2))) || (parentEnterDirection==6 && node_type==15) || (parentEnterDirection==7 && (node_type&0x8 || can_move_to(upperLeftX-1,upperLeftY)))) cost = 2; else { if(parentEnterDirection==0 && !source_blocked_exit_direction[1]) // direction 2 { if(source_locate_type==1||source_locate_type==3) cost = 1; else cost = 2; } else cost = 0; } } if(cost || (parentEnterDirection==0 && source_locate_type==3 && !source_blocked_exit_direction[1])) { err_when(parentEnterDirection==2); if(generate_succ(node_x-1,node_y+1,6,cost)) return 1; } } } } if( hasRight ) { //----------- Right, exit_direction=5 -----------// if(node_type&0x2 && can_move_to(upperLeftX+2,upperLeftY) && node_type&0x8 && can_move_to(upperLeftX+2,upperLeftY+1)) { if(parentEnterDirection==3 || parentEnterDirection==4 || parentEnterDirection==6 || parentEnterDirection==7) cost = 1; else { if(parentEnterDirection==1 || (parentEnterDirection==2 && (node_type&0x1 || can_move_to(upperLeftX+1,upperLeftY+2))) || (parentEnterDirection==8 && (node_type&0x4 || can_move_to(upperLeftX+1,upperLeftY-1)))) cost = 2; else { if(parentEnterDirection==0 && !source_blocked_exit_direction[4] && //direction 5 (source_locate_type==1||source_locate_type==3)) cost = 1; else cost = 0; } } if(cost||(parentEnterDirection==0&&!source_blocked_exit_direction[4]&&(source_locate_type==2||source_locate_type==4))) { err_when(parentEnterDirection==5); if(generate_succ(node_x+1,node_y,1,cost)) return 1; } } if( hasUp ) { //-------- Upper-Right, exit_direction=6 ---------// if(can_move_to(upperLeftX+1,upperLeftY-1) && can_move_to(upperLeftX+2,upperLeftY-1) && node_type&0x2 && can_move_to(upperLeftX+2,upperLeftY)) { if(parentEnterDirection==4 || parentEnterDirection==5 || parentEnterDirection==7 || parentEnterDirection==8) cost = 1; else { if((parentEnterDirection==1 && (node_type&0x8 || can_move_to(upperLeftX,upperLeftY-1))) || (parentEnterDirection==2 && node_type==15) || (parentEnterDirection==3 && (node_type&0x1 || can_move_to(upperLeftX+2,upperLeftY+1)))) cost = 2; else { if(parentEnterDirection==0 && !source_blocked_exit_direction[5]) // direction 6 { if(source_locate_type==1||source_locate_type==2) cost = 1; else cost = 2; } else cost = 0; } } if(cost) { err_when(parentEnterDirection==6); if(generate_succ(node_x+1,node_y-1,2,cost)) return 1; } } } if( hasDown ) { //--------- Lower-Right, exit_direction=4 ---------// if(node_type&0x8 && can_move_to(upperLeftX+2,upperLeftY+1) && can_move_to(upperLeftX+1,upperLeftY+2) && can_move_to(upperLeftX+2,upperLeftY+2)) { if(parentEnterDirection==2 || parentEnterDirection==3 || parentEnterDirection==5 || parentEnterDirection==6) cost = 1; else { if((parentEnterDirection==1 && (node_type&0x2 || can_move_to(upperLeftX,upperLeftY+2))) || (parentEnterDirection==8 && node_type==15) || (parentEnterDirection==7 && (node_type&0x4 || can_move_to(upperLeftX+2,upperLeftY)))) cost = 2; else { if(parentEnterDirection==0&&source_locate_type!=4&&!source_blocked_exit_direction[3]) // direction 4 cost = 1; else cost = 0; } } if(cost||(parentEnterDirection==0&&source_locate_type==4&&!source_blocked_exit_direction[3])) { err_when(parentEnterDirection==4); if(generate_succ(node_x+1,node_y+1,8,cost)) return 1; } } } } if( hasUp ) { //---------- Upper, exit_direction=7 -----------// if(can_move_to(upperLeftX,upperLeftY-1) && can_move_to(upperLeftX+1,upperLeftY-1) && node_type&0x1 && node_type&0x2) { if(parentEnterDirection==1 || parentEnterDirection==5 || parentEnterDirection==6 || parentEnterDirection==8) cost = 1; else { if((parentEnterDirection==2 && (node_type&0x8 || can_move_to(upperLeftX-1,upperLeftY))) || parentEnterDirection==3 || (parentEnterDirection==4 && (node_type&0x4 || can_move_to(upperLeftX+2,upperLeftY)))) cost = 2; else { if(parentEnterDirection==0 && !source_blocked_exit_direction[6]) // direction 7 { if(source_locate_type==1||source_locate_type==2) cost = 1; else cost = 2; } else cost = 0; } } if(cost) { err_when(parentEnterDirection==7); if(generate_succ(node_x,node_y-1,3,cost)) return 1; } } } if( hasDown ) { //---------- Lower, exit_direction=3 -----------// if(node_type&0x4 && node_type&0x8 && can_move_to(upperLeftX,upperLeftY+2) && can_move_to(upperLeftX+1,upperLeftY+2)) { if(parentEnterDirection==1 || parentEnterDirection==2 || parentEnterDirection==4 || parentEnterDirection==5) cost = 1; else { if((parentEnterDirection==6 && (node_type&0x1 || can_move_to(upperLeftX+2,upperLeftY+1))) || parentEnterDirection==7 || (parentEnterDirection==8 && (node_type&0x2 || can_move_to(upperLeftX-1,upperLeftY+1)))) cost = 2; else { if(parentEnterDirection==0&&(source_locate_type==1||source_locate_type==2)&&!source_blocked_exit_direction[2]) // direction 3 cost = 1; else cost = 0; } } if(cost||(parentEnterDirection==0&&(source_locate_type==3||source_locate_type==4)&&!source_blocked_exit_direction[2])) { err_when(parentEnterDirection==3); if(generate_succ(node_x,node_y+1,7,cost)) return 1; } } } return 0; } //------- End of function NodeS2::generate_successors -------// //-------- Begin of function NodeS2::generate_succ ---------// short NodeS2::generate_succ(short x, short y, short enter_direct,short cost) { int upperLeftX, upperLeftY; upperLeftX = x<<1; upperLeftY = y<<1; //----- if it points back to this node's parent ----// if( parent_node ) { if( parent_node->node_x==x && parent_node->node_y==y ) return 0; } //----- if there is an existing node at the given position ----// short c, g = node_g+cost; // g(Successor)=g(BestNode)+cost of getting from BestNode to Successor short nodeRecno; //if( (nodeRecno=cur_node_matrix_s2[y*(MAX_WORLD_X_LOC/2+1)+x]) > 0 ) if( (nodeRecno=cur_node_matrix_s2[y*(MAX_WORLD_X_LOC/2+1)+x]) > 0 && nodeRecnonode_g) { //-------------check whether the oldNode can process propagate down -----------// char canPropagateDown=1; if(oldNode->node_type!=15 && enter_direct%2==0) { NodeS2* oldChildNode; short xShift1 = x_shift_array[enter_direct-1]; short yShift1 = y_shift_array[enter_direct-1]; short xShift2, yShift2, xShift3, yShift3; if(enter_direct>1) { xShift2 = x_shift_array[enter_direct-2]; yShift2 = y_shift_array[enter_direct-2]; } else { xShift2 = x_shift_array[7]; yShift2 = y_shift_array[7]; } if(enter_direct<8) { xShift3 = x_shift_array[enter_direct]; yShift3 = y_shift_array[enter_direct]; } else { xShift3 = x_shift_array[0]; yShift3 = y_shift_array[0]; } for(c=0; cchild_node[c]; c++) // for each child of oldNode { oldChildNode = oldNode->child_node[c]; if(oldNode->parent_node != oldChildNode) { switch(enter_direct) // for entering at corner { case 2: if(oldChildNode->enter_direction==enter_direct && oldChildNode->node_x-oldNode->node_x==xShift1 && oldChildNode->node_y-oldNode->node_y==yShift1 && (!can_move_to(upperLeftX, upperLeftY) || !can_move_to(upperLeftX+1, upperLeftY+1))) canPropagateDown = 0; if(oldChildNode->enter_direction==enter_direct-1 && oldChildNode->node_x-oldNode->node_x==xShift2 && oldChildNode->node_x-oldNode->node_y==yShift2 && !can_move_to(upperLeftX,upperLeftY) && !can_move_to(upperLeftX+1,upperLeftY+2)) canPropagateDown = 0; if(oldChildNode->enter_direction==enter_direct+1 && oldChildNode->node_x-oldNode->node_x==xShift2 && oldChildNode->node_x-oldNode->node_y==yShift2 && !can_move_to(upperLeftX+1,upperLeftY+1) && !can_move_to(upperLeftX-1,upperLeftY)) canPropagateDown = 0; break; case 4: if(oldChildNode->enter_direction==enter_direct && oldChildNode->node_x-oldNode->node_x==xShift1 && oldChildNode->node_y-oldNode->node_y==yShift1 && (!can_move_to(upperLeftX+1, upperLeftY) || !can_move_to(upperLeftX, upperLeftY+1))) canPropagateDown = 0; if(oldChildNode->enter_direction==enter_direct-1 && oldChildNode->node_x-oldNode->node_x==xShift2 && oldChildNode->node_x-oldNode->node_y==yShift2 && !can_move_to(upperLeftX,upperLeftY+1)&& !can_move_to(upperLeftX+2,upperLeftY)) canPropagateDown = 0; if(oldChildNode->enter_direction==enter_direct+1 && oldChildNode->node_x-oldNode->node_x==xShift2 && oldChildNode->node_x-oldNode->node_y==yShift2 && !can_move_to(upperLeftX,upperLeftY+2) && !can_move_to(upperLeftX+1,upperLeftY)) canPropagateDown = 0; break; case 6: if(oldChildNode->enter_direction==enter_direct && oldChildNode->node_x-oldNode->node_x==xShift1 && oldChildNode->node_y-oldNode->node_y==yShift1 && (!can_move_to(upperLeftX, upperLeftY) || !can_move_to(upperLeftX+1, upperLeftY+1))) canPropagateDown = 0; if(oldChildNode->enter_direction==enter_direct-1 && oldChildNode->node_x-oldNode->node_x==xShift2 && oldChildNode->node_x-oldNode->node_y==yShift2 && !can_move_to(upperLeftX,upperLeftY-1)&& !can_move_to(upperLeftX+1,upperLeftY+1)) canPropagateDown = 0; if(oldChildNode->enter_direction==enter_direct+1 && oldChildNode->node_x-oldNode->node_x==xShift2 && oldChildNode->node_x-oldNode->node_y==yShift2 && !can_move_to(upperLeftX,upperLeftY) && !can_move_to(upperLeftX+2,upperLeftY+1)) canPropagateDown = 0; break; case 8: if(oldChildNode->enter_direction==enter_direct && oldChildNode->node_x-oldNode->node_x==xShift1 && oldChildNode->node_y-oldNode->node_y==yShift1 && (!can_move_to(upperLeftX+1, upperLeftY) || !can_move_to(upperLeftX, upperLeftY+1))) canPropagateDown = 0; if(oldChildNode->enter_direction==enter_direct-1 && oldChildNode->node_x-oldNode->node_x==xShift2 && oldChildNode->node_x-oldNode->node_y==yShift2 && !can_move_to(upperLeftX-1,upperLeftY+1)&& !can_move_to(upperLeftX+1,upperLeftY)) canPropagateDown = 0; if(oldChildNode->enter_direction==(enter_direct%8+1) && oldChildNode->node_x-oldNode->node_x==xShift2 && oldChildNode->node_x-oldNode->node_y==yShift2 && !can_move_to(upperLeftX+1,upperLeftY-1) && !can_move_to(upperLeftX,upperLeftY+1)) canPropagateDown = 0; break; default: err_here(); break; } } } } if(canPropagateDown) { oldNode->parent_node = this; oldNode->node_g = g; oldNode->node_f = g+oldNode->node_h; oldNode->enter_direction = (char)enter_direct; //-------- if it's a closed node ---------// if( oldNode->child_node[0] ) { //-------------------------------------------------// // Since we changed the g value of oldNode, we need // to propagate this new value downwards, i.e. // do a Depth-First traversal of the tree! //-------------------------------------------------// oldNode->propagate_down(); sys_yield(); } } } } else //------------ add a new node -----------// { NodeS2* succNode = cur_node_array_s2 + cur_seek_path_s2->node_count++; memset(succNode, 0, sizeof(NodeS2)); succNode->parent_node = this; succNode->node_g = g; succNode->node_h = (x-cur_dest_x_s2)*(x-cur_dest_x_s2)+(y-cur_dest_y_s2)*(y-cur_dest_y_s2); // should do sqrt(), but since we don't really succNode->node_f = g+succNode->node_h; // care about the distance but just which branch looks succNode->node_x = x; // better this should suffice. Anyayz it's faster. succNode->node_y = y; succNode->enter_direction = (char)enter_direct; succNode->node_type =can_move_to(upperLeftX,upperLeftY)+(can_move_to(upperLeftX+1,upperLeftY)<<1)+ (can_move_to(upperLeftX,upperLeftY+1)<<2)+(can_move_to(upperLeftX+1,upperLeftY+1)<<3); /*if(search_mode_s2==4 && nodeRecno>max_node_num_s2) { reuse_connect_node_exit_direction = nodeRecno - max_node_num_s2; reuse_result_node_ptr_s2 = succNode; return 1; }*/ if(search_mode_s2==SEARCH_MODE_REUSE && nodeRecno>max_node_num_s2) // path-reuse node found, but checking of can_walk(final_dest_?) is requested { int destIndex = nodeRecno - max_node_num_s2; int addNode = 1; switch(destIndex) { case 1: final_dest_x_s2 = x<<1; final_dest_y_s2 = y<<1; break; case 2: if(enter_direct==2 && (!succNode->node_type&0x1 || !can_move_to((x<<1)+1,(y<<1)+2) ) ) addNode = 0; if(addNode && enter_direct==8 && (!succNode->node_type&0x4 || !can_move_to((x<<1)+1,(y<<1)-1) ) ) addNode = 0; if(addNode) // not the two blocked cases { final_dest_x_s2 = (x<<1) + 1; final_dest_y_s2 = y<<1; } break; case 3: if(enter_direct==6 && (!succNode->node_type&0x1 || !can_move_to((x<<1)+2,(y<<1)+1) ) ) addNode = 0; if(addNode && enter_direct==8 && (!succNode->node_type&0x2 || !can_move_to((x<<1)-1,(y<<1)+1) ) ) addNode = 0; if(addNode) // not the two blocked cases { final_dest_x_s2 = x<<1; final_dest_y_s2 = (y<<1)+1; } break; case 4: if(enter_direct==1 && (!succNode->node_type&0x2 || !can_move_to(x<<1,(y<<1)+2) ) ) addNode = 0; if(addNode && enter_direct==7 && (!succNode->node_type&0x4 || !can_move_to((x<<1)+2,y<<1) ) ) addNode = 0; if(addNode && enter_direct==8 && (!succNode->node_type&0x2 || !succNode->node_type&0x4) ) addNode = 0; if(addNode) // not the two blocked cases { final_dest_x_s2 = (x<<1)+1; final_dest_y_s2 = (y<<1)+1; } break; default: err_here(); break; } if(addNode) { reuse_result_node_ptr_s2 = succNode; err_when(!can_move_to_s2(final_dest_x_s2, final_dest_y_s2)); return 1; // PATH_REUSE_FOUND } else // add nothing { memset(succNode, 0, sizeof(NodeS2)); cur_seek_path_s2->node_count--; return 0; } } cur_node_matrix_s2[y*(MAX_WORLD_X_LOC/2+1)+x] = cur_seek_path_s2->node_count; cur_seek_path_s2->insert_open_node(succNode); // insert succNode on open_node_list list wrt f for(c=0 ; cparent_node==this) break; cost = 2; // in fact, may be 1 or 2 if (g+cost <= childNode->node_g) // first checking { char canMove = 0; int childUpperLeftX = childNode->node_x<<1; int childUpperLeftY = childNode->node_y<<1; xShift = childNode->node_x-node_x; yShift = childNode->node_y-node_y; err_when(abs(xShift)>1 || abs(yShift)>1); //---------- calulate the new enter direction ------------// switch(yShift) { case -1: childEnterDirection = char(3-xShift); break; case 0: childEnterDirection = char(3-(xShift<<1)); break; case 1: childEnterDirection = char(7+xShift); break; } //---------- decide can move or not and use special case or not --------// switch(childEnterDirection) { case 1: err_when(node_x!=childNode->node_x-1 || node_y!=childNode->node_y); if(can_move_to(childUpperLeftX-1,childUpperLeftY) && childNode->node_type&0x1 && can_move_to(childUpperLeftX-1,childUpperLeftY+1) && childNode->node_type&0x4) //if the entering location is walkable { switch(enter_direction) { case 5: canMove = 0; //reverse direction break; case 1:case 3:case 4:case 6:case 7: // obviously canMove = 1; break; case 2: if(node_type&0x1 || can_move_to(childUpperLeftX-1, childUpperLeftY+2)) canMove = 1; break; case 8: if(node_type&0x4 || can_move_to(childUpperLeftX-1, childUpperLeftY-1)) canMove = 1; break; default: err_here(); break; } } break; case 2: err_when(node_x!=childNode->node_x-1 || node_y!=childNode->node_y+1); if(can_move_to(childUpperLeftX-1,childUpperLeftY+1) && childNode->node_type&0x4 && can_move_to(childUpperLeftX-1,childUpperLeftY+2) && can_move_to(childUpperLeftX,childUpperLeftY+2)) { switch(enter_direction) { case 6: canMove = 0; //reverse direction break; case 4:case 5:case 7:case 8: canMove = 1; break; case 1: if(node_type&0x8 || can_move_to(childUpperLeftX-2, childUpperLeftY+1)) canMove = 1; break; case 2: if(node_type==15) canMove = 1; else canMove = 0; break; case 3: if(node_type&0x1 || can_move_to(childUpperLeftX, childUpperLeftY+3)) canMove = 1; break; default: err_here(); break; } } break; case 3: err_when(node_x!=childNode->node_x || node_y!=childNode->node_y+1); if(childNode->node_type&0x4 && childNode->node_type&0x8 && can_move_to(childUpperLeftX,childUpperLeftY+2) && can_move_to(childUpperLeftX+1,childUpperLeftY+2)) { switch(enter_direction) { case 7: canMove = 0; //reverse direction break; case 1:case 3:case 5:case 6:case 8: canMove = 1; break; case 2: if(node_type&0x8 || can_move_to(childUpperLeftX-1, childUpperLeftY+2)) canMove = 1; break; case 4: if(node_type&0x4 || can_move_to(childUpperLeftX+2, childUpperLeftY+2)) canMove = 1; break; default: err_here(); break; } } break; case 4: err_when(node_x!=childNode->node_x+1 || node_y!=childNode->node_y+1); if(childNode->node_type&0x8 && can_move_to(childUpperLeftX+2,childUpperLeftY+1) && can_move_to(childUpperLeftX+1,childUpperLeftY+2) && can_move_to(childUpperLeftX+2,childUpperLeftY+2)) { switch(enter_direction) { case 8: canMove = 0; //reverse direction break; case 1:case 2:case 6:case 7: canMove = 1; break; case 3: if(node_type&0x2 || can_move_to(childUpperLeftX+1, childUpperLeftY+3)) canMove = 1; break; case 4: if(node_type==15) canMove = 1; else canMove = 0; break; case 5: if(node_type&0x4 || can_move_to(childUpperLeftX+3, childUpperLeftY+1)) canMove = 1; break; default: err_here(); break; } } break; case 5: err_when(node_x!=childNode->node_x+1 || node_y!=childNode->node_y); if(childNode->node_type&0x2 && can_move_to(childUpperLeftX+2,childUpperLeftY) && childNode->node_type&0x8 && can_move_to(childUpperLeftX+2,childUpperLeftY+1)) { switch(enter_direction) { case 1: canMove = 0; //reverse direction break; case 2:case 3:case 5:case 7:case 8: canMove = 1; break; case 4: if(node_type&0x2 || can_move_to(childUpperLeftX+2, childUpperLeftY+2)) canMove = 1; break; case 6: if(node_type&0x8 || can_move_to(childUpperLeftX+2, childUpperLeftY-1)) canMove = 1; break; default: err_here(); break; } } break; case 6: err_when(node_x!=childNode->node_x+1 || node_y!=childNode->node_y-1); if(can_move_to(childUpperLeftX+1,childUpperLeftY-1) && can_move_to(childUpperLeftX+2,childUpperLeftY-1) && childNode->node_type&0x2 && can_move_to(childUpperLeftX+2,childUpperLeftY)) { switch(enter_direction) { case 2: canMove = 0; //reverse direction break; case 1:case 3:case 4:case 8: canMove = 1; break; case 5: if(node_type&0x1 || can_move_to(childUpperLeftX+3, childUpperLeftY)) canMove = 1; break; case 6: if(node_type==15) canMove = 1; else canMove = 0; break; case 7: if(node_type&0x8 || can_move_to(childUpperLeftX+1, childUpperLeftY-2)) canMove = 1; break; default: err_here(); break; } } break; case 7: err_when(node_x!=childNode->node_x || node_y!=childNode->node_y-1); if(can_move_to(childUpperLeftX,childUpperLeftY-1) && can_move_to(childUpperLeftX+1,childUpperLeftY-1) && childNode->node_type&0x1 && childNode->node_type&0x2) { switch(enter_direction) { case 3: canMove = 0; //reverse direction break; case 1:case 2:case 4:case 5:case 7: canMove = 1; break; case 6: if(node_type&0x1 || can_move_to(childUpperLeftX+2, childUpperLeftY-1)) canMove = 1; break; case 8: if(node_type&0x2 || can_move_to(childUpperLeftX-1, childUpperLeftY-1)) canMove = 1; break; default: err_here(); break; } } break; case 8: err_when(node_x!=childNode->node_x-1 || node_y!=childNode->node_y-1); if(can_move_to(childUpperLeftX-1,childUpperLeftY-1) && can_move_to(childUpperLeftX,childUpperLeftY-1) && can_move_to(childUpperLeftX-1,childUpperLeftY) && childNode->node_type&0x1)//can_move_to(childUpperLeftX,childUpperLeftY)) { switch(enter_direction) { case 4: canMove = 0; //reverse direction break; case 2:case 3:case 5:case 6: canMove = 1; break; case 1: if(node_type&0x2 || can_move_to(childUpperLeftX-2, childUpperLeftY)) canMove = 1; break; case 7: if(node_type&0x4 || can_move_to(childUpperLeftX, childUpperLeftY-2)) canMove = 1; break; case 8: if(node_type==15) canMove = 1; else canMove = 0; break; default: err_here(); break; } } break; default: err_here(); break; } if(canMove) // can move in the child node { exitDirection = (childEnterDirection+3)%8+1; if(enter_direction > exitDirection) { if((enter_direction==8 && (exitDirection==1 || exitDirection==2)) || (enter_direction==7 && exitDirection==1)) testResult = exitDirection + 8 - enter_direction; else testResult = enter_direction - exitDirection; } else { if((exitDirection==8 && (enter_direction==1 || enter_direction==2)) || (exitDirection==7 && enter_direction==1)) testResult = enter_direction + 8 - exitDirection; else testResult = exitDirection - enter_direction; } if((exitDirection%2 && testResult<=2) || (!exitDirection%2 && testResult<=1)) cost = 1; else cost = 2; err_when(cost>2 || cost<1); if(g+cost < childNode->node_g) // second checking, mainly for cost = 2; { char canPropagateDown=1; if(childNode->node_type!=15 && childEnterDirection%2==0) { NodeS2* oldChildNode; short xShift1 = x_shift_array[childEnterDirection-1]; short yShift1 = y_shift_array[childEnterDirection-1]; short xShift2, yShift2, xShift3, yShift3; if(childEnterDirection>1) { xShift2 = x_shift_array[childEnterDirection-2]; yShift2 = y_shift_array[childEnterDirection-2]; } else { xShift2 = x_shift_array[7]; yShift2 = y_shift_array[7]; } if(childEnterDirection<8) { xShift3 = x_shift_array[childEnterDirection]; yShift3 = y_shift_array[childEnterDirection]; } else { xShift3 = x_shift_array[0]; yShift3 = y_shift_array[0]; } for(c=0; cchild_node[c]; c++) // for each child of oldNode { oldChildNode = childNode->child_node[c]; if(childNode->parent_node != oldChildNode) { switch(childEnterDirection) { case 2: if(oldChildNode->enter_direction==childEnterDirection && oldChildNode->node_x-childNode->node_x==xShift1 && oldChildNode->node_y-childNode->node_y==yShift1) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection-1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX,childUpperLeftY)&& !can_move_to(childUpperLeftX+1,childUpperLeftY+2)) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection+1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX+1,childUpperLeftY+1) && !can_move_to(childUpperLeftX-1,childUpperLeftY)) canPropagateDown = 0; break; case 4: if(oldChildNode->enter_direction==childEnterDirection && oldChildNode->node_x-childNode->node_x==xShift1 && oldChildNode->node_y-childNode->node_y==yShift1) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection-1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX,childUpperLeftY+1)&& !can_move_to(childUpperLeftX+2,childUpperLeftY)) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection+1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX,childUpperLeftY+2) && !can_move_to(childUpperLeftX+1,childUpperLeftY)) canPropagateDown = 0; break; case 6: if(oldChildNode->enter_direction==childEnterDirection && oldChildNode->node_x-childNode->node_x==xShift1 && oldChildNode->node_y-childNode->node_y==yShift1) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection-1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX,childUpperLeftY-1)&& !can_move_to(childUpperLeftX+1,childUpperLeftY+1)) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection+1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX,childUpperLeftY) && !can_move_to(childUpperLeftX+2,childUpperLeftY+1)) canPropagateDown = 0; break; case 8: if(oldChildNode->enter_direction==childEnterDirection && oldChildNode->node_x-childNode->node_x==xShift1 && oldChildNode->node_y-childNode->node_y==yShift1) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection-1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX-1,childUpperLeftY+1)&& !can_move_to(childUpperLeftX+1,childUpperLeftY)) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection+1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX+1,childUpperLeftY-1) && !can_move_to(childUpperLeftX,childUpperLeftY+1)) canPropagateDown = 0; break; default: err_here(); break; } } } } if(canPropagateDown) { childNode->node_g = g+cost; childNode->node_f = childNode->node_g+childNode->node_h; childNode->parent_node = this;// reset parent to new path. childNode->enter_direction = childEnterDirection; stack_push(childNode); // Now the childNode's branch need to be checked out. Remember the new cost must be propagated down. } } } } } while( cur_stack_pos_s2>0 ) { fatherNode=stack_pop(); g = fatherNode->node_g; for(c=0;c<8;c++) { if ((childNode=fatherNode->child_node[c])==NULL) // we may stop the propagation 2 ways: either break; if(childNode->parent_node==fatherNode) break; cost = 2; // in fact, may be 1 or 2 if (g+cost <= childNode->node_g) // first checking // there are no children, or that the g value of the child is equal or better than the cost we're propagating { char canMove = 0; int childUpperLeftX = childNode->node_x<<1; int childUpperLeftY = childNode->node_y<<1; xShift = childNode->node_x-fatherNode->node_x; yShift = childNode->node_y-fatherNode->node_y; err_when(abs(xShift)>1 || abs(yShift)>1); //---------- calulate the new enter direction ------------// switch(yShift) { case -1: childEnterDirection = char(3-xShift); break; case 0: childEnterDirection = char(3-(xShift<<1)); break; case 1: childEnterDirection = char(7+xShift); break; } switch(childEnterDirection) { case 1: err_when(fatherNode->node_x!=childNode->node_x-1 || fatherNode->node_y!=childNode->node_y); if(can_move_to(childUpperLeftX-1,childUpperLeftY) && childNode->node_type&0x1 && //can_move_to(childUpperLeftX,childUpperLeftY) && can_move_to(childUpperLeftX-1,childUpperLeftY+1) && childNode->node_type&0x4)//can_move_to(childUpperLeftX,childUpperLeftY+1)) { switch(fatherNode->enter_direction) { case 5: canMove = 0; //reverse direction break; case 1:case 3:case 4:case 6:case 7: canMove = 1; break; case 2: if(fatherNode->node_type&0x1 || can_move_to(childUpperLeftX-1, childUpperLeftY+2)) canMove = 1; break; case 8: if(fatherNode->node_type&0x4 || can_move_to(childUpperLeftX-1, childUpperLeftY-1)) canMove = 1; break; default: err_here(); break; } } break; case 2: err_when(fatherNode->node_x!=childNode->node_x-1 || fatherNode->node_y!=childNode->node_y+1); if(can_move_to(childUpperLeftX-1,childUpperLeftY+1) && childNode->node_type&0x4 &&//can_move_to(childUpperLeftX,childUpperLeftY+1) && can_move_to(childUpperLeftX-1,childUpperLeftY+2) && can_move_to(childUpperLeftX,childUpperLeftY+2)) { switch(fatherNode->enter_direction) { case 6: canMove = 0; //reverse direction break; case 4:case 5:case 7:case 8: canMove = 1; break; case 1: if(fatherNode->node_type&0x8 || can_move_to(childUpperLeftX-2,childUpperLeftY+1)) canMove = 1; break; case 2: if(fatherNode->node_type==15) canMove = 1; else canMove = 0; break; case 3: if(fatherNode->node_type&0x1 || can_move_to(childUpperLeftX,childUpperLeftY+3)) canMove = 1; break; default: err_here(); break; } canMove = 1; } break; case 3: err_when(fatherNode->node_x!=childNode->node_x || fatherNode->node_y!=childNode->node_y+1); if(childNode->node_type&0x4 && childNode->node_type&0x8 && can_move_to(childUpperLeftX,childUpperLeftY+2) && can_move_to(childUpperLeftX+1,childUpperLeftY+2)) { switch(fatherNode->enter_direction) { case 7: canMove = 0; //reverse direction break; case 1:case 3:case 5:case 6:case 8: canMove = 1; break; case 2: if(fatherNode->node_type&0x8 || can_move_to(childUpperLeftX-1,childUpperLeftY+2)) canMove = 1; break; case 4: if(fatherNode->node_type&0x4 || can_move_to(childUpperLeftX+2,childUpperLeftY+2)) canMove = 1; break; default: err_here(); break; } } break; case 4: err_when(fatherNode->node_x!=childNode->node_x+1 || fatherNode->node_y!=childNode->node_y+1); if(childNode->node_type&0x8 && can_move_to(childUpperLeftX+2,childUpperLeftY+1) && can_move_to(childUpperLeftX+1,childUpperLeftY+2) && can_move_to(childUpperLeftX+2,childUpperLeftY+2)) { switch(fatherNode->enter_direction) { case 8: canMove = 0; //reverse direction break; case 1:case 2:case 6:case 7: canMove = 1; break; case 3: if(fatherNode->node_type&0x2 || can_move_to(childUpperLeftX+1,childUpperLeftY+3)) canMove = 1; break; case 4: if(fatherNode->node_type==15) canMove = 1; else canMove = 0; break; case 5: if(fatherNode->node_type&0x4 && can_move_to(childUpperLeftX+3,childUpperLeftY+1)) canMove = 1; break; default: err_here(); break; } } break; case 5: err_when(fatherNode->node_x!=childNode->node_x+1 || fatherNode->node_y!=childNode->node_y); if(childNode->node_type&0x2 && can_move_to(childUpperLeftX+2,childUpperLeftY) && childNode->node_type&0x8 && can_move_to(childUpperLeftX+2,childUpperLeftY+1)) { switch(fatherNode->enter_direction) { case 1: canMove = 0; //reverse direction break; case 2:case 3:case 5:case 7:case 8: canMove = 1; break; case 4: if(fatherNode->node_type&0x2 || can_move_to(childUpperLeftX+2,childUpperLeftY+2)) canMove = 1; break; case 6: if(fatherNode->node_type&0x8 || can_move_to(childUpperLeftX+2,childUpperLeftY-1)) canMove = 1; break; default: err_here(); break; } } break; case 6: err_when(fatherNode->node_x!=childNode->node_x+1 || fatherNode->node_y!=childNode->node_y-1); if(can_move_to(childUpperLeftX+1,childUpperLeftY-1) && can_move_to(childUpperLeftX+2,childUpperLeftY-1) && childNode->node_type&0x2 && can_move_to(childUpperLeftX+2,childUpperLeftY)) { switch(fatherNode->enter_direction) { case 2: canMove = 0; //reverse direction break; case 1:case 3:case 4:case 8: canMove = 1; break; case 5: if(fatherNode->node_type&0x1 || can_move_to(childUpperLeftX+3,childUpperLeftY)) canMove = 1; break; case 6: if(fatherNode->node_type==15) canMove = 1; else canMove = 0; break; case 7: if(fatherNode->node_type&0x8 || can_move_to(childUpperLeftX+1,childUpperLeftY-2)) canMove = 1; break; default: err_here(); break; } } break; case 7: err_when(fatherNode->node_x!=childNode->node_x || fatherNode->node_y!=childNode->node_y-1); if(can_move_to(childUpperLeftX,childUpperLeftY-1) && can_move_to(childUpperLeftX+1,childUpperLeftY-1) && childNode->node_type&0x1 && childNode->node_type&0x2) { switch(fatherNode->enter_direction) { case 3: canMove = 0; //reverse direction break; case 1:case 2:case 4:case 5:case 7: canMove = 1; break; case 6: if(fatherNode->node_type&0x1 || can_move_to(childUpperLeftX+2,childUpperLeftY-1)) canMove = 1; break; case 8: if(fatherNode->node_type&0x2 || can_move_to(childUpperLeftX-1,childUpperLeftY-1)) canMove = 1; break; default: err_here(); break; } } break; case 8: err_when(fatherNode->node_x!=childNode->node_x-1 || fatherNode->node_y!=childNode->node_y-1); if(can_move_to(childUpperLeftX-1,childUpperLeftY-1) && can_move_to(childUpperLeftX,childUpperLeftY-1) && can_move_to(childUpperLeftX-1,childUpperLeftY) && childNode->node_type&0x1)//can_move_to(childUpperLeftX,childUpperLeftY)) { switch(fatherNode->enter_direction) { case 4: canMove = 0; //reverse direction break; case 2:case 3:case 5:case 6: canMove = 1; break; case 1: if(fatherNode->node_type&0x2 || can_move_to(childUpperLeftX-2,childUpperLeftY)) canMove = 1; break; case 8: if(fatherNode->node_type==15) canMove = 1; else canMove = 0; break; case 7: if(fatherNode->node_type&0x4 || can_move_to(childUpperLeftX,childUpperLeftY-2)) canMove = 1; break; default: err_here(); break; } } break; default: err_here(); break; } if(canMove) { exitDirection = (childEnterDirection+3)%8+1; if(fatherNode->enter_direction > exitDirection) { if((fatherNode->enter_direction==8 && (exitDirection==1 || exitDirection==2)) || (fatherNode->enter_direction==7 && exitDirection==1)) testResult = exitDirection + 8 - fatherNode->enter_direction; else testResult = fatherNode->enter_direction - exitDirection; } else { if((exitDirection==8 && (fatherNode->enter_direction==1 || fatherNode->enter_direction==2)) || (exitDirection==7 && fatherNode->enter_direction==1)) testResult = fatherNode->enter_direction + 8 - exitDirection; else testResult = exitDirection - fatherNode->enter_direction; } if((exitDirection%2 && testResult<=2) || (!exitDirection%2 && testResult<=1)) cost = 1; else cost = 2; err_when(cost>2 || cost<1); if(g+cost < childNode->node_g) // second checking, mainly for cost = 2; { char canPropagateDown=1; if(childNode->node_type!=15 && childEnterDirection%2==0) { NodeS2* oldChildNode; short xShift1 = x_shift_array[childEnterDirection-1]; short yShift1 = y_shift_array[childEnterDirection-1]; short xShift2, yShift2, xShift3, yShift3; if(childEnterDirection>1) { xShift2 = x_shift_array[childEnterDirection-2]; yShift2 = y_shift_array[childEnterDirection-2]; } else { xShift2 = x_shift_array[7]; yShift2 = y_shift_array[7]; } if(childEnterDirection<8) { xShift3 = x_shift_array[childEnterDirection]; yShift3 = y_shift_array[childEnterDirection]; } else { xShift3 = x_shift_array[0]; yShift3 = y_shift_array[0]; } for(c=0; cchild_node[c]; c++) // for each child of oldNode { oldChildNode = childNode->child_node[c]; if(childNode->parent_node != oldChildNode) { switch(childEnterDirection) { case 2: if(oldChildNode->enter_direction==childEnterDirection && oldChildNode->node_x-childNode->node_x==xShift1 && oldChildNode->node_y-childNode->node_y==yShift1) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection-1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX,childUpperLeftY)&& !can_move_to(childUpperLeftX+1,childUpperLeftY+2)) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection+1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX+1,childUpperLeftY+1) && !can_move_to(childUpperLeftX-1,childUpperLeftY)) canPropagateDown = 0; break; case 4: if(oldChildNode->enter_direction==childEnterDirection && oldChildNode->node_x-childNode->node_x==xShift1 && oldChildNode->node_y-childNode->node_y==yShift1) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection-1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX,childUpperLeftY+1)&& !can_move_to(childUpperLeftX+2,childUpperLeftY)) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection+1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX,childUpperLeftY+2) && !can_move_to(childUpperLeftX+1,childUpperLeftY)) canPropagateDown = 0; break; case 6: if(oldChildNode->enter_direction==childEnterDirection && oldChildNode->node_x-childNode->node_x==xShift1 && oldChildNode->node_y-childNode->node_y==yShift1) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection-1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX,childUpperLeftY-1)&& !can_move_to(childUpperLeftX+1,childUpperLeftY+1)) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection+1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX,childUpperLeftY) && !can_move_to(childUpperLeftX+2,childUpperLeftY+1)) canPropagateDown = 0; break; case 8: if(oldChildNode->enter_direction==childEnterDirection && oldChildNode->node_x-childNode->node_x==xShift1 && oldChildNode->node_y-childNode->node_y==yShift1) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection-1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX-1,childUpperLeftY+1)&& !can_move_to(childUpperLeftX+1,childUpperLeftY)) canPropagateDown = 0; if(oldChildNode->enter_direction==childEnterDirection+1 && oldChildNode->node_x-childNode->node_x==xShift2 && oldChildNode->node_x-childNode->node_y==yShift2 && !can_move_to(childUpperLeftX+1,childUpperLeftY-1) && !can_move_to(childUpperLeftX,childUpperLeftY+1)) canPropagateDown = 0; break; default: err_here(); break; } } } } if(canPropagateDown) { childNode->node_g = g+cost; childNode->node_f = childNode->node_g+childNode->node_h; childNode->parent_node = fatherNode; childNode->enter_direction = childEnterDirection; stack_push(childNode); } } } } } } } //------- End of function NodeS2::propagate_down -------// //-------- Begin of static function stack_push ---------// static void stack_push(NodeS2 *nodePtr) { stack_array[cur_stack_pos_s2++] = nodePtr; err_when( cur_stack_pos_s2 >= MAX_STACK_NUM ); } //--------- End of static function stack_push ---------// //-------- Begin of static function stack_pop ---------// static NodeS2* stack_pop() { return stack_array[--cur_stack_pos_s2]; } //--------- End of static function stack_pop ---------//