Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1805 yogev_ezra 1
#ifndef _HEADER_BOARD_H
2
#define _HEADER_BOARD_H
3
 
4
#ifndef __MENUET__
5
#include 
6
#include 
7
#include 
8
#include 
9
#include 
10
#include 
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