Subversion Repositories Kolibri OS

Rev

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

  1. #ifndef _HEADER_BOARD_H
  2. #define _HEADER_BOARD_H
  3.  
  4. #ifndef __MENUET__
  5. #include <string.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <time.h>
  9. #include <math.h>
  10. #include <limits.h>
  11. #endif
  12. #include "position.h"
  13. #include "history.h"
  14. #include "gr-draw.h"
  15.  
  16. int ssf = 0;
  17.  
  18. struct TIntPoint
  19. {
  20.   TIntPoint() {}
  21.   TIntPoint(int x, int y) : x(x), y(y) {}
  22.   TIntPoint(const TIntPoint &p) : x(p.x), y(p.y) {}
  23.  
  24.   TIntPoint &operator=(const TIntPoint &p) {x = p.x; y = p.y; return *this;}
  25.  
  26.   int x, y;
  27. };
  28.  
  29. struct TRealPoint
  30. {
  31.   TRealPoint() {}
  32.   TRealPoint(double x, double y) : x(x), y(y) {}
  33.   TRealPoint(const TRealPoint &p) : x(p.x), y(p.y) {}
  34.   TRealPoint(const TIntPoint &p) : x(p.x), y(p.y) {}
  35.  
  36.   TRealPoint &operator=(const TRealPoint &p) {x = p.x; y = p.y; return *this;}
  37.   TRealPoint &operator=(const TIntPoint &p) {x = p.x; y = p.y; return *this;}
  38.  
  39.   TIntPoint Round() {return TIntPoint((int)floor(x+0.5), (int)floor(y+0.5));}
  40.  
  41.   double x, y;
  42. };
  43.  
  44. struct TProjectivePoint
  45. {
  46.   TProjectivePoint() {}
  47.   TProjectivePoint(const TProjectivePoint &p) : x(p.x), y(p.y), z(p.z) {}
  48.   TProjectivePoint(double x, double y, double z = 1) : x(x), y(y), z(z) {}
  49.   TProjectivePoint(const TIntPoint &p, double z = 1) : x(p.x), y(p.y), z(z) {}
  50.   TProjectivePoint(const TRealPoint &p, double z = 1) : x(p.x), y(p.y), z(z) {}
  51.  
  52.   int IsCorrect() const {return fabs(x) > Eps || fabs(y) > Eps || fabs(z) > Eps;}
  53.   int IsFinite() const;
  54.   TRealPoint rpnt() const;
  55.   int rpnt(TRealPoint &p) const;
  56.   TIntPoint pnt() const;
  57.   int pnt(TIntPoint &p) const;
  58.  
  59.   TProjectivePoint &operator=(const TProjectivePoint &p);
  60.   TProjectivePoint &operator=(const TIntPoint &p) {x = p.x; y = p.y; z = 1; return *this;}
  61.   TProjectivePoint &operator=(const TRealPoint &p) {x = p.x; y = p.y; z = 1; return *this;}
  62.   TProjectivePoint &operator*=(int n) {x *= n; y *= n; z *= n; return *this;}
  63.   friend TProjectivePoint operator*(const TProjectivePoint &p, int n)
  64.                 {return TProjectivePoint(p.x * n, p.y * n, p.z * n);}
  65.   friend TProjectivePoint operator*(int n, const TProjectivePoint &p)
  66.                 {return TProjectivePoint(n * p.x, n * p.y, n * p.z);}
  67.   TProjectivePoint &operator*=(double n) {x *= n; y *= n; z *= n; return *this;}
  68.   friend TProjectivePoint operator*(const TProjectivePoint &p, double n)
  69.                 {return TProjectivePoint(p.x * n, p.y * n, p.z * n);}
  70.   friend TProjectivePoint operator*(double n, const TProjectivePoint &p)
  71.                 {return TProjectivePoint(n * p.x, n * p.y, n * p.z);}
  72.  
  73.   double px() const {return x/z;}
  74.   double py() const {return y/z;}
  75.  
  76.   double x, y, z;
  77.  
  78.   static const double Eps, FR;
  79. };
  80.  
  81. const double TProjectivePoint::Eps = 1e-12;
  82. const double TProjectivePoint::FR = 1e+4;
  83.  
  84. inline int TProjectivePoint::IsFinite() const
  85. {
  86.   double fz = fabs(z);
  87.   return fz > Eps && fabs(x) < fz * FR && fabs(y) < fz * FR;
  88. }
  89.  
  90. TRealPoint TProjectivePoint::rpnt() const
  91. {
  92.   if (!IsFinite()) return TRealPoint(0, 0);
  93.   else return TRealPoint(x/z, y/z);
  94. }
  95.  
  96. inline int TProjectivePoint::rpnt(TRealPoint &p) const
  97. {
  98.   if (!IsFinite()) {p.x = 0; p.y = 0; return 0;}
  99.   else {p.x = x/z; p.y = y/z; return 1;}
  100. }
  101.  
  102. inline TIntPoint TProjectivePoint::pnt() const
  103. {
  104.   if (!IsFinite()) return TIntPoint(INT_MIN, INT_MIN);
  105.   else return TIntPoint((int)floor(x/z + 0.5), (int)floor(y/z + 0.5));
  106. }
  107.  
  108. inline int TProjectivePoint::pnt(TIntPoint &p) const
  109. {
  110.   if (!IsFinite()) {p.x = INT_MIN; p.y = INT_MIN; return 0;}
  111.   else
  112.   {
  113.     p.x = (int)floor(x/z + 0.5);
  114.     p.y = (int)floor(y/z + 0.5);
  115.     return 1;
  116.   }
  117. }
  118.  
  119. TProjectivePoint &TProjectivePoint::operator=(const TProjectivePoint &p)
  120. {
  121.   x = p.x; y = p.y; z = p.z;
  122.   return *this;
  123. }
  124.  
  125.  
  126. class TProjectiveMap
  127. {
  128. public:
  129.   TProjectiveMap() {}
  130.   TProjectiveMap(int n) {p[0].x = p[1].y = p[2].z = n;
  131.                 p[0].y = p[0].z = p[1].x = p[1].z = p[2].x = p[2].y = 0;}
  132.   TProjectiveMap(const TProjectiveMap &map)
  133.                 {p[0] = map.p[0]; p[1] = map.p[1]; p[2] = map.p[2];}
  134.   TProjectiveMap(const TProjectivePoint pnt[])
  135.                 {p[0] = pnt[0]; p[1] = pnt[1]; p[2] = pnt[2];}
  136.   TProjectiveMap(const TProjectivePoint &p0, const TProjectivePoint &p1,
  137.                  const TProjectivePoint &p2) {p[0] = p0; p[1] = p1; p[2] = p2;}
  138.  
  139.   TProjectiveMap &operator=(const TProjectiveMap &map)
  140.                 {p[0] = map.p[0]; p[1] = map.p[1]; p[2] = map.p[2]; return *this;}
  141.   TProjectiveMap &operator=(const TProjectivePoint pnt[])
  142.                 {p[0] = pnt[0]; p[1] = pnt[1]; p[2] = pnt[2]; return *this;}
  143.   TProjectiveMap &operator=(int n) {p[0].x = p[1].y = p[2].z = n;
  144.                 p[0].y = p[0].z = p[1].x = p[1].z = p[2].x = p[2].y = 0; return *this;}
  145.  
  146.   TProjectivePoint operator()(const TProjectivePoint &point) const;
  147.   friend TProjectiveMap operator*(const TProjectiveMap &a, const TProjectiveMap &b);
  148.   TProjectiveMap &operator*=(const TProjectiveMap &b);
  149.   TProjectiveMap &operator*=(int n) {p[0] *= n; p[1] *= n; p[2] *= n; return *this;}
  150.   friend TProjectiveMap operator*(const TProjectiveMap &a, int n)
  151.                        {return TProjectiveMap(a.p[0] * n, a.p[1] * n, a.p[2] * n);}
  152.   friend TProjectiveMap operator*(int n, const TProjectiveMap &b)
  153.                        {return TProjectiveMap(n * b.p[0], n * b.p[1], n * b.p[2]);}
  154.   TProjectiveMap Reversed() const;
  155.   TProjectiveMap &Reverse() {return (*this) = Reversed();}
  156.   friend TProjectiveMap operator/(const TProjectiveMap &a, const TProjectiveMap &b)
  157.                                  {return a * b.Reversed();}
  158.   TProjectiveMap &operator/=(const TProjectiveMap &b) {return (*this) *= b.Reversed();}
  159.   TProjectiveMap &operator/=(int n) {if (!n) (*this) = 0; return *this;}
  160.   TProjectivePoint Reversed(const TProjectivePoint &point) const;
  161.  
  162.   TProjectivePoint operator()(double x, double y, double z = 1) const
  163.                            {return (*this)(TProjectivePoint(x, y, z));}
  164.   TProjectivePoint Reversed(double x, double y, double z = 1) const
  165.                            {return Reversed(TProjectivePoint(x, y, z));}
  166.  
  167.   TProjectiveMap &Set4(const TProjectivePoint &a0, const TProjectivePoint &a1,
  168.                        const TProjectivePoint &a2, const TProjectivePoint &a3);
  169.   TProjectiveMap &Set4(const TProjectivePoint a[]) {return Set4(a[0], a[1], a[2], a[3]);}
  170.   TProjectiveMap &Set4to4(const TProjectivePoint a[], const TProjectivePoint b[])
  171.               {return Set4(b) /= TProjectiveMap().Set4(a);}
  172.   TProjectiveMap &Set4to4(const TProjectivePoint &a0, const TProjectivePoint &a1,
  173.                           const TProjectivePoint &a2, const TProjectivePoint &a3,
  174.                           const TProjectivePoint b[])
  175.               {return Set4(b) /= TProjectiveMap().Set4(a0, a1, a2, a3);}
  176.   TProjectiveMap &Set4to4(const TProjectivePoint a[],
  177.                           const TProjectivePoint &b0, const TProjectivePoint &b1,
  178.                           const TProjectivePoint &b2, const TProjectivePoint &b3)
  179.               {return Set4(b0, b1, b2, b2) /= TProjectiveMap().Set4(a);}
  180.   TProjectiveMap &Set4to4(const TProjectivePoint &a0, const TProjectivePoint &a1,
  181.                           const TProjectivePoint &a2, const TProjectivePoint &a3,
  182.                           const TProjectivePoint &b0, const TProjectivePoint &b1,
  183.                           const TProjectivePoint &b2, const TProjectivePoint &b3)
  184.               {return Set4(b0, b1, b2, b2) /= TProjectiveMap().Set4(a0, a1, a2, a3);}
  185.  
  186. public:
  187.   TProjectivePoint p[3];
  188. };
  189.  
  190. TProjectivePoint TProjectiveMap::operator()(const TProjectivePoint &point) const
  191. {
  192.   return TProjectivePoint(p[0].x * point.x + p[1].x * point.y + p[2].x * point.z,
  193.                           p[0].y * point.x + p[1].y * point.y + p[2].y * point.z,
  194.                           p[0].z * point.x + p[1].z * point.y + p[2].z * point.z);
  195. }
  196.  
  197. TProjectiveMap operator*(const TProjectiveMap &a, const TProjectiveMap &b)
  198. {
  199.   return TProjectiveMap(a(b.p[0]), a(b.p[1]), a(b.p[2]));
  200. }
  201.  
  202. TProjectiveMap &TProjectiveMap::operator*=(const TProjectiveMap &b)
  203. {
  204.   TProjectivePoint p0 = (*this)(b.p[0]), p1 = (*this)(b.p[1]), p2 = (*this)(b.p[2]);
  205.   p[0] = p0; p[1] = p1; p[2] = p2;
  206.   return *this;
  207. }
  208.  
  209. TProjectiveMap TProjectiveMap::Reversed() const
  210. {
  211.   return TProjectiveMap(TProjectivePoint(p[1].y * p[2].z - p[2].y * p[1].z,
  212.            p[2].y * p[0].z - p[0].y * p[2].z, p[0].y * p[1].z - p[1].y * p[0].z),
  213.                         TProjectivePoint(p[1].z * p[2].x - p[2].z * p[1].x,
  214.            p[2].z * p[0].x - p[0].z * p[2].x, p[0].z * p[1].x - p[1].z * p[0].x),
  215.                         TProjectivePoint(p[1].x * p[2].y - p[2].x * p[1].y,
  216.            p[2].x * p[0].y - p[0].x * p[2].y, p[0].x * p[1].y - p[1].x * p[0].y));
  217. }
  218.  
  219. TProjectivePoint TProjectiveMap::Reversed(const TProjectivePoint &point) const
  220. {
  221.   return TProjectivePoint((p[1].y * p[2].z - p[2].y * p[1].z) * point.x +
  222.                           (p[1].z * p[2].x - p[2].z * p[1].x) * point.y +
  223.                           (p[1].x * p[2].y - p[2].x * p[1].y) * point.z,
  224.                  (p[2].y * p[0].z - p[0].y * p[2].z) * point.x +
  225.                  (p[2].z * p[0].x - p[0].z * p[2].x) * point.y +
  226.                  (p[2].x * p[0].y - p[0].x * p[2].y) * point.z,
  227.         (p[0].y * p[1].z - p[1].y * p[0].z) * point.x +
  228.         (p[0].z * p[1].x - p[1].z * p[0].x) * point.y +
  229.         (p[0].x * p[1].y - p[1].x * p[0].y) * point.z);
  230. }
  231.  
  232. TProjectiveMap &TProjectiveMap::Set4(const TProjectivePoint &a0,
  233.    const TProjectivePoint &a1, const TProjectivePoint &a2, const TProjectivePoint &a3)
  234. {
  235.   p[0] = a0; p[1] = a1; p[2] = a2;
  236.   TProjectivePoint K = Reversed(a3);
  237.   p[0] *= K.x; p[1] *= K.y; p[2] *= K.z;
  238.   return *this;
  239. }
  240.  
  241.  
  242. TRealPoint r_circle_pnt[13];
  243. TRealPoint r_star_pnt[13];
  244. const double r_star_large = 1.2, r_star_small = 0.8;
  245. const double r_ch_lines[] = {0.8, 0.7, 0.6, 0.5};
  246.  
  247. void InitBoardData()
  248. {
  249.   int i, len;
  250.   double a, r;
  251.   len = NELEM(r_circle_pnt) - 1;
  252.   for (i = 0; i < len; i++)
  253.   {
  254.     a = 2 * i * M_PI / len;
  255.     r_circle_pnt[i].x = cos(a);
  256.     r_circle_pnt[i].y = sin(a);
  257.   }
  258.   r_circle_pnt[len] = r_circle_pnt[0];
  259.   len = sizeof(r_star_pnt) / sizeof(r_star_pnt[0]) - 1;
  260.   for (i = 0; i < len; i++)
  261.   {
  262.     a = 2 * i * M_PI / len;
  263.     r = (i % 2) ? r_star_small : r_star_large;
  264.     r_star_pnt[i].x = cos(a) * r;
  265.     r_star_pnt[i].y = sin(a) * r;
  266.   }
  267.   r_star_pnt[len] = r_star_pnt[0];
  268. }
  269.  
  270. class TChBoard;
  271.  
  272. class TSomeDraw
  273. {
  274. public:
  275.   TSomeDraw() {}
  276.  
  277.   virtual void Draw(TGraphDraw *drw, int w, int h) = 0;
  278.   virtual void DrawB(TGraphDraw *drw, TChBoard &brd);
  279.   virtual TIntPoint GetDSize(int w, int h) {return TIntPoint(INT_MIN, INT_MIN);}
  280. };
  281.  
  282. class TChBoard
  283. {
  284. public:
  285.   TChBoard(int id = 0);
  286.  
  287.   TProjectiveMap Get4PMap() const;
  288.   int GetW() const {return width;}
  289.   int GetH() const {return height;}
  290.   void ClearWH() {width = -1; height = -1;}
  291.   void Resize(int w, int h);
  292.   void Resize(TIntPoint size) {Resize(size.x, size.y);}
  293.  
  294.   TIntPoint PlToWin(double x, double y) const;
  295.   TIntPoint PlToWin(TRealPoint rp) const {return PlToWin(rp.x, rp.y);}
  296.   TRealPoint WinToPl(int x, int y) const;
  297.   TRealPoint WinToPl(TIntPoint p) const {return WinToPl(p.x, p.y);}
  298.  
  299.   void NewGame();
  300.   int CanPlayerMove() const {return !IsPlayView && !game_end && !player[MainPos.wmove];}
  301.  
  302.   void Draw(TGraphDraw *drw);
  303.   int ResizeDraw(TGraphDraw *drw, int w, int h);
  304.   int CheckResize(TGraphDraw *drw);
  305.   int HaveCheckResize() const {return check_resize;}
  306.   void SetCheckResize(int cr) {check_resize = cr;}
  307.   int MouseClick(TGraphDraw *drw, int x, int y);
  308.   void UnMove(TGraphDraw *drw);
  309.  
  310.   int CMove(TGraphDraw *drw, int x, int y);
  311.   int AutoMove(TGraphDraw *drw, int nmove = 0, int draw_check = 1);
  312.  
  313.   enum PKey {PNull, PEnter, PLeft, PRight, PUp, PDown};
  314.   PKey GetKeySide(PKey key);
  315.   int PKeyEvent(TGraphDraw *drw, PKey key = PEnter);
  316. protected:
  317.   enum TextLineType {TLT_Main, TLT_Move, TLT_Wait, TLT_GameEnd, TLT_WrongMove,
  318.                      TLT_PlDidntMove, TLT_PlWrongMove, TLT_WrongColor,
  319.                      TLT_WfCell, TLT_WnfCell, TLT_WMustEat, TLT_WMustEatMore,
  320.                      TLT_WNoMove, TLT_WChBack, TLT_WNotDm, TLT_WOnlyDiag,
  321.                      TLT_WEatYour, TLT_WMoreOne, TLT_WNotDmE, TLT_WMustEatMoreD,
  322.                      TLT_WTurnBack};
  323.   void GetTextLine(char str[]) const;
  324.   void DrawTextLine(TGraphDraw *drw) const;
  325.   void LineB(TGraphDraw *drw, double x1, double y1, double x2, double y2) const;
  326.   void DrawCh(TGraphDraw *drw, double x0, double y0, const TRealPoint pnt[], int npnt,
  327.               int L = NELEM(r_ch_lines)) const;
  328.   void DrawIL(TGraphDraw *drw, double x0, double y0, int L) const;
  329.   void MoveErase();
  330.   void CurPointClear(TGraphDraw *drw) const;
  331.   void RenewMPos() {if (MainPlay.GetPos(MainPos, CurMoveN) < 0) MainPos.Init();}
  332.   void PrintLMove();
  333.   void SetNoMove(TGraphDraw *drw = 0, int force = 1);
  334.   TextLineType GetTLTfromA(int s) const;
  335.   void ChangeTLT(TGraphDraw *drw, TextLineType t);
  336.   TextLineType GetSimpleTLT() const;
  337. public:
  338.   void ResetTextLine(TGraphDraw *drw);
  339.   TChPlayer *GetPlayer(int k) const {return player[k];}
  340.   void SetPlayer(int k, TChPlayer *pl) {player[k] = pl;}
  341.   int GetBottomColor() const {return BottomColor;}
  342.   void SetBottomColor(int c) {BottomColor = c & 1;}
  343. public:
  344.   enum {textlineh = 14, min_brd = 120, max_delt = 20, min_brdsize = 70};
  345.   int GetTextLineY() const;
  346.   TSomeDraw *GetSomeDraw() const {return some_draw;}
  347.   void SetSomeDraw(TSomeDraw *drw) {some_draw = drw;}
  348.   TIntPoint GetMinWSize() const {return min_wsize;}
  349.   void SetMinWSize(TIntPoint mws) {min_wsize = mws; Resize(width, height);}
  350.   void SetMinWSize(int w, int h) {SetMinWSize(TIntPoint(w, h));}
  351.   void DrawTimer(TGraphDraw *drw, double t, int wh = 0) const;
  352.   int GetNumMove() const {return MainPlay.GetN() - 1;}
  353.   int GetCurMoveN() const {return CurMoveN;}
  354.   int SetCurMoveN(int n, TGraphDraw *drw = 0);
  355.   int SetPlay(const PlayWrite &play);
  356.   PlayWrite GetPlay() const {return MainPlay;}
  357.   int GetPViewStatus() const {return IsPlayView;}
  358.   void SetPViewStatus(int pv) {IsPlayView = pv;}
  359.   void GoToCurMove();
  360.   int GetGameEnd() const {return game_end;}
  361.   void EraseHistory() {hist_inited = 0;}
  362.   int ReinitHistory();
  363. protected:
  364.   double dw_delt, dw_cell;
  365.   int width, height;
  366.   TProjectiveMap PoleMap;
  367.   Position MainPos;
  368.   int BottomColor;
  369.   unsigned char TheMove[NUM_CELL];
  370.   unsigned char Eaten[NUM_CELL];
  371.   unsigned char BecameD;
  372.   TIntPoint CurPoint;
  373.   int game_end;
  374.   int check_resize;
  375.   TIntPoint delta_size;
  376.   TextLineType text_line_type;
  377.   PlayWrite MainPlay;
  378.   TChPlayer *player[2];
  379.   TSomeDraw *some_draw;
  380.   TIntPoint min_wsize;
  381.   int CurMoveN, IsPlayView;
  382.   THistory history;
  383.   int hist_inited;
  384. };
  385.  
  386. inline void TSomeDraw::DrawB(TGraphDraw *drw, TChBoard &brd)
  387. {
  388.   Draw(drw, brd.GetW(), brd.GetH());
  389. }
  390.  
  391. void TChBoard::MoveErase()
  392. {
  393.   TheMove[0] = 0;
  394.   Eaten[0] = 0;
  395.   BecameD = 0;
  396. }
  397.  
  398. TChBoard::TChBoard(int id) : history(id)
  399. {
  400.   InitBoardData();
  401.   player[0] = player[1] = 0;
  402.   dw_delt = 0.3;
  403.   dw_cell = 1;
  404.   BottomColor = 0;
  405.   check_resize = 0;
  406.   delta_size.x = 0; delta_size.y = 0;
  407.   some_draw = 0;
  408.   min_wsize.x = 80; min_wsize.y = 80;
  409.   ClearWH();
  410.   Resize(400, 400);
  411.   NewGame();
  412. }
  413.  
  414. TProjectiveMap TChBoard::Get4PMap() const
  415. {
  416.   return TProjectiveMap().Set4(TRealPoint(-dw_delt, -dw_delt),
  417.                   TRealPoint(NW_CELL*dw_cell + dw_delt, -dw_delt),
  418.                   TRealPoint(NW_CELL*dw_cell + dw_delt, NW_CELL*dw_cell + dw_delt),
  419.                   TRealPoint(-dw_delt, NW_CELL*dw_cell + dw_delt));
  420. }
  421.  
  422. void TChBoard::Resize(int w, int h)
  423. {
  424.   width = w; height = h;
  425.   if (width < min_wsize.x) width = min_wsize.x;
  426.   if (height < min_wsize.y) height = min_wsize.y;
  427.   for (;;)
  428.   {
  429.     if (some_draw)
  430.     {
  431.       TIntPoint dsz = some_draw->GetDSize(width, height);
  432.       if (dsz.x >= 0 && dsz.y >= 0) delta_size = dsz;
  433.     }
  434.     int change = 0;
  435.     if (width < delta_size.x + min_brdsize)
  436.     {
  437.       width = delta_size.x + min_brdsize;
  438.       change++;
  439.     }
  440.     if (height < delta_size.y + min_brdsize + textlineh)
  441.     {
  442.       height = delta_size.y + min_brdsize + textlineh;
  443.       change++;
  444.     }
  445.     if (!some_draw || !change) break;
  446.   }
  447.   double sx = max_delt, dx = width - 2*sx - delta_size.x;
  448.   double sy = max_delt, dy = height - 2*sy - delta_size.y - textlineh;
  449.   if (dy < min_brd)
  450.   {
  451.     double d = (min_brd - dy) / 2;
  452.     if (d > sy) d = sy;
  453.     sy -= d; dy += 2*d;
  454.   }
  455.   if (dx < min_brd)
  456.   {
  457.     double d = (min_brd - dx) / 2;
  458.     if (d > sx) d = sx;
  459.     sx -= d; dx += 2*d;
  460.   }
  461.   if (dy > dx) {sy += (dy - dx) / 2; dy = dx;}
  462.   double tx = (dx - dy * dy / dx) / 3;
  463.   PoleMap.Set4(TRealPoint(sx, sy + dy - 70*ssf), TRealPoint(sx + dx, sy + dy),
  464.                TRealPoint(sx + dx - tx, sy), TRealPoint(sx + tx, sy + 40*ssf));
  465.   PoleMap /= Get4PMap();
  466. }
  467.  
  468. TIntPoint TChBoard::PlToWin(double x, double y) const
  469. {
  470.   if (BottomColor == 1) y = NW_CELL*dw_cell - y;
  471.   else x = NW_CELL*dw_cell - x;
  472.   /**/if (ssf) y += 0.6 * sin(x);/**/
  473.   return PoleMap(x, y).pnt();
  474. }
  475.  
  476. TRealPoint TChBoard::WinToPl(int x, int y) const
  477. {
  478.   TRealPoint rpnt;
  479.   if (PoleMap.Reversed(x, y).rpnt(rpnt))
  480.   {
  481.     /**/if (ssf) rpnt.y -= 0.6 * sin(rpnt.x);/**/
  482.     if (BottomColor == 1) rpnt.y = NW_CELL*dw_cell - rpnt.y;
  483.     else rpnt.x = NW_CELL*dw_cell - rpnt.x;
  484.     return rpnt;
  485.   }
  486.   else return TRealPoint(-dw_cell - dw_delt, -dw_cell - dw_delt);
  487. }
  488.  
  489. void TChBoard::NewGame()
  490. {
  491.   int k;
  492.   MoveErase();
  493.   MainPos.Init();
  494.   MainPlay.Clear();
  495.   for (k = 0; k < NW_CELL * 3 / 2; k++) MainPos.SH[k] = 1;
  496.   for (k = 0; k < NW_CELL * 3 / 2; k++) MainPos.SH[NUM_CELL - k - 1] = 2;
  497.   MainPlay.Add(0, MainPos);
  498.   CurMoveN = 0;
  499.   text_line_type = TLT_Main;
  500.   game_end = 0;
  501.   CurPoint.x = -1; CurPoint.y = -1;
  502.   IsPlayView = 0;
  503.   printf("\nCheckers: New game.\n");
  504.   EraseHistory();
  505. }
  506.  
  507. int TChBoard::GetTextLineY() const
  508. {
  509.   int y = height - (max_delt + textlineh + delta_size.y);
  510.   int i, j;
  511.   for (i = 0; i <= 1; i++) for (j = 0; j <= 1; j++)
  512.   {
  513.     TRealPoint corner;
  514.     corner.x = (2*i - 1) * dw_delt + i * NW_CELL * dw_cell;
  515.     corner.y = (2*j - 1) * dw_delt + j * NW_CELL * dw_cell;
  516.     TIntPoint wcr = PlToWin(corner);
  517.     if (wcr.x != INT_MIN && wcr.y != INT_MIN)
  518.     {
  519.       if (y < wcr.y) y = wcr.y;
  520.     }
  521.   }
  522.   y -= textlineh;
  523.   if (y > height - delta_size.y - 2*textlineh)
  524.   {
  525.     y = height - delta_size.y - 2*textlineh;
  526.   }
  527.   return (y + height - delta_size.y) / 2;
  528. }
  529.  
  530. #ifdef BUILD_RUS
  531. #define aCheckersGame   "Игра в шашки."
  532. #define aRedMoves       "Красные ходят."
  533. #define aBlueMoves      "Синие ходят."
  534. #define aWait           "Подождите."
  535. #define aRedWins        "Красные выиграли."
  536. #define aBlueWins       "Синие выиграли."
  537. #define aDraw           "Ничья."
  538. #define aRed            "Красные "
  539. #define aBlue           "Синие "
  540. #define aMadeWrongMove  "сделали неправильный ход."
  541. #define aNoMove         "не смогли сделать ход."
  542. #define aEndGame        "Конец игры."
  543. #define aYouWin         " (Вы выиграли)"
  544. #define aYouLose        " (Вы проиграли)"
  545. #define aRedWin         " (Красные выиграли)"
  546. #define aBlueWin        " (Синие выиграли)"
  547. #define aWrongMove      "Неверный ход."
  548. #define aNotYourChecker "Это не ваша шашка."
  549. #define aFreeCell       "Эта клетка пустая."
  550. #define aNotFreeCell    "Шашки могут ходить только на свободные клетки."
  551. #define aMustEat        "Вы должны взять шашку."
  552. #define aMustEatMore    "Вы должны взять ещё шашку."
  553. #define aCheckerNoMove  "У этой шашки нет ходов."
  554. #define aNoBack         "Шашки не ходят назад."
  555. #define aNotDamka       "Это не дамка."
  556. #define aOnlyDiag       "Шашки ходят только по диагонали."
  557. #define aEatYour        "Шашки не могут есть своих."
  558. #define aMoreOne        "Вы не можете взять более одной шашки за раз."
  559. #define aNoTurnBack     "Шашки не могут разворачиваться назад при взятии."
  560. #else
  561. #define aCheckersGame   "The checkers game."
  562. #define aRedMoves       "Red moves."
  563. #define aBlueMoves      "Blue moves."
  564. #define aWait           "Please wait."
  565. #define aRedWins        "Red wins."
  566. #define aBlueWins       "Blue wins."
  567. #define aDraw           "Draw."
  568. #define aRed            "Red "
  569. #define aBlue           "Blue "
  570. #define aMadeWrongMove  "make a wrong move."
  571. #define aNoMove         "could not make a move."
  572. #define aEndGame        "End of the game."
  573. #define aYouWin         " (You win)"
  574. #define aYouLose        " (You lose)"
  575. #define aRedWin         " (Red win)"
  576. #define aBlueWin        " (Blue win)"
  577. #define aWrongMove      "Wrong move."
  578. #define aNotYourChecker "It isn't your checker."
  579. #define aFreeCell       "The cell is free."
  580. #define aNotFreeCell    "Checkers may be moved only on a free cell."
  581. #define aMustEat        "You must eat a checker."
  582. #define aMustEatMore    "You must eat more checkers."
  583. #define aCheckerNoMove  "The checker have no moves."
  584. #define aNoBack         "Checkers may not be moved back."
  585. #define aNotDamka       "It is not a damka."
  586. #define aOnlyDiag       "Checkers may be moved only along diagonal."
  587. #define aEatYour        "You may not eat your checkers."
  588. #define aMoreOne        "You may not eat more than one checker at a time."
  589. #define aNoTurnBack     "Checkers may not turn back when eating."
  590. #endif
  591.  
  592. void TChBoard::GetTextLine(char str[]) const
  593. {
  594.   str[0] = 0;
  595.   int g = (game_end - 1) % 2, h = 0;
  596.   switch(text_line_type)
  597.   {
  598.   case TLT_Main:
  599.     strcpy(str, aCheckersGame);
  600.     break;
  601.   case TLT_Move:
  602.     if (MainPos.wmove == 0)
  603.     {
  604.       strcpy(str, aRedMoves);
  605.     }
  606.     else strcpy(str, aBlueMoves);
  607.     break;
  608.   case TLT_Wait:
  609.     strcpy(str, aWait);
  610.     break;
  611.   case TLT_GameEnd:
  612.   case TLT_PlDidntMove:
  613.   case TLT_PlWrongMove:
  614.     if (!game_end) break;
  615.     if (text_line_type == TLT_GameEnd)
  616.     {
  617.       if (game_end == 1) strcpy(str, aRedWins);
  618.       else if (game_end == 2) strcpy(str, aBlueWins);
  619.       else if (game_end == 5) strcpy(str, aDraw);
  620.     }
  621.     if (!str[0])
  622.     {
  623.       if (game_end >= 1 && game_end <= 4)
  624.       {
  625.         if (g == 0) strcpy(str, aRed);
  626.         else strcpy(str, aBlue);
  627.         if (text_line_type == TLT_PlWrongMove)
  628.         {
  629.           strcat(str, aMadeWrongMove);
  630.         }
  631.         else strcat(str, aNoMove);
  632.         h = 1;
  633.       }
  634.       else strcpy(str, aEndGame);
  635.     }
  636.     if (game_end >= 1 && game_end <= 4)
  637.     {
  638.       if (!IsPlayView && player[1-g] && !player[g])
  639.       {
  640.         strcat(str, aYouWin);
  641.       }
  642.       else if (!IsPlayView && player[g] && !player[1-g])
  643.       {
  644.         strcat(str, aYouLose);
  645.       }
  646.       else if (h && g == 0) strcat(str, aRedWin);
  647.       else if (h && g == 1) strcat(str, aBlueWin);
  648.     }
  649.     break;
  650.   case TLT_WrongMove:
  651.     strcpy(str, aWrongMove);
  652.     break;
  653.   case TLT_WrongColor:
  654.     strcpy(str, aNotYourChecker);
  655.     break;
  656.   case TLT_WfCell:
  657.     strcpy(str, aFreeCell);
  658.     break;
  659.   case TLT_WnfCell:
  660.     strcpy(str, aNotFreeCell);
  661.     break;
  662.   case TLT_WMustEat:
  663.     strcpy(str, aMustEat);
  664.     break;
  665.   case TLT_WMustEatMore:
  666.   case TLT_WMustEatMoreD:
  667.     strcpy(str, aMustEatMore);
  668.     break;
  669.   case TLT_WNoMove:
  670.     strcpy(str, aCheckerNoMove);
  671.     break;
  672.   case TLT_WChBack:
  673.     strcpy(str, aNoBack);
  674.     break;
  675.   case TLT_WNotDm:
  676.   case TLT_WNotDmE:
  677.     strcpy(str, aNotDamka);
  678.     break;
  679.   case TLT_WOnlyDiag:
  680.     strcpy(str, aOnlyDiag);
  681.     break;
  682.   case TLT_WEatYour:
  683.     strcpy(str, aEatYour);
  684.     break;
  685.   case TLT_WMoreOne:
  686.     strcpy(str, aMoreOne);
  687.     break;
  688.   case TLT_WTurnBack:
  689.     strcpy(str, aNoTurnBack);
  690.     break;
  691.   }
  692. }
  693.  
  694. void TChBoard::DrawTextLine(TGraphDraw *drw) const
  695. {
  696.   if (!drw || !drw->IsDraw()) return;
  697.   char str[100];
  698.   GetTextLine(str);
  699.   if (str[0]) drw->DrawText(10, GetTextLineY(), str);
  700. }
  701.  
  702. void TChBoard::ResetTextLine(TGraphDraw *drw)
  703. {
  704.   if (!game_end && text_line_type != TLT_Move) ChangeTLT(drw, TLT_Move);
  705. }
  706.  
  707. void TChBoard::LineB(TGraphDraw *drw, double x1, double y1, double x2, double y2) const
  708. {
  709.   if (!drw || !drw->IsDraw()) return;
  710.   TIntPoint p1 = PlToWin(x1, y1), p2 = PlToWin(x2, y2);
  711.   if (p1.x != INT_MIN && p1.y != INT_MIN && p2.x != INT_MIN && p2.y != INT_MIN)
  712.   {
  713.     drw->DrawLine(p1.x, p1.y, p2.x, p2.y);
  714.   }
  715. }
  716.  
  717. void TChBoard::DrawCh(TGraphDraw *drw, double x0, double y0, const TRealPoint pnt[], int npnt, int L) const
  718. {
  719.   if (!drw || !drw->IsDraw()) return;
  720.   int i, j;
  721.   for (j = 0; j < L; j++)
  722.   {
  723.     for (i = 0; i < npnt - 1; i++)
  724.     {
  725.       LineB(drw, x0 + pnt[i].x * dw_cell * r_ch_lines[j] / 2,
  726.                  y0 + pnt[i].y * dw_cell * r_ch_lines[j] / 2,
  727.                  x0 + pnt[i+1].x * dw_cell * r_ch_lines[j] / 2,
  728.                  y0 + pnt[i+1].y * dw_cell * r_ch_lines[j] / 2);
  729.     }
  730.   }
  731. }
  732.  
  733. void TChBoard::DrawIL(TGraphDraw *drw, double x0, double y0, int L) const
  734. {
  735.   if (!drw || !drw->IsDraw()) return;
  736.   int i, j;
  737.   if (L == 0 || L == 1)
  738.   {
  739.     const int numDST[2] = {2, 4};
  740.     const double DST[2][4] = {{0.96, 0.88}, {0.8, 0.76, 0.72, 0.68}};
  741.     const int MULT[4][4] = {{-1, -1, -1, 1}, {-1, 1, 1, 1},
  742.                             {-1, -1, 1, -1}, {1, -1, 1, 1}};
  743.     for (i = 0; i < numDST[L]; i++) for (j = 0; j < 4; j++)
  744.     {
  745.       LineB(drw, x0 + dw_cell * DST[L][i] * MULT[j][0] / 2,
  746.                  y0 + dw_cell * DST[L][i] * MULT[j][1] / 2,
  747.                  x0 + dw_cell * DST[L][i] * MULT[j][2] / 2,
  748.                  y0 + dw_cell * DST[L][i] * MULT[j][3] / 2);
  749.     }
  750.   }
  751.   else if (L == 2)
  752.   {
  753.     const double DP[] = {0.85, 0.90, 0.95};
  754.     const int numDP = NELEM(DP);
  755.     for (i = 0; i < numDP; i++) for (j = -1; j <= 1; j += 2)
  756.     {
  757.       LineB(drw, x0 - j * dw_cell * DP[i] / 2,
  758.                  y0 - dw_cell * DP[numDP - i - 1] / 2,
  759.                  x0 + j * dw_cell * DP[numDP - i - 1] / 2,
  760.                  y0 + dw_cell * DP[i] / 2);
  761.     }
  762.   }
  763. }
  764.  
  765. void TChBoard::Draw(TGraphDraw *drw)
  766. {
  767.   if (!drw || !drw->IsDraw()) return;
  768.   if (CheckResize(drw)) drw->DrawClear();
  769.   int i, j, k, kn;
  770.   unsigned long black = drw->GetBlackColor();
  771.   unsigned long red = drw->CreateColor(65535u, 0, 0);
  772.   unsigned long green = drw->CreateColor(0, 49151u, 0);
  773.   unsigned long blue = drw->CreateColor(0, 0, 65535u);
  774.   drw->SetColor(black);
  775.   for (i = -1; i <= NW_CELL + 1; i++) for (j = -1; j <= NW_CELL; j++)
  776.   {
  777.     if (i < 0 || i > NW_CELL || j >= 0 && j < NW_CELL)
  778.     {
  779.       double mval = dw_cell * NW_CELL + dw_delt;
  780.       double x, y0, y1;
  781.       if (i < 0) x = -dw_delt;
  782.       else if (i > NW_CELL) x = mval;
  783.       else x = i * dw_cell;
  784.       if (j < 0) y0 = -dw_delt;
  785.       else if (j > NW_CELL) y0 = mval;
  786.       else y0 = j * dw_cell;
  787.       if ((j+1) < 0) y1 = -dw_delt;
  788.       else if ((j+1) > NW_CELL) y1 = mval;
  789.       else y1 = (j+1) * dw_cell;
  790.       LineB(drw, x, y0, x, y1);
  791.     }
  792.   }
  793.   for (i = -1; i <= NW_CELL; i++) for (j = -1; j <= NW_CELL + 1; j++)
  794.   {
  795.     if (j < 0 || j > NW_CELL || i >= 0 && i < NW_CELL)
  796.     {
  797.       double mval = dw_cell * NW_CELL + dw_delt;
  798.       double x0, x1, y;
  799.       if (i < 0) x0 = -dw_delt;
  800.       else if (i > NW_CELL) x0 = mval;
  801.       else x0 = i * dw_cell;
  802.       if ((i+1) < 0) x1 = -dw_delt;
  803.       else if ((i+1) > NW_CELL) x1 = mval;
  804.       else x1 = (i+1) * dw_cell;
  805.       if (j < 0) y = -dw_delt;
  806.       else if (j > NW_CELL) y = mval;
  807.       else y = j * dw_cell;
  808.       LineB(drw, x0, y, x1, y);
  809.     }
  810.   }
  811.   for (i = -1; i <= 1; i += 2)
  812.   {
  813.     drw->SetColor((i < 0) ? red : blue);
  814.     for (j = -1; j <= 1; j += 2)
  815.     {
  816.       double c = dw_cell * NW_CELL / 2;
  817.       double d = (dw_cell/2 > dw_delt) ? dw_delt : dw_cell/2;
  818.       LineB(drw, c + j * (c + 0.5*d), c + i * (c - 0.5*d),
  819.                   c + j * (c + 0.5*d), c + i * (c - 3.5*d));
  820.       LineB(drw, c + j * (c + 0.5*d), c + i * (c - 3.5*d),
  821.                   c + j * (c + 0.2*d), c + i * (c - 2.5*d));
  822.       LineB(drw, c + j * (c + 0.5*d), c + i * (c - 3.5*d),
  823.                   c + j * (c + 0.8*d), c + i * (c - 2.5*d));
  824.       LineB(drw, c + j * (c + 0.2*d), c + i * (c - 2.5*d),
  825.                   c + j * (c + 0.8*d), c + i * (c - 2.5*d));
  826.     }
  827.   }
  828.   for (i = 0; i < NW_CELL; i++) for (j = 0; j < NW_CELL; j++)
  829.   {
  830.     if (!PoleCpos(i, j))
  831.     {
  832.       drw->SetColor(black);
  833.       LineB(drw, (i+0.33) * dw_cell, j * dw_cell, (i+0.33) * dw_cell, (j+1) * dw_cell);
  834.       LineB(drw, (i+0.67) * dw_cell, j * dw_cell, (i+0.67) * dw_cell, (j+1) * dw_cell);
  835.       LineB(drw, i * dw_cell, (j+0.33) * dw_cell, (i+1) * dw_cell, (j+0.33) * dw_cell);
  836.       LineB(drw, i * dw_cell, (j+0.67) * dw_cell, (i+1) * dw_cell, (j+0.67) * dw_cell);
  837.       LineB(drw, i * dw_cell, j * dw_cell, (i+1) * dw_cell, (j+1) * dw_cell);
  838.       LineB(drw, (i+1) * dw_cell, j * dw_cell, i * dw_cell, (j+1) * dw_cell);
  839.     }
  840.     else
  841.     {
  842.       k = PoleToNum(i, j);
  843.       kn = MainPos.SH[k];
  844.       if (TheMove[0] > 0 && k == TheMove[1])
  845.       {
  846.         if (kn == 1 || kn == 2) kn = 5;
  847.         else if (kn == 3 || kn == 4) kn = 6;
  848.       }
  849.       if (TheMove[0] > 0 && k == TheMove[TheMove[0]])
  850.       {
  851.         kn = MainPos.SH[TheMove[1]];
  852.         if (kn <= 2 && BecameD) kn += 2;
  853.       }
  854.       if (kn == 1)
  855.       {
  856.         drw->SetColor(red);
  857.         DrawCh(drw, (i+0.5)*dw_cell, (j+0.5)*dw_cell,
  858.                      r_circle_pnt, NELEM(r_circle_pnt));
  859.       }
  860.       else if (kn == 2)
  861.       {
  862.         drw->SetColor(blue);
  863.         DrawCh(drw, (i+0.5)*dw_cell, (j+0.5)*dw_cell,
  864.                      r_circle_pnt, NELEM(r_circle_pnt));
  865.       }
  866.       else if (kn == 3)
  867.       {
  868.         drw->SetColor(red);
  869.         DrawCh(drw, (i+0.5)*dw_cell, (j+0.5)*dw_cell,
  870.                      r_star_pnt, NELEM(r_star_pnt));
  871.       }
  872.       else if (kn == 4)
  873.       {
  874.         drw->SetColor(blue);
  875.         DrawCh(drw, (i+0.5)*dw_cell, (j+0.5)*dw_cell,
  876.                      r_star_pnt, NELEM(r_star_pnt));
  877.       }
  878.       else if (kn == 5)
  879.       {
  880.         drw->SetColor(green);
  881.         DrawCh(drw, (i+0.5)*dw_cell, (j+0.5)*dw_cell,
  882.                   r_circle_pnt, NELEM(r_circle_pnt), 2);
  883.       }
  884.       else if (kn == 6)
  885.       {
  886.         drw->SetColor(green);
  887.         DrawCh(drw, (i+0.5)*dw_cell, (j+0.5)*dw_cell,
  888.                   r_circle_pnt, NELEM(r_circle_pnt), 2);
  889.       }
  890.     }
  891.   }
  892.   for (k = 1; k <= Eaten[0]; k++)
  893.   {
  894.     if (TheMove[0] <= 0 || Eaten[k] != TheMove[TheMove[0]])
  895.     {
  896.       NumToPole(Eaten[k], i, j);
  897.       kn = MainPos.SH[Eaten[k]];
  898.       if (kn)
  899.       {
  900.         if (kn == 1 || kn == 3) drw->SetColor(blue);
  901.         else if (kn == 2 || kn == 4) drw->SetColor(red);
  902.         DrawIL(drw, (i+0.5)*dw_cell, (j+0.5)*dw_cell, 2);
  903.       }
  904.     }
  905.   }
  906.   if (TheMove[0] > 0)
  907.   {
  908.     NumToPole(TheMove[TheMove[0]], i, j);
  909.     drw->SetColor(green);
  910.     DrawIL(drw, (i+0.5)*dw_cell, (j+0.5)*dw_cell, 1);
  911.   }
  912.   if (CurPoint.x >= 0 && CurPoint.y >= 0)
  913.   {
  914.     drw->SetColor(green);
  915.     DrawIL(drw, (CurPoint.x+0.5)*dw_cell, (CurPoint.y+0.5)*dw_cell, 0);
  916.   }
  917.   drw->SetColor(black);
  918.   DrawTextLine(drw);
  919.   if (some_draw) some_draw->DrawB(drw, *this);
  920.   drw->FreeColor(red);
  921.   drw->FreeColor(green);
  922.   drw->FreeColor(blue);
  923. }
  924.  
  925. int TChBoard::ResizeDraw(TGraphDraw *drw, int w, int h)
  926. {
  927.   int w0 = width, h0 = height;
  928.   Resize(w, h);
  929.   if (drw && drw->IsDraw() && (width != w0 || height != h0))
  930.   {
  931.     drw->DrawClear();
  932.     Draw(drw);
  933.     return 1;
  934.   }
  935.   else return 0;
  936. }
  937.  
  938. int TChBoard::CheckResize(TGraphDraw *drw)
  939. {
  940.   if (!drw || !check_resize) return 0;
  941.   int w, h;
  942.   drw->GetSize(w, h);
  943.   if (w < 0 || h < 0) return 0;
  944.   int w0 = width, h0 = height;
  945.   Resize(w, h);
  946.   return width != w0 || height != h0;
  947. }
  948.  
  949. void TChBoard::CurPointClear(TGraphDraw *drw) const
  950. {
  951.   if (!drw || !drw->IsDraw()) return;
  952.   drw->SetColor(drw->GetWhiteColor());
  953.   DrawIL(drw, (CurPoint.x+0.5)*dw_cell, (CurPoint.y+0.5)*dw_cell, 0);
  954. }
  955.  
  956. int TChBoard::MouseClick(TGraphDraw *drw, int x, int y)
  957. {
  958.   TRealPoint rpnt = WinToPl(x, y);
  959.   if (rpnt.x < -dw_delt || rpnt.y < -dw_delt ||
  960.       rpnt.x > NW_CELL*dw_cell + dw_delt ||
  961.       rpnt.y > NW_CELL*dw_cell + dw_delt) return -1;
  962.   if (CurPoint.x >= 0 && CurPoint.y >= 0)
  963.   {
  964.     CurPointClear(drw);
  965.     CurPoint.x = -1; CurPoint.y = -1;
  966.     Draw(drw);
  967.   }
  968.   ResetTextLine(drw);
  969.   if (AutoMove(drw)) return 3;
  970.   if (!CanPlayerMove()) return 0;
  971.   int i = (int)floor(rpnt.x / dw_cell), j = (int)floor(rpnt.y / dw_cell);
  972.   if (i < 0 || j < 0 || i >= NW_CELL || j >= NW_CELL) return 0;
  973.   if (!PoleCpos(i, j)) return 1;
  974.   return 2 + CMove(drw, i, j);
  975. }
  976.  
  977. TChBoard::PKey TChBoard::GetKeySide(PKey key)
  978. {
  979.   if (key != PLeft && key != PRight && key != PUp && key != PDown) return key;
  980.   TIntPoint a0 = PlToWin(4*dw_cell, 0);
  981.   TIntPoint a1 = PlToWin(4*dw_cell, 8*dw_cell);
  982.   TIntPoint b0 = PlToWin(0, 4*dw_cell);
  983.   TIntPoint b1 = PlToWin(8*dw_cell, 4*dw_cell);
  984.   double ax = a0.x - a1.x, ay = a0.y - a1.y;
  985.   double bx = b0.x - b1.x, by = b0.y - b1.y;
  986.   double t;
  987.   if (a0.x == INT_MIN || a0.y == INT_MIN || a1.x == INT_MIN ||
  988.       a1.y == INT_MIN || fabs(ax) < 0.5 && fabs(ay) < 0.5)
  989.   {
  990.     ax = 0, ay = 1;
  991.   }
  992.   if (b0.x == INT_MIN || b0.y == INT_MIN || b1.x == INT_MIN ||
  993.       b1.y == INT_MIN || fabs(bx) < 0.5 && fabs(by) < 0.5)
  994.   {
  995.     bx = 1, by = 0;
  996.   }
  997.   t = fabs(ax) + fabs(ay); ax /= t; ay /= t;
  998.   t = fabs(bx) + fabs(by); bx /= t; by /= t;
  999.   if (fabs(ax) <= fabs(bx))
  1000.   {
  1001.     if (key == PLeft) return (bx > 0) ? PRight : PLeft;
  1002.     if (key == PRight) return (bx > 0) ? PLeft : PRight;
  1003.     if (key == PUp) return (ay > 0) ? PDown : PUp;
  1004.     if (key == PDown) return (ay > 0) ? PUp : PDown;
  1005.   }
  1006.   else
  1007.   {
  1008.     if (key == PLeft) return (ax > 0) ? PDown : PUp;
  1009.     if (key == PRight) return (ax > 0) ? PUp : PDown;
  1010.     if (key == PUp) return (by > 0) ? PRight : PLeft;
  1011.     if (key == PDown) return (by > 0) ? PLeft : PRight;
  1012.   }
  1013.   return PNull;
  1014. }
  1015.  
  1016. int TChBoard::PKeyEvent(TGraphDraw *drw, PKey key)
  1017. {
  1018.   ResetTextLine(drw);
  1019.   if (AutoMove(drw)) return 3;
  1020.   if (!CanPlayerMove()) return 0;
  1021.   key = GetKeySide(key);
  1022.   if (CurPoint.x < 0 || CurPoint.y < 0 ||
  1023.       CurPoint.x >= NW_CELL || CurPoint.y >= NW_CELL)
  1024.   {
  1025.     CurPoint.x = NW_CELL / 2;
  1026.     CurPoint.y = NW_CELL / 2;
  1027.     Draw(drw);
  1028.     return 1;
  1029.   }
  1030.   if (key == PEnter) return 2 + CMove(drw, CurPoint.x, CurPoint.y);
  1031.   if (drw && drw->IsDraw() && CheckResize(drw))
  1032.   {
  1033.     drw->DrawClear();
  1034.     Draw(drw);
  1035.   }
  1036.   if (key == PLeft)
  1037.   {
  1038.     if (CurPoint.x == 0) return 0;
  1039.     CurPointClear(drw);
  1040.     CurPoint.x--;
  1041.     Draw(drw);
  1042.     return 1;
  1043.   }
  1044.   else if (key == PRight)
  1045.   {
  1046.     if (CurPoint.x == NW_CELL - 1) return 0;
  1047.     CurPointClear(drw);
  1048.     CurPoint.x++;
  1049.     Draw(drw);
  1050.     return 1;
  1051.   }
  1052.   else if (key == PUp)
  1053.   {
  1054.     if (CurPoint.y == 0) return 0;
  1055.     CurPointClear(drw);
  1056.     CurPoint.y--;
  1057.     Draw(drw);
  1058.     return 1;
  1059.   }
  1060.   else if (key == PDown)
  1061.   {
  1062.     if (CurPoint.y == NW_CELL - 1) return 0;
  1063.     CurPointClear(drw);
  1064.     CurPoint.y++;
  1065.     Draw(drw);
  1066.     return 1;
  1067.   }
  1068.   else return 0;
  1069. }
  1070.  
  1071. void TChBoard::UnMove(TGraphDraw *drw)
  1072. {
  1073.   MoveErase();
  1074.   if (drw && drw->IsDraw())
  1075.   {
  1076.     drw->DrawClear();
  1077.     Draw(drw);
  1078.   }
  1079. }
  1080.  
  1081. TChBoard::TextLineType TChBoard::GetTLTfromA(int s) const
  1082. {
  1083.   if (s >= 0) return TLT_Main;
  1084.   switch(s)
  1085.   {
  1086.     case Position::AWColor: return TLT_WrongColor;
  1087.     case Position::AfCell: return TLT_WfCell;
  1088.     case Position::AnfCell: return TLT_WnfCell;
  1089.     case Position::AMustEat: return TLT_WMustEat;
  1090.     case Position::AMustEatMore: return TLT_WMustEatMore;
  1091.     case Position::AMustEatMoreD: return TLT_WMustEatMoreD;
  1092.     case Position::ANoMove: return TLT_WNoMove;
  1093.     case Position::AChBack: return TLT_WChBack;
  1094.     case Position::ANotDm: return TLT_WNotDm;
  1095.     case Position::ANotDmE: return TLT_WNotDmE;
  1096.     case Position::AOnlyDiag: return TLT_WOnlyDiag;
  1097.     case Position::AEatYour: return TLT_WEatYour;
  1098.     case Position::AMoreOne: return TLT_WMoreOne;
  1099.     case Position::ATurnBack: return TLT_WTurnBack;
  1100.     default: return TLT_WrongMove;
  1101.   }
  1102. }
  1103.  
  1104. void TChBoard::ChangeTLT(TGraphDraw *drw, TextLineType t)
  1105. {
  1106.   if (text_line_type == t) return;
  1107.   if (drw && drw->IsDraw())
  1108.   {
  1109.     drw->SetColor(drw->GetWhiteColor());
  1110.     DrawTextLine(drw);
  1111.   }
  1112.   text_line_type = t;
  1113.   if (drw && drw->IsDraw())
  1114.   {
  1115.     drw->SetColor(drw->GetBlackColor());
  1116.     DrawTextLine(drw);
  1117.   }
  1118. }
  1119.  
  1120. TChBoard::TextLineType TChBoard::GetSimpleTLT() const
  1121. {
  1122.   if (game_end && CurMoveN >= MainPlay.GetN() - 1) return TLT_GameEnd;
  1123.   else return TLT_Move;
  1124. }
  1125.  
  1126. inline int TChBoard::ReinitHistory()
  1127. {
  1128.   if (history.Play(MainPlay)) {hist_inited = 1; return 1;}
  1129.   else {hist_inited = 0; return 0;}
  1130. }
  1131.  
  1132. void TChBoard::PrintLMove()
  1133. {
  1134.   PlayWrite::PMv pmv;
  1135.   if (MainPlay.GetMoveL(pmv.mv) >= 0)
  1136.   {
  1137.     MainPlay.GetPosL(pmv.pos, 1);
  1138.     char *s = new char[pmv.pos.GetLenMvEx(pmv.mv, 11)];
  1139.     if (s)
  1140.     {
  1141.       pmv.pos.WriteMvEx(pmv.mv, s, 11);
  1142.       printf("Checkers: %s%s\n", (pmv.pos.wmove == 1) ? "..." : "", s);
  1143.       delete[] s;
  1144.     }
  1145.     if (!hist_inited) ReinitHistory();
  1146.     else history.Move(pmv.pos, pmv.mv, MainPlay.GetN() - 1);
  1147.   }
  1148. }
  1149.  
  1150. int TChBoard::CMove(TGraphDraw *drw, int x, int y)
  1151. {
  1152.   if (AutoMove(drw)) return 1;
  1153.   if (!CanPlayerMove()) return 0;
  1154.   if (!game_end && text_line_type != TLT_Move) ChangeTLT(drw, TLT_Move);
  1155.   int k = PoleToNum(x, y), s;
  1156.   if (TheMove[0] > 0)
  1157.   {
  1158.     if (!PoleCpos(x, y) || k == TheMove[TheMove[0]]) {UnMove(drw); return 1;}
  1159.     int e = 1;
  1160.     s = MainPos.AMove(TheMove, k, e);
  1161.     if (s < 0)
  1162.     {
  1163.       ChangeTLT(drw, GetTLTfromA(s));
  1164.       return 0;
  1165.     }
  1166.     if (s < NUM_CELL) Eaten[++Eaten[0]] = (unsigned char)s;
  1167.     TheMove[++TheMove[0]] = (unsigned char)k;
  1168.     BecameD = BecameD || MainPos.BecameD(k, MainPos.SH[TheMove[1]]);
  1169.     if (e == 0)
  1170.     {
  1171.       if (MainPlay.Add(TheMove) != 0)
  1172.       {
  1173.         ChangeTLT(drw, TLT_WrongMove);
  1174.         return 0;
  1175.       }
  1176.       CurMoveN = MainPlay.GetN() - 1;
  1177.       MoveErase();
  1178.       RenewMPos();
  1179.       PrintLMove();
  1180.       if (AutoMove(drw)) return 1;
  1181.     }
  1182.     if (drw && drw->IsDraw())
  1183.     {
  1184.       drw->DrawClear();
  1185.       Draw(drw);
  1186.     }
  1187.     return 1;
  1188.   }
  1189.   else
  1190.   {
  1191.     if (!PoleCpos(x, y)) return 0;
  1192.     s = MainPos.AChCell(k);
  1193.     if (s != 1)
  1194.     {
  1195.       ChangeTLT(drw, GetTLTfromA(s));
  1196.       return 0;
  1197.     }
  1198.     TheMove[0] = 1;
  1199.     TheMove[1] = (unsigned char)k;
  1200.     Draw(drw);
  1201.     return 1;
  1202.   }
  1203. }
  1204.  
  1205. void TChBoard::SetNoMove(TGraphDraw *drw, int force)
  1206. {
  1207.   if (!force && CurPoint.x < 0 && CurPoint.y < 0 && TheMove[0] == 0 && Eaten[0] == 0)
  1208.   {
  1209.     return;
  1210.   }
  1211.   CurPoint.x = -1; CurPoint.y = -1;
  1212.   MoveErase();
  1213.   if (drw && drw->IsDraw())
  1214.   {
  1215.     drw->DrawClear();
  1216.     Draw(drw);
  1217.   }
  1218. }
  1219.  
  1220. int TChBoard::AutoMove(TGraphDraw *drw, int nmove, int draw_check)
  1221. {
  1222.   if (game_end || IsPlayView) {SetNoMove(drw, 0); return 0;}
  1223.   if (CurMoveN < MainPlay.GetN() - 1)
  1224.   {
  1225.     CurMoveN = MainPlay.GetN() - 1;
  1226.     RenewMPos();
  1227.     SetNoMove(drw);
  1228.     return 2;
  1229.   }
  1230.   if (!MainPos.AllCanEat() && !MainPos.AllCanMove())
  1231.   {
  1232.     game_end = 2 - MainPos.wmove;
  1233.     ChangeTLT(drw, TLT_GameEnd);
  1234.     if (!player[game_end - 1]) printf("Checkers: You win.\n");
  1235.     else printf("Checkers: You lose.\n");
  1236.     SetNoMove(drw);
  1237.     return 3;
  1238.   }
  1239.   else if (draw_check > 0 && MainPlay.IsDraw())
  1240.   {
  1241.     game_end = 5;
  1242.     ChangeTLT(drw, TLT_GameEnd);
  1243.     printf("Checkers: Draw.\n");
  1244.     SetNoMove(drw);
  1245.     return 3;
  1246.   }
  1247.   if (!player[MainPos.wmove]) return 0;
  1248.   TIntPoint CurP0 = CurPoint;
  1249.   if (CurPoint.x >= 0 && CurPoint.y >= 0)
  1250.   {
  1251.     if (drw) CurPointClear(drw);
  1252.     CurPoint.x = -1; CurPoint.y = -1;
  1253.   }
  1254.   MoveErase();
  1255.   int k;
  1256.   for (k = 0; player[MainPos.wmove] && (k < nmove || nmove == 0); k++)
  1257.   {
  1258.     TChPlayer::PMv pmv;
  1259.     pmv.pos = MainPos;
  1260.     Position::SetNullMv(pmv.mv);
  1261.     MainPlay.GetMoveL(pmv.mv);
  1262.     text_line_type = TLT_Move;
  1263.     if (!player[MainPos.wmove]->Move(pmv))
  1264.     {
  1265.       text_line_type = TLT_PlDidntMove;
  1266.       game_end = 4 - MainPos.wmove;
  1267.       break;
  1268.     }
  1269.     if (MainPlay.Add(pmv.mv) != 0)
  1270.     {
  1271.       text_line_type = TLT_PlWrongMove;
  1272.       game_end = 4 - MainPos.wmove;
  1273.       break;
  1274.     }
  1275.     CurMoveN = MainPlay.GetN() - 1;
  1276.     MoveErase();
  1277.     RenewMPos();
  1278.     PrintLMove();
  1279.     if (!MainPos.AllCanEat() && !MainPos.AllCanMove())
  1280.     {
  1281.       game_end = 2 - MainPos.wmove;
  1282.       text_line_type = TLT_GameEnd;
  1283.       if (!player[game_end - 1]) printf("Checkers: You win.\n");
  1284.       else printf("Checkers: You lose.\n");
  1285.       break;
  1286.     }
  1287.     else if (draw_check >= 0 && MainPlay.IsDraw())
  1288.     {
  1289.       game_end = 5;
  1290.       text_line_type = TLT_GameEnd;
  1291.       printf("Checkers: Draw.\n");
  1292.       break;
  1293.     }
  1294.   }
  1295.   if (!game_end)
  1296.   {
  1297.     text_line_type = TLT_Move;
  1298.     CurPoint = CurP0;
  1299.   }
  1300.   if (drw && drw->IsDraw())
  1301.   {
  1302.     drw->DrawClear();
  1303.     Draw(drw);
  1304.   }
  1305.   return 1;
  1306. }
  1307.  
  1308. void TChBoard::DrawTimer(TGraphDraw *drw, double t, int wh) const
  1309. {
  1310.   if (!drw || !drw->IsDraw()) return;
  1311.   if (wh) drw->SetColor(drw->GetWhiteColor());
  1312.   else drw->SetColor(drw->GetBlackColor());
  1313.   double r1 = dw_delt * 0.4, r2 = dw_delt * 0.45;
  1314.   double x = t * dw_cell * NW_CELL, y = -dw_delt / 2;
  1315.   if (MainPos.wmove == 1)
  1316.   {
  1317.     x = dw_cell * NW_CELL - x;
  1318.     y = dw_cell * NW_CELL - y;
  1319.   }
  1320.   LineB(drw, x - r1, y - r2, x + r2, y + r1);
  1321.   LineB(drw, x - r2, y - r1, x + r1, y + r2);
  1322.   LineB(drw, x - r1, y + r2, x + r2, y - r1);
  1323.   LineB(drw, x - r2, y + r1, x + r1, y - r2);
  1324.   if (wh)
  1325.   {
  1326.     int i, j, jj;
  1327.     drw->SetColor(drw->GetBlackColor());
  1328.     for (i = -1; i <= NW_CELL; i++)
  1329.     {
  1330.       double mval = dw_cell * NW_CELL + dw_delt;
  1331.       double x0, x1, y;
  1332.       if (i < 0) x0 = -dw_delt;
  1333.       else if (i > NW_CELL) x0 = mval;
  1334.       else x0 = i * dw_cell;
  1335.       if ((i+1) < 0) x1 = -dw_delt;
  1336.       else if ((i+1) > NW_CELL) x1 = mval;
  1337.       else x1 = (i+1) * dw_cell;
  1338.       if (fabs(x0 - x) < dw_delt || fabs(x1 - x) < dw_delt)
  1339.       {
  1340.         for (jj = 0; jj <= 1; jj++)
  1341.         {
  1342.           if (MainPos.wmove == 1) j = NW_CELL + jj;
  1343.           else j = -jj;
  1344.           if (j < 0 || j > NW_CELL || i >= 0 && i < NW_CELL)
  1345.           {
  1346.             if (j < 0) y = -dw_delt;
  1347.             else if (j > NW_CELL) y = mval;
  1348.             else y = j * dw_cell;
  1349.             LineB(drw, x0, y, x1, y);
  1350.           }
  1351.         }
  1352.       }
  1353.     }
  1354.   }
  1355. }
  1356.  
  1357. int TChBoard::SetCurMoveN(int n, TGraphDraw *drw)
  1358. {
  1359.   int nmove = MainPlay.GetN() - 1;
  1360.   if (n > nmove) n = nmove;
  1361.   if (n < 0) n = 0;
  1362.   if (CurMoveN != n)
  1363.   {
  1364.     CurMoveN = n;
  1365.     RenewMPos();
  1366.     if (n < nmove)
  1367.     {
  1368.       MoveErase();
  1369.       CurPoint.x = -1; CurPoint.y = -1;
  1370.     }
  1371.     text_line_type = GetSimpleTLT();
  1372.     if (drw && drw->IsDraw())
  1373.     {
  1374.       drw->DrawClear();
  1375.       Draw(drw);
  1376.     }
  1377.     return 1;
  1378.   }
  1379.   else return 0;
  1380. }
  1381.  
  1382. int TChBoard::SetPlay(const PlayWrite &play)
  1383. {
  1384.   if (play.GetN() <= 0) return 0;
  1385.   MainPlay = play;
  1386.   MoveErase();
  1387.   CurPoint.x = -1; CurPoint.y = -1;
  1388.   CurMoveN = INT_MIN;
  1389.   SetCurMoveN(play.GetN());
  1390.   if (!MainPos.AllCanEat() && !MainPos.AllCanMove()) game_end = 2 - MainPos.wmove;
  1391.   else if (MainPlay.IsDraw()) game_end = 5;
  1392.   else game_end = 0;
  1393.   text_line_type = GetSimpleTLT();
  1394.   IsPlayView = 1;
  1395.   EraseHistory();
  1396.   return 1;
  1397. }
  1398.  
  1399. void TChBoard::GoToCurMove()
  1400. {
  1401.   if (!MainPos.AllCanEat() && !MainPos.AllCanMove() ||
  1402.        MainPlay.IsDraw(CurMoveN + 1)) return;
  1403.   MainPlay.ClearFrom(CurMoveN + 1);
  1404.   MoveErase();
  1405.   game_end = 0;
  1406.   text_line_type = GetSimpleTLT();
  1407.   IsPlayView = 0;
  1408. }
  1409.  
  1410. #endif  //_HEADER_BOARD_H
  1411.