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 <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 }