PageRenderTime 58ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/lk/search.cpp

https://bitbucket.org/ugoertz/kombilo
C++ | 2150 lines | 1728 code | 269 blank | 153 comment | 906 complexity | fd616e00e117c47169245d420392f30d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. // File: search.cpp
  2. // part of libkombilo, http://www.u-go.net/kombilo/
  3. // Copyright (c) 2006-12 Ulrich Goertz <ug@geometry.de>
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy of
  5. // this software and associated documentation files (the "Software"), to deal in
  6. // the Software without restriction, including without limitation the rights to
  7. // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  8. // of the Software, and to permit persons to whom the Software is furnished to do
  9. // so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in all
  12. // copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. // SOFTWARE.
  21. #include "sgfparser.h"
  22. #include "abstractboard.h"
  23. #include "pattern.h"
  24. #include "algos.h"
  25. #include "search.h"
  26. #include "boost/unordered_map.hpp"
  27. #include <stdio.h>
  28. #include <string>
  29. #include <cstring>
  30. #include <iostream>
  31. #include <fstream>
  32. #include <sstream>
  33. #include <stdint.h>
  34. #include <inttypes.h>
  35. // FIXME check for security pbms (buffer overflow) in all places where a char[] of fixed length is used! (also in other files)
  36. unsigned long stringhash(int bs, unsigned char *str) { // returns hashcode of char[bs*bs]
  37. unsigned long hash = 0;
  38. for(int i=0; i<bs*bs; i++) hash = str[i] + (hash << 6) + (hash << 16) - hash;
  39. return hash;
  40. }
  41. Candidate::Candidate(char X, char Y, char ORIENTATION) {
  42. x = X;
  43. y = Y;
  44. orientation = ORIENTATION;
  45. }
  46. Hit::Hit(ExtendedMoveNumber* POS, char* LABEL) { // LABEL is a char[3]
  47. pos = POS; // note that we do not copy these!
  48. label = LABEL;
  49. }
  50. Hit::~Hit() {
  51. delete pos;
  52. delete [] label;
  53. }
  54. Hit::Hit(SnapshotVector& snv) {
  55. int length = snv.retrieve_int();
  56. int* data = snv.retrieve_intp();
  57. pos = new ExtendedMoveNumber(length, data);
  58. delete [] data;
  59. label = snv.retrieve_charp();
  60. }
  61. void Hit::to_snv(SnapshotVector& snv) {
  62. snv.pb_int(pos->length);
  63. snv.pb_intp(pos->data, pos->length);
  64. snv.pb_charp(label, 3);
  65. }
  66. bool Hit::cmp_pts(Hit* a, Hit* b) {
  67. if (a->pos->length != b->pos->length) return a->pos->length < b->pos->length;
  68. for(int i=0; i < a->pos->length; i++)
  69. if (a->pos->data[i] != b->pos->data[i]) return a->pos->data[i] < b->pos->data[i];
  70. return false;
  71. }
  72. SearchOptions::SearchOptions() {
  73. fixedColor = 0;
  74. moveLimit = 10000;
  75. nextMove = 0;
  76. trustHashFull = false;
  77. searchInVariations = true;
  78. algos = (1<<30) - 1; // use all available algorithms
  79. }
  80. SearchOptions::SearchOptions(int FIXEDCOLOR, int NEXTMOVE, int MOVELIMIT) {
  81. fixedColor = FIXEDCOLOR;
  82. moveLimit = MOVELIMIT;
  83. nextMove = NEXTMOVE;
  84. trustHashFull = false;
  85. searchInVariations = true;
  86. algos = (1<<30) - 1; // use all available algorithms
  87. }
  88. SearchOptions::SearchOptions(SnapshotVector& snv) {
  89. fixedColor = snv.retrieve_int();
  90. moveLimit = snv.retrieve_int();
  91. nextMove = snv.retrieve_int();
  92. trustHashFull = snv.retrieve_int();
  93. searchInVariations= snv.retrieve_int();
  94. algos = snv.retrieve_int();
  95. }
  96. void SearchOptions::to_snv(SnapshotVector& snv) {
  97. snv.pb_int(fixedColor);
  98. snv.pb_int(moveLimit);
  99. snv.pb_int(nextMove);
  100. snv.pb_int(trustHashFull);
  101. snv.pb_int(searchInVariations);
  102. snv.pb_int(algos);
  103. }
  104. ProcessOptions::ProcessOptions() {
  105. processVariations = true;
  106. sgfInDB = true;
  107. rootNodeTags = "BR,CA,DT,EV,HA,KM,PB,PC,PW,RE,RO,RU,SZ,US,WR";
  108. algos = ALGO_FINALPOS | ALGO_MOVELIST | ALGO_HASH_FULL | ALGO_HASH_CORNER;
  109. algo_hash_full_maxNumStones = 50;
  110. algo_hash_corner_maxNumStones = 20;
  111. professional_tag = 0;
  112. }
  113. ProcessOptions::ProcessOptions(string s) {
  114. int p = 0;
  115. if (s[p++] == 't') processVariations = true;
  116. else processVariations = false;
  117. if (s[p++] == 't') sgfInDB = true;
  118. else sgfInDB = false;
  119. professional_tag = s[p++] - (int)'0';
  120. p++;
  121. int pn = s.find('|', p) + 1;
  122. algos = atoi(s.substr(p, pn-p-1).c_str());
  123. p = pn;
  124. pn = s.find('|', p) + 1;
  125. algo_hash_full_maxNumStones = atoi(s.substr(p, pn-p-1).c_str());
  126. p = pn;
  127. pn = s.find('|', p) + 1;
  128. algo_hash_corner_maxNumStones = atoi(s.substr(p, pn-p-1).c_str());
  129. rootNodeTags = s.substr(pn);
  130. }
  131. string ProcessOptions::asString() {
  132. string result;
  133. if (processVariations) result += "t";
  134. else result += "f";
  135. if (sgfInDB) result += "t";
  136. else result += "f";
  137. char buf[200];
  138. sprintf(buf, "%d|%d|%d|%d|%s", professional_tag, algos, algo_hash_full_maxNumStones, algo_hash_corner_maxNumStones, rootNodeTags.c_str());
  139. result += buf;
  140. return result;
  141. }
  142. void ProcessOptions::validate() {
  143. string::iterator it = rootNodeTags.begin();
  144. while (it != rootNodeTags.end()) {
  145. if (*it == ' ') it = rootNodeTags.erase(it);
  146. else it++;
  147. }
  148. if (rootNodeTags.find("PB") == string::npos) rootNodeTags += ",PB";
  149. if (rootNodeTags.find("PW") == string::npos) rootNodeTags += ",PW";
  150. if (rootNodeTags.find("RE") == string::npos) rootNodeTags += ",RE";
  151. if (rootNodeTags.find("DT") == string::npos) rootNodeTags += ",DT";
  152. algos |= ALGO_FINALPOS | ALGO_MOVELIST; // these are mandatory at the moment
  153. }
  154. vector<string>* ProcessOptions::SGFTagsAsStrings() {
  155. vector<string>* SGFtags = new vector<string>;
  156. int ctr = 0;
  157. size_t p = 0;
  158. size_t pn = rootNodeTags.find(',', p);
  159. while (pn != string::npos) {
  160. SGFtags->push_back(rootNodeTags.substr(p,pn-p));
  161. ctr++;
  162. p = pn+1;
  163. pn = rootNodeTags.find(',', p);
  164. }
  165. SGFtags->push_back(rootNodeTags.substr(p));
  166. return SGFtags;
  167. }
  168. GameListEntry::GameListEntry(int ID, char WINNER, string GAMEINFOSTR, int DATE) {
  169. // printf("GLE %d %c %s\n", ID, WINNER, GAMEINFOSTR);
  170. id = ID;
  171. date = DATE;
  172. if (WINNER == 'B' || WINNER == 'b') winner = 'B';
  173. else if (WINNER == 'W' || WINNER == 'w') winner = 'W';
  174. else if (WINNER == 'J' || WINNER == 'j') winner = 'J';
  175. else winner = '-';
  176. gameInfoStr = GAMEINFOSTR;
  177. hits = 0;
  178. candidates = 0;
  179. }
  180. GameListEntry::~GameListEntry() {
  181. if (hits) {
  182. for(vector<Hit* >::iterator it = hits->begin(); it != hits->end(); it++) delete *it;
  183. delete hits;
  184. hits = 0;
  185. }
  186. if (candidates) {
  187. for(vector<Candidate* >::iterator it = candidates->begin(); it != candidates->end(); it++) delete *it;
  188. delete candidates;
  189. candidates = 0;
  190. }
  191. }
  192. void GameListEntry::hits_from_snv(SnapshotVector& snv) {
  193. int h_size = snv.retrieve_int();
  194. if (h_size==-1) hits=0;
  195. else {
  196. hits = new vector<Hit* >;
  197. for(int j=0; j<h_size; j++) {
  198. hits->push_back(new Hit(snv));
  199. }
  200. }
  201. }
  202. int insertEntry(void *gl, int argc, char **argv, char **azColName) {
  203. char winner = '-';
  204. if (argv[1] && (argv[1][0] == 'B' || argv[1][0] == 'W' || argv[1][0] == 'J')) winner = argv[1][0];
  205. else if (argv[1] && (argv[1][0] == '0')) winner = 'J'; // Officially SGF format says that Jigo should be given as RE[0].
  206. int date = 0;
  207. if (argv[2]) {
  208. // date is 12 * year + month - 1, where month in [1..12];
  209. // the string argv[2] has format YYYY-MM-DD.
  210. date = ((int)argv[2][0] - (int)'0')*12000 + ((int)argv[2][1] - (int)'0')*1200 + ((int)argv[2][2] - (int)'0')*120 + ((int)argv[2][3] - (int)'0')*12 + ((int)argv[2][5] - (int)'0')*10 + ((int)argv[2][6] - (int)'0') - 1;
  211. }
  212. string gameInfoStr = ((GameList*)gl)->format2;
  213. for(int i=0; i<((GameList*)gl)->numColumns; i++) {
  214. char strpip1[20];
  215. sprintf(strpip1, "[[%d[[F", i);
  216. size_t p = gameInfoStr.find(strpip1);
  217. if (p != string::npos) {
  218. if (argv[i]) {
  219. string fn = argv[i];
  220. if (fn.substr(fn.size()-4) == ".sgf" || fn.substr(fn.size()-4) == ".mgt")
  221. gameInfoStr.replace(p, strlen(strpip1), fn.substr(0,fn.size()-4));
  222. else gameInfoStr.replace(p, strlen(strpip1), fn);
  223. } else gameInfoStr.erase(gameInfoStr.find(strpip1), strlen(strpip1));
  224. continue;
  225. }
  226. sprintf(strpip1, "[[%d", i);
  227. p = gameInfoStr.find(strpip1);
  228. if (p != string::npos) {
  229. if (argv[i]) gameInfoStr.replace(p, strlen(strpip1), argv[i]);
  230. else gameInfoStr.erase(gameInfoStr.find(strpip1), strlen(strpip1));
  231. }
  232. }
  233. size_t p = gameInfoStr.find("[[W");
  234. if (p != string::npos) gameInfoStr.replace(p, 3, 1, winner);
  235. // printf("id %s\n", argv[0]);
  236. ((GameList*)gl)->all->push_back(new GameListEntry(atoi(argv[0]), winner, gameInfoStr, date));
  237. if (date >= DATE_PROFILE_START*12) ((GameList*)gl)->dates_all[date - DATE_PROFILE_START*12]++; // January of year DATE_PROFILE_START is 0; everything before is ignored
  238. return 0;
  239. }
  240. int dbinfo_callback(void *s, int argc, char **argv, char **asColName) {
  241. char** cpp = (char**)s;
  242. if (argc && argv[0]) {
  243. // printf("dbi_cb %s\n", argv[0]);
  244. *cpp = new char[strlen(argv[0])+1];
  245. strcpy(*cpp, argv[0]);
  246. }
  247. return 0;
  248. }
  249. GameList::GameList(const char* DBNAME, string ORDERBY, string FORMAT, ProcessOptions* p_options, int BOARDSIZE, int cache) throw(DBError) {
  250. boardsize = BOARDSIZE;
  251. labels = 0;
  252. mrs_pattern = 0;
  253. searchOptions = 0;
  254. dbname = new char[strlen(DBNAME)+1];
  255. strcpy(dbname, DBNAME);
  256. db = 0;
  257. // try to retrieve basic options from database
  258. int rc = sqlite3_open(dbname, &db);
  259. if (rc) {
  260. sqlite3_close(db);
  261. db = 0;
  262. throw DBError();
  263. }
  264. rc = sqlite3_busy_timeout(db, 200);
  265. if (rc) throw DBError();
  266. rc = sqlite3_exec(db, "pragma synchronous = off;", 0, 0, 0);
  267. if (rc) throw DBError();
  268. char cache_str[100];
  269. sprintf(cache_str, "pragma cache_size = %d", cache*1000);
  270. rc = sqlite3_exec(db, cache_str, 0, 0, 0);
  271. if (rc) throw DBError();
  272. rc = sqlite3_exec(db, "create table if not exists db_info ( info text );", 0, 0, 0);
  273. if (rc != SQLITE_OK) throw DBError();
  274. char* dbinfo = 0;
  275. // check whether this is a kombilo db file
  276. rc = sqlite3_exec(db, "select * from db_info where rowid = 1;", dbinfo_callback, &dbinfo, 0);
  277. if (rc != SQLITE_OK) throw DBError();
  278. if (dbinfo) {
  279. if (strcmp(dbinfo, "kombilo 0.7") && strcmp(dbinfo, "kombilo 0.8")) throw DBError();
  280. delete [] dbinfo;
  281. }
  282. rc = sqlite3_exec(db, "select * from db_info where rowid = 2;", dbinfo_callback, &dbinfo, 0);
  283. if (rc != SQLITE_OK) throw DBError();
  284. if (dbinfo) {
  285. // printf("dbinfo: %s\n", dbinfo);
  286. p_op = new ProcessOptions(dbinfo);
  287. delete [] dbinfo;
  288. char* bsizes = 0;
  289. rc = sqlite3_exec(db, "select * from db_info where rowid = 3;", dbinfo_callback, &bsizes, 0);
  290. if (rc != SQLITE_OK) throw DBError();
  291. if (bsizes) {
  292. boardsize = atoi(bsizes);
  293. delete [] bsizes;
  294. }
  295. addAlgos(0);
  296. } else { // if this does not work: create database and read p_options (or use defaults)
  297. // printf("retrieving dbinfo failed\n");
  298. // write version information to db_info
  299. rc = sqlite3_exec(db, "insert into db_info (rowid,info) values (1,'kombilo 0.8')", 0, 0, 0);
  300. if (p_options == 0) p_op = new ProcessOptions(); // use default values
  301. else {
  302. // printf("use p_options\n");
  303. p_op = new ProcessOptions(*p_options);
  304. p_op->validate(); // make sure the most important information is contained in rootNodeTags list
  305. }
  306. string sql = "insert into db_info (rowid,info) values (2,'";
  307. sql += p_op->asString();
  308. sql += "');";
  309. rc = sqlite3_exec(db, sql.c_str(), 0, 0, 0);
  310. if (rc != SQLITE_OK) throw DBError();
  311. sql = "insert into db_info (rowid, info) values (3, '";
  312. char buf[5];
  313. sprintf(buf, "%d", boardsize);
  314. sql += buf;
  315. sql += "');";
  316. rc = sqlite3_exec(db, sql.c_str(), 0, 0, 0);
  317. if (rc != SQLITE_OK) throw DBError();
  318. addAlgos(1);
  319. }
  320. // set up snapshot db
  321. rc = sqlite3_exec(db, "create table if not exists snapshots ( data text );", 0, 0, 0);
  322. if (rc != SQLITE_OK) throw DBError();
  323. all = 0;
  324. for(int i = 0; i < (DATE_PROFILE_END - DATE_PROFILE_START)*12; i++) dates_all.push_back(0);
  325. for(int i = 0; i < DATE_PROFILE_END - DATE_PROFILE_START + 1; i++) dates_all_per_year.push_back(0);
  326. currentList = oldList = 0;
  327. resetFormat(ORDERBY, FORMAT);
  328. // printf("dapy size %d expected %d\n", dates_all_per_year.size(), DATE_PROFILE_END - DATE_PROFILE_START + 1);
  329. // printf("done\n");
  330. }
  331. void GameList::resetFormat(string ORDERBY, string FORMAT) {
  332. // printf("enter resetFormat\n");
  333. if (FORMAT == "") { // use default format string
  334. numColumns = 5;
  335. format1 = "id,re,date,pw,pb,dt";
  336. format2 = "[[3 - [[4 ([[W), [[5, ";
  337. } else {
  338. char buf[10];
  339. format1 = "id,re,date";
  340. numColumns = 3; // 3 columns already assigned
  341. format2 = FORMAT;
  342. size_t p = 0;
  343. size_t q = 0;
  344. while (p != string::npos) {
  345. p = format2.find("[[",p);
  346. q = format2.find("]]",p);
  347. if (p+2 < format2.size() && q != string::npos) {
  348. string col = format2.substr(p+2, q-p-2);
  349. // check availability
  350. if (col == "id" || col == "filename" || col == "pos" || col == "duplicate" || p_op->rootNodeTags.find(col) != string::npos) {
  351. sprintf(buf, "[[%d", numColumns++);
  352. format2.replace(p,q+2-p, buf);
  353. format1 += ",";
  354. format1 += col;
  355. } else if (col == "winner") {
  356. format2.replace(p,q+2-p, "[[W");
  357. } else if (col == "date") {
  358. format2.replace(p,q+2-p, "[[2");
  359. } else if (col == "filename.") {
  360. sprintf(buf, "[[%d[[F", numColumns++);
  361. format2.replace(p, q+2-p, buf);
  362. format1 += ",filename";
  363. p += 4;
  364. }
  365. p++;
  366. } else break;
  367. }
  368. }
  369. if (ORDERBY == "" || ORDERBY == "id" || ORDERBY == "ID" || ORDERBY == "Id" || ORDERBY == "iD") orderby = "id";
  370. else orderby = ORDERBY + ",id";
  371. // printf("finished parsing\n");
  372. readDB();
  373. }
  374. void GameList::addAlgos(bool NEW) {
  375. // create algo pointers; if not new, read data from file
  376. // FIXME be more careful in validating input ...
  377. // printf("add algos %d %d %d\n", bs, ctr, p_op->algos);
  378. for(int i=0; i<20; i++) algo_ps.push_back(0);
  379. string a_dbname(dbname);
  380. a_dbname[a_dbname.size()-1] = 'a';
  381. ifstream is(a_dbname.c_str(), ios::binary);
  382. string dbname_str(dbname);
  383. if (NEW) {
  384. algo_ps[0] = new Algo_signature(boardsize, SnapshotVector());
  385. if (p_op->algos & ALGO_FINALPOS) algo_ps[algo_finalpos] = new Algo_finalpos(boardsize, SnapshotVector());
  386. if (p_op->algos & ALGO_MOVELIST) algo_ps[algo_movelist] = new Algo_movelist(boardsize, SnapshotVector());
  387. if (p_op->algos & ALGO_HASH_FULL) algo_ps[algo_hash_full] = new Algo_hash_full(boardsize, SnapshotVector(), dbname_str+"1", p_op->algo_hash_full_maxNumStones);
  388. if (p_op->algos & ALGO_HASH_CORNER) algo_ps[algo_hash_corner] = new Algo_hash_corner(boardsize, SnapshotVector(), dbname_str+"2", 7, p_op->algo_hash_corner_maxNumStones);
  389. } else {
  390. // printf("read algo db\n");
  391. size_t si;
  392. { is.read((char *)&si, sizeof(si));
  393. // printf("read algo db %lld\n", si);
  394. char* d = new char[si];
  395. is.read(d, si);
  396. SnapshotVector data(d, si);
  397. delete [] d;
  398. algo_ps[0] = new Algo_signature(boardsize, data);
  399. }
  400. if (p_op->algos & ALGO_FINALPOS) {
  401. is.read((char *)&si, sizeof(si));
  402. // printf("read algo db %lld\n", si);
  403. char* d = new char[si];
  404. is.read(d, si);
  405. SnapshotVector data(d, si);
  406. delete [] d;
  407. algo_ps[algo_finalpos] = new Algo_finalpos(boardsize, data);
  408. }
  409. if (p_op->algos & ALGO_MOVELIST) {
  410. is.read((char *)&si, sizeof(si));
  411. // printf("read algo db %lld\n", si);
  412. char* d = new char[si];
  413. is.read(d, si);
  414. SnapshotVector data(d, si);
  415. delete [] d;
  416. algo_ps[algo_movelist] = new Algo_movelist(boardsize, data);
  417. }
  418. if (p_op->algos & ALGO_HASH_FULL) {
  419. is.read((char *)&si, sizeof(si));
  420. // printf("read algo db %lld\n", si);
  421. char* d = new char[si];
  422. is.read(d, si);
  423. SnapshotVector data(d, si);
  424. delete [] d;
  425. algo_ps[algo_hash_full] = new Algo_hash_full(boardsize, data, dbname_str+"1", p_op->algo_hash_full_maxNumStones);
  426. }
  427. if (p_op->algos & ALGO_HASH_CORNER) {
  428. is.read((char *)&si, sizeof(si));
  429. // printf("read algo db %lld\n", si);
  430. char* d = new char[si];
  431. is.read(d, si);
  432. SnapshotVector data(d, si);
  433. delete [] d;
  434. algo_ps[algo_hash_corner] = new Algo_hash_corner(boardsize, data, dbname_str+"2", 7, p_op->algo_hash_corner_maxNumStones);
  435. }
  436. }
  437. // for(int a=20*ctr; a<20*(ctr+1); a++) printf("aa %d %p\n", a, algo_ps[a]);
  438. // if (algos & ALGO_HASH_SIDE)
  439. // algo_ps[algo_hash_side] = new Algo_hash_side(boardsize, 6, 4, p_op->algo_hash_side_maxNumStones);
  440. }
  441. void GameList::readDB() throw(DBError) {
  442. // printf("read dbs\n");
  443. if (oldList) delete oldList;
  444. if (currentList) delete currentList;
  445. if (all) {
  446. for(vector<GameListEntry* >::iterator it = all->begin(); it != all->end(); it++)
  447. delete *it;
  448. delete all;
  449. }
  450. current = -1;
  451. all = new vector<GameListEntry* >;
  452. currentList = 0;
  453. oldList = 0;
  454. int rc;
  455. rc = sqlite3_exec(db, "begin transaction;", 0, 0, 0);
  456. if (rc) throw DBError();
  457. string sql = "select ";
  458. sql += format1;
  459. sql += " from GAMES order by ";
  460. sql += orderby;
  461. // printf("sql: %s\n", sql.c_str());
  462. rc = sqlite3_exec(db, sql.c_str(), insertEntry, this, 0);
  463. if (rc != SQLITE_OK && rc != SQLITE_ERROR) {
  464. throw DBError();
  465. }
  466. // printf("read.\n");
  467. // SQLITE_ERROR may occur since table might not yet exist
  468. for(int i=0; i < (DATE_PROFILE_END - DATE_PROFILE_START); i++) {
  469. int sum = 0;
  470. for(int j = 0; j < 12; j++)
  471. sum += dates_all[i * 12 + j];
  472. dates_all_per_year[i] = sum;
  473. // printf("dapy %d\n", dates_all_per_year[i]);
  474. }
  475. readPlayersList();
  476. readNumOfWins();
  477. rc = sqlite3_exec(db, "commit;", 0, 0, 0);
  478. if (rc != SQLITE_OK) throw DBError();
  479. // printf("read.\n");
  480. reset();
  481. // printf("leave readDB\n");
  482. }
  483. GameList::~GameList() {
  484. // printf("enter ~GameList\n");
  485. if (mrs_pattern) delete mrs_pattern;
  486. if (searchOptions) delete searchOptions;
  487. if (p_op) delete p_op;
  488. if (labels) delete [] labels;
  489. for (std::vector<Continuation *>::const_iterator i = continuations.begin(); i != continuations.end(); ++i) {
  490. delete *i;
  491. }
  492. delete [] dbname;
  493. if (all) {
  494. for(vector<GameListEntry* >::iterator it = all->begin(); it != all->end(); it++)
  495. delete *it;
  496. delete all;
  497. }
  498. if (currentList) delete currentList;
  499. if (oldList) delete oldList;
  500. for(unsigned int i=0; i<20; i++)
  501. if (algo_ps[i]) delete algo_ps[i];
  502. if (db) sqlite3_close(db);
  503. db = 0;
  504. // printf("leave ~GameList\n");
  505. }
  506. int GameList::start() {
  507. current = 0;
  508. if (oldList) delete oldList;
  509. oldList = currentList;
  510. currentList = new vector<pair<int,int> >;
  511. if (oldList && oldList->size()) return (*oldList)[0].first;
  512. else {
  513. if (oldList) delete oldList;
  514. oldList = 0;
  515. return -1;
  516. }
  517. }
  518. int GameList::startO() {
  519. current = 0;
  520. if (oldList) delete oldList;
  521. oldList = currentList;
  522. currentList = new vector<pair<int,int> >;
  523. return oldList->size();
  524. }
  525. int GameList::next() {
  526. current++;
  527. if (current < (int)oldList->size()) return (*oldList)[current].first;
  528. else {
  529. if (oldList) delete oldList;
  530. oldList = 0;
  531. return -1;
  532. }
  533. }
  534. bool sndcomp(const pair<int,int>& a, const pair<int,int>& b) {
  535. return a.second < b.second;
  536. }
  537. int GameList::start_sorted() {
  538. current = 0;
  539. if (oldList) delete oldList;
  540. oldList = currentList;
  541. currentList = new vector<pair<int,int> >;
  542. if (!oldList || !oldList->size()) {
  543. if (oldList) delete oldList;
  544. oldList = 0;
  545. return -1;
  546. }
  547. sort(oldList->begin(), oldList->end());
  548. return 0;
  549. }
  550. int GameList::end_sorted() {
  551. sort(currentList->begin(), currentList->end(), sndcomp);
  552. delete oldList;
  553. oldList = 0;
  554. Bwins = Wwins = 0;
  555. for(vector<pair<int,int> >::iterator it = currentList->begin(); it != currentList->end(); it++) {
  556. if ((*all)[it->second]->winner == 'B') Bwins++;
  557. if ((*all)[it->second]->winner == 'W') Wwins++;
  558. }
  559. return 0;
  560. }
  561. void GameList::update_dates_current() {
  562. dates_current.clear();
  563. for(int i=0; i<(DATE_PROFILE_END - DATE_PROFILE_START)*12; i++) dates_current.push_back(0);
  564. for(vector<pair<int,int> >::iterator it = currentList->begin(); it != currentList->end(); it++) {
  565. if ((*all)[it->second]->date >= DATE_PROFILE_START*12) dates_current[(*all)[it->second]->date - DATE_PROFILE_START*12]++;
  566. }
  567. }
  568. char GameList::getCurrentWinner() {
  569. return (*all)[(*oldList)[current].second]->winner;
  570. }
  571. int GameList::getCurrentDate() {
  572. return (*all)[(*oldList)[current].second]->date;
  573. }
  574. vector<Candidate* > * GameList::getCurrentCandidateList() {
  575. return (*all)[(*oldList)[current].second]->candidates;
  576. }
  577. void GameList::makeCurrentCandidate(vector<Candidate* > * candidates) {
  578. GameListEntry* gle = (*all)[(*oldList)[current].second];
  579. if (gle->candidates) delete gle->candidates;
  580. gle->candidates = candidates;
  581. currentList->push_back((*oldList)[current]);
  582. }
  583. void GameList::makeCurrentHit(vector<Hit* > * hits) {
  584. GameListEntry* gle = (*all)[(*oldList)[current].second];
  585. if (gle->hits) delete gle->hits;
  586. gle->hits = hits;
  587. sort(gle->hits->begin(), gle->hits->end(), Hit::cmp_pts);
  588. currentList->push_back((*oldList)[current]);
  589. }
  590. void GameList::setCurrentFromIndex(int index) {
  591. int start = current;
  592. int end = oldList->size();
  593. int m = start;
  594. while (start < end) {
  595. m = (end+start)/2;
  596. if (index == (*oldList)[m].first) {
  597. break;
  598. } else {
  599. if (index < (*oldList)[m].first) end = m;
  600. else start = m+1;
  601. }
  602. }
  603. current = m;
  604. }
  605. void GameList::makeIndexHit(int index, vector<Hit* > * hits, vector<int>* CL) {
  606. int m = get_current_index(index, &current);
  607. if (m != -1) {
  608. if (CL)
  609. CL->push_back(m);
  610. else {
  611. currentList->push_back((*oldList)[m]);
  612. if (hits) {
  613. if ((*all)[(*oldList)[m].second]->hits) delete (*all)[(*oldList)[m].second]->hits;
  614. (*all)[(*oldList)[m].second]->hits = hits;
  615. }
  616. }
  617. }
  618. }
  619. void GameList::makeIndexCandidate(int index, vector<Candidate* > * candidates) {
  620. int m = get_current_index(index, &current);
  621. if (m != -1) {
  622. currentList->push_back((*oldList)[m]);
  623. if (candidates) {
  624. if ((*all)[(*oldList)[m].second]->candidates) delete (*all)[(*oldList)[m].second]->candidates;
  625. (*all)[(*oldList)[m].second]->candidates = candidates;
  626. }
  627. }
  628. }
  629. void GameList::reset() {
  630. if (oldList) delete oldList;
  631. oldList = 0;
  632. if (currentList) delete currentList;
  633. currentList = new vector<pair<int,int> >;
  634. int counter = 0;
  635. for(vector<GameListEntry* >::iterator it = all->begin(); it != all->end(); it++) {
  636. if ((*it)->hits) {
  637. for(vector<Hit* >::iterator ith = (*it)->hits->begin(); ith != (*it)->hits->end(); ith++)
  638. delete *ith;
  639. delete (*it)->hits;
  640. (*it)->hits = 0;
  641. }
  642. if ((*it)->candidates) {
  643. for(vector<Candidate* >::iterator itc = (*it)->candidates->begin(); itc != (*it)->candidates->end(); itc++)
  644. delete *itc;
  645. delete (*it)->candidates;
  646. (*it)->candidates = 0;
  647. }
  648. currentList->push_back(make_pair((*it)->id, counter++));
  649. }
  650. num_hits = 0;
  651. num_switched = 0;
  652. Bwins = BwinsAll;
  653. Wwins = WwinsAll;
  654. dates_current.clear();
  655. for(int i = 0; i < (DATE_PROFILE_END - DATE_PROFILE_START)*12; i++) dates_current.push_back(dates_all[i]);
  656. }
  657. void GameList::tagsearch(int tag) throw(DBError) {
  658. char sql[200];
  659. if (!tag) return;
  660. if (tag > 0) {
  661. sprintf(sql, "select GAMES.id from GAMES join game_tags on GAMES.id = game_tags.game_id where game_tags.tag_id = %d order by GAMES.id", tag);
  662. // use join here to make sure we only get IDs from GAMES (does not seem necessary, if game_tags is always updated correctly - but this way we are on the safe side)
  663. } else {
  664. sprintf(sql, "select GAMES.id from GAMES except select GAMES.id from GAMES join game_tags on GAMES.id = game_tags.game_id where game_tags.tag_id = %d order by GAMES.id;", -tag);
  665. }
  666. gisearch(sql, 1);
  667. }
  668. void GameList::export_tags(string tag_db_name, vector<int> which_tags) {
  669. // build list of tags to be included as string
  670. string which = "(";
  671. if (which_tags.size()) {
  672. stringstream out;
  673. vector<int>::iterator it = which_tags.begin();
  674. out << *it;
  675. it++;
  676. for(; it != which_tags.end(); it++) {
  677. out << ", " << *it;
  678. }
  679. which += out.str() + ")";
  680. }
  681. // printf("export tags %s\n", which.c_str());
  682. // open db
  683. sqlite3* tag_db;
  684. int rc = sqlite3_open(tag_db_name.c_str(), &tag_db);
  685. if (rc) {
  686. sqlite3_close(tag_db);
  687. throw DBError();
  688. }
  689. rc = sqlite3_busy_timeout(tag_db, 200);
  690. if (rc) { throw DBError(); }
  691. rc = sqlite3_exec(tag_db, "pragma synchronous = off;", 0, 0, 0);
  692. if (rc) { throw DBError(); }
  693. // add all tags that are in current db to tag db
  694. rc = sqlite3_exec(tag_db,
  695. "create table if not exists TAGS ( id integer primary key, signature text, fphash integer, tag_id integer, unique(signature, fphash, tag_id) );",
  696. 0, 0, 0);
  697. if (rc != SQLITE_OK) { throw DBError(); }
  698. char *sql = new char[100+strlen(dbname)];
  699. sprintf(sql, "attach '%s' as g1;", dbname);
  700. rc = sqlite3_exec(tag_db, sql, 0, 0, 0);
  701. if (rc != SQLITE_OK) { throw DBError(); }
  702. delete [] sql;
  703. // write tags into tags db
  704. if (which_tags.size()) {
  705. char* sql1 = new char[250+which.size()];
  706. sprintf(sql1, "insert or ignore into TAGS (signature, fphash, tag_id) select g1.GAMES.signature, g1.GAMES.fphash, g1.GAME_TAGS.tag_id from g1.GAMES join g1.GAME_TAGS on g1.GAMES.id = g1.GAME_TAGS.game_id where g1.GAME_TAGS.tag_id in %s;", which.c_str());
  707. rc = sqlite3_exec(tag_db, sql1, 0, 0, 0);
  708. delete [] sql1;
  709. } else
  710. rc = sqlite3_exec(tag_db, "insert or ignore into TAGS (signature, fphash, tag_id) select g1.GAMES.signature, g1.GAMES.fphash, g1.GAME_TAGS.tag_id from g1.GAMES join g1.GAME_TAGS on g1.GAMES.id = g1.GAME_TAGS.game_id", 0, 0, 0);
  711. if (rc!=SQLITE_OK) { throw DBError(); }
  712. rc = sqlite3_exec(tag_db, "detach g1;", 0, 0, 0);
  713. if (rc != SQLITE_OK) { throw DBError(); }
  714. // close db
  715. sqlite3_close(tag_db);
  716. }
  717. void GameList::import_tags(string tag_db_name) {
  718. // open db
  719. sqlite3* tag_db;
  720. int rc = sqlite3_open(tag_db_name.c_str(), &tag_db);
  721. if (rc) {
  722. sqlite3_close(tag_db);
  723. throw DBError();
  724. }
  725. rc = sqlite3_busy_timeout(tag_db, 200);
  726. if (rc) { throw DBError(); }
  727. rc = sqlite3_exec(tag_db, "pragma synchronous = off;", 0, 0, 0);
  728. if (rc) { throw DBError(); }
  729. // add all tags from tag_db to db.GAME_TAGS
  730. char *sql = new char[200+strlen(dbname)];
  731. sprintf(sql, "attach '%s' as g1;", dbname);
  732. rc = sqlite3_exec(tag_db, sql, 0, 0, 0);
  733. if (rc != SQLITE_OK) { throw DBError(); }
  734. rc = sqlite3_exec(tag_db, "insert or ignore into g1.GAME_TAGS (game_id, tag_id) select g1.GAMES.id, tags.tag_id from tags join g1.GAMES on g1.GAMES.signature = tags.signature and g1.GAMES.fphash = tags.fphash;", 0, 0, 0);
  735. if (rc!=SQLITE_OK) { throw DBError(); }
  736. rc = sqlite3_exec(tag_db, "detach g1;", 0, 0, 0);
  737. if (rc != SQLITE_OK) { throw DBError(); }
  738. // close db
  739. sqlite3_close(tag_db);
  740. }
  741. void GameList::tagsearchSQL(char* query) throw(DBError) {
  742. char sql[1000];
  743. sprintf(sql, "select GAMES.id from GAMES where %s order by GAMES.id", query);
  744. gisearch(sql, 1);
  745. }
  746. void GameList::setTagID(int tag, int i) throw(DBError) {
  747. int rc = sqlite3_exec(db, "begin transaction", 0, 0, 0);
  748. if (rc != SQLITE_OK) {
  749. throw DBError();
  750. }
  751. if (!getTagsID(i, tag).size()) {
  752. char sql[200];
  753. sprintf(sql, "insert or ignore into GAME_TAGS (game_id, tag_id) values (%d, %d)", i, tag); // uniqueness ascertained by corresponding constraint in db
  754. rc = sqlite3_exec(db, sql, 0, 0, 0);
  755. if (rc != SQLITE_OK) {
  756. // printf("settagid: %d %d %d\n", i, tag, rc);
  757. throw DBError();
  758. }
  759. }
  760. rc = sqlite3_exec(db, "commit", 0, 0, 0);
  761. if (rc != SQLITE_OK) {
  762. throw DBError();
  763. }
  764. }
  765. void GameList::setTag(int tag, int start, int end) throw(DBError) {
  766. if (end==0) end = start+1;
  767. if (start>end || end > (int)currentList->size()) return;
  768. int rc = sqlite3_exec(db, "begin transaction", 0, 0, 0);
  769. if (rc != SQLITE_OK) throw DBError();
  770. for(int i = start; i < end; i++) {
  771. if (getTags(i, tag).size()) continue;
  772. char sql[200];
  773. sprintf(sql, "insert or ignore into GAME_TAGS (game_id, tag_id) values (%d, %d)", (*all)[(*currentList)[i].second]->id, tag);
  774. // uniqueness ascertained by corresponding constraint in db
  775. rc = sqlite3_exec(db, sql, 0, 0, 0);
  776. if (rc != SQLITE_OK) throw DBError();
  777. }
  778. rc = sqlite3_exec(db, "commit", 0, 0, 0);
  779. if (rc != SQLITE_OK) throw DBError();
  780. }
  781. void GameList::deleteTag(int tag, int i) throw(DBError) {
  782. char sql[200];
  783. if (i == -1) sprintf(sql, "delete from game_tags where tag_id=%d", tag);
  784. else sprintf(sql, "delete from game_tags where game_id=%d and tag_id=%d", (*all)[(*currentList)[i].second]->id, tag);
  785. int rc = sqlite3_exec(db, sql, 0, 0, 0);
  786. if (rc != SQLITE_OK) throw DBError();
  787. }
  788. int gettags_callback(void *res, int argc, char **argv, char **azColName) {
  789. if (!argc) return 1;
  790. ((vector<int>*)res)->push_back(atoi(argv[0]));
  791. return 0;
  792. }
  793. vector<int> GameList::getTagsID(int i, int tag) throw(DBError) {
  794. vector<int> result;
  795. char sql[200];
  796. if (tag==0) sprintf(sql, "select tag_id from game_tags where game_id=%d order by tag_id", i);
  797. else sprintf(sql, "select tag_id from game_tags where game_id=%d and tag_id=%d", i, tag);
  798. int rc = sqlite3_exec(db, sql, gettags_callback, &result, 0);
  799. if (rc != SQLITE_OK) throw DBError();
  800. return result;
  801. }
  802. vector<int> GameList::getTags(unsigned int i, int tag) throw(DBError) {
  803. vector<int> result;
  804. if (i < 0 || i >= currentList->size()) return result;
  805. char sql[200];
  806. if (tag==0) sprintf(sql, "select tag_id from game_tags where game_id=%d order by tag_id", (*all)[(*currentList)[i].second]->id);
  807. else sprintf(sql, "select tag_id from game_tags where game_id=%d and tag_id=%d", (*all)[(*currentList)[i].second]->id, tag);
  808. int rc = sqlite3_exec(db, sql, gettags_callback, &result, 0);
  809. if (rc != SQLITE_OK) throw DBError();
  810. return result;
  811. }
  812. int GameList::get_current_index(int id, int* start) {
  813. // use this in between start_sorted() and end_sorted() only!
  814. int end = oldList->size();
  815. int m = *start;
  816. while (*start < end) {
  817. m = (end+*start)/2;
  818. if (id == (*oldList)[m].first) {
  819. *start = m;
  820. return m;
  821. } else {
  822. if (id < (*oldList)[m].first) end = m;
  823. else *start = m+1;
  824. }
  825. }
  826. return -1;
  827. }
  828. void GameList::sigsearch(char* sig) throw(DBError) {
  829. if (start_sorted() == 0) {
  830. vector<int> result = sigsearchNC(sig);
  831. for(vector<int>::iterator it = result.begin(); it != result.end(); it++) {
  832. makeIndexHit(*it, 0);
  833. }
  834. end_sorted();
  835. update_dates_current();
  836. }
  837. }
  838. vector<int> GameList::sigsearchNC(char* sig) throw(DBError) {
  839. vector<int> result;
  840. int rc;
  841. sqlite3_stmt *ppStmt=0;
  842. // first prepare sql statement; need some case distinction
  843. bool sig_contains_wildcards = false;
  844. for(int i=0; i<12; i++) {
  845. if (sig[i] == '_') {
  846. sig_contains_wildcards = true;
  847. break;
  848. }
  849. }
  850. if (sig_contains_wildcards) { // if sig contains wildcards, then need to search for all flipped sigs
  851. string query = "select id from GAMES where signature like ? or signature like ? or signature like ? or signature like ? or signature like ? or signature like ? or signature like ? or signature like ? order by id";
  852. char** sigs = new char*[8];
  853. for (int f=0; f<8; f++) sigs[f] = flipped_sig(f, sig, boardsize);
  854. rc = sqlite3_prepare(db, query.c_str(), -1, &ppStmt, 0);
  855. if (rc != SQLITE_OK || ppStmt==0) throw DBError();
  856. for (int f=0; f<8; f++) {
  857. rc = sqlite3_bind_blob(ppStmt, f+1, sigs[f], 12, SQLITE_TRANSIENT);
  858. if (rc != SQLITE_OK || ppStmt==0) throw DBError();
  859. }
  860. for (int f=0; f<8; f++) delete [] sigs[f];
  861. delete [] sigs;
  862. } else { // no wildcards, so we just search for the symmetrized signature
  863. char* symmetrized_sig = symmetrize(sig, boardsize);
  864. string query = "select id from GAMES where signature like ? order by id";
  865. rc = sqlite3_prepare(db, query.c_str(), -1, &ppStmt, 0);
  866. if (rc != SQLITE_OK || ppStmt==0) throw DBError();
  867. rc = sqlite3_bind_blob(ppStmt, 1, symmetrized_sig, 12, SQLITE_TRANSIENT);
  868. if (rc != SQLITE_OK || ppStmt==0) throw DBError();
  869. delete [] symmetrized_sig;
  870. }
  871. // now do the search
  872. do {
  873. rc = sqlite3_step(ppStmt);
  874. if (rc != SQLITE_DONE && rc != SQLITE_ROW) throw DBError();
  875. if (rc == SQLITE_ROW) result.push_back(sqlite3_column_int(ppStmt, 0));
  876. } while (rc == SQLITE_ROW);
  877. rc = sqlite3_finalize(ppStmt);
  878. if (rc != SQLITE_OK) throw DBError();
  879. // clean up
  880. return result;
  881. }
  882. int gis_callback(void *gl, int argc, char **argv, char **azColName) {
  883. if (!argc) return 1;
  884. ((GameList*)gl)->makeIndexHit(atoi(argv[0]), 0);
  885. return 0;
  886. }
  887. void GameList::gisearch(const char* sql, int complete) throw(DBError) {
  888. if (start_sorted() == 0) {
  889. string query;
  890. if (!complete) query = "select id from GAMES where ";
  891. query += sql;
  892. if (!complete) query += " order by id";
  893. // printf("%s\n", query.c_str());
  894. int rc = sqlite3_exec(db, query.c_str(), gis_callback, this, 0);
  895. if( rc!=SQLITE_OK ) throw DBError();
  896. end_sorted();
  897. update_dates_current();
  898. }
  899. }
  900. int gis_callbackNC(void *pair_gl_CL, int argc, char **argv, char **azColName) {
  901. if (!argc) return 1;
  902. pair<GameList*, vector<int>* >* pp = (pair<GameList*, vector<int>* >*)pair_gl_CL;
  903. pp->first->makeIndexHit(atoi(argv[0]), 0, pp->second);
  904. return 0;
  905. }
  906. vector<int>* GameList::gisearchNC(const char* sql, int complete) throw(DBError) {
  907. current = 0;
  908. if (oldList) delete oldList;
  909. oldList = new vector<pair<int,int> >;
  910. for(vector<pair<int, int> >::iterator it = currentList->begin(); it != currentList->end(); it++)
  911. oldList->push_back(*it);
  912. if (!oldList || !oldList->size()) {
  913. if (oldList) delete oldList;
  914. oldList = 0;
  915. return new vector<int>;
  916. }
  917. sort(oldList->begin(), oldList->end());
  918. vector<int>* CL = new vector<int>;
  919. string query;
  920. if (!complete) query = "select id from GAMES where ";
  921. query += sql;
  922. if (!complete) query += " order by id";
  923. // printf("%s\n", query.c_str());
  924. pair<GameList*, vector<int>* >* pp = new pair<GameList*, vector<int>* >(this, CL);
  925. int rc = sqlite3_exec(db, query.c_str(), gis_callbackNC, pp, 0);
  926. if( rc!=SQLITE_OK ) throw DBError();
  927. delete pp;
  928. sort(CL->begin(), CL->end());
  929. delete oldList;
  930. oldList = 0;
  931. return CL;
  932. }
  933. int GameList::numHits() {
  934. return num_hits;
  935. }
  936. int GameList::size() {
  937. return currentList->size();
  938. }
  939. int GameList::size_all() {
  940. return all->size();
  941. }
  942. string GameList::resultsStr(GameListEntry* gle) {
  943. string result;
  944. if (!gle->hits) return result;
  945. char buf[20];
  946. result.reserve(gle->hits->size()*8);
  947. for(vector<Hit* >::iterator it = gle->hits->begin(); it != gle->hits->end(); it++) {
  948. sprintf(buf, "%d", (*it)->pos->data[0]);
  949. result += buf;
  950. for(int i=1; i<(*it)->pos->length; i++) {
  951. sprintf(buf, "-%d", (*it)->pos->data[i]);
  952. result += buf;
  953. }
  954. if ((*it)->label[0] != NO_CONT) {
  955. char lb = lookupLabel((*it)->label[0], (*it)->label[1]); // coordinates of Hit
  956. if ('0' <= lb && lb <= '9') result += '@';
  957. result += lb;
  958. }
  959. if ((*it)->label[2]) result += "-, ";
  960. else result += ", ";
  961. }
  962. return result;
  963. }
  964. void GameList::setLabel(char x, char y, char label) {
  965. if (!labels || !mrs_pattern || x < 0 || x >= mrs_pattern->sizeX || y < 0 || y >= mrs_pattern->sizeY) return;
  966. labels[x+y*mrs_pattern->sizeX] = label;
  967. }
  968. char GameList::lookupLabel(char x, char y) {
  969. if (!labels || !mrs_pattern || x < 0 || x >= mrs_pattern->sizeX || y < 0 || y >= mrs_pattern->sizeY) return '?';
  970. return labels[x+y*mrs_pattern->sizeX];
  971. }
  972. Continuation GameList::lookupContinuation(char x, char y) {
  973. if (!continuations.size() || !mrs_pattern || x < 0 || x >= mrs_pattern->sizeX || y < 0 || y >= mrs_pattern->sizeY) return Continuation(this);
  974. return *continuations[x+y*mrs_pattern->sizeX];
  975. }
  976. vector<string> GameList::currentEntriesAsStrings(int start, int end) {
  977. if (end==0) end = currentList->size();
  978. vector<string> result;
  979. if (start>end || end > (int)currentList->size()) return result;
  980. for(int i=start; i<end; i++) {
  981. result.push_back((*all)[(*currentList)[i].second]->gameInfoStr + resultsStr((*all)[(*currentList)[i].second]));
  982. }
  983. return result;
  984. }
  985. string GameList::currentEntryAsString(int i) {
  986. if (i < 0 || i >= (int)currentList->size()) {
  987. return "";
  988. } else return (*all)[(*currentList)[i].second]->gameInfoStr + resultsStr((*all)[(*currentList)[i].second]);
  989. }
  990. int getpropcallback(void *s, int argc, char **argv, char **azColName) {
  991. char** prop = (char**)s;
  992. if (argc && argv[0]) {
  993. *prop = new char[strlen(argv[0])+1];
  994. strcpy(*prop, argv[0]);
  995. }
  996. return 0;
  997. }
  998. string GameList::getSignature(int i) throw(DBError) {
  999. if (i < 0 || i >= (int)currentList->size()) {
  1000. // printf("index out of range\n");
  1001. return "";
  1002. }
  1003. int index = (*all)[(*currentList)[i].second]->id;
  1004. char* prop = 0;
  1005. char sql[200];
  1006. sprintf(sql, "select signature from GAMES where id = %d;", index);
  1007. // printf("%s\n", sql);
  1008. int rc = sqlite3_exec(db, sql, getpropcallback, &prop, 0);
  1009. if (rc != SQLITE_OK) throw DBError();
  1010. if (!prop) throw DBError();
  1011. string prop_str(prop);
  1012. delete [] prop;
  1013. return prop_str;
  1014. }
  1015. string GameList::getSGF(int i) throw(DBError) {
  1016. if (!p_op->sgfInDB) return "";
  1017. return getCurrentProperty(i, "sgf");
  1018. }
  1019. string GameList::getCurrentProperty(int i, string tag) throw(DBError) {
  1020. if (i < 0 || i >= (int)currentList->size()) {
  1021. // printf("index out of range\n");
  1022. return "";
  1023. }
  1024. int index = (*all)[(*currentList)[i].second]->id;
  1025. char* prop = 0;
  1026. char sql[200];
  1027. sprintf(sql, "select %s from GAMES where id = %d;", tag.c_str(), index);
  1028. // printf("%s\n", sql);
  1029. int rc = sqlite3_exec(db, sql, getpropcallback, &prop, 0);
  1030. if (rc != SQLITE_OK) throw DBError();
  1031. if (!prop) return "";
  1032. string prop_str(prop);
  1033. delete [] prop;
  1034. return prop_str;
  1035. }
  1036. void GameList::search(Pattern& pattern, SearchOptions* so) throw(DBError) {
  1037. if (mrs_pattern) delete mrs_pattern;
  1038. mrs_pattern = new Pattern(pattern);
  1039. if (searchOptions) delete searchOptions;
  1040. if (so) searchOptions = new SearchOptions(*so);
  1041. else searchOptions = new SearchOptions();
  1042. PatternList pl(pattern, searchOptions->fixedColor, searchOptions->nextMove, this);
  1043. if (boardsize != pattern.boardsize) {
  1044. delete searchOptions;
  1045. searchOptions = 0;
  1046. if (oldList) delete oldList;
  1047. oldList = 0;
  1048. if (currentList) delete currentList;
  1049. currentList = new vector<pair<int,int> >;
  1050. return;
  1051. }
  1052. int hash_result = -1;
  1053. // FULL BOARD PATTERN?
  1054. if ((searchOptions->algos & ALGO_HASH_FULL) && pattern.sizeX==pattern.boardsize && pattern.sizeY==pattern.boardsize && algo_ps[algo_hash_full]) {
  1055. hash_result = ((Algo_hash_full*)algo_ps[algo_hash_full])->search(pl, *this, *searchOptions);
  1056. // printf("hash result %d\n", hash_result);
  1057. if (hash_result == 1) {
  1058. // hashing worked and fullboard hash algorithm is trusted
  1059. } else if (hash_result == 0) {
  1060. // hashing worked, but we will check with algo_movelist
  1061. if (searchOptions->algos & ALGO_MOVELIST && algo_ps[algo_movelist])
  1062. algo_ps[algo_movelist]->search(pl, *this, *searchOptions);
  1063. }
  1064. }
  1065. if (hash_result == -1) { // not a full board pattern (or not hashable)
  1066. // printf("hr -1\n");
  1067. // CORNER PATTERN?
  1068. if ((searchOptions->algos & ALGO_HASH_CORNER) && algo_ps[algo_hash_corner]) {
  1069. hash_result = ((Algo_hash_corner*)algo_ps[algo_hash_corner])->search(pl, *this, *searchOptions);
  1070. if (hash_result == 0) {
  1071. // printf("use hash corner\n");
  1072. if (searchOptions->algos & ALGO_MOVELIST && algo_ps[algo_movelist])
  1073. algo_ps[algo_movelist]->search(pl, *this, *searchOptions);
  1074. // printf("%d candidates\n", oldList->size());
  1075. }
  1076. }
  1077. if (hash_result == -1) {
  1078. // printf("no hashing\n");
  1079. if (searchOptions->algos & ALGO_FINALPOS && algo_ps[algo_finalpos])
  1080. algo_ps[algo_finalpos]->search(pl, *this, *searchOptions);
  1081. // printf("%d candidates\n", currentList->size());
  1082. if (searchOptions->algos & ALGO_MOVELIST && algo_ps[algo_movelist])
  1083. algo_ps[algo_movelist]->search(pl, *this, *searchOptions);
  1084. }
  1085. }
  1086. if (labels) delete [] labels;
  1087. labels = pl.sortContinuations();
  1088. for(vector<Continuation* >::iterator it = continuations.begin(); it != continuations.end(); it++)
  1089. delete *it;
  1090. continuations.clear();
  1091. for(vector<Continuation* >::iterator it = pl.continuations.begin(); it != pl.continuations.end(); it++)
  1092. continuations.push_back(*it);
  1093. // printf("cont %d\n", continuations[15+15*19].B+continuations[15+15*19].W);
  1094. pl.continuations.clear();
  1095. update_dates_current();
  1096. }
  1097. int GameList::plSize() {
  1098. return pl.size();
  1099. }
  1100. string GameList::plEntry(int i) {
  1101. if (i < 0 || i >= (int)pl.size()) return "";
  1102. else return pl[i];
  1103. }
  1104. int rpl_callback(void *pl, int argc, char **argv, char **azColName) {
  1105. if (!argc) return 1;
  1106. ((vector<string>*)pl)->push_back(string(argv[0]));
  1107. return 0;
  1108. }
  1109. void GameList::readPlayersList() throw(DBError) {
  1110. if (pl.size()) pl = vector<string>();
  1111. sqlite3_exec(db, "select p from (select pw p from GAMES union select pb p from GAMES) order by lower(p)", rpl_callback, &pl, 0);
  1112. // we ignore possible errors, since the table might not yet exist
  1113. }
  1114. int rnw_callback(void *num, int argc, char **argv, char **azColName) {
  1115. int* n = (int*)num;
  1116. if (!argc) return 1;
  1117. *n = atoi(argv[0]);
  1118. return 0;
  1119. }
  1120. void GameList::readNumOfWins() throw(DBError) {
  1121. int* pi = new int;
  1122. sqlite3_exec(db, "select count(rowid) from GAMES where RE like 'B%'", rnw_callback, pi, 0);
  1123. Bwins = BwinsAll = *pi;
  1124. sqlite3_exec(db, "select count(rowid) from GAMES where RE like 'W%'", rnw_callback, pi, 0);
  1125. Wwins = WwinsAll = *pi;
  1126. delete pi;
  1127. }
  1128. void GameList::createGamesDB() throw(DBError) {
  1129. SGFtags = p_op->SGFTagsAsStrings();
  1130. string sql1 = "create table if not exists GAMES ( ";
  1131. sql1 += "id integer primary key, ";
  1132. sql1 += "path text, ";
  1133. sql1 += "filename text, ";
  1134. sql1 += "pos integer default 0, ";
  1135. // sql1 += "duplicate integer, ";
  1136. sql1 += "signature text, "; // symmetrized signature
  1137. sql1 += "fphash long, "; // hashcode of final position to detect duplicates
  1138. sql1 += "dbtree text, ";
  1139. sql1 += "date date";
  1140. sql_ins_rnp = "insert into GAMES (path, filename, pos, dbtree, date";
  1141. string question_marks = "?,?,?,?,?";
  1142. if (p_op->sgfInDB) {
  1143. sql1 += ", sgf text";
  1144. sql_ins_rnp += ", sgf";
  1145. question_marks += ",?";
  1146. }
  1147. SGFtagsSize = SGFtags->size();
  1148. int ctr = 0;
  1149. posDT = posSZ = posWR = posBR = posHA = -1;
  1150. for(vector<string>::iterator it = SGFtags->begin(); it != SGFtags->end(); it++) {
  1151. sql1 += ", " + *it + " text";
  1152. sql_ins_rnp += ", " + *it;
  1153. question_marks += ",?";
  1154. if (*it == "DT") posDT = ctr;
  1155. if (*it == "SZ") posSZ = ctr;
  1156. if (*it == "WR") posWR = ctr;
  1157. if (*it == "BR") posBR = ctr;
  1158. if (*it == "HA") posHA = ctr;
  1159. ctr++;
  1160. }
  1161. if (posDT == -1) throw DBError();
  1162. if (posSZ == -1) {
  1163. posSZ = SGFtags->size();
  1164. SGFtags->push_back("SZ");
  1165. }
  1166. if (posWR == -1) {
  1167. posWR = SGFtags->size();
  1168. SGFtags->push_back("WR");
  1169. }
  1170. if (posBR == -1) {
  1171. posBR = SGFtags->size();
  1172. SGFtags->push_back("BR");
  1173. }
  1174. if (posHA == -1) {
  1175. posHA = SGFtags->size();
  1176. SGFtags->push_back("HA");
  1177. }
  1178. sql1 += ");";
  1179. sql_ins_rnp += ") values (" + question_marks + ");";
  1180. // printf("sql insert %s\n", sql_ins_rnp.c_str());
  1181. int rc = sqlite3_exec(db, sql1.c_str(), 0, 0, 0);
  1182. if(rc != SQLITE_OK) throw DBError();
  1183. sql1 = "create index if not exists dateindex on GAMES (date);";
  1184. rc = sqlite3_exec(db, sql1.c_str(), 0, 0, 0);
  1185. if (rc != SQLITE_OK) throw DBError();
  1186. sql1 = "create table if not exists GAME_TAGS ( id integer primary key, game_id integer, tag_id integer, unique(game_id, tag_id) );";
  1187. rc = sqlite3_exec(db, sql1.c_str(), 0, 0, 0);
  1188. if (rc != SQLITE_OK) throw DBError();
  1189. }
  1190. void GameList::start_processing(int PROCESSVARIATIONS) throw(DBError) {
  1191. // printf("enter start_processing %p\n", p_op);
  1192. // printf("dt %d sz %d\n", posDT, posSZ);
  1193. processVariations = (PROCESSVARIATIONS != -1) ? PROCESSVARIATIONS : p_op->processVariations;
  1194. delete_all_snapshots();
  1195. createGamesDB();
  1196. current = 0;
  1197. const char* sql = "begin transaction;";
  1198. int rc = sqlite3_exec(db, sql, 0, 0, 0);
  1199. if (rc) { throw DBError(); }
  1200. }
  1201. void GameList::finalize_processing() throw(DBError) {
  1202. // printf("enter finalize_processing %d\n", db);
  1203. for(unsigned int a=0; a<20; a++) if (algo_ps[a]) algo_ps[a]->finalize_process();
  1204. int rc = sqlite3_exec(db, "commit;", 0, 0, 0);
  1205. if (rc != SQLITE_OK) {
  1206. sqlite3_close(db);
  1207. db = 0;
  1208. throw DBError();
  1209. }
  1210. if (rc != SQLITE_OK) throw DBError();
  1211. // sqlite3_close(db);
  1212. // db = 0;
  1213. // write algorithm data to file
  1214. string a_dbname(dbname);
  1215. a_dbname[a_dbname.size()-1] = 'a';
  1216. ofstream os(a_dbname.c_str(), ios::binary);
  1217. for(vector<algo_p>::iterator it = algo_ps.begin(); it != algo_ps.end(); it++) {
  1218. if (*it) {
  1219. SnapshotVector data = (*it)->get_data();
  1220. size_t size1 = data.size();
  1221. os.write((const char*)&size1, sizeof(size1));
  1222. os.write((const char*)&data[0], size1);
  1223. }
  1224. }
  1225. os.close();
  1226. readDB();
  1227. delete SGFtags;
  1228. }
  1229. int GameList::process(const char* sgf, const char* path, const char* fn, std::vector<GameList* > glists, const char* DBTREE, int flags) throw(SGFError,DBError) {
  1230. process_results_vector.clear();
  1231. const char* dbtree = "";
  1232. if (DBTREE) dbtree = DBTREE;
  1233. Cursor* c = 0;
  1234. try {
  1235. c = new Cursor(sgf, 1); // parse sgf sloppily
  1236. } catch (SGFError) {
  1237. return 0;
  1238. }
  1239. Node* root = c->root->next;
  1240. int pos = 0;
  1241. while (root) {
  1242. current++;
  1243. int return_val = 0;
  1244. // if (!(current%1000)) {
  1245. // char* sql = "end transaction;";
  1246. // int rc = sqlite3_exec(db, sql, 0, 0, 0);
  1247. // if (rc) {
  1248. // sqlite3_close(db);
  1249. // db = 0;
  1250. // throw DBError();
  1251. // }
  1252. // sql = "begin transaction;";
  1253. // rc = sqlite3_exec(db, sql, 0, 0, 0);
  1254. // if (rc) {
  1255. // sqlite3_close(db);
  1256. // db = 0;
  1257. // throw DBError();
  1258. // }
  1259. // }
  1260. vector<string>* rootNodeProperties = parseRootNode(root, SGFtags);
  1261. // for(vector<string>::iterator rnp = rootNodeProperties->begin(); rnp != rootNodeProperties->end(); rnp++)
  1262. // printf("rnp %s\n", rnp->c_str());
  1263. // check board size
  1264. string sz = (*rootNodeProperties)[posSZ];
  1265. // printf("sz %s\n", sz.c_str());
  1266. if (sz=="") sz = "19";
  1267. int bs = atoi(sz.c_str());
  1268. if (bs != boardsize) {
  1269. return_val |= UNACCEPTABLE_BOARDSIZE;
  1270. process_results_vector.push_back(return_val);
  1271. delete rootNodeProperties;
  1272. root = root->down;
  1273. pos++;
  1274. continue;
  1275. }
  1276. // parse DT tag
  1277. string dt = (*rootNodeProperties)[posDT];
  1278. // printf("dt %s\n", dt.c_str());
  1279. string date;
  1280. bool year_found = false;
  1281. int p = 0;
  1282. while (!year_found && p < (int)dt.size()) {
  1283. p = dt.find_first_of("0123456789", p);
  1284. if (p == (int)string::npos || p+4 > (int)dt.size() ) break;
  1285. else {
  1286. year_found = (('0' <= dt[p] && dt[p] <= '9') && ('0' <= dt[p+1] && dt[p+1] <= '9') && ('0' <= dt[p+2] && dt[p+2] <= '9') && ('0' <= dt[p+3] && dt[p+3] <= '9'));
  1287. if (year_found && (int)dt.find_first_of("0123456789", p+4) != p+4) { // success: found 4 digits in a row
  1288. date += dt.substr(p,4);
  1289. date += '-';
  1290. dt.erase(p,4);
  1291. } else {
  1292. while ('0' <= dt[p] && dt[p] <= '9') p++;
  1293. year_found = false;
  1294. continue;
  1295. }
  1296. }
  1297. }
  1298. if (!year_found) date = "0000-00-00";
  1299. else {
  1300. bool month_found = false;
  1301. p = 0;
  1302. while (!month_found && p < (int)dt.size()) {
  1303. p = dt.find_first_of("0123456789", p);
  1304. if (p == (int)string::npos || p+2 > (int)dt.size() ) break;
  1305. else {
  1306. month_found = ('0' <= dt[p] && dt[p] <= '9' && '0' <= dt[p+1] && dt[p+1] <= '9');
  1307. if (month_found && (int)dt.find_first_of("0123456789", p+2) != p+2) {
  1308. date += dt.substr(p,2);
  1309. date += '-';
  1310. dt.erase(p,2);
  1311. } else {
  1312. while ('0' <= dt[p] && dt[p] <= '9') p++;
  1313. month_found = false;
  1314. continue;
  1315. }
  1316. }
  1317. }
  1318. if (!month_found) date += "00-00";
  1319. else {
  1320. bool day_found = false;
  1321. p = 0;
  1322. while (!day_found && p < (int)dt.size()) {
  1323. p = dt.find_first_of("0123456789", p);
  1324. if (p == (int)string::npos || p+2 > (int)dt.size() ) break;
  1325. else {
  1326. day_found = ('0' <= dt[p] && dt[p] <= '9' && '0' <= dt[p+1] && dt[p+1] <= '9');
  1327. if (day_found && (int)dt.find_first_of("0123456789", p+2) != p+2) {
  1328. date += dt.substr(p,2);
  1329. } else {
  1330. while ('0' <= dt[p] && dt[p] <= '9') p++;
  1331. day_found = false;
  1332. continue;
  1333. }
  1334. }
  1335. }
  1336. if (!day_found) date += "00";
  1337. }
  1338. }
  1339. // printf("sql %s\n", sql_ins_rnp.c_str());
  1340. sqlite3_stmt *ppStmt=0;
  1341. int rc = sqlite3_prepare(db, sql_ins_rnp.c_str(), -1, &ppStmt, 0);
  1342. if (rc != SQLITE_OK || ppStmt==0) {
  1343. throw DBError();
  1344. }
  1345. int stmt_ctr = 1;
  1346. rc = sqlite3_bind_text(ppStmt, stmt_ctr++, path, -1, SQLITE_TRANSIENT);
  1347. if (rc != SQLITE_OK) throw DBError

Large files files are truncated, but you can click here to view the full file