kolibrios-fun/programs/games/checkers/trunk/checkers.cpp
CleverMouse fbdccce9a4 * gcc flags: add -march=pentium-mmx -fno-rtti
* menuetlibc: fix printf, sprintf
* menuetlibc: alias clock() to sysfn 26.9.
  Not exactly what is required by POSIX, but better than zero
* autobuild games/checkers

git-svn-id: svn://kolibrios.org@5123 a494cfbc-eb01-0410-851d-a64ba20cac60
2014-09-15 09:42:01 +00:00

1176 lines
32 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//#define LANG_RUS
#define NDEBUG
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
// sprintf is too heavy
int itoa(char* dst, int number)
{
int result = 0;
if (number < 0) {
result++;
*dst++ = '-';
number = -number;
}
char digits[16];
int ndigits = 0;
do {
digits[ndigits++] = number % 10;
number /= 10;
} while (number);
result += ndigits;
for (; ndigits--; )
*dst++ = digits[ndigits] + '0';
return result;
}
#include "gr-draw.h"
#include "board.h"
#include "player.h"
#include "buttons.h"
#include "sysproc.h"
char *strskipref(char *s1, char *s2)
{
int L = strlen(s2);
if (strncmp(s1, s2, L) == 0) return s1 + L;
else return 0;
}
class TPlayArray
{
public:
TPlayArray(int d = 10) : play(0), nplay(0), mplay(0) {}
~TPlayArray() {Clear();}
void Clear();
void Add(const PlayWrite &pl);
PlayWrite &operator[](int i) {return play[i];}
int GetNPlay() const {return nplay;}
#ifndef NO_FILES
int OpenFile(const char *name, int kind);
int MsgOpenFile(const char *name, int kind);
int SaveFile(const char *name, int num, int kind);
int MsgSaveFile(const char *name, int num, int kind);
#endif
void Del(int n);
protected:
void Extend(int n = -1);
PlayWrite *play;
int nplay, mplay;
protected:
#ifndef NO_FILES
static const char *const search[];
static int AnalizeKind(FILE *f, const int w[], const char *smb = 0);
static int ReadFileTo(FILE *f, char c);
static int ReadFileTo(FILE *f, const char *c);
static int ReadTheText(FILE *f, const char *s);
#endif
};
#ifdef LANG_RUS //Pending Russian Translations
#define CHECKERS_CANT_OPEN_STR "\n˜ èª¨: <20>¥ ¬®£ã ®âªàëâì ä ©« \"%s\".\n"
#define CHECKERS_FILE_EMPTY_STR "\n˜ èª¨: ” ©« \"%s\" ¯ãáâ.\n"
#define CHECKERS_INVALID_FILE_STR "\n˜ èª¨: ” ©« \"%s\" ®è¨¡®ç­ë©.\n"
#define FILE_WRONG_TYPE_STR "\n˜ èª¨: ” ©« \"%s\" ¨¬¥¥â ­¥¢¥à­ë© ⨯.\n"
#define ERROR_OPENING_FILE_STR "\n˜ èª¨: Žè¨¡ª  ®âªàëâ¨ï ä ©«  \"%s\".\n"
#define FILE_HAS_NO_GAMES_STR "\n˜ èª¨: ” ©« \"%s\" ­¥ ᮤ¥à¦¨â ¨£à.\n"
#define CANT_OPEN_FILE_STR "\n˜ èª¨: <20>¥ ¬®£ã ®âªàëâì ä ©« \"%s\" ­  § ¯¨áì.\n"
#define CHECKERS_STR "˜ èª¨"
#define FILE_SAVED_STR "\n˜ èª¨: ” ©« \"%s\" á®åà ­ñ­.\n"
#define ERROR_SAVING_FILE_STR "\n˜ èª¨: Žè¨¡ª  á®åà ­¥­¨ï ä ©«  \"%s\".\n"
#define NOT_ENOUGH_MEM_STR "\n˜ èª¨: <20>¥ ¤®áâ â®ç­® ¯ ¬ï⨠¤«ï á®åà ­¥­¨ï ä ©«  \"%s\".\n"
#define KIND_EQ2 "kind = 2\n"
#define END_STR "[end]"
#define PLAYV11_STR "[play_v1.1]"
#define CHECKERS_PLAY_STR "checkers-play:text\n"
#define CHECKERS_BIN_STR "checkers-play:bin_1.0\n"
#define BLUE_STR "blue: "
#define RED_STR "red: "
#define INPUT_STR "input"
#define COMPUTER_STR "computer"
#define NEW_GAME_STR "new game"
#define LIST_STR "list"
#define DELETE_STR "delete"
#define CLEAR_STR "clear"
#define SAVE_STR "save"
#define ROTATE_BOARD_STR "rotate board"
#define EXIT_STR "exit"
#define CHECKERS_INVALID_STR "Checkers: Invalid key %s\n"
#ifndef NO_FILES
const char *const TPlayArray::search[] =
{"checkers-", "play:", "text", "bin_1.0\n", "history_", "1.0", "1.1"};
#endif
#else /*For all other languages except RUS*/
#define CHECKERS_CANT_OPEN_STR "\nCheckers: Can't open the file \"%s\".\n"
#define CHECKERS_FILE_EMPTY_STR "\nCheckers: The file \"%s\" is empty.\n"
#define CHECKERS_INVALID_FILE_STR "\nCheckers: Invalid file \"%s\".\n"
#define FILE_WRONG_TYPE_STR "\nCheckers: The file \"%s\" has the wrong type.\n"
#define ERROR_OPENING_FILE_STR "\nCheckers: Error opening the file \"%s\".\n"
#define FILE_HAS_NO_GAMES_STR "\nCheckers: File \"%s\" doesn't contain games.\n"
#define CANT_OPEN_FILE_STR "\nCheckers: Can't open the file \"%s\" to write.\n"
#define NOT_ENOUGH_MEM_STR "\nCheckers: Not enough memory to save the file \"%s\".\n"
#define ERROR_SAVING_FILE_STR "\nCheckers: Error saving the file \"%s\".\n"
#define FILE_SAVED_STR "\nCheckers: File \"%s\" saved.\n"
#define CHECKERS_STR "Checkers"
#define KIND_EQ2 "kind = 2\n"
#define END_STR "[end]"
#define PLAYV11_STR "[Play_v1.1]"
#define CHECKERS_PLAY_STR "checkers-play:text\n"
#define CHECKERS_BIN_STR "checkers-play:bin_1.0\n"
#define BLUE_STR "blue: "
#define RED_STR "red: "
#define INPUT_STR "input"
#define COMPUTER_STR "computer"
#define NEW_GAME_STR "new game"
#define LIST_STR "list"
#define DELETE_STR "delete"
#define CLEAR_STR "clear"
#define SAVE_STR "save"
#define ROTATE_BOARD_STR "rotate board"
#define EXIT_STR "exit"
#define CHECKERS_INVALID_STR "Checkers: Invalid key %s\n"
#ifndef NO_FILES
const char *const TPlayArray::search[] =
{"checkers-", "play:", "text", "bin_1.0\n", "history_", "1.0", "1.1"};
#endif
#endif
void TPlayArray::Clear()
{
if (play) delete[] play;
play = 0; nplay = 0; mplay = 0;
}
void TPlayArray::Extend(int n)
{
if (n < 0) n = nplay + 1;
if (mplay < n)
{
PlayWrite *p_old = play;
int m_old = mplay;
mplay = n * 2;
play = new PlayWrite[mplay];
if (p_old)
{
for (int i = 0; i < m_old; i++) play[i] = p_old[i];
delete[] p_old;
}
}
}
void TPlayArray::Add(const PlayWrite &pl)
{
Extend();
play[nplay] = pl;
nplay++;
}
#ifndef NO_FILES
int TPlayArray::AnalizeKind(FILE *f, const int w[], const char *smb)
{
int i, L, was1 = 1;
unsigned char ch;
int fnd[NELEM(search)];
for (i = 0; i < NELEM(search); i++) fnd[i] = 1;
for (L = 0; was1; L++)
{
was1 = 0;
if (fread(&ch, 1, 1, f) != 1) return (L == 0) ? -2 : -1;
for (i = 0; w[i] >= 0; i++) if (fnd[i])
{
if (tolower(ch) != tolower(search[w[i]][L])) fnd[i] = 0;
else
{
was1 = 1;
if (search[w[i]][L+1] == 0)
{
if (smb && smb[0] && fread(&ch, 1, 1, f) == 1)
{
ungetc(ch, f);
if (strchr(smb, tolower(ch)) || isalpha(ch) && strchr(smb, toupper(ch)))
{
break;
}
}
return i;
}
}
}
}
return -10 - L;
}
int TPlayArray::ReadFileTo(FILE *f, char c)
{
char ch;
do
{
if (fread(&ch, 1, 1, f) != 1) return 0;
}
while(ch != c);
return 1;
}
int TPlayArray::ReadFileTo(FILE *f, const char *c)
{
char ch;
do
{
if (fread(&ch, 1, 1, f) != 1) return 0;
}
while(!strchr(c, ch));
return 1;
}
int TPlayArray::ReadTheText(FILE *f, const char *s)
{
char ch;
while (*s)
{
if (fread(&ch, 1, 1, f) != 1 || ch != *s) return 0;
s++;
}
return 1;
}
int TPlayArray::OpenFile(const char *name, int kind)
{
int k_fnd = 0;
FILE *f = fopen(name, "rb");
if (!f) return -1;
if (kind == -1)
{
const int w[] = {0, -1};
int r = AnalizeKind(f, w);
if (r >= 0) {kind = w[r]; k_fnd = 1;}
else if (r == -11) {kind = 3; k_fnd = 3;}
else {fclose(f); return (kind == -2) ? -2 : -10;}
}
if (kind == 0)
{
if (k_fnd < 1 && !ReadFileTo(f, '-')) {fclose(f); return -10;}
k_fnd = 1;
const int w[] = {1, 4, -1};
int r = AnalizeKind(f, w);
if (r >= 0) {kind = w[r]; k_fnd = 2;}
else {fclose(f); return -10;}
}
if (kind == 1)
{
if (k_fnd < 2 && !ReadFileTo(f, ':')) {fclose(f); return -10;}
k_fnd = 2;
const int w[] = {2, 3, -1};
int r = AnalizeKind(f, w);
if (r >= 0) {kind = w[r]; k_fnd = 3;}
else {fclose(f); return -10;}
}
if (kind == 4)
{
if (k_fnd < 2 && !ReadFileTo(f, '_')) {fclose(f); return -10;}
k_fnd = 2;
const int w[] = {5, 6, -1};
int r = AnalizeKind(f, w, ".1234567890");
if (r >= 0) {kind = w[r]; k_fnd = 3;}
else {fclose(f); return -10;}
}
if (kind == 5) {kind = 3; k_fnd = 0;}
if (kind == 6)
{
if (!ReadFileTo(f, "\n\r")) {fclose(f); return -4;}
k_fnd = 3;
PlayWrite *pl = 0;
int np = THistory::HRead(f, pl);
if (np > 0 && pl)
{
int i;
Extend(nplay + np);
for (i = 0; i < np; i++)
{
if (pl[i].GetN() >= 3) play[nplay++] = pl[i];
}
}
if (pl) delete[] pl;
fclose(f);
return 1;
}
if (kind == 2)
{
printf(KIND_EQ2);
unsigned char ch;
do
{
if (fread(&ch, 1, 1, f) != 1) {fclose(f); return -10;}
}
while(!isspace(ch));
PlayWrite pl;
char word[101];
int i, kind = 0;
for (;;)
{
do
{
if (fread(&ch, 1, 1, f) != 1) break;
}
while(ch == 0 || isspace(ch));
if (feof(f)) strcpy(word, END_STR);
else
{
i = 0;
while(ch != 0 && !isspace(ch))
{
if (i < 100) word[i++] = ch;
if (fread(&ch, 1, 1, f) != 1) break;
}
word[i] = 0;
}
if (word[0] != '[')
{
if (kind == 1)
{
if (word[0] != '#' && word[0] != '$' && word[0] != '%')
{
Position pos;
pos.Read(word, 1);
pl.Clear();
pl.Add(0, pos);
kind = 2;
}
}
else if (kind == 2)
{
if (word[0] != '#' && word[0] != '$' && word[0] != '%')
{
for (i = 0; word[i] && word[i] != '.' && word[i] != ','; i++)
{
if (!isdigit((unsigned char)word[i])) {i = -1; break;}
}
if (i == -1)
{
PlayWrite::PMv pmv;
if (pl.GetPosL(pmv.pos) < 0) kind = 3;
else if (!pmv.pos.ReadMv(pmv.mv, word, 1)) kind = 3;
else if (pl.Add(pmv.mv) != 0) kind = 3;
}
}
}
}
else
{
char end_literal[] = END_STR;
char playv11_literal[] = PLAYV11_STR;
if (kind == 2 || kind == 3)
{
if (pl.GetN() > 0) Add(pl);
pl.Clear();
}
kind = 0;
for (i = 0; word[i]; i++)
{
word[i] = (char)tolower((unsigned char)word[i]);
}
if (strskipref(word, end_literal)) break;
else if (strskipref(word, playv11_literal)) kind = 1;
}
}
fclose(f);
return 1;
}
if (kind == 3)
{
char ch[LEN_WPOS];
if (k_fnd < 3 && !ReadFileTo(f, '\n')) {fclose(f); return -10;}
k_fnd = 3;
do
{
PlayWrite pl;
for (;;)
{
int i;
for (i = 0; i < LEN_WPOS; i++)
{
if (fread(ch + i, 1, 1, f) != 1 || ch[i] < 0) break;
}
if (i < LEN_WPOS) break;
PlayWrite::PMv pmv0, pmv1;
pmv1.pos.Read(ch);
pmv1.pos.Reverse();
if (pl.GetPMvL(pmv0) >= 0)
{
TComputerPlayer::Z z;
z.FindAllMoves(pmv0);
int r;
for (r = 0; r < z.narr; r++)
{
if (memcmp(z.array[r].pos.SH, pmv1.pos.SH, sizeof(pmv1.pos.SH)) == 0)
{
pmv1 = z.array[r];
break;
}
}
if (r < z.narr) pl.Add(pmv1);
else {fclose(f); return -3;}
}
else pl.Add(0, pmv1.pos);
}
if (pl.GetN() > 0) Add(pl);
}
while(!feof(f));
fclose(f);
return 1;
}
fclose(f);
return -10;
}
int TPlayArray::MsgOpenFile(const char *name, int kind)
{
int n0 = nplay, no_games = 0;
int r = OpenFile(name, kind);
if (r <= 0)
{
if (r == -1)
{
printf(CHECKERS_CANT_OPEN_STR, name);
return 0;
}
else if (r == -2)
{
printf(CHECKERS_FILE_EMPTY_STR, name);
return 0;
}
else if (r == -3)
{
printf(CHECKERS_INVALID_FILE_STR, name);
return 0;
}
else if (r == -4) no_games = 1;
else if (r == -10)
{
printf(FILE_WRONG_TYPE_STR, name);
return 0;
}
else
{
printf(ERROR_OPENING_FILE_STR, name);
return 0;
}
}
if (!no_games && nplay > n0) return 1;
else
{
printf(FILE_HAS_NO_GAMES_STR, name);
return 0;
}
}
int TPlayArray::SaveFile(const char *name, int num, int kind)
{
FILE *f = 0;
if (kind == 0 || kind == 1 || kind == 2)
{
f = fopen(name, "wt");
if (!f) return -1;
fprintf(f, CHECKERS_PLAY_STR);
int i0 = num, i;
if (num < 0) {i0 = 0; num = nplay-1;}
for (i = i0; i <= num; i++) if (play[i].GetN() > 0)
{
PlayWrite::PMv pmv;
if (play[i].GetPos(pmv.pos, 0) < 0) return -9;
char *str = new char[10 + NUM_CELL];
if (!str) return -5;
pmv.pos.Write(str, 1);
fprintf(f, "\n"PLAYV11_STR"#%d %s\n", i - i0 + 1, str);
delete[] str;
int j;
for (j = 1; j < play[i].GetN(); j++)
{
if (play[i].GetPos(pmv.pos, j - 1) < 0) return -9;
if (play[i].GetMove(pmv.mv, j) < 0) return -9;
str = new char[pmv.pos.GetLenMvEx(pmv.mv, 11)];
if (!str) return -5;
pmv.pos.WriteMvEx(pmv.mv, str, 11);
if (j % 2 == 1)
{
int nbytes = fprintf(f, "%d. ", (j + 1) / 2);
while(nbytes++ < 5) fprintf(f, " ");
}
fprintf(f, "%s", str);
if (j % 2 == 0 || j == play[i].GetN() - 1) fprintf(f, "\n");
else fprintf(f, " ,\t");
delete[] str;
}
}
fclose(f);
return 1;
}
else if (kind == -1 || kind == 3)
{
f = fopen(name, "wb");
if (!f) return -1;
if (kind == 3) fprintf(f, CHECKERS_BIN_STR);
int i = num;
if (num < 0) {i = 0; num = nplay-1;}
for (; i <= num; i++)
{
char ch[LEN_WPOS];
Position pos;
play[i].GetPosL(pos);
if (!pos.AllCanEat() && !pos.AllCanMove())
{
ch[0] = (pos.wmove == 0) ? char(-3) : char(-1);
}
else ch[0] = char(-2);
fwrite(ch, 1, 1, f);
int j;
for (j = 0; j < play[i].GetN(); j++)
{
Position pos;
play[i].GetPos(pos, j);
pos.Reverse();
pos.Write(ch);
fwrite(ch, LEN_WPOS, 1, f);
}
}
fclose(f);
return 1;
}
if (f) fclose(f);
return -10;
}
int TPlayArray::MsgSaveFile(const char *name, int num, int kind)
{
int r = SaveFile(name, num, kind);
if (r <= 0)
{
if (r == -1)
{
printf(CANT_OPEN_FILE_STR, name);
}
else if (r == -5)
{
printf(NOT_ENOUGH_MEM_STR, name);
}
else if (r == -10)
{
printf(FILE_WRONG_TYPE_STR, name);
}
else
{
printf(ERROR_SAVING_FILE_STR, name);
}
return 0;
}
else
{
printf(FILE_SAVED_STR, name);
return 1;
}
}
#endif
void TPlayArray::Del(int n)
{
if (!play || n < 0 || n >= nplay) return;
else if (nplay <= 1) {Clear(); return;}
int i;
for (i = n; i < nplay - 1; i++) play[i] = play[i+1];
play[nplay - 1].Clear();
nplay--;
}
void SetPlayerString(char *str, int c, TChPlayer *p)
{
strcpy(str, c ? BLUE_STR : RED_STR);
if (!p) strcat(str, INPUT_STR);
else strcat(str, COMPUTER_STR);
}
class TMainDraw : public TSomeDraw
{
public:
TMainDraw() : undo_redo(0), ur_type(-1), cur_play(0),
def_savefile("save.che"), def_savekind(2) {InitButton();}
virtual void Draw(TGraphDraw *drw, int w, int h)
{
int d = button.GetDelt();
int hh = button.GetHeight(w - 2*d);
if (hh != 0) hh += d;
drw->SetColor(drw->GetBlackColor());
button.Draw(drw, d, h - hh, w - 2*d);
}
virtual void DrawB(TGraphDraw *drw, TChBoard &board)
{
int urt = (board.GetCurMoveN() <= 0) +
2*(board.GetCurMoveN() >= board.GetNumMove());
if (ur_type != urt) SetButtonKind(board);
Draw(drw, board.GetW(), board.GetH());
}
virtual TIntPoint GetDSize(int w, int h)
{
int d = button.GetDelt();
int hh = button.GetHeight(w - 2*d);
if (hh != 0) hh += d;
return TIntPoint(0, hh);
}
virtual int ButtonPnt(int xp, int yp, int w, int h, int &n, int k = 0)
{
int d = button.GetDelt();
int hh = button.GetHeight(w - 2*d);
if (hh != 0) hh += d;
return button.ButtonPnt(xp - d, yp - (h - hh), w - 2*d, n, k);
}
void InitButton();
void SetButtonKind(const TChBoard &board);
void PressUR(int n, TChBoard &board, TGraphDraw *drw);
void PressLS(int n, TChBoard &board, TGraphDraw *drw);
void CurPlayNorm()
{
if (cur_play < 0 || cur_play >= play.GetNPlay()) cur_play = 0;
}
TXButtonArray button;
TMultiButton *undo_redo, *play_list;
char player_str[2][50], play_num[2][10];
TPlayArray play;
int cur_play;
char *def_savefile;
int def_savekind;
protected:
int ur_type;
};
void TMainDraw::InitButton()
{
static char newgame_literal[] = NEW_GAME_STR;
static char list_literal[] = LIST_STR;
static char delete_literal[] = DELETE_STR;
static char clear_literal[] = CLEAR_STR;
static char save_literal[] = SAVE_STR;
static char rotateboard_literal[] = ROTATE_BOARD_STR;
static char exit_literal[] = EXIT_STR;
static char one_literal[] = "1";
static char dash_literal[] = "-";
static char plus_literal[] = "+";
static char leftshift_literal[] = "<<";
static char rightshift_literal[] = ">>";
static char lessthan_literal[] = "<";
static char greaterthan_literal[] = ">";
static char xor_literal[] = "^";
button.Add(1, 80, 22, newgame_literal);
button.Add(6, 60, 22, list_literal);
button.Add(7, 60, 22, delete_literal);
play_list = new TMultiButton(20);
play_list->a.Add(26, 20, 22, one_literal);
play_list->a.Add(21, 20, 22, dash_literal);
play_list->a.Add(23, 37, 22, play_num[0], -2);
play_list->a.Add(22, 20, 22, plus_literal);
play_list->a.Add(27, 37, 22, play_num[1]);
play_list->SetDefW();
button.Add(play_list);
button.Add(24, 50, 22, clear_literal);
#ifndef NO_FILES
button.Add(25, 50, 22, save_literal);
#endif
button.Add(2, 120, 22, player_str[0]);
button.Add(3, 120, 22, player_str[1]);
button.Add(4, 110, 22, rotateboard_literal);
undo_redo = new TMultiButton(10);
undo_redo->a.Add(11, 27, 22, leftshift_literal);
undo_redo->a.Add(12, 20, 22, lessthan_literal);
undo_redo->a.Add(15, 20, 22, xor_literal);
undo_redo->a.Add(13, 20, 22, greaterthan_literal);
undo_redo->a.Add(14, 27, 22, rightshift_literal);
undo_redo->SetDefW();
button.Add(undo_redo);
button.Add(5, 60, 22, exit_literal);
}
void TMainDraw::SetButtonKind(const TChBoard &board)
{
int thick;
TextButton *txb;
TXButton *bt1;
ur_type = 0;
SetPlayerString(player_str[0], 0, board.GetPlayer(0));
SetPlayerString(player_str[1], 1, board.GetPlayer(1));
int is_drw = !board.GetPViewStatus();
bt1 = button.GetButton(2);
if (bt1) bt1->drw = is_drw;
bt1 = button.GetButton(3);
if (bt1) bt1->drw = is_drw;
if (board.GetCurMoveN() <= 0) {ur_type++; thick = 0;}
else thick = 3;
// txb = dynamic_cast<TextButton*>(undo_redo->a.GetButton(11));
// if (txb) txb->thick = thick;
// txb = dynamic_cast<TextButton*>(undo_redo->a.GetButton(12));
// if (txb) txb->thick = thick;
// we can use simple static cast
((TextButton*)(undo_redo->a.GetButton(11)))->thick = thick;
((TextButton*)(undo_redo->a.GetButton(12)))->thick = thick;
if (board.GetCurMoveN() >= board.GetNumMove()) {ur_type += 2; thick = 0;}
else thick = 3;
// txb = dynamic_cast<TextButton*>(undo_redo->a.GetButton(13));
// if (txb) txb->thick = thick;
// txb = dynamic_cast<TextButton*>(undo_redo->a.GetButton(14));
// if (txb) txb->thick = thick;
((TextButton*)(undo_redo->a.GetButton(13)))->thick = thick;
((TextButton*)(undo_redo->a.GetButton(14)))->thick = thick;
if (board.GetCurMoveN() < board.GetNumMove() ||
(board.GetPViewStatus() && board.GetGameEnd() <= 0))
{
thick = 3;
}
else thick = 0;
// txb = dynamic_cast<TextButton*>(undo_redo->a.GetButton(15));
// if (txb) txb->thick = thick;
((TextButton*)(undo_redo->a.GetButton(15)))->thick = thick;
if (play.GetNPlay() == 0) is_drw = 1;
bt1 = button.GetButton(6);
if (bt1) bt1->drw = is_drw;
bt1 = button.GetButton(7);
if (bt1) bt1->drw = !is_drw;
#ifndef NO_FILES
bt1 = button.GetButton(25);
if (bt1) bt1->drw = !is_drw;
#endif
is_drw = board.GetPViewStatus() && play.GetNPlay() > 1;
bt1 = button.GetButton(20);
if (bt1) bt1->drw = is_drw;
bt1 = button.GetButton(24);
if (bt1) bt1->drw = is_drw;
if (is_drw)
{
play_num[0][0] = 0; play_num[1][0] = 0;
if (cur_play >= 0) itoa(play_num[0], cur_play + 1);
itoa(play_num[1], play.GetNPlay());
thick = (cur_play <= 0) ? 0 : 3;
txb = static_cast<TextButton*>(play_list->a.GetButton(21));
if (txb) txb->thick = thick;
txb = static_cast<TextButton*>(play_list->a.GetButton(26));
if (txb) txb->thick = thick;
thick = (cur_play >= play.GetNPlay() - 1) ? 0 : 3;
txb = static_cast<TextButton*>(play_list->a.GetButton(22));
if (txb) txb->thick = thick;
txb = static_cast<TextButton*>(play_list->a.GetButton(27));
if (txb) txb->thick = thick;
}
}
void TMainDraw::PressUR(int n, TChBoard &board, TGraphDraw *drw)
{
int mv;
if (n == 11) mv = 0;
else if (n == 12) mv = board.GetCurMoveN() - 1;
else if (n == 13) mv = board.GetCurMoveN() + 1;
else mv = board.GetNumMove();
if (board.SetCurMoveN(mv))
{
SetButtonKind(board);
if (drw && drw->IsDraw())
{
drw->DrawClear();
board.Draw(drw);
}
}
else Draw(drw, board.GetW(), board.GetH());
}
void TMainDraw::PressLS(int n, TChBoard &board, TGraphDraw *drw)
{
int need_redraw = 0;
if (n == 6)
{
if (!board.GetPViewStatus() || play.GetNPlay() == 0)
{
PlayWrite cur_pw = board.GetPlay();
if (cur_pw.GetN() > 2 || play.GetNPlay() == 0) play.Add(board.GetPlay());
cur_play = play.GetNPlay() - 1;
board.SetPlay(play[cur_play]);
need_redraw = 1;
}
}
else if (n == 7)
{
if (board.GetPViewStatus() && play.GetNPlay() != 0)
{
play.Del(cur_play);
if (play.GetNPlay() >= 1)
{
if (cur_play >= play.GetNPlay()) cur_play--;
board.SetPlay(play[cur_play]);
}
need_redraw = 1;
}
}
else if (n == 21)
{
if (cur_play > 0) {board.SetPlay(play[--cur_play]); need_redraw = 1;}
}
else if (n == 22)
{
if (cur_play < play.GetNPlay() - 1)
{
board.SetPlay(play[++cur_play]); need_redraw = 1;
}
}
else if (n == 26)
{
if (cur_play > 0)
{
cur_play = 0;
board.SetPlay(play[cur_play]); need_redraw = 1;
}
}
else if (n == 27)
{
if (cur_play < play.GetNPlay() - 1)
{
cur_play = play.GetNPlay() - 1;
board.SetPlay(play[cur_play]); need_redraw = 1;
}
}
else if (n == 24) {play.Clear(); cur_play = 0; need_redraw = 1;}
#ifndef NO_FILES
else if (n == 25)
{
if (play.GetNPlay() > 0) play.MsgSaveFile(def_savefile, -1, def_savekind);
}
else if (n == 28)
{
if (play.GetNPlay() > 0) play.MsgSaveFile(def_savefile, cur_play, def_savekind);
}
#endif
if (need_redraw)
{
SetButtonKind(board);
if (drw && drw->IsDraw())
{
drw->DrawClear();
board.Draw(drw);
}
}
else Draw(drw, board.GetW(), board.GetH());
}
struct TTimerDraw
{
TTimerDraw(TChBoard *brd, TGraphDraw *drw) : brd(brd), drw(drw) {}
TChBoard *brd;
clock_t st, ut, dt;
double x0;
TGraphDraw *drw;
static void draw(void *v, int k = 0);
};
void TTimerDraw::draw(void *v, int k)
{
TTimerDraw &d = *(TTimerDraw*)v;
clock_t t = clock();
if (k == 0 && t - d.ut < CLOCKS_PER_SEC * 0.01) return;
if (k > 0)
{
d.st = t;
if (!d.drw || !d.drw->IsDraw()) return;
d.drw->DrawClear();
d.brd->Draw(d.drw);
d.dt = t;
}
else if (!d.drw || !d.drw->IsDraw()) return;
double xold = d.x0;
if (k >= 0)
{
d.x0 = (1 - cos(2.0 * (t - d.st) / CLOCKS_PER_SEC)) / 2;
d.brd->DrawTimer(d.drw, d.x0, 0);
d.ut = t;
if (k == 0 && t - d.dt > CLOCKS_PER_SEC * 0.5)
{
d.brd->Draw(d.drw);
d.dt = t;
}
}
if (k <= 0) d.brd->DrawTimer(d.drw, xold, 1);
}
struct TMainData
{
TChBoard board;
TComputerPlayer player;
TMainDraw main_draw;
TMainData(int id = 0);
void InitDef();
static int EventFunction(const TGraphDraw::event &ev);
void NewGame(TGraphDraw *drw);
void RotateBoard(TGraphDraw *drw);
void PlayerPress(int np, TGraphDraw *drw);
void GoToCurMove(TGraphDraw *drw);
};
TMainData::TMainData(int id) : board(id)
{
board.SetCheckResize(1);
board.SetPlayer(1, &player);
board.SetBottomColor(0);
board.SetSomeDraw(&main_draw);
board.SetMinWSize(90, 140);
}
void TMainData::InitDef()
{
if (main_draw.play.GetNPlay() > 0)
{
main_draw.CurPlayNorm();
board.SetPlay(main_draw.play[main_draw.cur_play]);
}
main_draw.SetButtonKind(board);
}
void TMainData::NewGame(TGraphDraw *drw)
{
board.NewGame();
main_draw.SetButtonKind(board);
if (drw && drw->IsDraw()) {drw->DrawClear(); board.Draw(drw);}
}
void TMainData::RotateBoard(TGraphDraw *drw)
{
board.SetBottomColor(3 - board.GetBottomColor());
if (drw && drw->IsDraw()) {drw->DrawClear(); board.Draw(drw);}
}
void TMainData::PlayerPress(int np, TGraphDraw *drw)
{
if (np != 0 && np != 1) return;
if (board.GetPlayer(np)) board.SetPlayer(np, 0);
else board.SetPlayer(np, &player);
if (board.GetPlayer(0) && !board.GetPlayer(1))
{
board.SetBottomColor(1);
}
if (board.GetPlayer(1) && !board.GetPlayer(0))
{
board.SetBottomColor(0);
}
main_draw.SetButtonKind(board);
if (drw && drw->IsDraw()) {drw->DrawClear(); board.Draw(drw);}
}
void TMainData::GoToCurMove(TGraphDraw *drw)
{
board.GoToCurMove();
main_draw.SetButtonKind(board);
if (drw && drw->IsDraw()) {drw->DrawClear(); board.Draw(drw);}
}
int TMainData::EventFunction(const TGraphDraw::event &ev)
{
if (!ev.any.drw->data) return -100;
TMainData &data = *(TMainData*)ev.any.drw->data;
int nbutton, ret = 0;
switch(ev.type)
{
case TGraphDraw::event::button_down:
if (ev.button.n != 1) break;
ev.button.drw->OpenDraw();
if (data.main_draw.ButtonPnt(ev.button.x, ev.button.y,
data.board.GetW(), data.board.GetH(), nbutton, 1) > 0)
{
data.main_draw.Draw(ev.button.drw, data.board.GetW(), data.board.GetH());
ret |= TGraphDraw::ret_setcapture;
}
else data.board.MouseClick(ev.button.drw, ev.button.x, ev.button.y);
ev.button.drw->CloseDraw();
break;
case TGraphDraw::event::mouse_move:
if (ev.button.n >= 0 && ev.button.n != 1) break;
ev.button.drw->OpenDraw();
if (data.main_draw.ButtonPnt(ev.button.x, ev.button.y,
data.board.GetW(), data.board.GetH(), nbutton, 2) >= 1000)
{
data.main_draw.Draw(ev.button.drw, data.board.GetW(), data.board.GetH());
}
ev.button.drw->CloseDraw();
break;
case TGraphDraw::event::button_up:
if (ev.button.n != 1) break;
ev.button.drw->OpenDraw();
if (data.main_draw.ButtonPnt(ev.button.x, ev.button.y,
data.board.GetW(), data.board.GetH(), nbutton, 3) > 0)
{
switch(nbutton)
{
case 1:
data.NewGame(ev.button.drw);
break;
case 2:
case 3:
data.PlayerPress(nbutton - 2, ev.button.drw);
break;
case 4:
data.RotateBoard(ev.button.drw);
break;
case 5:
data.main_draw.Draw(ev.button.drw, data.board.GetW(), data.board.GetH());
ev.button.drw->Quit();
break;
case 11:
case 12:
case 13:
case 14:
data.main_draw.PressUR(nbutton, data.board, ev.button.drw);
break;
case 15:
data.GoToCurMove(ev.button.drw);
break;
case 6:
case 7:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
case 27:
data.main_draw.PressLS(nbutton, data.board, ev.button.drw);
break;
default:
data.main_draw.Draw(ev.button.drw, data.board.GetW(), data.board.GetH());
break;
}
}
ev.button.drw->CloseDraw();
break;
case TGraphDraw::event::draw:
ev.button.drw->OpenDraw();
data.board.Draw(ev.button.drw);
ev.button.drw->CloseDraw();
break;
case TGraphDraw::event::key_down:
ev.button.drw->OpenDraw();
if (ev.key.k == XK_Left) data.board.PKeyEvent(ev.button.drw, TChBoard::PLeft);
else if (ev.key.k == XK_Right) data.board.PKeyEvent(ev.button.drw, TChBoard::PRight);
else if (ev.key.k == XK_Up) data.board.PKeyEvent(ev.button.drw, TChBoard::PUp);
else if (ev.key.k == XK_Down) data.board.PKeyEvent(ev.button.drw, TChBoard::PDown);
else if (ev.key.k == XK_Return || ev.key.k == XK_space)
{
data.board.PKeyEvent(ev.button.drw, TChBoard::PEnter);
}
else if (ev.key.k == XK_Escape) ev.button.drw->Quit();
else if (ev.key.k == XK_less) data.main_draw.PressUR(11, data.board, ev.button.drw);
else if (ev.key.k == XK_comma) data.main_draw.PressUR(12, data.board, ev.button.drw);
else if (ev.key.k == XK_period) data.main_draw.PressUR(13, data.board, ev.button.drw);
else if (ev.key.k == XK_greater) data.main_draw.PressUR(14, data.board, ev.button.drw);
else if (ev.key.k == XK_minus) data.main_draw.PressLS(21, data.board, ev.button.drw);
else if (ev.key.k == XK_equal) data.main_draw.PressLS(22, data.board, ev.button.drw);
else if (ev.key.k == XK_underscore) data.main_draw.PressLS(26, data.board, ev.button.drw);
else if (ev.key.k == XK_plus) data.main_draw.PressLS(27, data.board, ev.button.drw);
else if (ev.key.k == XK_Delete) data.main_draw.PressLS(7, data.board, ev.button.drw);
else if (ev.key.k == XK_F8) data.main_draw.PressLS(24, data.board, ev.button.drw);
else if (ev.key.k == XK_l || ev.key.k == XK_L) data.main_draw.PressLS(6, data.board, ev.button.drw);
#ifndef NO_FILES
else if (ev.key.k == XK_F2) data.main_draw.PressLS(25, data.board, ev.button.drw);
#endif
else if (ev.key.k == XK_s || ev.key.k == XK_S) data.main_draw.PressLS(28, data.board, ev.button.drw);
else if (ev.key.k == XK_slash || ev.key.k == XK_question) data.GoToCurMove(ev.button.drw);
else if (ev.key.k == XK_n || ev.key.k == XK_N) data.NewGame(ev.button.drw);
else if (ev.key.k == XK_t || ev.key.k == XK_T) data.RotateBoard(ev.button.drw);
else if (ev.key.k == XK_r || ev.key.k == XK_R) data.PlayerPress(0, ev.button.drw);
else if (ev.key.k == XK_b || ev.key.k == XK_B) data.PlayerPress(1, ev.button.drw);
else if (ev.key.k == XK_f || ev.key.k == XK_F)
{
int w, h;
ev.button.drw->GetSize(w, h);
ev.button.drw->CloseDraw();
if (DuplicateProcess() == 0)
{
ev.button.drw->ResReinit(w, h);
data.board.EraseHistory();
}
}
ev.button.drw->CloseDraw();
break;
case TGraphDraw::event::close:
ret = 1;
break;
}
return ret;
}
int main(int argc, char **argv)
{
randomize();
#ifndef NO_FILES
THistory::InitHFile(argv[0]);
#endif
TMainData data(-1);
if (argv && argc >= 2)
{
int i, kx = 1;
for (i = 1; i < argc; i++)
{
if (kx == 1 && argv[i][0] == '-')
{
if (strcmp(argv[i], "--") == 0) kx = 0;
else if (strcmp(argv[i], "-ssf") == 0) ssf = 1;
else if (strncmp(argv[i], "-save", 5) == 0)
{
int j = 5;
if (argv[i][j])
{
if (argv[i][j] != '=' || !argv[i][j+1])
{
data.main_draw.def_savekind = atoi(argv[i] + j);
while (argv[i][j] && argv[i][j] != '=') j++;
if (argv[i][j] != '=' || !argv[i][j+1]) continue;
}
data.main_draw.def_savefile = argv[i] + j + 1;
}
}
else printf(CHECKERS_INVALID_STR, argv[i]);
}
else if (kx == 0 || kx == 1)
{
#ifndef NO_FILES
data.main_draw.play.MsgOpenFile(argv[i], -1);
#endif
}
}
}
data.InitDef();
TMainGraphDraw graph(CHECKERS_STR);
TTimerDraw timer_draw(&data.board, &graph);
data.player.draw = TTimerDraw::draw; data.player.data = &timer_draw;
graph.evfunc = TMainData::EventFunction; graph.data = &data;
graph.SetAboutInfo(1);
graph.Run(TGraphDraw::button_down_mask | TGraphDraw::button_up_mask |
TGraphDraw::key_down_mask | TGraphDraw::mouse_drag_mask,
450 + 100 * ssf, 528);
return 0;
}