Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #ifndef _HEADER_POSITION_H
  2. #define _HEADER_POSITION_H
  3.  
  4. #ifndef __MENUET__
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include <ctype.h>
  9. #endif
  10.  
  11. #define NELEM(a) (sizeof(a) / sizeof((a)[0]))
  12.  
  13. const int NW_CELL = 8;
  14.  
  15. const int NUM_CELL = NW_CELL * NW_CELL / 2;
  16. const int LEN_WPOS = (NUM_CELL + 2) / 3;
  17.  
  18. inline int PoleCpos(int i, int j)
  19. {
  20.   return (i + j) % 2 != 0;
  21. }
  22.  
  23. inline int PoleToNum(int i, int j)
  24. {
  25.   return j * (NW_CELL / 2) + i/2;
  26. }
  27.  
  28. inline void NumToPole(int k, int &i, int &j)
  29. {
  30.   j = k / (NW_CELL / 2);
  31.   i = k % (NW_CELL / 2);
  32.   i *= 2;
  33.   if (j % 2 == 0) i++;
  34. }
  35.  
  36. class Position
  37. {
  38. public:
  39.   char SH[NUM_CELL];
  40.   char wmove;
  41.  
  42.   Position() {Init();}
  43.   Position(const Position &p);
  44.   Position& operator=(const Position &p);
  45.  
  46.   void Init();
  47.   int IsNull() const;
  48.   void Add(int np, char sh) {SH[np] = sh;}
  49.   void Del(int np) {SH[np] = 0;}
  50.   void Move(int np0, int np1) {if (np0 != np1) {SH[np1] = SH[np0]; SH[np0] = 0;}}
  51.   static int BecameD(int np, char ch);
  52.  
  53.   enum {AWrong = -1, AWColor = -2, AfCell = -3, AnfCell = -4,
  54.         AMustEatMore = -5, AMustEat = -6, ANoMove = -7, AChBack = -8,
  55.         ANotDm = -9, AOnlyDiag = -10, AEatYour = -11, AMoreOne = -12,
  56.         ANotDmE = -13, AMustEatMoreD = -14, ATurnBack = -15};
  57.  
  58.   int ScanSide(int x, int y, int sx, int sy, int sh_k = -1) const;
  59.   int CanEat(int k, int psx = 0, int psy = 0, int sh_k = -1) const;
  60.   int CanMove(int k) const;
  61.   int AChCell(int k);
  62.   int AMove(const unsigned char MV[], int k = -1, int &mkmove = *(int*)0);
  63.   int AllCanEat(int w = -1) const;
  64.   int AllCanMove(int w = -1) const;
  65.  
  66.   char *Write(char WP[], int how = 0) const;
  67.   Position &Read(const char WP[], int how = 0);
  68.   static char *WriteMv(const unsigned char mv[], char WP[], int how = 0);
  69.   int WriteMvEx(const unsigned char mv[], char WP[], int how = 0) const;
  70.   static unsigned char *ReadMv(unsigned char mv[], const char WP[], int how = 0);
  71.   static int GetLenMv(const unsigned char mv[], int how = 0);
  72.   int GetLenMvEx(const unsigned char mv[], int how = 0) const;
  73.   static int GetLenMwr(const char WP[], int how = 0);
  74.   static void SetNullMv(unsigned char mv[]) {mv[0] = 0;}
  75.   void Reverse();
  76. };
  77.  
  78. Position::Position(const Position &p) : wmove(p.wmove)
  79. {
  80.   for(int i = 0; i < NUM_CELL; i++) SH[i] = p.SH[i];
  81. }
  82.  
  83. Position& Position::operator=(const Position &p)
  84. {
  85.   wmove = p.wmove;
  86.   for(int i = 0; i < NUM_CELL; i++) SH[i] = p.SH[i];
  87.   return *this;
  88. }
  89.  
  90. void Position::Init()
  91. {
  92.   wmove = 0;
  93.   for (int i = 0; i < NUM_CELL; i++) SH[i] = 0;
  94. }
  95.  
  96. int Position::IsNull() const
  97. {
  98.   for (int i = 0; i < NUM_CELL; i++) if (SH[i] != 0) return 0;
  99.   return 1;
  100. }
  101.  
  102. inline int Position::BecameD(int np, char ch)
  103. {
  104.   int x, y;
  105.   NumToPole(np, x, y);
  106.   return ch == 1 && y == NW_CELL - 1 || ch == 2 && y == 0;
  107. }
  108.  
  109. char *Position::Write(char WP[], int how) const
  110. {
  111.   if (how == 0)
  112.   {
  113.     int i = 0, j;
  114.     for (j = 0; i < NUM_CELL; j++)
  115.     {
  116.       WP[j] = SH[i++];
  117.       if (i < NUM_CELL) {WP[j] *= (char)5; WP[j] += SH[i++];}
  118.       if (i < NUM_CELL) {WP[j] *= (char)5; WP[j] += SH[i++];}
  119.       if (i >= NUM_CELL) {WP[j] *= (char)2; WP[j] += wmove;}
  120.       WP[j]++;
  121.     }
  122.   }
  123.   else if (how == 1)
  124.   {
  125.     int i;
  126.     for (i = NUM_CELL - 1; i >= 0; i--)
  127.     {
  128.       if (SH[i] < 0 || SH[i] >= 5) return 0;
  129.     }
  130.     for (i = 0; i < NUM_CELL; i++)
  131.     {
  132.       const char SYMBOL[5] = {'0', 'R', 'B', 'X', 'Z'};
  133.       WP[i] = SYMBOL[SH[NUM_CELL - 1 - i]];
  134.     }
  135.     WP[NUM_CELL] = ':';
  136.     WP[NUM_CELL + 1] = (wmove == 0) ? 'r' : 'b';
  137.     WP[NUM_CELL + 2] = 0;
  138.   }
  139.   return WP;
  140. }
  141.  
  142. Position &Position::Read(const char WP[], int how)
  143. {
  144.   if (how == 0)
  145.   {
  146.     int i = 0, j, ii;
  147.     for (j = 0; i < NUM_CELL; j++)
  148.     {
  149.       unsigned int cwp = WP[j] - 1;
  150.       if (i >= NUM_CELL - 3)
  151.       {
  152.         wmove = char(cwp % 2);
  153.         cwp /= 2;
  154.         ii = NUM_CELL - 1;
  155.       }
  156.       else ii = i + 2;
  157.       while(ii >= i) {SH[ii--] = char(cwp % 5); cwp /= 5;}
  158.       i += 3;
  159.     }
  160.   }
  161.   else if (how == 1)
  162.   {
  163.     int i;
  164.     wmove = 0;
  165.     for (i = 0; i < NUM_CELL; i++)
  166.     {
  167.       switch(WP[i])
  168.       {
  169.       case '0':
  170.       case '-': case '.':
  171.       case 'F': case 'f':
  172.         SH[NUM_CELL - 1 - i] = 0;
  173.         break;
  174.       case '1':
  175.       case 'A': case 'a':
  176.       case 'R': case 'r':
  177.         SH[NUM_CELL - 1 - i] = 1;
  178.         break;
  179.       case '2':
  180.       case 'B': case 'b':
  181.       case 'S': case 's':
  182.         SH[NUM_CELL - 1 - i] = 2;
  183.         break;
  184.       case '3':
  185.       case 'W': case 'w':
  186.       case 'X': case 'x':
  187.         SH[NUM_CELL - 1 - i] = 3;
  188.         break;
  189.       case '4':
  190.       case 'Y': case 'y':
  191.       case 'Z': case 'z':
  192.         SH[NUM_CELL - 1 - i] = 4;
  193.         break;
  194.       default:
  195.         Init();
  196.         return *this;
  197.       }
  198.     }
  199.     if (WP[NUM_CELL] == ':')
  200.     {
  201.       char c = WP[NUM_CELL + 1];
  202.       if (c == 'B' || c == 'b' || c == 'S' || c == 's' ||
  203.           c == 'Y' || c == 'y' || c == 'Z' || c == 'z')
  204.       {
  205.         wmove = 1;
  206.       }
  207.     }
  208.   }
  209.   return *this;
  210. }
  211.  
  212. char *Position::WriteMv(const unsigned char mv[], char WP[], int how)
  213. {
  214.   int i, nmv = 0;
  215.   if (mv) nmv = mv[0];
  216.   if (how == 0)
  217.   {
  218.     WP[0] = char(nmv + 1);
  219.     for (i = 1; i <= nmv; i++) WP[i] = char(mv[i] + 1);
  220.   }
  221.   else if (how == 1)
  222.   {
  223.     int j = 0;
  224.     for (i = 1; i <= nmv; i++)
  225.     {
  226.       int x, y;
  227.       NumToPole(mv[i], x, y);
  228.       WP[j++] = char('a' + NW_CELL - 1 - x);
  229.       int r = sprintf(WP + j, "%d", 1 + y);
  230.       if (r > 0) j += r;
  231.       if (i != nmv) WP[j++] = '-';
  232.     }
  233.     WP[j] = 0;
  234.   }
  235.   return WP;
  236. }
  237.  
  238. unsigned char *Position::ReadMv(unsigned char mv[], const char WP[], int how)
  239. {
  240.   int i;
  241.   if (how == 0)
  242.   {
  243.     mv[0] = char(WP[0] - 1);
  244.     for (i = 1; i <= mv[0]; i++) mv[i] = char(WP[i] - 1);
  245.   }
  246.   else if (how == 1)
  247.   {
  248.     int j = 0, x = -1, y = -1;
  249.     mv[0] = 0;
  250.     for (;;)
  251.     {
  252.       if (isdigit(WP[j]))
  253.       {
  254.         y = atoi(WP + j) - 1;
  255.         while (isdigit(WP[j])) j++;
  256.       }
  257.       else if (islower(WP[j])) x = NW_CELL - 1 - (WP[j++] - 'a');
  258.       else
  259.       {
  260.         if (x >= 0 && y >= 0 && x < NW_CELL && y < NW_CELL)
  261.         {
  262.           mv[++mv[0]] = (char)PoleToNum(x, y);
  263.         }
  264.         else if (y >= 0 && y < NUM_CELL) mv[++mv[0]] = (char)(NUM_CELL - 1 - y);
  265.         x = -1; y = -1;
  266.         if (WP[j] == '-' || WP[j] == '*' || WP[j] == ':') j++;
  267.         else break;
  268.       }
  269.       if (x >= 0 && y >= 0 && x < NW_CELL && y < NW_CELL)
  270.       {
  271.         mv[++mv[0]] = (char)PoleToNum(x, y);
  272.         x = -1; y = -1;
  273.       }
  274.     }
  275.   }
  276.   return mv;
  277. }
  278.  
  279. int Position::GetLenMv(const unsigned char mv[], int how)
  280. {
  281.   if (how == 0) return mv ? (1 + mv[0]) : 1;
  282.   else if (how == 1)
  283.   {
  284.     int i, j = 0;
  285.     if (!mv) return 1;
  286.     for (i = 1; i <= mv[0]; i++)
  287.     {
  288.       int x, y;
  289.       NumToPole(mv[i], x, y);
  290.       j++; y++;
  291.       while(y > 0) {j++; y /= 10;}
  292.       if (i != mv[0]) j++;
  293.     }
  294.     return ++j;
  295.   }
  296.   else return 0;
  297. }
  298.  
  299. int Position::GetLenMwr(const char WP[], int how)
  300. {
  301.   if (how == 0) return (unsigned char)WP[0];
  302.   else if (how == 1)
  303.   {
  304.     int j;
  305.     for (j = 0; WP[j] == '-' || WP[j] == '*' ||
  306.                 WP[j] == ':' || isdigit(j) || islower(j); j++);
  307.     return j + 1;
  308.   }
  309.   else return 0;
  310. }
  311.  
  312. inline int Position::GetLenMvEx(const unsigned char mv[], int how) const
  313. {
  314.   return WriteMvEx(mv, 0, how);
  315. }
  316.  
  317. int Position::WriteMvEx(const unsigned char mv[], char WP[], int how) const
  318. {
  319.   if (how == 11)
  320.   {
  321.     Position pos = *this;
  322.     int p, L = 0, was_d = 0;
  323.     for (p = 1; p <= mv[0]; p++)
  324.     {
  325.       if (!was_d && pos.SH[mv[p]] > 2)
  326.       {
  327.         if (WP) WP[L] = '*';
  328.         L++;
  329.         was_d = 1;
  330.       }
  331.       int x0, y0, x1, y1;
  332.       NumToPole(mv[p], x0, y0);
  333.       if (WP)
  334.       {
  335.         WP[L++] = char('a' + NW_CELL - 1 - x0);
  336.         int r = sprintf(WP + L, "%d", 1 + y0);
  337.         if (r > 0) L += r;
  338.       }
  339.       else
  340.       {
  341.         L++;
  342.         int g = y0 + 1;
  343.         while(g > 0) {L++; g /= 10;}
  344.       }
  345.       if (p >= mv[0]) break;
  346.       NumToPole(mv[p+1], x1, y1);
  347.       int mi = abs(x1 - x0), i, eat = -1;
  348.       if (mi > 0 && mi == abs(y1 - y0))
  349.       {
  350.         int sx = (x1 > x0) ? 1 : -1;
  351.         int sy = (y1 > y0) ? 1 : -1;
  352.         for (i = 1; i < mi; i++)
  353.         {
  354.           int r = PoleToNum(x0 + i * sx, y0 + i * sy);
  355.           if (pos.SH[r] != 0)
  356.           {
  357.             eat = r;
  358.             pos.Del(r);
  359.           }
  360.         }
  361.       }
  362.       if (WP) WP[L] = (eat >= 0) ? ':' : '-';
  363.       L++;
  364.       if (pos.SH[mv[p]] == 1 && y1 == NW_CELL - 1) pos.SH[mv[p]] = 3;
  365.       else if (pos.SH[mv[p]] == 2 && y1 == 0) pos.SH[mv[p]] = 4;
  366.       pos.Move(mv[p], mv[p+1]);
  367.     }
  368.     if (WP) WP[L] = 0;
  369.     L++;
  370.     return L;
  371.   }
  372.   else
  373.   {
  374.     if (WP) WriteMv(mv, WP, how);
  375.     return GetLenMv(mv, how);
  376.   }
  377. }
  378.  
  379. int Position::ScanSide(int x, int y, int sx, int sy, int sh_k) const
  380. {
  381.   if (sh_k < 0) sh_k = SH[PoleToNum(x, y)];
  382.   if (sh_k < 1 || sh_k > 4) return -2;
  383.   if (sh_k >= 2) sh_k -= 2;
  384.   int i, i0, i1, f = 0, g = 0;
  385.   if (sx < 0) i0 = x;
  386.   else i0 = NW_CELL - x - 1;
  387.   if (sy < 0) i1 = y;
  388.   else i1 = NW_CELL - y - 1;
  389.   if (i0 > i1) i0 = i1;
  390.   for (i = 1; i <= i0; i++)
  391.   {
  392.     char nk = SH[PoleToNum(x + i*sx, y + i*sy)];
  393.     if (nk)
  394.     {
  395.       if (f || (nk != 3 - sh_k && nk != 5 - sh_k)) return g;
  396.       else f = 1;
  397.     }
  398.     else if (f) return (i == 2) ? 4 : (2 + g);
  399.     else if (i == 1) g = 1;
  400.   }
  401.   return g;
  402. }
  403.  
  404. int Position::CanEat(int k, int psx, int psy, int sh_k) const
  405. {
  406.   int x, y, sx, sy;
  407.   if (sh_k < 0) sh_k = SH[k];
  408.   if (sh_k < 1 || sh_k > 6) return 0;
  409.   NumToPole(k, x, y);
  410.   if (sh_k > 4)
  411.   {
  412.     int i, i0, i1, f = 0;
  413.     if (-psx < 0) i0 = x;
  414.     else i0 = NW_CELL - x - 1;
  415.     if (-psy < 0) i1 = y;
  416.     else i1 = NW_CELL - y - 1;
  417.     if (i0 > i1) i0 = i1;
  418.     for (i = 1; i <= i0; i++)
  419.     {
  420.       int nk = SH[PoleToNum(x - i*psx, y - i*psy)];
  421.       if (nk)
  422.       {
  423.         if (f || (nk != 7 - sh_k && nk != 9 - sh_k)) break;
  424.         else f = 1;
  425.       }
  426.       else
  427.       {
  428.         if (f) return 1;
  429.         if (ScanSide(x - i*psx, y - i*psy, psy, -psx, sh_k-2) >= 2) return 1;
  430.         if (ScanSide(x - i*psx, y - i*psy, -psy, psx, sh_k-2) >= 2) return 1;
  431.       }
  432.     }
  433.   }
  434.   else for (sx = -1; sx <= 1; sx += 2) if (x + 2*sx >= 0 && x + 2*sx < NW_CELL)
  435.   {
  436.     for (sy = -1; sy <= 1; sy += 2)
  437.     {
  438.       if ((sx != psx || sy != psy) && y + 2*sy >= 0 && y + 2*sy < NW_CELL)
  439.       {
  440.         if (sh_k <= 2)
  441.         {
  442.           if (SH[PoleToNum(x + 2*sx, y + 2*sy)] == 0)
  443.           {
  444.             int nk = SH[PoleToNum(x + sx, y + sy)];
  445.             if (nk == 3 - sh_k || nk == 5 - sh_k) return 1;
  446.           }
  447.         }
  448.         else if (ScanSide(x, y, sx, sy, sh_k) >= 2) return 1;
  449.       }
  450.     }
  451.   }
  452.   return 0;
  453. }
  454.  
  455. int Position::CanMove(int k) const
  456. {
  457.   int x, y, xx, yy, y1, y2;
  458.   NumToPole(k, x, y);
  459.   if (SH[k] == 1) y1 = y2 = y + 1;
  460.   else if (SH[k] == 2) y1 = y2 = y - 1;
  461.   else if (SH[k] != 3 && SH[k] != 4) return 0;
  462.   else {y1 = y - 1; y2 = y + 1;}
  463.   for (yy = y1; yy <= y2; yy += 2) if (yy >= 0 && yy < NW_CELL)
  464.   {
  465.     for (xx = x - 1; xx <= x + 1; xx += 2) if (xx >= 0 && xx < NW_CELL)
  466.     {
  467.       if (SH[PoleToNum(xx, yy)] == 0) return 1;
  468.     }
  469.   }
  470.   return 0;
  471. }
  472.  
  473. int Position::AChCell(int k)
  474. {
  475.   if (k < 0 || k >= NUM_CELL) return AWrong;
  476.   if (SH[k] == 0) return AfCell;
  477.   if (SH[k] != 1 + wmove && SH[k] != 3 + wmove) return AWColor;
  478.   if (CanEat(k)) return 1;
  479.   if (AllCanEat()) return AMustEat;
  480.   if (CanMove(k)) return 1;
  481.   return ANoMove;
  482. }
  483.  
  484. int Position::AMove(const unsigned char MV[], int k, int &mkmove)
  485. {
  486.   if (k >= NUM_CELL) return AWrong;
  487.   if (MV[0] <= 0)
  488.   {
  489.     if (k < 0) return NUM_CELL;
  490.     int s = AChCell(k);
  491.     if (s < 0) return s;
  492.     else return NUM_CELL;
  493.   }
  494.   if (MV[0] == 1 && k < 0)
  495.   {
  496.     int s = AChCell(MV[1]);
  497.     if (s < 0) return s;
  498.     else return NUM_CELL;
  499.   }
  500.   if (SH[MV[1]] == 0) return AfCell;
  501.   if (SH[MV[1]] != 1 + wmove && SH[MV[1]] != 3 + wmove) return AWColor;
  502.   int i, mi, p, MV_L, MV_N = MV[0], eat = -1, r;
  503.   int psx = 0, psy = 0;
  504.   if (k >= 0) MV_N++;
  505.   Position pos = *this;
  506.   for (p = 1; p < MV_N; p++)
  507.   {
  508.     int x0, y0, x1, y1, i_eat;
  509.     if (p < MV[0]) MV_L = MV[p+1];
  510.     else if (k < 0) break;
  511.     else MV_L = k;
  512.     if (pos.SH[MV_L] != 0) return AnfCell;
  513.     NumToPole(MV[p], x0, y0);
  514.     NumToPole(MV_L, x1, y1);
  515.     mi = abs(x1 - x0);
  516.     if (mi <= 0 || mi != abs(y1 - y0)) return AOnlyDiag;
  517.     int sx = (x1 > x0) ? 1 : -1;
  518.     int sy = (y1 > y0) ? 1 : -1;
  519.     if (sx == psx && sy == psy) return ATurnBack;
  520.     psx = -sx; psy = -sy;
  521.     eat = -1; i_eat = -1;
  522.     for (i = 1; i < mi; i++)
  523.     {
  524.       r = PoleToNum(x0 + i * sx, y0 + i * sy);
  525.       if (pos.SH[r] != 0)
  526.       {
  527.         if (eat >= 0) return AMoreOne;
  528.         if (pos.SH[r] != 2 - wmove && pos.SH[r] != 4 - wmove) return AEatYour;
  529.         eat = r; i_eat = i;
  530.         pos.Del(r);
  531.       }
  532.     }
  533.     if (eat >= 0)
  534.     {
  535.       if (pos.SH[MV[p]] <= 2 && mi != 2) return ANotDmE;
  536.     }
  537.     else
  538.     {
  539.       if (MV_N > 2) return AMustEatMore;
  540.       if (pos.SH[MV[p]] <= 2)
  541.       {
  542.         if (mi != 1) return ANotDm;
  543.         if (wmove == 0 && y1 < y0 || wmove == 1 && y1 > y0) return AChBack;
  544.       }
  545.       if (AllCanEat()) return AMustEat;
  546.     }
  547.     if (i_eat >= 0 && pos.SH[MV[p]] > 2)
  548.     {
  549.       if (!pos.CanEat(MV_L, psx, psy, pos.SH[MV[p]]))
  550.       {
  551.         if (pos.CanEat(PoleToNum(x0 + i_eat*sx, y0 + i_eat*sy),
  552.                                  psx, psy, pos.SH[MV[p]] + 2))
  553.         {
  554.           return AMustEatMoreD;
  555.         }
  556.       }
  557.     }
  558.     if (wmove == 0 && y1 == NW_CELL - 1) pos.SH[MV[p]] = 3;
  559.     else if (wmove == 1 && y1 == 0) pos.SH[MV[p]] = 4;
  560.     pos.Move(MV[p], MV_L);
  561.   }
  562.   if (&mkmove)
  563.   {
  564.     int end = MV_N > 1 && (eat < 0 || !pos.CanEat(MV_L, psx, psy));
  565.     if (mkmove == 1 && end)
  566.     {
  567.       *this = pos;
  568.       wmove = !wmove;
  569.     }
  570.     if (end) mkmove = 0;
  571.     else
  572.     {
  573.       if (MV_N > 1 && eat >= 0) mkmove = AMustEatMore;
  574.       else mkmove = AWrong;
  575.     }
  576.   }
  577.   if (k < 0 || eat < 0) eat = NUM_CELL;
  578.   return eat;
  579. }
  580.  
  581. int Position::AllCanEat(int w) const
  582. {
  583.   int k;
  584.   if (w < 0) w = wmove;
  585.   for (k = 0; k < NUM_CELL; k++)
  586.   {
  587.     if ((SH[k] == w+1 || SH[k] == w+3) && CanEat(k)) return 1;
  588.   }
  589.   return 0;
  590. }
  591.  
  592. int Position::AllCanMove(int w) const
  593. {
  594.   int k;
  595.   if (w < 0) w = wmove;
  596.   for (k = 0; k < NUM_CELL; k++)
  597.   {
  598.     if ((SH[k] == w+1 || SH[k] == w+3) && CanMove(k)) return 1;
  599.   }
  600.   return 0;
  601. }
  602.  
  603. void Position::Reverse()
  604. {
  605.   int i;
  606.   for (i = 0; i <= (NUM_CELL-1) / 2; i++)
  607.   {
  608.     int sh1 = SH[i], sh2 = SH[NUM_CELL - 1 - i];
  609.     if (sh1 == 1) sh1 = 2;
  610.     else if (sh1 == 2) sh1 = 1;
  611.     else if (sh1 == 3) sh1 = 4;
  612.     else if (sh1 == 4) sh1 = 3;
  613.     if (sh2 == 1) sh2 = 2;
  614.     else if (sh2 == 2) sh2 = 1;
  615.     else if (sh2 == 3) sh2 = 4;
  616.     else if (sh2 == 4) sh2 = 3;
  617.     SH[i] = (char)sh2; SH[NUM_CELL - 1 - i] = (char)sh1;
  618.   }
  619.   wmove = !wmove;
  620. }
  621.  
  622.  
  623. class PlayWrite
  624. {
  625. public:
  626.   PlayWrite() : play(0), mplay(0), nplay(0), start(0), mstart(0), nstart(0) {}
  627.   PlayWrite(const PlayWrite &pl) : play(0), mplay(0), nplay(0),
  628.                start(0), mstart(0), nstart(0) {(*this) = pl;}
  629.   ~PlayWrite() {Clear();}
  630.  
  631.   void Clear();
  632.   PlayWrite &operator=(const PlayWrite &pl);
  633.   int GetN() const {return nstart - 1;}
  634.   int GetLen() const {return nplay - sizeof(int);}
  635.  
  636.   struct PMv
  637.   {
  638.     Position pos;
  639.     unsigned char mv[NUM_CELL];
  640.   };
  641.  
  642.   void Add(const unsigned char move[], const Position &pos);
  643.   void Add(const PMv &pmv) {Add(pmv.mv, pmv.pos);}
  644.   int Add(const unsigned char move[]);
  645.   int GetMove(unsigned char move[], int k) const;
  646.   int GetPos(Position &pos, int k) const;
  647.   int GetPMv(PMv &pmv, int k) const;
  648.   int GetMoveL(unsigned char move[], int k = 0) const
  649.               {return GetMove(move, nstart - 2 - k);}
  650.   int GetPosL(Position &pos, int k = 0) const {return GetPos(pos, nstart - 2 - k);}
  651.   int GetPMvL(PMv &pmv, int k = 0) const {return GetPMv(pmv, nstart - 2 - k);}
  652.   int ClearFrom(int k = 0);
  653.   int IsDraw(int nmove = -1);
  654. protected:
  655.   void IncPlay(int k);
  656.   void IncStart(int k);
  657.   void IncStart() {IncStart(nstart + 1);}
  658.   void AddStart() {IncStart(); start[nstart++] = nplay;}
  659.   void Split();
  660.   void SplitClear();
  661. protected:
  662.   char *play;
  663.   int *start;
  664.   int mplay, nplay, mstart, nstart;
  665. };
  666.  
  667. void PlayWrite::Clear()
  668. {
  669.   if (play)
  670.   {
  671.     if ((*(int*)play) > 0) (*(int*)play)--;
  672.     else delete[] play;
  673.   }
  674.   play = 0; mplay = 0; nplay = 0;
  675.   if (start)
  676.   {
  677.     if (start[0] > 0) start[0]--;
  678.     else delete[] start;
  679.   }
  680.   start = 0; mstart = 0; nstart = 0;
  681. }
  682.  
  683. void PlayWrite::Split()
  684. {
  685.   if (play && (*(int*)play) > 0)
  686.   {
  687.     (*(int*)play)--;
  688.     char *play0 = play;
  689.     mplay = nplay;
  690.     play = new char[mplay];
  691.     memcpy(play, play0, nplay * sizeof(play[0]));
  692.     (*(int*)play) = 0;
  693.   }
  694.   if (start && start[0] > 0)
  695.   {
  696.     start[0]--;
  697.     int *start0 = start;
  698.     mstart = nstart;
  699.     start = new int[mstart];
  700.     memcpy(start, start0, nstart * sizeof(start[0]));
  701.     start[0] = 0;
  702.   }
  703. }
  704.  
  705. void PlayWrite::SplitClear()
  706. {
  707.   if (play && (*(int*)play) > 0)
  708.   {
  709.     (*(int*)play)--;
  710.     play = 0;
  711.     nplay = 0; mplay = 0;
  712.   }
  713.   if (start && start[0] > 0)
  714.   {
  715.     start[0]--;
  716.     start = 0;
  717.     nstart = 0; mstart = 0;
  718.   }
  719. }
  720.  
  721. PlayWrite &PlayWrite::operator=(const PlayWrite &pl)
  722. {
  723.   if (&pl != this)
  724.   {
  725.     play = pl.play;
  726.     (*(int*)play)++;
  727.     nplay = pl.nplay; mplay = pl.mplay;
  728.     start = pl.start;
  729.     start[0]++;
  730.     nstart = pl.nstart; mstart = pl.mstart;
  731.   }
  732.   return *this;
  733. }
  734.  
  735. void PlayWrite::IncPlay(int k)
  736. {
  737.   if (mplay < k)
  738.   {
  739.     int m0 = mplay;
  740.     char *play0 = play;
  741.     mplay = 2*k + 10;
  742.     play = new char[mplay];
  743.     memcpy(play, play0, m0 * sizeof(play[0]));
  744.     (*(int*)play) = 0;
  745.     if (play0)
  746.     {
  747.       if ((*(int*)play0) > 0) (*(int*)play0)--;
  748.       else delete[] play0;
  749.     }
  750.   }
  751. }
  752.  
  753. void PlayWrite::IncStart(int k)
  754. {
  755.   if (mstart < k)
  756.   {
  757.     int m0 = mstart;
  758.     int *start0 = start;
  759.     mstart = 2*k + 10;
  760.     start = new int[mstart];
  761.     memcpy(start, start0, m0 * sizeof(start[0]));
  762.     start[0] = 0;
  763.     if (start0)
  764.     {
  765.       if (start0[0] > 0) start0[0]--;
  766.       else delete[] start0;
  767.     }
  768.   }
  769. }
  770.  
  771. void PlayWrite::Add(const unsigned char move[], const Position &pos)
  772. {
  773.   Split();
  774.   int k = Position::GetLenMv(move);
  775.   if (nstart < 1) nstart = 1;
  776.   if (nplay < sizeof(int)) nplay = sizeof(int);
  777.   AddStart();
  778.   IncPlay(nplay + k + LEN_WPOS);
  779.   Position::WriteMv(move, play + nplay, 0);
  780.   nplay += k;
  781.   pos.Write(play + nplay, 0);
  782.   nplay += LEN_WPOS;
  783. }
  784.  
  785. int PlayWrite::Add(const unsigned char move[])
  786. {
  787.   if (nstart <= 1) return 1;
  788.   Position pos;
  789.   GetPosL(pos);
  790.   int mkmove = 1;
  791.   int res = pos.AMove(move, -1, mkmove);
  792.   if (res < 0) return res;
  793.   else if (mkmove != 0) return mkmove;
  794.   Add(move, pos);
  795.   return 0;
  796. }
  797.  
  798. int PlayWrite::GetMove(unsigned char move[], int k) const
  799. {
  800.   if (!play || !start) return -1;
  801.   k++;
  802.   if (k <= 0 || k >= nstart) return -1;
  803.   Position::ReadMv(move, play + start[k], 0);
  804.   return Position::GetLenMv(move);
  805. }
  806.  
  807. int PlayWrite::GetPos(Position &pos, int k) const
  808. {
  809.   if (!play || !start) return -1;
  810.   k++;
  811.   if (k <= 0 || k >= nstart) return -1;
  812.   int mlen = Position::GetLenMwr(play + start[k], 0);
  813.   pos.Read(play + start[k] + mlen, 0);
  814.   return LEN_WPOS;
  815. }
  816.  
  817. int PlayWrite::GetPMv(PMv &pmv, int k) const
  818. {
  819.   if (!play || !start) return -1;
  820.   k++;
  821.   if (k <= 0 || k >= nstart) return -1;
  822.   Position::ReadMv(pmv.mv, play + start[k], 0);
  823.   int mlen = Position::GetLenMv(pmv.mv);
  824.   pmv.pos.Read(play + start[k] + mlen, 0);
  825.   return mlen + LEN_WPOS;
  826. }
  827.  
  828. int PlayWrite::ClearFrom(int k)
  829. {
  830.   if (!play || !start) return 0;
  831.   k++;
  832.   if (k >= nstart) return 0;
  833.   if (k <= 1) {Clear(); return 2;}
  834.   nplay = start[k];
  835.   nstart = k;
  836.   return 1;
  837. }
  838.  
  839. int PlayWrite::IsDraw(int nmove)
  840. {
  841.   nmove++;
  842.   if (nmove <= 0 || nmove > nstart) nmove = nstart;
  843.   if (!start || nmove <= 3) return 0;
  844.   int i, j, k, draw = 0;
  845.   for (i = 1; i < nmove; i++)
  846.   {
  847.     k = 1;
  848.     char *p1 = play + start[i] + Position::GetLenMwr(play + start[i], 0);
  849.     for (j = 1; j < i; j++)
  850.     {
  851.       char *p2 = play + start[j] + Position::GetLenMwr(play + start[j], 0);
  852.       if (memcmp(p1, p2, LEN_WPOS) == 0) k++;
  853.     }
  854.     if (k >= 3) {draw = 1; break;}
  855.   }
  856.   return draw;
  857. }
  858.  
  859.  
  860. class TChPlayer
  861. {
  862. public:
  863.   TChPlayer() {}
  864.  
  865.   typedef struct PlayWrite::PMv PMv;
  866.  
  867.   virtual int PlayerID() {return 0;}
  868.   virtual int Move(PMv &pmv) = 0;
  869.  
  870.   int Move(Position &pos, char mv[]);
  871. };
  872.  
  873. int TChPlayer::Move(Position &pos, char mv[])
  874. {
  875.   PMv pmv;
  876.   pmv.pos = pos; memcpy(pmv.mv, mv, sizeof(pmv.mv));
  877.   int res = Move(pmv);
  878.   pos = pmv.pos; memcpy(mv, pmv.mv, sizeof(pmv.mv));
  879.   return res;
  880. }
  881.  
  882. #endif  //_HEADER_POSITION_H
  883.