#ifndef _HEADER_HISTORY_H #define _HEADER_HISTORY_H #include "position.h" #include "hash.h" #include "sysproc.h" class THistory { #ifndef NO_FILES public: static char FileName[1024]; #endif public: THistory(int id = 0) {if (id >= 0) Hid = NHid++; else Hid = id;} int GetId() const {return Hid;} static int GetNId() {return NHid;} int Start(const Position &pos) const; int Move(const Position &pos, const unsigned char mv[], int nmove) const; int Play(const PlayWrite &play) const; #ifndef NO_FILES static int InitHFile(char *dname = 0); static int HRead(FILE *f, PlayWrite *&play); protected: int Print(const char *str) const; #endif int Hid; static int NHid; protected: struct TStr { TStr(const char *ss = 0) : s(0) {(*this) = ss;} TStr(const TStr &ss) : s(0) {(*this) = ss.s;} ~TStr() {(*this) = 0;} TStr &operator=(const char *ss); TStr &operator=(const TStr &ss) {return (*this) = ss.s;} operator char*() {return s;} operator const char*() const {return s;} char &operator*() {return *s;} const char &operator*() const {return *s;} char &operator[](int i) {return s[i];} const char &operator[](int i) const {return s[i];} void Extend(int n); friend int operator==(const TStr &s1, const TStr &s2) {return strcmp(s1, s2) == 0;} friend int operator==(const char *s1, const TStr &s2) {return strcmp(s1, s2) == 0;} friend int operator==(const TStr &s1, const char *s2) {return strcmp(s1, s2) == 0;} friend int operator!=(const TStr &s1, const TStr &s2) {return strcmp(s1, s2) != 0;} friend int operator!=(const char *s1, const TStr &s2) {return strcmp(s1, s2) != 0;} friend int operator!=(const TStr &s1, const char *s2) {return strcmp(s1, s2) != 0;} friend int operator>=(const TStr &s1, const TStr &s2) {return strcmp(s1, s2) >= 0;} friend int operator>=(const char *s1, const TStr &s2) {return strcmp(s1, s2) >= 0;} friend int operator>=(const TStr &s1, const char *s2) {return strcmp(s1, s2) >= 0;} friend int operator<=(const TStr &s1, const TStr &s2) {return strcmp(s1, s2) <= 0;} friend int operator<=(const char *s1, const TStr &s2) {return strcmp(s1, s2) <= 0;} friend int operator<=(const TStr &s1, const char *s2) {return strcmp(s1, s2) <= 0;} friend int operator>(const TStr &s1, const TStr &s2) {return strcmp(s1, s2) > 0;} friend int operator>(const char *s1, const TStr &s2) {return strcmp(s1, s2) > 0;} friend int operator>(const TStr &s1, const char *s2) {return strcmp(s1, s2) > 0;} friend int operator<(const TStr &s1, const TStr &s2) {return strcmp(s1, s2) < 0;} friend int operator<(const char *s1, const TStr &s2) {return strcmp(s1, s2) < 0;} friend int operator<(const TStr &s1, const char *s2) {return strcmp(s1, s2) < 0;} char *s; }; class THash { public: void init(int _m); int operator()(const TStr &str) const; protected: int m; int K[16]; }; struct TTableItem { TTableItem(const char *s = 0, int k = 0) : str(s), k(k) {} TTableItem(const TStr &s, int k = 0) : str(s), k(k) {} TTableItem(const TTableItem &t) : str(t.str), k(t.k) {} operator TStr&() {return str;} operator const TStr&() const {return str;} TStr str; int k; }; }; #ifndef NO_FILES char THistory::FileName[1024] = "history.che"; #endif int THistory::NHid = 0; #ifndef NO_FILES int THistory::Print(const char *str) const { char *line = new char[30 + strlen(str)]; if (!line) return 0; unsigned long pr_id = GetProcessId(); if (Hid == -1) sprintf(line, "%lu %s\n", pr_id, str); else if (Hid < 0) sprintf(line, "%lu%c %s\n", pr_id, (char)Hid, str); else sprintf(line, "%lu:%d %s\n", pr_id, Hid, str); FILE *f = fopen(FileName, "at"); if (!f) { clock_t cc = clock(); do {f = fopen(FileName, "at");} while(!f && (clock() - cc) <= 0.05 * CLOCKS_PER_SEC); } if (!f) {delete[] line; return 0;} fputs(line, f); fclose(f); delete[] line; return 1; } #endif int THistory::Start(const Position &pos) const { #ifndef NO_FILES char str[20 + NUM_CELL] = "Start "; if (!pos.Write(str + strlen(str), 1)) return 0; if (!Print(str)) return 0; #endif return 1; } int THistory::Move(const Position &pos, const unsigned char mv[], int nmove) const { #ifndef NO_FILES char *str = new char[15 + pos.GetLenMvEx(mv, 11)]; if (!str) return 0; sprintf(str, "%d.%s ", (nmove + 1) / 2, (nmove % 2 == 0) ? ".." : ""); pos.WriteMvEx(mv, str + strlen(str), 11); if (!Print(str)) {delete[] str; return 0;} delete[] str; #endif return 1; } int THistory::Play(const PlayWrite &play) const { if (play.GetN() <= 0) return 0; Position pos; if (play.GetPos(pos, 0) < 0) return 0; if (!Start(pos)) return 0; int i; unsigned char mv[NUM_CELL]; for (i = 1; i < play.GetN(); i++) { if (play.GetPos(pos, i - 1) < 0) return 0; if (play.GetMove(mv, i) < 0) return 0; if (!Move(pos, mv, i)) return 0; } return 1; } #ifndef NO_FILES int THistory::InitHFile(char *dname) { if (dname && dname[0]) { char fnm[1024]; strcpy(fnm, dname); int i; for (i = strlen(fnm) - 1; i >= 0; i--) { if (fnm[i] == DIR_SEPARATOR) break; } if (i >= 0) { strcpy(fnm + i + 1, FileName); strcpy(FileName, fnm); } } int e = 1; FILE *f = fopen(FileName, "rt"); if (f) {e = feof(f); fclose(f);} if (!e) return 0; f = fopen(FileName, "wt"); if (!f) return -1; fputs("checkers-history_1.1\n", f); fclose(f); return 1; } #endif THistory::TStr &THistory::TStr::operator=(const char *ss) { if (s) delete[] s; if (ss) { s = new char[strlen(ss) + 1]; strcpy(s, ss); } else s = 0; return *this; } void THistory::TStr::Extend(int n) { if (n <= 0) {(*this) = 0; return;} char *ss = s; s = new char[n+1]; if (ss) { strncpy(s, ss, n); s[n] = 0; delete[] ss; } else s[0] = 0; } void THistory::THash::init(int _m) { m = _m; for (int i = 0; i < 16; i++) { K[i] = (2*random(32767) + 1) & ((1 << m) - 1); } } int THistory::THash::operator()(const TStr &str) const { int i, r = 0; const char *s = str; for (i = 0; *s; i = (i+1) & 15) r += *(s++) * K[i]; r &= (1 << m) - 1; return r; } #ifndef NO_FILES int THistory::HRead(FILE *f, PlayWrite *&play) { const int MAX_INP_WORD = 100; int nplay = 0, mplay = 10; play = new PlayWrite[mplay]; THashTable table; TStr word; char inp_word[MAX_INP_WORD + 1]; int r, maxword = 0; unsigned char ch; int i, k = 0, kind = 0, wasspace = 1, nmove = 0; for (;;) { r = (fread(&ch, 1, 1, f) == 1); if (!r || isspace(ch)) { if (!wasspace) { if (kind == 0) kind = 1; else if (kind == 2) { for (i = 0; inp_word[i]; i++) { inp_word[i] = (char)tolower((unsigned char)inp_word[i]); } if (strcmp(inp_word, "start") == 0) kind = 5; else kind = -1; inp_word[0] = 0; k = 0; } else if (kind == 3) { nmove *= 2; if (k <= 1) nmove--; inp_word[0] = 0; k = 0; kind = 4; } else if (kind == 4) { TTableItem *n_pl = table.find(word); if (!n_pl) kind = -1; else if (nmove < 1 || nmove > play[n_pl->k].GetN()) kind = -1; else { PlayWrite::PMv pmv; if (play[n_pl->k].GetPos(pmv.pos, nmove - 1) < 0) kind = -1; else if (!pmv.pos.ReadMv(pmv.mv, inp_word, 1)) kind = -1; else { play[n_pl->k].ClearFrom(nmove); if (play[n_pl->k].Add(pmv.mv) != 0) kind = -1; else {k = n_pl->k; kind = 11;} } } } else if (kind == 5) { Position pos; pos.Read(inp_word, 1); if (pos.IsNull()) kind = -1; else { TTableItem *n_pl = table.find(word); if (!n_pl) { table.push(TTableItem(word, nplay)); n_pl = table.find(word); } if (!n_pl) kind = -1; else { if (nplay >= mplay) { PlayWrite *play0 = play; int mplay0 = mplay; mplay = 2*nplay + 3; play = new PlayWrite[mplay]; if (play0) { for (i = 0; i < mplay0; i++) play[i] = play0[i]; delete[] play0; } } n_pl->k = nplay++; play[n_pl->k].Add(0, pos); k = n_pl->k; kind = 12; } } } } if (!r || ch == '\n' || ch == '\r') { k = 0; kind = 0; if (!r) break; } wasspace = 1; } else { if (kind == 0) { if (k >= maxword) word.Extend(2*k + 3); word[k++] = ch; word[k] = 0; } else if (kind == 1) { if (isdigit(ch)) {nmove = ch - '0'; k = 0; kind = 3;} else { inp_word[0] = ch; inp_word[1] = 0; k = 1; kind = 2; } } else if (kind == 2 || kind == 4 || kind == 5) { if (k < MAX_INP_WORD) { inp_word[k++] = ch; inp_word[k] = 0; } } else if (kind == 3) { if (k == 0 && isdigit(ch)) nmove = 10 * nmove + ch - '0'; else if (ch == '.') k++; else kind = -1; } wasspace = 0; } } return nplay; } #endif #endif //_HEADER_HISTORY_H