Knight-Path 1.0.D018

/home/archives/knight-path/branch.1/branch.0/delta5682.018/knight-path/solver/taxi.cc

Go to the documentation of this file.
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 }