std :: string * Grid :: find_path ( Tile * start, Tile * finish ) {

#ifdef DEBUG

gui :: log ( "Now finding path from tile [" + std :: to_string ( start - > ret_x ( ) / TILE_SIZE ) + ", " + std :: to_string ( start - > ret_y ( ) / TILE_SIZE ) + "] to tile [" + std :: to_string ( finish - > ret_x ( ) / TILE_SIZE ) + ", " + std :: to_string ( finish - > ret_y ( ) / TILE_SIZE ) + "]" ) ;

#endif

std :: string * to_ret = new std :: string ;

std :: vector < struct fp_node * > open_list ;

std :: vector < struct fp_node * > closed_list ;

closed_list. push_back ( fp_new_node ( start, finish, ' ' ) ) ;

gui :: log ( "Open list size: " + std :: to_string ( open_list. size ( ) ) ) ;

gui :: log ( "Closed list size: " + std :: to_string ( closed_list. size ( ) ) ) ;

/*

** TODO:

** while we haven't found a solution:

** take the last node of the closed list

** get all possible tiles of this node and add them to the open list (check them one by one)

** get the lowest scoring tile of the open list and add it to the closed list

**

*/

while ( closed_list. back ( ) - > t ! = finish ) {

struct fp_node * last_node = closed_list. back ( ) ;

#ifdef DEBUG

printf ( "Currently checking against 0x%08x

" , last_node - > t ) ;

#endif

Tile * cur_possibility ;

cur_possibility = last_node - > t - > ret_up ( ) ;

if ( cur_possibility == finish ) {

closed_list. push_back ( fp_new_node ( cur_possibility, finish, 'u' , last_node ) ) ;

break ;

}

if ( cur_possibility && ! cur_possibility - > full ( ) && cur_possibility ! = last_node - > t ) {

#ifdef DEBUG

gui :: log ( " \t adding up tile" ) ;

#endif

open_list. push_back ( fp_new_node ( cur_possibility, finish, 'u' , last_node ) ) ;

}

cur_possibility = last_node - > t - > ret_left ( ) ;

if ( cur_possibility == finish ) {

closed_list. push_back ( fp_new_node ( cur_possibility, finish, 'l' , last_node ) ) ;

break ;

}

if ( cur_possibility && ! cur_possibility - > full ( ) && cur_possibility ! = last_node - > t ) {

#ifdef DEBUG

gui :: log ( " \t adding left tile" ) ;

#endif

open_list. push_back ( fp_new_node ( cur_possibility, finish, 'l' , last_node ) ) ;

}

cur_possibility = last_node - > t - > ret_down ( ) ;

if ( cur_possibility == finish ) {

closed_list. push_back ( fp_new_node ( cur_possibility, finish, 'd' , last_node ) ) ;

break ;

}

if ( cur_possibility && ! cur_possibility - > full ( ) && cur_possibility ! = last_node - > t ) {

#ifdef DEBUG

gui :: log ( " \t adding down tile" ) ;

#endif

open_list. push_back ( fp_new_node ( cur_possibility, finish, 'd' , last_node ) ) ;

}

cur_possibility = last_node - > t - > ret_right ( ) ;

if ( cur_possibility == finish ) {

closed_list. push_back ( fp_new_node ( cur_possibility, finish, 'r' , last_node ) ) ;

break ;

}

if ( cur_possibility && ! cur_possibility - > full ( ) && cur_possibility ! = last_node - > t ) {

#ifdef DEBUG

gui :: log ( " \t adding right tile" ) ;

#endif

open_list. push_back ( fp_new_node ( cur_possibility, finish, 'r' , last_node ) ) ;

}

#ifdef DEBUG

gui :: log ( "Finished adding latest nodes (max 4)" ) ;

gui :: log ( " \t Open list size: " + std :: to_string ( open_list. size ( ) ) ) ;

gui :: log ( " \t Closed list size: " + std :: to_string ( closed_list. size ( ) ) ) ;

#endif

for ( unsigned int i = 0 ; i < open_list. size ( ) ; ++ i ) {

for ( unsigned int j = 0 ; j < closed_list. size ( ) ; ++ j ) {

if ( open_list [ i ] - > t == closed_list [ j ] - > t ) open_list. erase ( open_list. begin ( ) + i ) ;

}

}

#ifdef DEBUG

gui :: log ( "Finished removing dupes" ) ;

gui :: log ( " \t Open list size: " + std :: to_string ( open_list. size ( ) ) ) ;

gui :: log ( " \t Closed list size: " + std :: to_string ( closed_list. size ( ) ) ) ;

#endif

unsigned int lowest_score_s_index = 0 ;

for ( unsigned int i = 1 ; i < open_list. size ( ) ; ++ i ) {

if ( open_list [ i ] - > score < open_list [ lowest_score_s_index ] - > score ) lowest_score_s_index = i ;

}

#ifdef DEBUG

gui :: log ( "Finished getting lowest scoring tile: " + std :: to_string ( lowest_score_s_index ) ) ;

open_list [ lowest_score_s_index ] - > t - > print_tile ( ) ;

gui :: log ( "With a score of " + std :: to_string ( open_list [ lowest_score_s_index ] - > score ) ) ;

#endif

closed_list. push_back ( open_list [ lowest_score_s_index ] ) ;

open_list. clear ( ) ;

#ifdef DEBUG

gui :: log ( "Moved best tile choice from the open list to the closed list" ) ;

gui :: log ( " \t Open list size: " + std :: to_string ( open_list. size ( ) ) ) ;

gui :: log ( " \t Closed list size: " + std :: to_string ( closed_list. size ( ) ) ) ;

#endif

}

#ifdef DEBUG

gui :: log ( "Now generating return string" ) ;

#endif

for ( unsigned int i = 0 ; i < closed_list. size ( ) ; ++ i ) {

to_ret - > push_back ( closed_list [ i ] - > type ) ;

}

//Try to dodge them memory leaks

#ifdef DEBUG

gui :: log ( "Now freeing open list and closed list" ) ;

#endif

for ( unsigned int i = 0 ; i < open_list. size ( ) ; ++ i ) free ( open_list [ i ] ) ;

for ( unsigned int i = 0 ; i < closed_list. size ( ) ; ++ i ) free ( closed_list [ i ] ) ;

#ifdef DEBUG

gui :: log ( "Now returning" ) ;

#endif

return to_ret ;

}

struct Grid :: fp_node * Grid :: fp_new_node ( Tile * t, Tile * end, char type, struct fp_node * parent /* = nullptr*/ ) {

struct fp_node * to_ret = ( struct fp_node * ) calloc ( 1 , sizeof ( struct fp_node ) ) ;

to_ret - > t = t ;

to_ret - > h = fp_calc_distance ( t, end ) ;

to_ret - > type = type ;

to_ret - > parent = parent ;

if ( parent ) { //If it's not the first node

to_ret - > g = parent - > g + 1 ;

} else { //It is the first node (start)

to_ret - > g = 0 ;

}

to_ret - > score = to_ret - > g + to_ret - > h ;

return to_ret ;

}

unsigned int Grid :: fp_calc_distance ( Tile * t1, Tile * t2 ) {

int x = t1 - > ret_x ( ) / TILE_SIZE - t2 - > ret_x ( ) / TILE_SIZE ;

int y = t1 - > ret_y ( ) / TILE_SIZE - t2 - > ret_y ( ) / TILE_SIZE ;

if ( x < 0 ) x * = - 1 ;

if ( y < 0 ) y * = - 1 ;

return x + y ;