main.cpp 

/**
 * Author Malte Pagel
 * Free to use for any purpose
 * Runability or usefulness is NOT guaranteed
 */



#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <stdio.h>
#include <time.h>

using namespace std;

#include "KnightPosition.h"


#define ASK_USER 1

#define COL_MIN 5
#define COL_MAX 16
#define DEFAULT_COLS 8


void ask_user(void);

char letters[] = { 'A''B''C''D''E''F''G''H''I''J''K''L''M''N''O''P' };

int cols;
int column;
int row;


void ask_user () {
    
int i;
    
char c;

    
cout << endl;

    
cout << "How many rows resp. columns (" << COL_MIN << " - " << COL_MAX << ")?" << endl;
    
scanf("%d", &i);
    if ( 
COL_MIN || COL_MAX ) {
        
cout << "Invalid value! Taking " << DEFAULT_COLS << endl;
        
cols DEFAULT_COLS;
    }
    else
        
cols i;


    
cout << "Start in which column ('A' to '" << (letters[cols 1]) << "')?" << endl;
    
scanf("%s", &c);
    
= (int) 97;
    if ( 
>= && cols )
        
column i;
    else {
        
= (int) 65;
        if ( 
>= && cols )
            
column i;
        else {
            
column rand() % cols;
            
cout << "Invalid value! Taking " << letters[column] << endl;
        }
    }


    
cout << "Start in which row (1 to " << cols << ")?" << endl;
    
scanf("%d", &i);
    if ( 
&& <= cols )
        
row 1;
    else {
        
row rand() % cols;
        
cout << "Invalid value! Taking " << (row 1) << endl;
    }
}


int main (int argcchar** argv) {

    
KnightPosition start_position;
    
KnightPosition *** complete_collection;
    
int ij;

    
time_t t;
    
time(&t);
    
srand((unsigned intt);

    if ( 
ASK_USER )
        
ask_user();
    else {
        
cols DEFAULT_COLS;
        
column rand() % cols;
        
row rand() % cols;
    }

    
/**
     * Matrix of pointers needed for a moment
     */
    
complete_collection = new KnightPosition**[cols];
    for ( 
0colsi++ )
        
complete_collection[i] = new KnightPosition*[cols];
    for ( 
0colsi++ )
        for ( 
0colsj++ )
            
complete_collection[i][j] = NULL;

    
/**
     * 'start_position' is - no one would ever guess this - the field where to start,
     * temporarily stored at [column][row] in 'complete_collection'
     */
    
start_position = new KnightPosition(columnrowcolscomplete_collection);

    
/**
     * All fields should be initialized; matrix not needed any longer
     */
    
delete[](complete_collection);


    
/**
     * Setting a knight on 'start_position' and invoking path search
     */
    
start_position->set_knight_and_start_search(NULL);


    
/**
     * Preparing show,
     * cleaning memory
     */
    
int ** show_collection = new int*[cols];
    for ( 
0colsi++ ) {
        
show_collection[i] = new int[cols];
        for ( 
0colsj++ )
            
show_collection[i][j] = 0;
    }
    
0;
    
KnightPosition position start_position;
    
KnightPosition position_to_delete;
    do {
        
show_collection[cols position->row 1][position->column] = ++i;
        
position_to_delete position;
        if ( 
position->next_position )
            
position position->next_position;
        
delete(position_to_delete);
    }
    while ( 
position->next_position );
    
delete(position);
    
show_collection[cols position->row 1][position->column] = ++i;


    
/**
     * Dont' blame me for not using 'cout' consequently -
     * formatted output is much more readable
     */
    
cout << endl;
    for ( 
0colsi++ ) {
        
printf("%2d", (cols i));
        
cout << " |";
        for ( 
0colsj++ )
            
printf("%5d"show_collection[i][j]);
        
cout << endl;
    }
    
cout << "     ";
    for ( 
0colsi++ )
        
cout << "-----";
    
cout << endl;
    
printf("%4s"" ");
    for ( 
0colsi++ )
        
printf("%5c"letters[i]);
    
cout << endl;
    
    
    
/**
     * The result should be visible also on windows systems
     */
#ifdef _WIN32
    
char c 'n';
    while ( 
!= 'y' ) {
        
cout << "Quit application [y/n]?" << endl;
        
scanf("%s", &c);
    }
#endif


    
return 0;
}
 



 KnightPosition.h 

// File: KnightPosition.h

/*
 * Author: maltepagel
 *
 * Created November 2013
 */

#ifndef KNIGHTPOSITION_H
#define        KNIGHTPOSITION_H

#include <iostream>
#include <cmath>
#include <cstdlib>

using namespace std;


/*
 IMPORTANT: HIGHER VALUES MIGHT BREAK THE STACK
 */
#define MEMORY_LIMIT 4096


class KnightPosition {
        
public:
        
KnightPosition(intintintKnightPosition***);
        
virtual ~KnightPosition();
        
        
        static 
int knight_count;
        static 
int knight_number;
        static 
long memory_count;
        
        
        
int has_knight;
        
int columnrow;
        
int center_distance;
        
        
        
KnightPosition next_position;
        
        
        
void set_knight_and_start_search(KnightPosition*);
        
int get_num_possibilities(void);
        
void another_try_from_above(void);
        
private:
        static 
char letters[];
        
        
        static 
int cols;
        
        
        static 
int reachable_positions_offset_set;
        
        
        
KnightPosition previous_position;
        
        
        
struct reachable_position_pointer {
                
KnightPosition possible_position;
                
int heuristic;
                
struct reachable_position_pointer next;
                
struct reachable_position_pointer basic_next;
        };
        
struct reachable_position_pointer first_collected_position;
        
struct reachable_position_pointer last_collected_position;
        
        
struct reachable_position_pointer first_position_to_try;
        
struct reachable_position_pointer last_position_to_try;
        
        
        
int lower_or_equalreachable_positions_offset;
        
        
        
void fill_reachable_positions(KnightPosition***);
        
void add_to_reachable_positions(KnightPosition*);
        
void order_reachable_positions(void);
        
void do_search(void);
        
void go_back(void);
};

#endif        /* KNIGHTPOSITION_H */
 



 KnightPosition.cpp 

// File: KnightPosition.cpp

/*
 * Author: maltepagel
 *
 * Created November 2013
 */

#include "KnightPosition.h"


int KnightPosition::knight_count 0;
int KnightPosition::knight_number 0;
int KnightPosition::cols 0;
long KnightPosition::memory_count 0;
char KnightPosition::letters[] = { 'A''B''C''D''E''F''G''H''I''J''K''L''M''N''O''P' };
int KnightPosition::reachable_positions_offset_set 0;

/**
 * Constructor.
 * Takes basic values,
 * invokes building of other knight positions,
 * memorizes reachable knight positions
 *
 * @param <int> column, row [where are we?]
 * @param <int> num_cols [number rows resp. columns of play table]
 * @param <KnightPosition***> collection [matrix to temporarily store knight positions]
 */
KnightPosition::KnightPosition(int columnint rowint num_colsKnightPosition*** collection) {
        
    
collection[column][row] = this;
        
    
this->column column;
    
this->row row;
        
    if ( !
cols )
        
cols num_cols;
        
    
has_knight 0;
        
    
next_position NULL;
    
previous_position NULL;
        
    
first_collected_position NULL;
    
last_collected_position NULL;
        
    
/**
     * Maybe you have to write 'center_distance = abs((float) ((cols - 1) - (2 * column) - (2 * row)));'
     */
    
center_distance abs((cols 1) - (column) - (row));
        
    if ( !
reachable_positions_offset_set ) {
        if ( 
column ) {
            if ( 
row )
                
reachable_positions_offset 4;
            else
                
reachable_positions_offset 6;
        }
        else {
            if ( 
row )
                
reachable_positions_offset 2;
                        else
                                
reachable_positions_offset 0;
                }
        
reachable_positions_offset_set 1;
    }
        
    
fill_reachable_positions(collection);
        
    
knight_count++;

    
lower_or_equal = ( rand() % (cols cols center_distance knight_count) == ) ? 0;
        
    
//cout << "KnightPosition number " << knight_count << " constructed at " << letters[column] << (row + 1) << endl;
}

/**
 * Clears all allocated memory
 */
KnightPosition::~KnightPosition() {
        
    
struct reachable_position_pointer tmp_position, * next_tmp_position;
        
    if ( !
first_collected_position )
        return;
        
    
tmp_position first_collected_position->basic_next;
    while ( 
tmp_position ) {
        
next_tmp_position first_collected_position->basic_next->basic_next;
        
first_collected_position->basic_next next_tmp_position;
        
delete(tmp_position);
        
tmp_position next_tmp_position;
    }
    
delete(first_collected_position->basic_next);
    
delete(first_collected_position);
    
first_collected_position NULL;
        
    
//cout << "KnightPosition " << (cols * cols - --knight_count) << " at " << letters[column] << (row + 1) << " destroyed" << endl;
}

/**
 * Counts number of possible jumps to free field (i.e. without knight)
 *
 * @return <int> [number of possible jumps]
 */
int KnightPosition::get_num_possibilities () {
    
int possibilities 0;
        
    if ( !
first_collected_position )
        return 
0;
        
    
struct reachable_position_pointer tmp_position first_collected_position;
    while ( 
tmp_position ) {
        if ( !
tmp_position->possible_position->has_knight )
            
possibilities++;
        
tmp_position tmp_position->basic_next;
    }
        
    return 
possibilities;
}

/**
 * Important heuristic: positions with more possible moves are worse
 * Less important heuristic: positions near the center are worse
 */
void KnightPosition::order_reachable_positions () {
        
    
int possibilitiessuccess;
        
    
struct reachable_position_pointer tmp_position_to_add;
    
struct reachable_position_pointer tmp_tmp_position;
    
struct reachable_position_pointer tmp_tmp_tmp_position;
        
    
struct reachable_position_pointer tmp_position first_collected_position;
        
    while ( 
tmp_position != NULL ) {
                
        
possibilities tmp_position->possible_position->get_num_possibilities();
                
        if ( !
tmp_position->possible_position->has_knight ) {
                        
            if ( !
possibilities )
                
possibilities cols 8;
                        
            
tmp_position_to_add tmp_position;
            
tmp_position_to_add->possible_position tmp_position->possible_position;
            
tmp_position_to_add->heuristic cols possibilities tmp_position->possible_position->center_distance;
            
tmp_position_to_add->next NULL;
                        
            if ( !
first_position_to_try ) {
                
first_position_to_try tmp_position_to_add;
                
last_position_to_try first_position_to_try;
            }
            else {
                
tmp_tmp_position first_position_to_try;
                
success 0;
                while ( 
tmp_tmp_position && !success ) {
                    if ( 
tmp_position_to_add->heuristic tmp_tmp_position->heuristic || (lower_or_equal && tmp_position_to_add->heuristic == tmp_tmp_position->heuristic) ) {
                        if ( 
tmp_tmp_position == first_position_to_try ) {
                            
tmp_position_to_add->next tmp_tmp_position;
                            
first_position_to_try tmp_position_to_add;
                            
success 1;
                        }
                        else {
                            
tmp_tmp_tmp_position first_position_to_try;
                            while ( 
tmp_tmp_tmp_position->next != tmp_tmp_position )
                                
tmp_tmp_tmp_position tmp_tmp_tmp_position->next;
                            
tmp_position_to_add->next tmp_tmp_tmp_position->next;
                            
tmp_tmp_tmp_position->next tmp_position_to_add;
                            
success 1;
                        }
                    }
                    
tmp_tmp_position tmp_tmp_position->next;
                }
                if ( !
success ) {
                    
last_position_to_try->next tmp_position_to_add;
                    
last_position_to_try tmp_position_to_add;
                }
            }
        }
                
        
tmp_position tmp_position->basic_next;
    }
}

/**
 * Jumps to probably best position.
 * Clears this position from list.
 * Stops if play table is full
 */
void KnightPosition::do_search () {
    
struct reachable_position_pointer position_to_try first_position_to_try;
        
    
next_position position_to_try->possible_position;
        
    
first_position_to_try = (first_position_to_try->next) ? first_position_to_try->next NULL;
        
    if ( 
knight_number >= (cols cols 1) ) {
        
cout << endl;
        
cout << "\t**********" << endl;
        
cout << "\t* SOLVED *" << endl;
        
cout << "\t**********" << endl;
        
cout << endl;
        return;
    }
        
    
next_position->set_knight_and_start_search(this);
}

/**
 * Last jump was bad - try the next best or, if there is none, go back
 */
void KnightPosition::another_try_from_above () {
    
next_position->next_position NULL;
        
    if ( !
first_position_to_try ) {
        
go_back();
        return;
    }
        
    if ( 
memory_count MEMORY_LIMIT || (memory_count && knight_number == 1) ) {
        if ( 
knight_number == )
            
cout << "Does not seem to be solvable" << endl;
        else
            
cout << "Too much recursion, I'm giving up; knights: " << knight_number << " / " << (cols cols) << endl;
        return;
    }
        
    
cout << "I am at " << letters[column] << (row 1) << " at step " << knight_number << " (" << memory_count << " tries)" << endl;
    
cout << "I came from " << letters[next_position->column] << (next_position->row 1) << endl;
    
cout << "I want to try " << letters[first_position_to_try->possible_position->column] << (first_position_to_try->possible_position->row 1) << endl;
    
cout << "---" << endl;
        
    
do_search();
}

/**
 * Delete this position from list of jumps and go back
 */
void KnightPosition::go_back () {
    
memory_count++;
    
knight_number--;
    
has_knight 0;
    
previous_position->another_try_from_above();
}

/**
 * Remembers previous position,
 * estimates quality of possible jumps,
 * invokes jumping (if possible)
 *
 * @param <KnightPosition*> last_position [position where we came from,
 *                                      i.e. previous position in list of jumps]
 */
void KnightPosition::set_knight_and_start_search (KnightPositionlast_position) {
    
knight_number++;
    
has_knight 1;
    
previous_position last_position;
        
    
last_position_to_try NULL;
    
first_position_to_try NULL;
        
    
order_reachable_positions();
        
    if ( !
first_position_to_try ) {
        
go_back();
        return;
    }
        
    
do_search();
}

/**
 * Creates a data collection for each reachable position
 *
 * @param <KnightPosition*> position [to add]
 */
void KnightPosition::add_to_reachable_positions (KnightPositionposition) {
        
    
struct reachable_position_pointer position_data = new reachable_position_pointer;
        
    
position_data->possible_position position;
    
position_data->heuristic 0;
    
position_data->next NULL;
    
position_data->basic_next NULL;
        
    if ( !
first_collected_position ) {
        
first_collected_position position_data;
        
last_collected_position first_collected_position;
    }
    else {
        
last_collected_position->basic_next position_data;
        
last_collected_position position_data;
    }
}
/**
 * Evaluates possible positions for jumping.
 * Adds - if not already there - position to 'collection',
 * invokes putting it to list of reachable positions
 *
 * @param <KnightPosition***> collection [matrix to temporarily store knight positions]
 */
void KnightPosition::fill_reachable_positions (KnightPosition*** collection) {
    
int x_move[] = { 1221, -1, -2, -2, -11221, -1, -};
    
int y_move[] = { -2, -11221, -1, -2, -2, -1122};
    
int ixy;
    
KnightPosition tmp_position;
        
    for ( 
reachable_positions_offset< (reachable_positions_offset); i++ ) {
        
column x_move[i];
        
row y_move[i];
                
        if ( 
|| > (cols 1) || || > (cols 1) )
            continue;
        if ( !
collection[x][y] ) {
            
tmp_position = new KnightPosition(xycolscollection);
            
add_to_reachable_positions(tmp_position);
        }
        else
            
add_to_reachable_positions(collection[x][y]);
    }
}