#ifndef _HEADER_POSITION_H #define _HEADER_POSITION_H #include #include #include #include #define NELEM(a) (sizeof(a) / sizeof((a)[0])) const int NW_CELL = 8; const int NUM_CELL = NW_CELL * NW_CELL / 2; const int LEN_WPOS = (NUM_CELL + 2) / 3; inline int PoleCpos(int i, int j) { return (i + j) % 2 != 0; } inline int PoleToNum(int i, int j) { return j * (NW_CELL / 2) + i/2; } inline void NumToPole(int k, int &i, int &j) { j = k / (NW_CELL / 2); i = k % (NW_CELL / 2); i *= 2; if (j % 2 == 0) i++; } class Position { public: char SH[NUM_CELL]; char wmove; Position() {Init();} Position(const Position &p); Position& operator=(const Position &p); void Init(); int IsNull() const; void Add(int np, char sh) {SH[np] = sh;} void Del(int np) {SH[np] = 0;} void Move(int np0, int np1) {if (np0 != np1) {SH[np1] = SH[np0]; SH[np0] = 0;}} static int BecameD(int np, char ch); enum {AWrong = -1, AWColor = -2, AfCell = -3, AnfCell = -4, AMustEatMore = -5, AMustEat = -6, ANoMove = -7, AChBack = -8, ANotDm = -9, AOnlyDiag = -10, AEatYour = -11, AMoreOne = -12, ANotDmE = -13, AMustEatMoreD = -14, ATurnBack = -15}; int ScanSide(int x, int y, int sx, int sy, int sh_k = -1) const; int CanEat(int k, int psx = 0, int psy = 0, int sh_k = -1) const; int CanMove(int k) const; int AChCell(int k); int AMove(const unsigned char MV[], int k = -1, int &mkmove = *(int*)0); int AllCanEat(int w = -1) const; int AllCanMove(int w = -1) const; char *Write(char WP[], int how = 0) const; Position &Read(const char WP[], int how = 0); static char *WriteMv(const unsigned char mv[], char WP[], int how = 0); int WriteMvEx(const unsigned char mv[], char WP[], int how = 0) const; static unsigned char *ReadMv(unsigned char mv[], const char WP[], int how = 0); static int GetLenMv(const unsigned char mv[], int how = 0); int GetLenMvEx(const unsigned char mv[], int how = 0) const; static int GetLenMwr(const char WP[], int how = 0); static void SetNullMv(unsigned char mv[]) {mv[0] = 0;} void Reverse(); }; Position::Position(const Position &p) : wmove(p.wmove) { for(int i = 0; i < NUM_CELL; i++) SH[i] = p.SH[i]; } Position& Position::operator=(const Position &p) { wmove = p.wmove; for(int i = 0; i < NUM_CELL; i++) SH[i] = p.SH[i]; return *this; } void Position::Init() { wmove = 0; for (int i = 0; i < NUM_CELL; i++) SH[i] = 0; } int Position::IsNull() const { for (int i = 0; i < NUM_CELL; i++) if (SH[i] != 0) return 0; return 1; } inline int Position::BecameD(int np, char ch) { int x, y; NumToPole(np, x, y); return ch == 1 && y == NW_CELL - 1 || ch == 2 && y == 0; } char *Position::Write(char WP[], int how) const { if (how == 0) { int i = 0, j; for (j = 0; i < NUM_CELL; j++) { WP[j] = SH[i++]; if (i < NUM_CELL) {WP[j] *= (char)5; WP[j] += SH[i++];} if (i < NUM_CELL) {WP[j] *= (char)5; WP[j] += SH[i++];} if (i >= NUM_CELL) {WP[j] *= (char)2; WP[j] += wmove;} WP[j]++; } } else if (how == 1) { int i; for (i = NUM_CELL - 1; i >= 0; i--) { if (SH[i] < 0 || SH[i] >= 5) return 0; } for (i = 0; i < NUM_CELL; i++) { const char SYMBOL[5] = {'0', 'R', 'B', 'X', 'Z'}; WP[i] = SYMBOL[SH[NUM_CELL - 1 - i]]; } WP[NUM_CELL] = ':'; WP[NUM_CELL + 1] = (wmove == 0) ? 'r' : 'b'; WP[NUM_CELL + 2] = 0; } return WP; } Position &Position::Read(const char WP[], int how) { if (how == 0) { int i = 0, j, ii; for (j = 0; i < NUM_CELL; j++) { unsigned int cwp = WP[j] - 1; if (i >= NUM_CELL - 3) { wmove = char(cwp % 2); cwp /= 2; ii = NUM_CELL - 1; } else ii = i + 2; while(ii >= i) {SH[ii--] = char(cwp % 5); cwp /= 5;} i += 3; } } else if (how == 1) { int i; wmove = 0; for (i = 0; i < NUM_CELL; i++) { switch(WP[i]) { case '0': case '-': case '.': case 'F': case 'f': SH[NUM_CELL - 1 - i] = 0; break; case '1': case 'A': case 'a': case 'R': case 'r': SH[NUM_CELL - 1 - i] = 1; break; case '2': case 'B': case 'b': case 'S': case 's': SH[NUM_CELL - 1 - i] = 2; break; case '3': case 'W': case 'w': case 'X': case 'x': SH[NUM_CELL - 1 - i] = 3; break; case '4': case 'Y': case 'y': case 'Z': case 'z': SH[NUM_CELL - 1 - i] = 4; break; default: Init(); return *this; } } if (WP[NUM_CELL] == ':') { char c = WP[NUM_CELL + 1]; if (c == 'B' || c == 'b' || c == 'S' || c == 's' || c == 'Y' || c == 'y' || c == 'Z' || c == 'z') { wmove = 1; } } } return *this; } char *Position::WriteMv(const unsigned char mv[], char WP[], int how) { int i, nmv = 0; if (mv) nmv = mv[0]; if (how == 0) { WP[0] = char(nmv + 1); for (i = 1; i <= nmv; i++) WP[i] = char(mv[i] + 1); } else if (how == 1) { int j = 0; for (i = 1; i <= nmv; i++) { int x, y; NumToPole(mv[i], x, y); WP[j++] = char('a' + NW_CELL - 1 - x); int r = itoa(WP + j, 1 + y); if (r > 0) j += r; if (i != nmv) WP[j++] = '-'; } WP[j] = 0; } return WP; } unsigned char *Position::ReadMv(unsigned char mv[], const char WP[], int how) { int i; if (how == 0) { mv[0] = char(WP[0] - 1); for (i = 1; i <= mv[0]; i++) mv[i] = char(WP[i] - 1); } else if (how == 1) { int j = 0, x = -1, y = -1; mv[0] = 0; for (;;) { if (isdigit(WP[j])) { y = atoi(WP + j) - 1; while (isdigit(WP[j])) j++; } else if (islower(WP[j])) x = NW_CELL - 1 - (WP[j++] - 'a'); else { if (x >= 0 && y >= 0 && x < NW_CELL && y < NW_CELL) { mv[++mv[0]] = (char)PoleToNum(x, y); } else if (y >= 0 && y < NUM_CELL) mv[++mv[0]] = (char)(NUM_CELL - 1 - y); x = -1; y = -1; if (WP[j] == '-' || WP[j] == '*' || WP[j] == ':') j++; else break; } if (x >= 0 && y >= 0 && x < NW_CELL && y < NW_CELL) { mv[++mv[0]] = (char)PoleToNum(x, y); x = -1; y = -1; } } } return mv; } int Position::GetLenMv(const unsigned char mv[], int how) { if (how == 0) return mv ? (1 + mv[0]) : 1; else if (how == 1) { int i, j = 0; if (!mv) return 1; for (i = 1; i <= mv[0]; i++) { int x, y; NumToPole(mv[i], x, y); j++; y++; while(y > 0) {j++; y /= 10;} if (i != mv[0]) j++; } return ++j; } else return 0; } int Position::GetLenMwr(const char WP[], int how) { if (how == 0) return (unsigned char)WP[0]; else if (how == 1) { int j; for (j = 0; WP[j] == '-' || WP[j] == '*' || WP[j] == ':' || isdigit(j) || islower(j); j++); return j + 1; } else return 0; } inline int Position::GetLenMvEx(const unsigned char mv[], int how) const { return WriteMvEx(mv, 0, how); } int Position::WriteMvEx(const unsigned char mv[], char WP[], int how) const { if (how == 11) { Position pos = *this; int p, L = 0, was_d = 0; for (p = 1; p <= mv[0]; p++) { if (!was_d && pos.SH[mv[p]] > 2) { if (WP) WP[L] = '*'; L++; was_d = 1; } int x0, y0, x1, y1; NumToPole(mv[p], x0, y0); if (WP) { WP[L++] = char('a' + NW_CELL - 1 - x0); int r = itoa(WP + L, 1 + y0); if (r > 0) L += r; } else { L++; int g = y0 + 1; while(g > 0) {L++; g /= 10;} } if (p >= mv[0]) break; NumToPole(mv[p+1], x1, y1); int mi = abs(x1 - x0), i, eat = -1; if (mi > 0 && mi == abs(y1 - y0)) { int sx = (x1 > x0) ? 1 : -1; int sy = (y1 > y0) ? 1 : -1; for (i = 1; i < mi; i++) { int r = PoleToNum(x0 + i * sx, y0 + i * sy); if (pos.SH[r] != 0) { eat = r; pos.Del(r); } } } if (WP) WP[L] = (eat >= 0) ? ':' : '-'; L++; if (pos.SH[mv[p]] == 1 && y1 == NW_CELL - 1) pos.SH[mv[p]] = 3; else if (pos.SH[mv[p]] == 2 && y1 == 0) pos.SH[mv[p]] = 4; pos.Move(mv[p], mv[p+1]); } if (WP) WP[L] = 0; L++; return L; } else { if (WP) WriteMv(mv, WP, how); return GetLenMv(mv, how); } } int Position::ScanSide(int x, int y, int sx, int sy, int sh_k) const { if (sh_k < 0) sh_k = SH[PoleToNum(x, y)]; if (sh_k < 1 || sh_k > 4) return -2; if (sh_k >= 2) sh_k -= 2; int i, i0, i1, f = 0, g = 0; if (sx < 0) i0 = x; else i0 = NW_CELL - x - 1; if (sy < 0) i1 = y; else i1 = NW_CELL - y - 1; if (i0 > i1) i0 = i1; for (i = 1; i <= i0; i++) { char nk = SH[PoleToNum(x + i*sx, y + i*sy)]; if (nk) { if (f || (nk != 3 - sh_k && nk != 5 - sh_k)) return g; else f = 1; } else if (f) return (i == 2) ? 4 : (2 + g); else if (i == 1) g = 1; } return g; } int Position::CanEat(int k, int psx, int psy, int sh_k) const { int x, y, sx, sy; if (sh_k < 0) sh_k = SH[k]; if (sh_k < 1 || sh_k > 6) return 0; NumToPole(k, x, y); if (sh_k > 4) { int i, i0, i1, f = 0; if (-psx < 0) i0 = x; else i0 = NW_CELL - x - 1; if (-psy < 0) i1 = y; else i1 = NW_CELL - y - 1; if (i0 > i1) i0 = i1; for (i = 1; i <= i0; i++) { int nk = SH[PoleToNum(x - i*psx, y - i*psy)]; if (nk) { if (f || (nk != 7 - sh_k && nk != 9 - sh_k)) break; else f = 1; } else { if (f) return 1; if (ScanSide(x - i*psx, y - i*psy, psy, -psx, sh_k-2) >= 2) return 1; if (ScanSide(x - i*psx, y - i*psy, -psy, psx, sh_k-2) >= 2) return 1; } } } else for (sx = -1; sx <= 1; sx += 2) if (x + 2*sx >= 0 && x + 2*sx < NW_CELL) { for (sy = -1; sy <= 1; sy += 2) { if ((sx != psx || sy != psy) && y + 2*sy >= 0 && y + 2*sy < NW_CELL) { if (sh_k <= 2) { if (SH[PoleToNum(x + 2*sx, y + 2*sy)] == 0) { int nk = SH[PoleToNum(x + sx, y + sy)]; if (nk == 3 - sh_k || nk == 5 - sh_k) return 1; } } else if (ScanSide(x, y, sx, sy, sh_k) >= 2) return 1; } } } return 0; } int Position::CanMove(int k) const { int x, y, xx, yy, y1, y2; NumToPole(k, x, y); if (SH[k] == 1) y1 = y2 = y + 1; else if (SH[k] == 2) y1 = y2 = y - 1; else if (SH[k] != 3 && SH[k] != 4) return 0; else {y1 = y - 1; y2 = y + 1;} for (yy = y1; yy <= y2; yy += 2) if (yy >= 0 && yy < NW_CELL) { for (xx = x - 1; xx <= x + 1; xx += 2) if (xx >= 0 && xx < NW_CELL) { if (SH[PoleToNum(xx, yy)] == 0) return 1; } } return 0; } int Position::AChCell(int k) { if (k < 0 || k >= NUM_CELL) return AWrong; if (SH[k] == 0) return AfCell; if (SH[k] != 1 + wmove && SH[k] != 3 + wmove) return AWColor; if (CanEat(k)) return 1; if (AllCanEat()) return AMustEat; if (CanMove(k)) return 1; return ANoMove; } int Position::AMove(const unsigned char MV[], int k, int &mkmove) { if (k >= NUM_CELL) return AWrong; if (MV[0] <= 0) { if (k < 0) return NUM_CELL; int s = AChCell(k); if (s < 0) return s; else return NUM_CELL; } if (MV[0] == 1 && k < 0) { int s = AChCell(MV[1]); if (s < 0) return s; else return NUM_CELL; } if (SH[MV[1]] == 0) return AfCell; if (SH[MV[1]] != 1 + wmove && SH[MV[1]] != 3 + wmove) return AWColor; int i, mi, p, MV_L, MV_N = MV[0], eat = -1, r; int psx = 0, psy = 0; if (k >= 0) MV_N++; Position pos = *this; for (p = 1; p < MV_N; p++) { int x0, y0, x1, y1, i_eat; if (p < MV[0]) MV_L = MV[p+1]; else if (k < 0) break; else MV_L = k; if (pos.SH[MV_L] != 0) return AnfCell; NumToPole(MV[p], x0, y0); NumToPole(MV_L, x1, y1); mi = abs(x1 - x0); if (mi <= 0 || mi != abs(y1 - y0)) return AOnlyDiag; int sx = (x1 > x0) ? 1 : -1; int sy = (y1 > y0) ? 1 : -1; if (sx == psx && sy == psy) return ATurnBack; psx = -sx; psy = -sy; eat = -1; i_eat = -1; for (i = 1; i < mi; i++) { r = PoleToNum(x0 + i * sx, y0 + i * sy); if (pos.SH[r] != 0) { if (eat >= 0) return AMoreOne; if (pos.SH[r] != 2 - wmove && pos.SH[r] != 4 - wmove) return AEatYour; eat = r; i_eat = i; pos.Del(r); } } if (eat >= 0) { if (pos.SH[MV[p]] <= 2 && mi != 2) return ANotDmE; } else { if (MV_N > 2) return AMustEatMore; if (pos.SH[MV[p]] <= 2) { if (mi != 1) return ANotDm; if (wmove == 0 && y1 < y0 || wmove == 1 && y1 > y0) return AChBack; } if (AllCanEat()) return AMustEat; } if (i_eat >= 0 && pos.SH[MV[p]] > 2) { if (!pos.CanEat(MV_L, psx, psy, pos.SH[MV[p]])) { if (pos.CanEat(PoleToNum(x0 + i_eat*sx, y0 + i_eat*sy), psx, psy, pos.SH[MV[p]] + 2)) { return AMustEatMoreD; } } } if (wmove == 0 && y1 == NW_CELL - 1) pos.SH[MV[p]] = 3; else if (wmove == 1 && y1 == 0) pos.SH[MV[p]] = 4; pos.Move(MV[p], MV_L); } if (&mkmove) { int end = MV_N > 1 && (eat < 0 || !pos.CanEat(MV_L, psx, psy)); if (mkmove == 1 && end) { *this = pos; wmove = !wmove; } if (end) mkmove = 0; else { if (MV_N > 1 && eat >= 0) mkmove = AMustEatMore; else mkmove = AWrong; } } if (k < 0 || eat < 0) eat = NUM_CELL; return eat; } int Position::AllCanEat(int w) const { int k; if (w < 0) w = wmove; for (k = 0; k < NUM_CELL; k++) { if ((SH[k] == w+1 || SH[k] == w+3) && CanEat(k)) return 1; } return 0; } int Position::AllCanMove(int w) const { int k; if (w < 0) w = wmove; for (k = 0; k < NUM_CELL; k++) { if ((SH[k] == w+1 || SH[k] == w+3) && CanMove(k)) return 1; } return 0; } void Position::Reverse() { int i; for (i = 0; i <= (NUM_CELL-1) / 2; i++) { int sh1 = SH[i], sh2 = SH[NUM_CELL - 1 - i]; if (sh1 == 1) sh1 = 2; else if (sh1 == 2) sh1 = 1; else if (sh1 == 3) sh1 = 4; else if (sh1 == 4) sh1 = 3; if (sh2 == 1) sh2 = 2; else if (sh2 == 2) sh2 = 1; else if (sh2 == 3) sh2 = 4; else if (sh2 == 4) sh2 = 3; SH[i] = (char)sh2; SH[NUM_CELL - 1 - i] = (char)sh1; } wmove = !wmove; } class PlayWrite { public: PlayWrite() : play(0), mplay(0), nplay(0), start(0), mstart(0), nstart(0) {} PlayWrite(const PlayWrite &pl) : play(0), mplay(0), nplay(0), start(0), mstart(0), nstart(0) {(*this) = pl;} ~PlayWrite() {Clear();} void Clear(); PlayWrite &operator=(const PlayWrite &pl); int GetN() const {return nstart - 1;} int GetLen() const {return nplay - sizeof(int);} struct PMv { Position pos; unsigned char mv[NUM_CELL]; }; void Add(const unsigned char move[], const Position &pos); void Add(const PMv &pmv) {Add(pmv.mv, pmv.pos);} int Add(const unsigned char move[]); int GetMove(unsigned char move[], int k) const; int GetPos(Position &pos, int k) const; int GetPMv(PMv &pmv, int k) const; int GetMoveL(unsigned char move[], int k = 0) const {return GetMove(move, nstart - 2 - k);} int GetPosL(Position &pos, int k = 0) const {return GetPos(pos, nstart - 2 - k);} int GetPMvL(PMv &pmv, int k = 0) const {return GetPMv(pmv, nstart - 2 - k);} int ClearFrom(int k = 0); int IsDraw(int nmove = -1); protected: void IncPlay(int k); void IncStart(int k); void IncStart() {IncStart(nstart + 1);} void AddStart() {IncStart(); start[nstart++] = nplay;} void Split(); void SplitClear(); protected: char *play; int *start; int mplay, nplay, mstart, nstart; }; void PlayWrite::Clear() { if (play) { if ((*(int*)play) > 0) (*(int*)play)--; else delete[] play; } play = 0; mplay = 0; nplay = 0; if (start) { if (start[0] > 0) start[0]--; else delete[] start; } start = 0; mstart = 0; nstart = 0; } void PlayWrite::Split() { if (play && (*(int*)play) > 0) { (*(int*)play)--; char *play0 = play; mplay = nplay; play = new char[mplay]; memcpy(play, play0, nplay * sizeof(play[0])); (*(int*)play) = 0; } if (start && start[0] > 0) { start[0]--; int *start0 = start; mstart = nstart; start = new int[mstart]; memcpy(start, start0, nstart * sizeof(start[0])); start[0] = 0; } } void PlayWrite::SplitClear() { if (play && (*(int*)play) > 0) { (*(int*)play)--; play = 0; nplay = 0; mplay = 0; } if (start && start[0] > 0) { start[0]--; start = 0; nstart = 0; mstart = 0; } } PlayWrite &PlayWrite::operator=(const PlayWrite &pl) { if (&pl != this) { play = pl.play; (*(int*)play)++; nplay = pl.nplay; mplay = pl.mplay; start = pl.start; start[0]++; nstart = pl.nstart; mstart = pl.mstart; } return *this; } void PlayWrite::IncPlay(int k) { if (mplay < k) { int m0 = mplay; char *play0 = play; mplay = 2*k + 10; play = new char[mplay]; memcpy(play, play0, m0 * sizeof(play[0])); (*(int*)play) = 0; if (play0) { if ((*(int*)play0) > 0) (*(int*)play0)--; else delete[] play0; } } } void PlayWrite::IncStart(int k) { if (mstart < k) { int m0 = mstart; int *start0 = start; mstart = 2*k + 10; start = new int[mstart]; memcpy(start, start0, m0 * sizeof(start[0])); start[0] = 0; if (start0) { if (start0[0] > 0) start0[0]--; else delete[] start0; } } } void PlayWrite::Add(const unsigned char move[], const Position &pos) { Split(); int k = Position::GetLenMv(move); if (nstart < 1) nstart = 1; if (nplay < sizeof(int)) nplay = sizeof(int); AddStart(); IncPlay(nplay + k + LEN_WPOS); Position::WriteMv(move, play + nplay, 0); nplay += k; pos.Write(play + nplay, 0); nplay += LEN_WPOS; } int PlayWrite::Add(const unsigned char move[]) { if (nstart <= 1) return 1; Position pos; GetPosL(pos); int mkmove = 1; int res = pos.AMove(move, -1, mkmove); if (res < 0) return res; else if (mkmove != 0) return mkmove; Add(move, pos); return 0; } int PlayWrite::GetMove(unsigned char move[], int k) const { if (!play || !start) return -1; k++; if (k <= 0 || k >= nstart) return -1; Position::ReadMv(move, play + start[k], 0); return Position::GetLenMv(move); } int PlayWrite::GetPos(Position &pos, int k) const { if (!play || !start) return -1; k++; if (k <= 0 || k >= nstart) return -1; int mlen = Position::GetLenMwr(play + start[k], 0); pos.Read(play + start[k] + mlen, 0); return LEN_WPOS; } int PlayWrite::GetPMv(PMv &pmv, int k) const { if (!play || !start) return -1; k++; if (k <= 0 || k >= nstart) return -1; Position::ReadMv(pmv.mv, play + start[k], 0); int mlen = Position::GetLenMv(pmv.mv); pmv.pos.Read(play + start[k] + mlen, 0); return mlen + LEN_WPOS; } int PlayWrite::ClearFrom(int k) { if (!play || !start) return 0; k++; if (k >= nstart) return 0; if (k <= 1) {Clear(); return 2;} nplay = start[k]; nstart = k; return 1; } int PlayWrite::IsDraw(int nmove) { nmove++; if (nmove <= 0 || nmove > nstart) nmove = nstart; if (!start || nmove <= 3) return 0; int i, j, k, draw = 0; for (i = 1; i < nmove; i++) { k = 1; char *p1 = play + start[i] + Position::GetLenMwr(play + start[i], 0); for (j = 1; j < i; j++) { char *p2 = play + start[j] + Position::GetLenMwr(play + start[j], 0); if (memcmp(p1, p2, LEN_WPOS) == 0) k++; } if (k >= 3) {draw = 1; break;} } return draw; } class TChPlayer { public: TChPlayer() {} typedef struct PlayWrite::PMv PMv; virtual int PlayerID() {return 0;} virtual int Move(PMv &pmv) = 0; int Move(Position &pos, char mv[]); }; int TChPlayer::Move(Position &pos, char mv[]) { PMv pmv; pmv.pos = pos; memcpy(pmv.mv, mv, sizeof(pmv.mv)); int res = Move(pmv); pos = pmv.pos; memcpy(mv, pmv.mv, sizeof(pmv.mv)); return res; } #endif //_HEADER_POSITION_H