Subversion Repositories Kolibri OS

Rev

Rev 4652 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5123 clevermous 1
//#define LANG_RUS
2
#define NDEBUG
1805 yogev_ezra 3
#include 
4
#include 
5
#include 
6
#include 
7
#include 
8
 
5123 clevermous 9
// sprintf is too heavy
10
int itoa(char* dst, int number)
1805 yogev_ezra 11
{
5123 clevermous 12
	int result = 0;
13
	if (number < 0) {
14
		result++;
15
		*dst++ = '-';
16
		number = -number;
1805 yogev_ezra 17
	}
5123 clevermous 18
	char digits[16];
19
	int ndigits = 0;
20
	do {
21
		digits[ndigits++] = number % 10;
22
		number /= 10;
23
	} while (number);
24
	result += ndigits;
25
	for (; ndigits--; )
26
		*dst++ = digits[ndigits] + '0';
27
	return result;
1805 yogev_ezra 28
}
29
 
30
#include "gr-draw.h"
31
#include "board.h"
32
#include "player.h"
33
#include "buttons.h"
34
#include "sysproc.h"
35
 
36
char *strskipref(char *s1, char *s2)
37
{
38
  int L = strlen(s2);
39
  if (strncmp(s1, s2, L) == 0) return s1 + L;
40
  else return 0;
41
}
42
 
43
class TPlayArray
44
{
45
public:
46
  TPlayArray(int d = 10) : play(0), nplay(0), mplay(0) {}
47
  ~TPlayArray() {Clear();}
48
 
49
  void Clear();
50
  void Add(const PlayWrite &pl);
51
  PlayWrite &operator[](int i) {return play[i];}
52
  int GetNPlay() const {return nplay;}
5123 clevermous 53
#ifndef NO_FILES
1805 yogev_ezra 54
  int OpenFile(const char *name, int kind);
55
  int MsgOpenFile(const char *name, int kind);
56
  int SaveFile(const char *name, int num, int kind);
57
  int MsgSaveFile(const char *name, int num, int kind);
58
#endif
59
  void Del(int n);
60
protected:
61
  void Extend(int n = -1);
62
 
63
  PlayWrite *play;
64
  int nplay, mplay;
65
protected:
5123 clevermous 66
#ifndef NO_FILES
1805 yogev_ezra 67
  static const char *const search[];
68
  static int AnalizeKind(FILE *f, const int w[], const char *smb = 0);
69
  static int ReadFileTo(FILE *f, char c);
70
  static int ReadFileTo(FILE *f, const char *c);
71
  static int ReadTheText(FILE *f, const char *s);
72
#endif
73
};
74
 
5123 clevermous 75
#ifdef LANG_RUS //Pending Russian Translations
4652 ashmew2 76
    #define CHECKERS_CANT_OPEN_STR "\nШашки: Не могу открыть файл \"%s\".\n"
77
    #define CHECKERS_FILE_EMPTY_STR "\nШашки: Файл \"%s\" пуст.\n"
78
    #define CHECKERS_INVALID_FILE_STR "\nШашки: Файл \"%s\" ошибочный.\n"
79
    #define FILE_WRONG_TYPE_STR "\nШашки: Файл \"%s\" имеет неверный тип.\n"
80
    #define ERROR_OPENING_FILE_STR "\nШашки: Ошибка открытия файла \"%s\".\n"
81
    #define FILE_HAS_NO_GAMES_STR "\nШашки: Файл \"%s\" не содержит игр.\n"
82
    #define CANT_OPEN_FILE_STR "\nШашки: Не могу открыть файл \"%s\" на запись.\n"
83
    #define CHECKERS_STR "Шашки"
84
    #define FILE_SAVED_STR "\nШашки: Файл \"%s\" сохранён.\n"
85
    #define ERROR_SAVING_FILE_STR "\nШашки: Ошибка сохранения файла \"%s\".\n"
86
    #define NOT_ENOUGH_MEM_STR "\nШашки: Не достаточно памяти для сохранения файла \"%s\".\n"
87
    #define KIND_EQ2 "kind = 2\n"
88
    #define END_STR "[end]"
89
    #define PLAYV11_STR "[play_v1.1]"
90
    #define CHECKERS_PLAY_STR "checkers-play:text\n"
91
    #define CHECKERS_BIN_STR "checkers-play:bin_1.0\n"
92
    #define BLUE_STR "blue: "
93
    #define RED_STR "red: "
94
    #define INPUT_STR "input"
95
    #define COMPUTER_STR "computer"
96
    #define NEW_GAME_STR "new game"
97
    #define LIST_STR "list"
98
    #define DELETE_STR "delete"
99
    #define CLEAR_STR "clear"
100
    #define SAVE_STR "save"
101
    #define ROTATE_BOARD_STR "rotate board"
102
    #define EXIT_STR "exit"
103
    #define CHECKERS_INVALID_STR "Checkers: Invalid key %s\n"
104
 
5123 clevermous 105
#ifndef NO_FILES
1805 yogev_ezra 106
const char *const TPlayArray::search[] =
4652 ashmew2 107
  {"checkers-", "play:", "text", "bin_1.0\n", "history_", "1.0", "1.1"};
5123 clevermous 108
#endif
4652 ashmew2 109
 
110
#else /*For all other languages except RUS*/
111
    #define CHECKERS_CANT_OPEN_STR "\nCheckers: Can't open the file \"%s\".\n"
112
    #define CHECKERS_FILE_EMPTY_STR "\nCheckers: The file \"%s\" is empty.\n"
113
    #define CHECKERS_INVALID_FILE_STR "\nCheckers: Invalid file \"%s\".\n"
114
    #define FILE_WRONG_TYPE_STR "\nCheckers: The file \"%s\" has the wrong type.\n"
115
    #define ERROR_OPENING_FILE_STR "\nCheckers: Error opening the file \"%s\".\n"
116
    #define FILE_HAS_NO_GAMES_STR "\nCheckers: File \"%s\" doesn't contain games.\n"
117
    #define CANT_OPEN_FILE_STR "\nCheckers: Can't open the file \"%s\" to write.\n"
118
    #define NOT_ENOUGH_MEM_STR "\nCheckers: Not enough memory to save the file \"%s\".\n"
119
    #define ERROR_SAVING_FILE_STR "\nCheckers: Error saving the file \"%s\".\n"
120
    #define FILE_SAVED_STR "\nCheckers: File \"%s\" saved.\n"
121
    #define CHECKERS_STR "Checkers"
122
    #define KIND_EQ2 "kind = 2\n"
123
    #define END_STR "[end]"
124
    #define PLAYV11_STR "[Play_v1.1]"
125
    #define CHECKERS_PLAY_STR "checkers-play:text\n"
126
    #define CHECKERS_BIN_STR "checkers-play:bin_1.0\n"
127
    #define BLUE_STR "blue: "
128
    #define RED_STR "red: "
129
    #define INPUT_STR "input"
130
    #define COMPUTER_STR "computer"
131
    #define NEW_GAME_STR "new game"
132
    #define LIST_STR "list"
133
    #define DELETE_STR "delete"
134
    #define CLEAR_STR "clear"
135
    #define SAVE_STR "save"
136
    #define ROTATE_BOARD_STR "rotate board"
137
    #define EXIT_STR "exit"
138
    #define CHECKERS_INVALID_STR "Checkers: Invalid key %s\n"
5123 clevermous 139
 
140
#ifndef NO_FILES
4652 ashmew2 141
const char *const TPlayArray::search[] =
1805 yogev_ezra 142
     {"checkers-", "play:", "text", "bin_1.0\n", "history_", "1.0", "1.1"};
5123 clevermous 143
#endif
4652 ashmew2 144
 
1805 yogev_ezra 145
#endif
146
void TPlayArray::Clear()
147
{
148
  if (play) delete[] play;
149
  play = 0; nplay = 0; mplay = 0;
150
}
151
 
152
void TPlayArray::Extend(int n)
153
{
154
  if (n < 0) n = nplay + 1;
155
  if (mplay < n)
156
  {
157
    PlayWrite *p_old = play;
158
    int m_old = mplay;
159
    mplay = n * 2;
160
    play = new PlayWrite[mplay];
161
    if (p_old)
162
    {
163
      for (int i = 0; i < m_old; i++) play[i] = p_old[i];
164
      delete[] p_old;
165
    }
166
  }
167
}
168
 
169
void TPlayArray::Add(const PlayWrite &pl)
170
{
171
  Extend();
172
  play[nplay] = pl;
173
  nplay++;
174
}
175
 
5123 clevermous 176
#ifndef NO_FILES
1805 yogev_ezra 177
int TPlayArray::AnalizeKind(FILE *f, const int w[], const char *smb)
178
{
179
  int i, L, was1 = 1;
180
  unsigned char ch;
181
  int fnd[NELEM(search)];
182
  for (i = 0; i < NELEM(search); i++) fnd[i] = 1;
183
  for (L = 0; was1; L++)
184
  {
185
    was1 = 0;
186
    if (fread(&ch, 1, 1, f) != 1) return (L == 0) ? -2 : -1;
187
    for (i = 0; w[i] >= 0; i++) if (fnd[i])
188
    {
189
      if (tolower(ch) != tolower(search[w[i]][L])) fnd[i] = 0;
190
      else
191
      {
192
        was1 = 1;
193
        if (search[w[i]][L+1] == 0)
194
        {
195
          if (smb && smb[0] && fread(&ch, 1, 1, f) == 1)
196
          {
197
            ungetc(ch, f);
198
            if (strchr(smb, tolower(ch)) || isalpha(ch) && strchr(smb, toupper(ch)))
199
            {
200
              break;
201
            }
202
          }
203
          return i;
204
        }
205
      }
206
    }
207
  }
208
  return -10 - L;
209
}
210
 
211
int TPlayArray::ReadFileTo(FILE *f, char c)
212
{
213
  char ch;
214
  do
215
  {
216
    if (fread(&ch, 1, 1, f) != 1) return 0;
217
  }
218
  while(ch != c);
219
  return 1;
220
}
221
 
222
int TPlayArray::ReadFileTo(FILE *f, const char *c)
223
{
224
  char ch;
225
  do
226
  {
227
    if (fread(&ch, 1, 1, f) != 1) return 0;
228
  }
229
  while(!strchr(c, ch));
230
  return 1;
231
}
232
 
233
int TPlayArray::ReadTheText(FILE *f, const char *s)
234
{
235
  char ch;
236
  while (*s)
237
  {
238
    if (fread(&ch, 1, 1, f) != 1 || ch != *s) return 0;
239
    s++;
240
  }
241
  return 1;
242
}
243
 
244
int TPlayArray::OpenFile(const char *name, int kind)
245
{
246
  int k_fnd = 0;
247
  FILE *f = fopen(name, "rb");
248
  if (!f) return -1;
249
  if (kind == -1)
250
  {
251
    const int w[] = {0, -1};
252
    int r = AnalizeKind(f, w);
253
    if (r >= 0) {kind = w[r]; k_fnd = 1;}
254
    else if (r == -11) {kind = 3; k_fnd = 3;}
255
    else {fclose(f); return (kind == -2) ? -2 : -10;}
256
  }
257
  if (kind == 0)
258
  {
259
    if (k_fnd < 1 && !ReadFileTo(f, '-')) {fclose(f); return -10;}
260
    k_fnd = 1;
261
    const int w[] = {1, 4, -1};
262
    int r = AnalizeKind(f, w);
263
    if (r >= 0) {kind = w[r]; k_fnd = 2;}
264
    else {fclose(f); return -10;}
265
  }
266
  if (kind == 1)
267
  {
268
    if (k_fnd < 2 && !ReadFileTo(f, ':')) {fclose(f); return -10;}
269
    k_fnd = 2;
270
    const int w[] = {2, 3, -1};
271
    int r = AnalizeKind(f, w);
272
    if (r >= 0) {kind = w[r]; k_fnd = 3;}
273
    else {fclose(f); return -10;}
274
  }
275
  if (kind == 4)
276
  {
277
    if (k_fnd < 2 && !ReadFileTo(f, '_')) {fclose(f); return -10;}
278
    k_fnd = 2;
279
    const int w[] = {5, 6, -1};
280
    int r = AnalizeKind(f, w, ".1234567890");
281
    if (r >= 0) {kind = w[r]; k_fnd = 3;}
282
    else {fclose(f); return -10;}
283
  }
284
  if (kind == 5) {kind = 3; k_fnd = 0;}
285
  if (kind == 6)
286
  {
287
    if (!ReadFileTo(f, "\n\r")) {fclose(f); return -4;}
288
    k_fnd = 3;
289
    PlayWrite *pl = 0;
290
    int np = THistory::HRead(f, pl);
291
    if (np > 0 && pl)
292
    {
293
      int i;
294
      Extend(nplay + np);
295
      for (i = 0; i < np; i++)
296
      {
297
        if (pl[i].GetN() >= 3) play[nplay++] = pl[i];
298
      }
299
    }
300
    if (pl) delete[] pl;
301
    fclose(f);
302
    return 1;
303
  }
304
  if (kind == 2)
305
  {
4652 ashmew2 306
    printf(KIND_EQ2);
1805 yogev_ezra 307
    unsigned char ch;
308
    do
309
    {
310
      if (fread(&ch, 1, 1, f) != 1) {fclose(f); return -10;}
311
    }
312
    while(!isspace(ch));
313
    PlayWrite pl;
314
    char word[101];
315
    int i, kind = 0;
316
    for (;;)
317
    {
318
      do
319
      {
320
        if (fread(&ch, 1, 1, f) != 1) break;
321
      }
322
      while(ch == 0 || isspace(ch));
4652 ashmew2 323
      if (feof(f)) strcpy(word, END_STR);
1805 yogev_ezra 324
      else
325
      {
326
        i = 0;
327
        while(ch != 0 && !isspace(ch))
328
        {
329
          if (i < 100) word[i++] = ch;
330
          if (fread(&ch, 1, 1, f) != 1) break;
331
        }
332
        word[i] = 0;
333
      }
334
      if (word[0] != '[')
335
      {
336
        if (kind == 1)
337
        {
338
          if (word[0] != '#' && word[0] != '$' && word[0] != '%')
339
          {
340
            Position pos;
341
            pos.Read(word, 1);
342
            pl.Clear();
343
            pl.Add(0, pos);
344
            kind = 2;
345
          }
346
        }
347
        else if (kind == 2)
348
        {
349
          if (word[0] != '#' && word[0] != '$' && word[0] != '%')
350
          {
351
            for (i = 0; word[i] && word[i] != '.' && word[i] != ','; i++)
352
            {
353
              if (!isdigit((unsigned char)word[i])) {i = -1; break;}
354
            }
355
            if (i == -1)
356
            {
357
              PlayWrite::PMv pmv;
358
              if (pl.GetPosL(pmv.pos) < 0) kind = 3;
359
              else if (!pmv.pos.ReadMv(pmv.mv, word, 1)) kind = 3;
360
              else if (pl.Add(pmv.mv) != 0) kind = 3;
361
            }
362
          }
363
        }
364
      }
365
      else
366
      {
4652 ashmew2 367
	char end_literal[] = END_STR;
368
	char playv11_literal[] = PLAYV11_STR;
369
 
1805 yogev_ezra 370
        if (kind == 2 || kind == 3)
371
        {
372
          if (pl.GetN() > 0) Add(pl);
373
          pl.Clear();
374
        }
375
        kind = 0;
376
        for (i = 0; word[i]; i++)
377
        {
378
          word[i] = (char)tolower((unsigned char)word[i]);
379
        }
4652 ashmew2 380
        if (strskipref(word, end_literal)) break;
381
        else if (strskipref(word, playv11_literal)) kind = 1;
1805 yogev_ezra 382
      }
383
    }
384
    fclose(f);
385
    return 1;
386
  }
387
  if (kind == 3)
388
  {
389
    char ch[LEN_WPOS];
390
    if (k_fnd < 3 && !ReadFileTo(f, '\n')) {fclose(f); return -10;}
391
    k_fnd = 3;
392
    do
393
    {
394
      PlayWrite pl;
395
      for (;;)
396
      {
397
        int i;
398
        for (i = 0; i < LEN_WPOS; i++)
399
        {
400
          if (fread(ch + i, 1, 1, f) != 1 || ch[i] < 0) break;
401
        }
402
        if (i < LEN_WPOS) break;
403
        PlayWrite::PMv pmv0, pmv1;
404
        pmv1.pos.Read(ch);
405
        pmv1.pos.Reverse();
406
        if (pl.GetPMvL(pmv0) >= 0)
407
        {
408
          TComputerPlayer::Z z;
409
          z.FindAllMoves(pmv0);
410
          int r;
411
          for (r = 0; r < z.narr; r++)
412
          {
413
            if (memcmp(z.array[r].pos.SH, pmv1.pos.SH, sizeof(pmv1.pos.SH)) == 0)
414
            {
415
              pmv1 = z.array[r];
416
              break;
417
            }
418
          }
419
          if (r < z.narr) pl.Add(pmv1);
420
          else {fclose(f); return -3;}
421
        }
422
        else pl.Add(0, pmv1.pos);
423
      }
424
      if (pl.GetN() > 0) Add(pl);
425
    }
426
    while(!feof(f));
427
    fclose(f);
428
    return 1;
429
  }
430
  fclose(f);
431
  return -10;
432
}
433
 
434
int TPlayArray::MsgOpenFile(const char *name, int kind)
435
{
436
  int n0 = nplay, no_games = 0;
437
  int r = OpenFile(name, kind);
438
  if (r <= 0)
439
  {
440
    if (r == -1)
441
    {
4652 ashmew2 442
      printf(CHECKERS_CANT_OPEN_STR, name);
1805 yogev_ezra 443
      return 0;
444
    }
445
    else if (r == -2)
446
    {
4652 ashmew2 447
      printf(CHECKERS_FILE_EMPTY_STR, name);
1805 yogev_ezra 448
      return 0;
449
    }
450
    else if (r == -3)
451
    {
4652 ashmew2 452
      printf(CHECKERS_INVALID_FILE_STR, name);
1805 yogev_ezra 453
      return 0;
454
    }
455
    else if (r == -4) no_games = 1;
456
    else if (r == -10)
457
    {
4652 ashmew2 458
      printf(FILE_WRONG_TYPE_STR, name);
1805 yogev_ezra 459
      return 0;
460
    }
461
    else
462
    {
4652 ashmew2 463
      printf(ERROR_OPENING_FILE_STR, name);
1805 yogev_ezra 464
      return 0;
465
    }
466
  }
467
  if (!no_games && nplay > n0) return 1;
468
  else
469
  {
4652 ashmew2 470
    printf(FILE_HAS_NO_GAMES_STR, name);
1805 yogev_ezra 471
    return 0;
472
  }
473
}
474
 
475
int TPlayArray::SaveFile(const char *name, int num, int kind)
476
{
477
  FILE *f = 0;
478
  if (kind == 0 || kind == 1 || kind == 2)
479
  {
480
    f = fopen(name, "wt");
481
    if (!f) return -1;
4652 ashmew2 482
 
483
    fprintf(f, CHECKERS_PLAY_STR);
1805 yogev_ezra 484
    int i0 = num, i;
485
    if (num < 0) {i0 = 0; num = nplay-1;}
486
    for (i = i0; i <= num; i++) if (play[i].GetN() > 0)
487
    {
488
      PlayWrite::PMv pmv;
489
      if (play[i].GetPos(pmv.pos, 0) < 0) return -9;
490
      char *str = new char[10 + NUM_CELL];
491
      if (!str) return -5;
492
      pmv.pos.Write(str, 1);
4652 ashmew2 493
      fprintf(f, "\n"PLAYV11_STR"#%d  %s\n", i - i0 + 1, str);
1805 yogev_ezra 494
      delete[] str;
495
      int j;
496
      for (j = 1; j < play[i].GetN(); j++)
497
      {
498
        if (play[i].GetPos(pmv.pos, j - 1) < 0) return -9;
499
        if (play[i].GetMove(pmv.mv, j) < 0) return -9;
500
        str = new char[pmv.pos.GetLenMvEx(pmv.mv, 11)];
501
        if (!str) return -5;
502
        pmv.pos.WriteMvEx(pmv.mv, str, 11);
503
        if (j % 2 == 1)
504
        {
505
          int nbytes = fprintf(f, "%d. ", (j + 1) / 2);
506
          while(nbytes++ < 5) fprintf(f, " ");
507
        }
508
        fprintf(f, "%s", str);
509
        if (j % 2 == 0 || j == play[i].GetN() - 1) fprintf(f, "\n");
510
        else fprintf(f, " ,\t");
511
        delete[] str;
512
      }
513
    }
514
    fclose(f);
515
    return 1;
516
  }
517
  else if (kind == -1 || kind == 3)
518
  {
519
    f = fopen(name, "wb");
520
    if (!f) return -1;
4652 ashmew2 521
    if (kind == 3) fprintf(f, CHECKERS_BIN_STR);
522
 
1805 yogev_ezra 523
    int i = num;
524
    if (num < 0) {i = 0; num = nplay-1;}
525
    for (; i <= num; i++)
526
    {
527
      char ch[LEN_WPOS];
528
      Position pos;
529
      play[i].GetPosL(pos);
530
      if (!pos.AllCanEat() && !pos.AllCanMove())
531
      {
532
        ch[0] = (pos.wmove == 0) ? char(-3) : char(-1);
533
      }
534
      else ch[0] = char(-2);
535
      fwrite(ch, 1, 1, f);
536
      int j;
537
      for (j = 0; j < play[i].GetN(); j++)
538
      {
539
        Position pos;
540
        play[i].GetPos(pos, j);
541
        pos.Reverse();
542
        pos.Write(ch);
543
        fwrite(ch, LEN_WPOS, 1, f);
544
      }
545
    }
546
    fclose(f);
547
    return 1;
548
  }
549
  if (f) fclose(f);
550
  return -10;
551
}
552
 
553
int TPlayArray::MsgSaveFile(const char *name, int num, int kind)
554
{
555
  int r = SaveFile(name, num, kind);
556
  if (r <= 0)
557
  {
558
    if (r == -1)
559
    {
4652 ashmew2 560
      printf(CANT_OPEN_FILE_STR, name);
1805 yogev_ezra 561
    }
562
    else if (r == -5)
563
    {
4652 ashmew2 564
      printf(NOT_ENOUGH_MEM_STR, name);
1805 yogev_ezra 565
    }
566
    else if (r == -10)
567
    {
4652 ashmew2 568
      printf(FILE_WRONG_TYPE_STR, name);
1805 yogev_ezra 569
    }
570
    else
571
    {
4652 ashmew2 572
      printf(ERROR_SAVING_FILE_STR, name);
1805 yogev_ezra 573
    }
574
    return 0;
575
  }
576
  else
577
  {
4652 ashmew2 578
    printf(FILE_SAVED_STR, name);
1805 yogev_ezra 579
    return 1;
580
  }
581
}
582
#endif
583
 
584
void TPlayArray::Del(int n)
585
{
586
  if (!play || n < 0 || n >= nplay) return;
587
  else if (nplay <= 1) {Clear(); return;}
588
  int i;
589
  for (i = n; i < nplay - 1; i++) play[i] = play[i+1];
590
  play[nplay - 1].Clear();
591
  nplay--;
592
}
593
 
594
 
595
void SetPlayerString(char *str, int c, TChPlayer *p)
596
{
4652 ashmew2 597
  strcpy(str, c ? BLUE_STR : RED_STR);
598
  if (!p) strcat(str, INPUT_STR);
599
  else strcat(str, COMPUTER_STR);
1805 yogev_ezra 600
}
601
 
602
class TMainDraw : public TSomeDraw
603
{
604
public:
4652 ashmew2 605
 
1805 yogev_ezra 606
  TMainDraw() : undo_redo(0), ur_type(-1), cur_play(0),
607
                def_savefile("save.che"), def_savekind(2) {InitButton();}
4652 ashmew2 608
 
1805 yogev_ezra 609
  virtual void Draw(TGraphDraw *drw, int w, int h)
610
  {
611
    int d = button.GetDelt();
612
    int hh = button.GetHeight(w - 2*d);
613
    if (hh != 0) hh += d;
614
    drw->SetColor(drw->GetBlackColor());
615
    button.Draw(drw, d, h - hh, w - 2*d);
616
  }
617
 
618
  virtual void DrawB(TGraphDraw *drw, TChBoard &board)
619
  {
620
    int urt = (board.GetCurMoveN() <= 0) +
621
            2*(board.GetCurMoveN() >= board.GetNumMove());
622
    if (ur_type != urt) SetButtonKind(board);
623
    Draw(drw, board.GetW(), board.GetH());
624
  }
625
 
626
  virtual TIntPoint GetDSize(int w, int h)
627
  {
628
    int d = button.GetDelt();
629
    int hh = button.GetHeight(w - 2*d);
630
    if (hh != 0) hh += d;
631
    return TIntPoint(0, hh);
632
  }
633
 
634
  virtual int ButtonPnt(int xp, int yp, int w, int h, int &n, int k = 0)
635
  {
636
    int d = button.GetDelt();
637
    int hh = button.GetHeight(w - 2*d);
638
    if (hh != 0) hh += d;
639
    return button.ButtonPnt(xp - d, yp - (h - hh), w - 2*d, n, k);
640
  }
641
 
642
  void InitButton();
643
  void SetButtonKind(const TChBoard &board);
644
  void PressUR(int n, TChBoard &board, TGraphDraw *drw);
645
  void PressLS(int n, TChBoard &board, TGraphDraw *drw);
646
  void CurPlayNorm()
647
  {
648
    if (cur_play < 0 || cur_play >= play.GetNPlay()) cur_play = 0;
649
  }
650
 
651
  TXButtonArray button;
652
  TMultiButton *undo_redo, *play_list;
653
  char player_str[2][50], play_num[2][10];
654
  TPlayArray play;
655
  int cur_play;
656
  char *def_savefile;
657
  int def_savekind;
658
protected:
659
  int ur_type;
660
};
661
 
662
void TMainDraw::InitButton()
663
{
5123 clevermous 664
  static char newgame_literal[] = NEW_GAME_STR;
665
  static char list_literal[] = LIST_STR;
666
  static char delete_literal[] = DELETE_STR;
667
  static char clear_literal[] = CLEAR_STR;
668
  static char save_literal[] = SAVE_STR;
669
  static char rotateboard_literal[] = ROTATE_BOARD_STR;
670
  static char exit_literal[] = EXIT_STR;
4652 ashmew2 671
 
5123 clevermous 672
  static char one_literal[] = "1";
673
  static char dash_literal[] = "-";
674
  static char plus_literal[] = "+";
675
  static char leftshift_literal[] = "<<";
676
  static char rightshift_literal[] = ">>";
677
  static char lessthan_literal[] = "<";
678
  static char greaterthan_literal[] = ">";
679
  static char xor_literal[] = "^";
4652 ashmew2 680
 
681
  button.Add(1, 80, 22, newgame_literal);
682
  button.Add(6, 60, 22, list_literal);
683
  button.Add(7, 60, 22, delete_literal);
1805 yogev_ezra 684
  play_list = new TMultiButton(20);
4652 ashmew2 685
  play_list->a.Add(26, 20, 22, one_literal);
686
  play_list->a.Add(21, 20, 22, dash_literal);
1805 yogev_ezra 687
  play_list->a.Add(23, 37, 22, play_num[0], -2);
4652 ashmew2 688
  play_list->a.Add(22, 20, 22, plus_literal);
1805 yogev_ezra 689
  play_list->a.Add(27, 37, 22, play_num[1]);
690
  play_list->SetDefW();
691
  button.Add(play_list);
4652 ashmew2 692
  button.Add(24, 50, 22, clear_literal);
5123 clevermous 693
#ifndef NO_FILES
4652 ashmew2 694
  button.Add(25, 50, 22, save_literal);
1805 yogev_ezra 695
#endif
696
  button.Add(2, 120, 22, player_str[0]);
697
  button.Add(3, 120, 22, player_str[1]);
4652 ashmew2 698
  button.Add(4, 110, 22, rotateboard_literal);
1805 yogev_ezra 699
  undo_redo = new TMultiButton(10);
4652 ashmew2 700
  undo_redo->a.Add(11, 27, 22, leftshift_literal);
701
  undo_redo->a.Add(12, 20, 22, lessthan_literal);
702
  undo_redo->a.Add(15, 20, 22, xor_literal);
703
  undo_redo->a.Add(13, 20, 22, greaterthan_literal);
704
  undo_redo->a.Add(14, 27, 22, rightshift_literal);
1805 yogev_ezra 705
  undo_redo->SetDefW();
706
  button.Add(undo_redo);
4652 ashmew2 707
  button.Add(5, 60, 22, exit_literal);
1805 yogev_ezra 708
}
709
 
710
void TMainDraw::SetButtonKind(const TChBoard &board)
711
{
712
  int thick;
713
  TextButton *txb;
714
  TXButton *bt1;
715
  ur_type = 0;
716
  SetPlayerString(player_str[0], 0, board.GetPlayer(0));
717
  SetPlayerString(player_str[1], 1, board.GetPlayer(1));
718
  int is_drw = !board.GetPViewStatus();
719
  bt1 = button.GetButton(2);
720
  if (bt1) bt1->drw = is_drw;
721
  bt1 = button.GetButton(3);
722
  if (bt1) bt1->drw = is_drw;
723
  if (board.GetCurMoveN() <= 0) {ur_type++; thick = 0;}
724
  else thick =  3;
725
//  txb = dynamic_cast(undo_redo->a.GetButton(11));
726
//  if (txb) txb->thick = thick;
727
//  txb = dynamic_cast(undo_redo->a.GetButton(12));
728
//  if (txb) txb->thick = thick;
729
// we can use simple static cast
730
	((TextButton*)(undo_redo->a.GetButton(11)))->thick = thick;
731
	((TextButton*)(undo_redo->a.GetButton(12)))->thick = thick;
732
  if (board.GetCurMoveN() >= board.GetNumMove()) {ur_type += 2; thick = 0;}
733
  else thick = 3;
734
//  txb = dynamic_cast(undo_redo->a.GetButton(13));
735
//  if (txb) txb->thick = thick;
736
//  txb = dynamic_cast(undo_redo->a.GetButton(14));
737
//  if (txb) txb->thick = thick;
738
	((TextButton*)(undo_redo->a.GetButton(13)))->thick = thick;
739
	((TextButton*)(undo_redo->a.GetButton(14)))->thick = thick;
740
  if (board.GetCurMoveN() < board.GetNumMove() ||
741
     (board.GetPViewStatus() && board.GetGameEnd() <= 0))
742
  {
743
    thick = 3;
744
  }
745
  else thick = 0;
746
//  txb = dynamic_cast(undo_redo->a.GetButton(15));
747
//  if (txb) txb->thick = thick;
748
	((TextButton*)(undo_redo->a.GetButton(15)))->thick = thick;
749
  if (play.GetNPlay() == 0) is_drw = 1;
750
  bt1 = button.GetButton(6);
751
  if (bt1) bt1->drw = is_drw;
752
  bt1 = button.GetButton(7);
753
  if (bt1) bt1->drw = !is_drw;
5123 clevermous 754
#ifndef NO_FILES
1805 yogev_ezra 755
  bt1 = button.GetButton(25);
756
  if (bt1) bt1->drw = !is_drw;
757
#endif
758
  is_drw = board.GetPViewStatus() && play.GetNPlay() > 1;
759
  bt1 = button.GetButton(20);
760
  if (bt1) bt1->drw = is_drw;
761
  bt1 = button.GetButton(24);
762
  if (bt1) bt1->drw = is_drw;
763
  if (is_drw)
764
  {
765
    play_num[0][0] = 0; play_num[1][0] = 0;
5123 clevermous 766
    if (cur_play >= 0) itoa(play_num[0], cur_play + 1);
767
    itoa(play_num[1], play.GetNPlay());
1805 yogev_ezra 768
    thick = (cur_play <= 0) ? 0 : 3;
5123 clevermous 769
    txb = static_cast(play_list->a.GetButton(21));
1805 yogev_ezra 770
    if (txb) txb->thick = thick;
5123 clevermous 771
    txb = static_cast(play_list->a.GetButton(26));
1805 yogev_ezra 772
    if (txb) txb->thick = thick;
773
    thick = (cur_play >= play.GetNPlay() - 1) ? 0 : 3;
5123 clevermous 774
    txb = static_cast(play_list->a.GetButton(22));
1805 yogev_ezra 775
    if (txb) txb->thick = thick;
5123 clevermous 776
    txb = static_cast(play_list->a.GetButton(27));
1805 yogev_ezra 777
    if (txb) txb->thick = thick;
778
  }
779
}
780
 
781
void TMainDraw::PressUR(int n, TChBoard &board, TGraphDraw *drw)
782
{
783
  int mv;
784
  if (n == 11) mv = 0;
785
  else if (n == 12) mv = board.GetCurMoveN() - 1;
786
  else if (n == 13) mv = board.GetCurMoveN() + 1;
787
  else mv = board.GetNumMove();
788
  if (board.SetCurMoveN(mv))
789
  {
790
    SetButtonKind(board);
791
    if (drw && drw->IsDraw())
792
    {
793
      drw->DrawClear();
794
      board.Draw(drw);
795
    }
796
  }
797
  else Draw(drw, board.GetW(), board.GetH());
798
}
799
 
800
void TMainDraw::PressLS(int n, TChBoard &board, TGraphDraw *drw)
801
{
802
  int need_redraw = 0;
803
  if (n == 6)
804
  {
805
    if (!board.GetPViewStatus() || play.GetNPlay() == 0)
806
    {
807
      PlayWrite cur_pw = board.GetPlay();
808
      if (cur_pw.GetN() > 2 || play.GetNPlay() == 0) play.Add(board.GetPlay());
809
      cur_play = play.GetNPlay() - 1;
810
      board.SetPlay(play[cur_play]);
811
      need_redraw = 1;
812
    }
813
  }
814
  else if (n == 7)
815
  {
816
    if (board.GetPViewStatus() && play.GetNPlay() != 0)
817
    {
818
      play.Del(cur_play);
819
      if (play.GetNPlay() >= 1)
820
      {
821
        if (cur_play >= play.GetNPlay()) cur_play--;
822
        board.SetPlay(play[cur_play]);
823
      }
824
      need_redraw = 1;
825
    }
826
  }
827
  else if (n == 21)
828
  {
829
    if (cur_play > 0) {board.SetPlay(play[--cur_play]); need_redraw = 1;}
830
  }
831
  else if (n == 22)
832
  {
833
    if (cur_play < play.GetNPlay() - 1)
834
    {
835
      board.SetPlay(play[++cur_play]); need_redraw = 1;
836
    }
837
  }
838
  else if (n == 26)
839
  {
840
    if (cur_play > 0)
841
    {
842
      cur_play = 0;
843
      board.SetPlay(play[cur_play]); need_redraw = 1;
844
    }
845
  }
846
  else if (n == 27)
847
  {
848
    if (cur_play < play.GetNPlay() - 1)
849
    {
850
      cur_play = play.GetNPlay() - 1;
851
      board.SetPlay(play[cur_play]); need_redraw = 1;
852
    }
853
  }
854
  else if (n == 24) {play.Clear(); cur_play = 0; need_redraw = 1;}
5123 clevermous 855
#ifndef NO_FILES
1805 yogev_ezra 856
  else if (n == 25)
857
  {
858
    if (play.GetNPlay() > 0) play.MsgSaveFile(def_savefile, -1, def_savekind);
859
  }
860
  else if (n == 28)
861
  {
862
    if (play.GetNPlay() > 0) play.MsgSaveFile(def_savefile, cur_play, def_savekind);
863
  }
864
#endif
865
  if (need_redraw)
866
  {
867
    SetButtonKind(board);
868
    if (drw && drw->IsDraw())
869
    {
870
      drw->DrawClear();
871
      board.Draw(drw);
872
    }
873
  }
874
  else Draw(drw, board.GetW(), board.GetH());
875
}
876
 
877
struct TTimerDraw
878
{
879
  TTimerDraw(TChBoard *brd, TGraphDraw *drw) : brd(brd), drw(drw) {}
880
 
881
  TChBoard *brd;
882
  clock_t st, ut, dt;
883
  double x0;
884
  TGraphDraw *drw;
885
 
886
  static void draw(void *v, int k = 0);
887
};
888
 
889
void TTimerDraw::draw(void *v, int k)
890
{
891
  TTimerDraw &d = *(TTimerDraw*)v;
892
  clock_t t = clock();
893
  if (k == 0 && t - d.ut < CLOCKS_PER_SEC * 0.01) return;
894
  if (k > 0)
895
  {
896
    d.st = t;
897
    if (!d.drw || !d.drw->IsDraw()) return;
898
    d.drw->DrawClear();
899
    d.brd->Draw(d.drw);
900
    d.dt = t;
901
  }
902
  else if (!d.drw || !d.drw->IsDraw()) return;
903
  double xold = d.x0;
904
  if (k >= 0)
905
  {
906
    d.x0 = (1 - cos(2.0 * (t - d.st) / CLOCKS_PER_SEC)) / 2;
907
    d.brd->DrawTimer(d.drw, d.x0, 0);
908
    d.ut = t;
909
    if (k == 0 && t - d.dt > CLOCKS_PER_SEC * 0.5)
910
    {
911
      d.brd->Draw(d.drw);
912
      d.dt = t;
913
    }
914
  }
915
  if (k <= 0) d.brd->DrawTimer(d.drw, xold, 1);
916
}
917
 
918
 
919
struct TMainData
920
{
921
  TChBoard board;
922
  TComputerPlayer player;
923
  TMainDraw main_draw;
924
 
925
  TMainData(int id = 0);
926
  void InitDef();
927
  static int EventFunction(const TGraphDraw::event &ev);
928
  void NewGame(TGraphDraw *drw);
929
  void RotateBoard(TGraphDraw *drw);
930
  void PlayerPress(int np, TGraphDraw *drw);
931
  void GoToCurMove(TGraphDraw *drw);
932
};
933
 
934
TMainData::TMainData(int id) : board(id)
935
{
936
  board.SetCheckResize(1);
937
  board.SetPlayer(1, &player);
938
  board.SetBottomColor(0);
939
  board.SetSomeDraw(&main_draw);
940
  board.SetMinWSize(90, 140);
941
}
942
 
943
void TMainData::InitDef()
944
{
945
  if (main_draw.play.GetNPlay() > 0)
946
  {
947
    main_draw.CurPlayNorm();
948
    board.SetPlay(main_draw.play[main_draw.cur_play]);
949
  }
950
  main_draw.SetButtonKind(board);
951
}
952
 
953
void TMainData::NewGame(TGraphDraw *drw)
954
{
955
  board.NewGame();
956
  main_draw.SetButtonKind(board);
957
  if (drw && drw->IsDraw()) {drw->DrawClear(); board.Draw(drw);}
958
}
959
 
960
void TMainData::RotateBoard(TGraphDraw *drw)
961
{
962
  board.SetBottomColor(3 - board.GetBottomColor());
963
  if (drw && drw->IsDraw()) {drw->DrawClear(); board.Draw(drw);}
964
}
965
 
966
void TMainData::PlayerPress(int np, TGraphDraw *drw)
967
{
968
  if (np != 0 && np != 1) return;
969
  if (board.GetPlayer(np)) board.SetPlayer(np, 0);
970
  else board.SetPlayer(np, &player);
971
  if (board.GetPlayer(0) && !board.GetPlayer(1))
972
  {
973
    board.SetBottomColor(1);
974
  }
975
  if (board.GetPlayer(1) && !board.GetPlayer(0))
976
  {
977
    board.SetBottomColor(0);
978
  }
979
  main_draw.SetButtonKind(board);
980
  if (drw && drw->IsDraw()) {drw->DrawClear(); board.Draw(drw);}
981
}
982
 
983
void TMainData::GoToCurMove(TGraphDraw *drw)
984
{
985
  board.GoToCurMove();
986
  main_draw.SetButtonKind(board);
987
  if (drw && drw->IsDraw()) {drw->DrawClear(); board.Draw(drw);}
988
}
989
 
990
int TMainData::EventFunction(const TGraphDraw::event &ev)
991
{
992
  if (!ev.any.drw->data) return -100;
993
  TMainData &data = *(TMainData*)ev.any.drw->data;
994
  int nbutton, ret = 0;
995
  switch(ev.type)
996
  {
997
  case TGraphDraw::event::button_down:
998
    if (ev.button.n != 1) break;
999
    ev.button.drw->OpenDraw();
1000
    if (data.main_draw.ButtonPnt(ev.button.x, ev.button.y,
1001
             data.board.GetW(), data.board.GetH(), nbutton, 1) > 0)
1002
    {
1003
      data.main_draw.Draw(ev.button.drw, data.board.GetW(), data.board.GetH());
1004
      ret |= TGraphDraw::ret_setcapture;
1005
    }
1006
    else data.board.MouseClick(ev.button.drw, ev.button.x, ev.button.y);
1007
    ev.button.drw->CloseDraw();
1008
    break;
1009
  case TGraphDraw::event::mouse_move:
1010
    if (ev.button.n >= 0 && ev.button.n != 1) break;
1011
    ev.button.drw->OpenDraw();
1012
    if (data.main_draw.ButtonPnt(ev.button.x, ev.button.y,
1013
             data.board.GetW(), data.board.GetH(), nbutton, 2) >= 1000)
1014
    {
1015
      data.main_draw.Draw(ev.button.drw, data.board.GetW(), data.board.GetH());
1016
    }
1017
    ev.button.drw->CloseDraw();
1018
    break;
1019
  case TGraphDraw::event::button_up:
1020
    if (ev.button.n != 1) break;
1021
    ev.button.drw->OpenDraw();
1022
    if (data.main_draw.ButtonPnt(ev.button.x, ev.button.y,
1023
             data.board.GetW(), data.board.GetH(), nbutton, 3) > 0)
1024
    {
1025
      switch(nbutton)
1026
      {
1027
      case 1:
1028
        data.NewGame(ev.button.drw);
1029
        break;
1030
      case 2:
1031
      case 3:
1032
        data.PlayerPress(nbutton - 2, ev.button.drw);
1033
        break;
1034
      case 4:
1035
        data.RotateBoard(ev.button.drw);
1036
        break;
1037
      case 5:
1038
        data.main_draw.Draw(ev.button.drw, data.board.GetW(), data.board.GetH());
1039
        ev.button.drw->Quit();
1040
        break;
1041
      case 11:
1042
      case 12:
1043
      case 13:
1044
      case 14:
1045
        data.main_draw.PressUR(nbutton, data.board, ev.button.drw);
1046
        break;
1047
      case 15:
1048
        data.GoToCurMove(ev.button.drw);
1049
        break;
1050
      case 6:
1051
      case 7:
1052
      case 21:
1053
      case 22:
1054
      case 23:
1055
      case 24:
1056
      case 25:
1057
      case 26:
1058
      case 27:
1059
        data.main_draw.PressLS(nbutton, data.board, ev.button.drw);
1060
        break;
1061
      default:
1062
        data.main_draw.Draw(ev.button.drw, data.board.GetW(), data.board.GetH());
1063
        break;
1064
      }
1065
    }
1066
    ev.button.drw->CloseDraw();
1067
    break;
1068
  case TGraphDraw::event::draw:
1069
    ev.button.drw->OpenDraw();
1070
    data.board.Draw(ev.button.drw);
1071
    ev.button.drw->CloseDraw();
1072
    break;
1073
  case TGraphDraw::event::key_down:
1074
    ev.button.drw->OpenDraw();
1075
    if (ev.key.k == XK_Left) data.board.PKeyEvent(ev.button.drw, TChBoard::PLeft);
1076
    else if (ev.key.k == XK_Right) data.board.PKeyEvent(ev.button.drw, TChBoard::PRight);
1077
    else if (ev.key.k == XK_Up) data.board.PKeyEvent(ev.button.drw, TChBoard::PUp);
1078
    else if (ev.key.k == XK_Down) data.board.PKeyEvent(ev.button.drw, TChBoard::PDown);
1079
    else if (ev.key.k == XK_Return || ev.key.k == XK_space)
1080
    {
1081
      data.board.PKeyEvent(ev.button.drw, TChBoard::PEnter);
1082
    }
1083
    else if (ev.key.k == XK_Escape) ev.button.drw->Quit();
1084
    else if (ev.key.k == XK_less) data.main_draw.PressUR(11, data.board, ev.button.drw);
1085
    else if (ev.key.k == XK_comma) data.main_draw.PressUR(12, data.board, ev.button.drw);
1086
    else if (ev.key.k == XK_period) data.main_draw.PressUR(13, data.board, ev.button.drw);
1087
    else if (ev.key.k == XK_greater) data.main_draw.PressUR(14, data.board, ev.button.drw);
1088
    else if (ev.key.k == XK_minus) data.main_draw.PressLS(21, data.board, ev.button.drw);
1089
    else if (ev.key.k == XK_equal) data.main_draw.PressLS(22, data.board, ev.button.drw);
1090
    else if (ev.key.k == XK_underscore) data.main_draw.PressLS(26, data.board, ev.button.drw);
1091
    else if (ev.key.k == XK_plus) data.main_draw.PressLS(27, data.board, ev.button.drw);
1092
    else if (ev.key.k == XK_Delete) data.main_draw.PressLS(7, data.board, ev.button.drw);
1093
    else if (ev.key.k == XK_F8) data.main_draw.PressLS(24, data.board, ev.button.drw);
1094
    else if (ev.key.k == XK_l || ev.key.k == XK_L) data.main_draw.PressLS(6, data.board, ev.button.drw);
5123 clevermous 1095
#ifndef NO_FILES
1805 yogev_ezra 1096
    else if (ev.key.k == XK_F2) data.main_draw.PressLS(25, data.board, ev.button.drw);
1097
#endif
1098
    else if (ev.key.k == XK_s || ev.key.k == XK_S) data.main_draw.PressLS(28, data.board, ev.button.drw);
1099
    else if (ev.key.k == XK_slash || ev.key.k == XK_question) data.GoToCurMove(ev.button.drw);
1100
    else if (ev.key.k == XK_n || ev.key.k == XK_N) data.NewGame(ev.button.drw);
1101
    else if (ev.key.k == XK_t || ev.key.k == XK_T) data.RotateBoard(ev.button.drw);
1102
    else if (ev.key.k == XK_r || ev.key.k == XK_R) data.PlayerPress(0, ev.button.drw);
1103
    else if (ev.key.k == XK_b || ev.key.k == XK_B) data.PlayerPress(1, ev.button.drw);
1104
    else if (ev.key.k == XK_f || ev.key.k == XK_F)
1105
    {
1106
      int w, h;
1107
      ev.button.drw->GetSize(w, h);
1108
      ev.button.drw->CloseDraw();
1109
      if (DuplicateProcess() == 0)
1110
      {
1111
        ev.button.drw->ResReinit(w, h);
1112
        data.board.EraseHistory();
1113
      }
1114
    }
1115
    ev.button.drw->CloseDraw();
1116
    break;
1117
  case TGraphDraw::event::close:
1118
    ret = 1;
1119
    break;
1120
  }
1121
  return ret;
1122
}
1123
 
1124
int main(int argc, char **argv)
1125
{
1126
  randomize();
5123 clevermous 1127
#ifndef NO_FILES
1805 yogev_ezra 1128
  THistory::InitHFile(argv[0]);
5123 clevermous 1129
#endif
1805 yogev_ezra 1130
  TMainData data(-1);
1131
  if (argv && argc >= 2)
1132
  {
1133
    int i, kx = 1;
1134
    for (i = 1; i < argc; i++)
1135
    {
1136
      if (kx == 1 && argv[i][0] == '-')
1137
      {
1138
        if (strcmp(argv[i], "--") == 0) kx = 0;
1139
        else if (strcmp(argv[i], "-ssf") == 0) ssf = 1;
1140
        else if (strncmp(argv[i], "-save", 5) == 0)
1141
        {
1142
          int j = 5;
1143
          if (argv[i][j])
1144
          {
1145
            if (argv[i][j] != '=' || !argv[i][j+1])
1146
            {
1147
              data.main_draw.def_savekind = atoi(argv[i] + j);
1148
              while (argv[i][j] && argv[i][j] != '=') j++;
1149
              if (argv[i][j] != '=' || !argv[i][j+1]) continue;
1150
            }
1151
            data.main_draw.def_savefile = argv[i] + j + 1;
1152
          }
1153
        }
4652 ashmew2 1154
 
1155
        else printf(CHECKERS_INVALID_STR, argv[i]);
1805 yogev_ezra 1156
      }
1157
      else if (kx == 0 || kx == 1)
1158
      {
5123 clevermous 1159
#ifndef NO_FILES
1805 yogev_ezra 1160
        data.main_draw.play.MsgOpenFile(argv[i], -1);
5123 clevermous 1161
#endif
1805 yogev_ezra 1162
      }
1163
    }
1164
  }
1165
  data.InitDef();
4652 ashmew2 1166
  TMainGraphDraw graph(CHECKERS_STR);
1805 yogev_ezra 1167
  TTimerDraw timer_draw(&data.board, &graph);
1168
  data.player.draw = TTimerDraw::draw; data.player.data = &timer_draw;
1169
  graph.evfunc = TMainData::EventFunction; graph.data = &data;
1170
  graph.SetAboutInfo(1);
1171
  graph.Run(TGraphDraw::button_down_mask | TGraphDraw::button_up_mask |
1172
            TGraphDraw::key_down_mask | TGraphDraw::mouse_drag_mask,
1173
            450 + 100 * ssf, 528);
1174
  return 0;
1175
}