Knight-Path 1.0.D018
|
00001 // 00002 // knight-path - shortest knight path between two squares 00003 // Copyright (C) 2011 Peter Miller 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation; either version 3 of the License, or (at 00008 // your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 // General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License along 00016 // with this program. If not, see <http://www.gnu.org/licenses/>. 00017 // 00018 00019 #include <knight-path/solver/taxi.h> 00020 #include <knight-path/taxi_distance.h> 00021 00022 00023 solver_taxi::~solver_taxi() 00024 { 00025 } 00026 00027 00028 solver_taxi::solver_taxi() 00029 { 00030 } 00031 00032 00033 solver_taxi::pointer 00034 solver_taxi::create(void) 00035 { 00036 return pointer(new solver_taxi()); 00037 } 00038 00039 00040 solver::list_t 00041 solver_taxi::solve(const position &from, const position &to) 00042 { 00043 shortest_solution.clear(); 00044 list_t path; 00045 // By including the from position in the path, we can eliminate 00046 // backtracking to there. 00047 path.push_back(from); 00048 ply(from, to, path); 00049 00050 // Return a list of positions through which the Knight passes. 00051 // It must include the ending position, but exclude the starting 00052 // position. 00053 list_t result = shortest_solution; 00054 shortest_solution.clear(); 00055 if (result.size() > 1) 00056 result.pop_front(); 00057 return result; 00058 } 00059 00060 00061 void 00062 solver_taxi::ply(const position &from, const position &to, 00063 const list_t &progress) 00064 { 00065 // See if we have arrived at the destination. 00066 if (from == to) 00067 { 00068 if 00069 ( 00070 shortest_solution.empty() 00071 || 00072 progress.size() < shortest_solution.size() 00073 ) 00074 { 00075 shortest_solution = progress; 00076 } 00077 return; 00078 } 00079 00080 // The longest possible path is six jumps 00081 // plus one for the start position. 00082 size_t too_big = shortest_solution.empty() ? 7 : shortest_solution.size(); 00083 if (progress.size() >= too_big) 00084 return; 00085 00086 // 00087 // Ask the position for a list of knight move positions 00088 // that can be reached from there. 00089 // 00090 position::list_t possibilities = from.knight_moves(); 00091 00092 // 00093 // Sort the list of positions by their distance from the goal position. 00094 // 00095 sort(possibilities.begin(), possibilities.end(), taxi_distance(to)); 00096 00097 // 00098 // Try each of those possibilities. 00099 // 00100 for 00101 ( 00102 position::list_t::const_iterator it = possibilities.begin(); 00103 it != possibilities.end(); 00104 ++it 00105 ) 00106 { 00107 // Don't revisit any position. 00108 if (std::find(progress.begin(), progress.end(), *it) == progress.end()) 00109 { 00110 list_t one_longer(progress); 00111 one_longer.push_back(*it); 00112 ply(*it, to, one_longer); 00113 } 00114 } 00115 }