Knight-Path 1.0.D018

/home/archives/knight-path/branch.1/branch.0/delta5682.018/knight-path/main.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 <cstdlib>
00020 #include <cstring>
00021 #include <iostream>
00022 #include <fstream>
00023 #include <sys/time.h>
00024 #include <sys/resource.h>
00025 #include <unistd.h>
00026 #include <iomanip>
00027 #include <sstream>
00028 
00029 #include <lib/print_version.h>
00030 #include <lib/progname.h>
00031 
00032 #include <knight-path/position.h>
00033 #include <knight-path/solver.h>
00034 
00035 
00036 static bool print_seconds;
00037 static bool print_board;
00038 
00039 
00040 static double
00041 cpu_seconds(void)
00042 {
00043 #if 0
00044     struct rusage r;
00045     if (getrusage(RUSAGE_SELF, &r) < 0)
00046     {
00047         perror("getrusage");
00048         exit(EXIT_FAILURE);
00049     }
00050     return
00051         (
00052             (r.ru_utime.tv_sec + r.ru_stime.tv_sec)
00053         +
00054             1e-6 * (r.ru_utime.tv_usec + r.ru_stime.tv_usec)
00055         );
00056 #else
00057     struct timeval tv;
00058     if (gettimeofday(&tv, 0) < 0)
00059     {
00060         perror("gettimeofday");
00061         exit(EXIT_FAILURE);
00062     }
00063     return (tv.tv_sec + 1e-6 * tv.tv_usec);
00064 #endif
00065 }
00066 
00067 
00068 static void
00069 process(std::istream &f, const solver::pointer &how)
00070 {
00071     //
00072     // Read the start and finish positions.
00073     //
00074     position p1;
00075     f >> p1;
00076     position p2;
00077     f >> p2;
00078 
00079     //
00080     // Solve for the shortest path.
00081     //
00082     double t1 = cpu_seconds();
00083     solver::list_t result = how->solve(p1, p2);
00084     double t2 = cpu_seconds();
00085     if (result.empty())
00086     {
00087         std::cerr << "no path from " << p1 << " to " << p2 << std::endl;
00088         exit(EXIT_FAILURE);
00089     }
00090     assert(p2 == result.back());
00091 
00092     if (print_seconds)
00093     {
00094         //
00095         // Print the time used.  This helps measure which solution algorithm
00096         // is the best one.
00097         //
00098         std::cout << std::fixed << std::setprecision(6) << (t2 - t1)
00099             << " seconds" << std::endl;
00100     }
00101 
00102     //
00103     // Print the list of positions.
00104     //
00105     std::cout << "path:";
00106     for
00107     (
00108         solver::list_t::const_iterator it = result.begin();
00109         it != result.end();
00110         ++it
00111     )
00112     {
00113         std::cout << ' ';
00114         std::cout << *it;
00115     }
00116     std::cout << std::endl;
00117 
00118     if (print_board)
00119     {
00120         //
00121         // Plot it on a chess board, to make it easier to visualise.
00122         //
00123         char board[8][8];
00124         memset(board, ' ', sizeof(board));
00125         p1.plot(board, '0');
00126         char n = '1';
00127         for
00128         (
00129             solver::list_t::const_iterator it = result.begin();
00130             it != result.end();
00131             ++it, ++n
00132         )
00133         {
00134             it->plot(board, n);
00135         }
00136         for (int y = 7; y >= 0; --y)
00137         {
00138             std::cout << "  +---+---+---+---+---+---+---+---+" << std::endl;
00139             std::cout << (y + 1) << " |";
00140             for (int x = 0; x < 8; ++x)
00141             {
00142                 std::cout << ' ';
00143                 std::cout << board[y][x];
00144                 std::cout << " |";
00145             }
00146             std::cout << std::endl;
00147         }
00148         std::cout << "  +---+---+---+---+---+---+---+---+" << std::endl;
00149         std::cout << "    a   b   c   d   e   f   g   h" << std::endl;
00150     }
00151 }
00152 
00153 
00154 static void
00155 usage(void)
00156 {
00157     std::cerr << "Usage: " << progname_get() << " [ -a <name> ][ <filename> ]"
00158         << std::endl;
00159     std::cerr << "       " << progname_get() << " -V" << std::endl;
00160     exit(EXIT_FAILURE);
00161 }
00162 
00163 
00164 int
00165 main(int argc, char **argv)
00166 {
00167     progname_set(argv[0]);
00168     solver::pointer how;
00169     for (;;)
00170     {
00171         int c = getopt(argc, argv, "a:blsV");
00172         if (c < 0)
00173             break;
00174         switch (c)
00175         {
00176         case 'a':
00177             if (how)
00178             {
00179                 std::cerr << "only one algorithm may be specified" << std::endl;
00180                 exit(EXIT_FAILURE);
00181             }
00182             how = solver::factory(optarg);
00183             break;
00184 
00185         case 'b':
00186             print_board = true;
00187             break;
00188 
00189         case 'l':
00190             solver::list_algorithms();
00191             return EXIT_SUCCESS;
00192 
00193         case 's':
00194             print_seconds = true;
00195             break;
00196 
00197         case 'V':
00198             print_version();
00199             return EXIT_SUCCESS;
00200 
00201         default:
00202             usage();
00203             // NOTREACHED
00204         }
00205     }
00206 
00207     // By default, use the brute force solver.
00208     if (!how)
00209         how = solver::factory("fastest");
00210 
00211     switch (argc - optind)
00212     {
00213     case 0:
00214         process(std::cin, how);
00215         break;
00216 
00217     case 1:
00218         {
00219             const char *filename = argv[optind];
00220             std::ifstream f;
00221             f.open(filename);
00222             if (f.fail())
00223             {
00224                 perror(filename);
00225                 exit(1);
00226             }
00227             process(f, how);
00228         }
00229         break;
00230 
00231     case 2:
00232         {
00233             std::string s = argv[optind];
00234             s += " ";
00235             s += argv[optind + 1];
00236             std::istringstream f(s);
00237             process(f, how);
00238         }
00239         break;
00240 
00241     default:
00242         usage();
00243     }
00244     return EXIT_SUCCESS;
00245 }