Subversion Repositories Kolibri OS

Rev

Rev 1805 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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