--- /dev/null
+/*
+ * FILE: init.c
+ *
+ * ----------------------------------------------------------------------
+ * Copyright (c) 1993, 1994, 1995 Matthias Mutz
+ * Copyright (c) 1999 Michael Vanier and the Free Software Foundation
+ *
+ * GNU SHOGI is based on GNU CHESS
+ *
+ * Copyright (c) 1988, 1989, 1990 John Stanback
+ * Copyright (c) 1992 Free Software Foundation
+ *
+ * This file is part of GNU SHOGI.
+ *
+ * GNU Shogi is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 1, or (at your option) any
+ * later version.
+ *
+ * GNU Shogi is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with GNU Shogi; see the file COPYING. If not, write to the Free
+ * Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * ----------------------------------------------------------------------
+ *
+ */
+
+#include "gnushogi.h"
+
+#if defined HAVE_GETTIMEOFDAY
+#include <sys/time.h>
+#endif
+
+#include <signal.h>
+
+#include "pattern.h"
+
+/****************************************
+ * A variety of global flags.
+ ****************************************/
+
+/*
+ * If hard_time_limit is nonzero, exceeding the time limit means
+ * losing the game.
+ */
+
+short hard_time_limit = 1;
+short barebones = 0; /* Suppress printing of statistics
+ * (mainly for xshogi). */
+#ifdef LIST_ON_EXIT
+short nolist = 0; /* List the game after exit. */
+#else
+short nolist = 1; /* Don't list the game after exit. */
+#endif
+
+/*
+ * The default display type can be DISPLAY_RAW, DISPLAY_CURSES,
+ * or DISPLAY_X; the default is DISPLAY_X to make life easier for xshogi.
+ */
+
+display_t display_type = DISPLAY_X;
+
+unsigned int ttbllimit;
+
+/* .... MOVE GENERATION VARIABLES AND INITIALIZATIONS .... */
+
+
+#define max(a, b) (((a) < (b))?(b):(a))
+#define odd(a) ((a) & 1)
+
+
+const small_short piece_of_ptype[NO_PTYPE_PIECES] =
+{
+ pawn, lance, knight, silver, gold, bishop, rook, pbishop, prook, king,
+ pawn, lance, knight, silver, gold
+};
+
+
+const small_short side_of_ptype[NO_PTYPE_PIECES] =
+{
+ black, black, black, black, black, black, black, black, black, black,
+ white, white, white, white, white
+};
+
+#ifdef SAVE_NEXTPOS
+const small_short psweep[NO_PTYPE_PIECES] =
+{
+ false, true, false, false, false, true, true, true, true, false,
+ false, true, false, false, false
+};
+#endif
+
+const small_short sweep[NO_PIECES] =
+{
+ false, false, true, false, false, false, true, true,
+ false, false, false, false, true, true, false
+};
+
+
+#if !defined EXTLANGFILE
+
+char *CP[CPSIZE] =
+
+{
+/* 000: eng: */ "",
+#ifdef LANGFILE
+#include LANGFILE
+#else
+#include "gnushogi.lng"
+#endif
+};
+
+#else
+
+char *CP[CPSIZE];
+
+#endif
+
+
+/*
+ * Determine the minimum number of moves for a piece from
+ * square "f" to square "t". If the piece cannot reach "t",
+ * the count is set to CANNOT_REACH.
+ */
+
+#define csquare(sq) ((side == black) ? sq : (NO_SQUARES - 1 - sq))
+#define crow(sq) row(csquare(sq))
+#define ccol(sq) column(csquare(sq))
+
+short
+ptype_distance(short ptyp, short f, short t)
+{
+ short side, piece;
+ short colf, colt, rowf, rowt, dcol, drow;
+
+ if (f == t)
+ return 0;
+
+ piece = piece_of_ptype[ptyp];
+ side = side_of_ptype[ptyp];
+
+ dcol = (colt = ccol(t)) - (colf = ccol(f));
+ drow = (rowt = crow(t)) - (rowf = crow(f));
+
+ switch (piece)
+ {
+ case pawn:
+ if ((dcol != 0) || (drow < 1))
+ return CANNOT_REACH;
+ else
+ return drow;
+
+ case lance:
+ if ((dcol != 0) || (drow < 1))
+ return CANNOT_REACH;
+ else
+ return 1;
+
+ case knight:
+ if (odd(drow) || (odd(drow / 2) != odd(dcol)))
+ return CANNOT_REACH;
+ else if ((drow == 0) || ((drow / 2) < abs(dcol)))
+ return CANNOT_REACH;
+ else
+ return (drow / 2);
+
+ case silver:
+ if (drow > 0)
+ {
+ if (odd(drow) == odd(dcol))
+ {
+ return max(abs(drow), abs(dcol));
+ }
+ else
+ {
+ if (abs(dcol) <= drow)
+ return drow;
+ else
+ return (max(abs(drow), abs(dcol)) + 1);
+ }
+ }
+ else
+ {
+ if (odd(drow) == odd(dcol))
+ return (max(abs(drow), abs(dcol)));
+ else
+ return (max(abs(drow) + 1, abs(dcol)) + 1);
+ };
+
+ case gold:
+ case ppawn:
+ case pknight:
+ case plance:
+ case psilver:
+ if (abs(dcol) == 0)
+ return (abs(drow));
+ else if (drow >= 0)
+ return max(drow, abs(dcol));
+ else
+ return (abs(dcol) - drow);
+
+ case bishop:
+ if (odd(dcol) != odd(drow))
+ return CANNOT_REACH;
+ else
+ return ((abs(dcol) == abs(drow)) ? 1 : 2);
+
+ case pbishop:
+ if (odd(dcol) != odd(drow))
+ {
+ if ((abs(dcol) <= 1) && (abs(drow) <= 1))
+ return 1;
+ else if (abs(abs(dcol) - abs(drow)) == 1)
+ return 2;
+ else
+ return 3;
+ }
+ else
+ {
+ return ((abs(dcol) == abs(drow)) ? 1 : 2);
+ }
+
+ case rook:
+ if ((dcol == 0) || (drow == 0))
+ return 1;
+ else
+ return 2;
+
+ case prook:
+ if ((dcol == 0) || (drow == 0))
+ return 1;
+ else if ((abs(dcol) == 1) && (abs(drow) == 1))
+ return 1;
+ else
+ return 2;
+
+ case king:
+ return max(abs(drow), abs(dcol));
+
+ default:
+ /* should never occur */
+ return (CANNOT_REACH);
+ }
+}
+
+
+#ifdef SAVE_DISTDATA
+short
+distance(short a, short b)
+{
+ return (short)computed_distance(a, b);
+}
+#else
+short
+distance(short a, short b)
+{
+ return (use_distdata
+ ? (short)(*distdata)[(int)a][(int)b]
+ : (short)computed_distance(a, b));
+}
+#endif
+
+
+#ifdef SAVE_PTYPE_DISTDATA
+short
+piece_distance(short side, short piece, short f, short t)
+{
+ return ((f > NO_SQUARES)
+ ? (short)1
+ : (short)ptype_distance(ptype[side][piece], f, t));
+}
+#else
+short
+piece_distance(short side, short piece, short f, short t)
+{
+ return ((f > NO_SQUARES)
+ ? (short)1
+ : (use_ptype_distdata
+ ? (short)(*ptype_distdata[ptype[side][piece]])[f][t]
+ : (short)ptype_distance(ptype[side][piece], f, t)));
+}
+#endif
+
+
+void
+Initialize_dist(void)
+{
+ short a, b, d, di, ptyp;
+#ifndef SAVE_DISTDATA
+ for (a = 0; a < NO_SQUARES; a++)
+ {
+ for (b = 0; b < NO_SQUARES; b++)
+ {
+ d = abs(column(a) - column(b));
+ di = abs(row(a) - row(b));
+ (*distdata)[a][b] = (small_short)((d > di) ? d : di);
+ }
+ }
+#endif
+#ifndef SAVE_PTYPE_DISTDATA
+ for (ptyp = 0; ptyp < NO_PTYPE_PIECES; ptyp++)
+ {
+ for (a = 0; a < NO_SQUARES; a++)
+ for (b = 0; b < NO_SQUARES; b++)
+ (*ptype_distdata[ptyp])[a][b] = ptype_distance(ptyp, a, b);
+ }
+#endif
+}
+
+
+/*
+ * nextpos[piece][from-square], nextdir[piece][from-square] gives vector
+ * of positions reachable from from-square in ppos with piece such that the
+ * sequence
+ *
+ * ppos = nextpos[piece][from-square];
+ * pdir = nextdir[piece][from-square];
+ * u = ppos[sq];
+ *
+ * do
+ * {
+ * u = ppos[u];
+ *
+ * if(color[u] != neutral)
+ * u = pdir[u];
+ * }
+ * while (sq != u);
+ *
+ * will generate the sequence of all squares reachable from sq.
+ *
+ * If the path is blocked u = pdir[sq] will generate the continuation of the
+ * sequence in other directions.
+ */
+
+
+/*
+ * ptype is used to separate black and white pawns, like this; ptyp =
+ * ptype[side][piece] piece can be used directly in nextpos/nextdir when
+ * generating moves for pieces that are not white pawns.
+ */
+
+const small_short ptype[2][NO_PIECES] =
+{
+ {
+ ptype_no_piece, ptype_pawn, ptype_lance, ptype_knight,
+ ptype_silver, ptype_gold, ptype_bishop, ptype_rook,
+ ptype_gold, ptype_gold, ptype_gold, ptype_gold,
+ ptype_pbishop, ptype_prook, ptype_king
+ },
+ {
+ ptype_no_piece, ptype_wpawn, ptype_wlance, ptype_wknight,
+ ptype_wsilver, ptype_wgold, ptype_bishop, ptype_rook,
+ ptype_wgold, ptype_wgold, ptype_wgold, ptype_wgold,
+ ptype_pbishop, ptype_prook, ptype_king
+ },
+};
+
+const small_short promoted[NO_PIECES] =
+{
+ no_piece, ppawn, plance, pknight, psilver, gold, pbishop, prook,
+ ppawn, plance, pknight, psilver, pbishop, prook, king
+};
+
+const small_short unpromoted[NO_PIECES] =
+{
+ no_piece, pawn, lance, knight, silver, gold, bishop, rook,
+ pawn, lance, knight, silver, bishop, rook, king
+};
+
+const small_short is_promoted[NO_PIECES] =
+{
+ false, false, false, false, false, false, false, false,
+ true, true, true, true, true, true, false
+};
+
+/* data used to generate nextpos/nextdir */
+#if !defined SAVE_NEXTPOS
+static
+#endif
+const small_short direc[NO_PTYPE_PIECES][8] =
+{
+ { 11, 0, 0, 0, 0, 0, 0, 0 }, /* 0 ptype_pawn */
+ { 11, 0, 0, 0, 0, 0, 0, 0 }, /* 1 ptype_lance */
+ { 21, 23, 0, 0, 0, 0, 0, 0 }, /* 2 ptype_knight */
+ { 10, 11, 12, -12, -10, 0, 0, 0 }, /* 3 ptype_silver */
+ { 10, 11, 12, -1, 1, -11, 0, 0 }, /* 4 ptype_gold */
+ { 10, 12, -12, -10, 0, 0, 0, 0 }, /* 5 ptype_bishop */
+ { 11, -1, 1, -11, 0, 0, 0, 0 }, /* 6 ptype_rook */
+ { 10, 12, -12, -10, 11, -1, 1, -11 }, /* 7 ptype_pbishop */
+ { 11, -1, 1, -11, 10, 12, -12, -10 }, /* 8 ptype_prook */
+ { 10, 11, 12, -1, 1, -12, -11, -10 }, /* 9 ptype_king */
+ { -11, 0, 0, 0, 0, 0, 0, 0 }, /* 10 ptype_wpawn */
+ { -11, 0, 0, 0, 0, 0, 0, 0 }, /* 11 ptype_wlance */
+ { -21, -23, 0, 0, 0, 0, 0, 0 }, /* 12 ptype_wknight */
+ { -10, -11, -12, 12, 10, 0, 0, 0 }, /* 13 ptype_wsilver */
+ { -10, -11, -12, 1, -1, 11, 0, 0 }
+}; /* 14 ptype_wgold */
+
+
+small_short diagonal(short d)
+{
+ return (abs(d) == 10 || abs(d) == 12);
+}
+
+
+static const small_short max_steps[NO_PTYPE_PIECES] =
+{
+ 1, 8, 1, 1, 1, 8, 8, 8, 8, 1, 1, 8, 1, 1, 1
+};
+
+
+const small_short nunmap[(NO_COLS + 2)*(NO_ROWS + 4)] =
+{
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1,
+ -1, 9, 10, 11, 12, 13, 14, 15, 16, 17, -1,
+ -1, 18, 19, 20, 21, 22, 23, 24, 25, 26, -1,
+ -1, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1,
+ -1, 36, 37, 38, 39, 40, 41, 42, 43, 44, -1,
+ -1, 45, 46, 47, 48, 49, 50, 51, 52, 53, -1,
+ -1, 54, 55, 56, 57, 58, 59, 60, 61, 62, -1,
+ -1, 63, 64, 65, 66, 67, 68, 69, 70, 71, -1,
+ -1, 72, 73, 74, 75, 76, 77, 78, 79, 80, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+};
+
+
+const small_short inunmap[NO_SQUARES] =
+{
+ 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 34, 35, 36, 37, 38, 39, 40, 41, 42,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53,
+ 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86,
+ 89, 90, 91, 92, 93, 94, 95, 96, 97,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108,
+ 111, 112, 113, 114, 115, 116, 117, 118, 119
+};
+
+
+int InitFlag = false;
+
+
+#if defined SAVE_NEXTPOS
+
+short
+next_direction(short ptyp, short *d, short sq)
+{
+ short delta, to, sfrom = inunmap[sq];
+
+ do
+ {
+ (*d)++;
+ if (*d >= 8)
+ return sq;
+
+ delta = direc[ptyp][*d];
+ if (delta == 0)
+ return sq;
+
+ to = nunmap[sfrom + delta];
+ }
+ while (to < 0);
+
+ return to;
+}
+
+
+short
+next_position(short ptyp, short *d, short sq, short u)
+{
+ if (*d < 4 && psweep[ptyp])
+ {
+ short to = nunmap[inunmap[u] + direc[ptyp][*d]];
+
+ if (to < 0)
+ return next_direction(ptyp, d, sq);
+ else
+ return to;
+ }
+ else
+ {
+ return next_direction(ptyp, d, sq);
+ }
+}
+
+
+short
+first_direction(short ptyp, short *d, short sq)
+{
+ *d = -1;
+ return next_direction(ptyp, d, sq);
+}
+
+#else
+
+/*
+ * This procedure pre-calculates all moves for every piece from every
+ * square. This data is stored in nextpos/nextdir and used later in the
+ * move generation routines.
+ */
+
+void
+Initialize_moves(void)
+{
+ short ptyp, po, p0, d, di, s, delta;
+ unsigned char *ppos, *pdir;
+ short dest[8][9];
+ short sorted[9];
+ short steps[8];
+ short fpo = 23, tpo = 120;
+
+ for (ptyp = 0; ptyp < NO_PTYPE_PIECES; ptyp++)
+ {
+ for (po = 0; po < NO_SQUARES; po++)
+ {
+ for (p0 = 0; p0 < NO_SQUARES; p0++)
+ {
+ (*nextpos[ptyp])[po][p0] = (unsigned char)po;
+ (*nextdir[ptyp])[po][p0] = (unsigned char)po;
+ }
+ }
+ }
+
+ for (ptyp = 0; ptyp < NO_PTYPE_PIECES; ptyp++)
+ {
+ for (po = fpo; po < tpo; po++)
+ {
+ if (nunmap[po] >= (small_short)0)
+ {
+ ppos = (*nextpos[ptyp])[nunmap[po]];
+ pdir = (*nextdir[ptyp])[nunmap[po]];
+
+ /* dest is a function of direction and steps */
+ for (d = 0; d < 8; d++)
+ {
+ dest[d][0] = nunmap[po];
+ delta = direc[ptyp][d];
+
+ if (delta != 0)
+ {
+ p0 = po;
+
+ for (s = 0; s < max_steps[ptyp]; s++)
+ {
+ p0 = p0 + delta;
+
+ /*
+ * break if (off board) or (promoted rooks
+ * wishes to move two steps diagonal) or
+ * (promoted bishops wishes to move two steps
+ * non-diagonal)
+ */
+ if ((nunmap[p0] < (small_short)0)
+ || ((ptyp == ptype_prook)
+ && (s > 0)
+ && diagonal(delta))
+ || ((ptyp == ptype_pbishop)
+ && (s > 0)
+ && !diagonal(delta)))
+ break;
+ else
+ dest[d][s] = nunmap[p0];
+ }
+ }
+ else
+ {
+ s = 0;
+ }
+
+ /*
+ * Sort dest in number of steps order; currently no sort
+ * is done due to compatibility with the move generation
+ * order in old gnuchess.
+ */
+
+ steps[d] = s;
+
+ for (di = d; s > 0 && di > 0; di--)
+ {
+ if (steps[sorted[di - 1]] == 0) /* should be: < s */
+ sorted[di] = sorted[di - 1];
+ else
+ break;
+ }
+
+ sorted[di] = d;
+ }
+
+ /*
+ * update nextpos/nextdir
+ */
+
+ p0 = nunmap[po];
+ pdir[p0] = (unsigned char)dest[sorted[0]][0];
+
+ for (d = 0; d < 8; d++)
+ {
+ for (s = 0; s < steps[sorted[d]]; s++)
+ {
+ ppos[p0] = (unsigned char)dest[sorted[d]][s];
+ p0 = dest[sorted[d]][s];
+
+ if (d < 7)
+ pdir[p0] = (unsigned char)dest[sorted[d + 1]][0];
+
+ /*
+ * else is already initialized
+ */
+ }
+ }
+ }
+ }
+ }
+}
+
+#endif
+
+
+
+/*
+ * Reset the board and other variables to start a new game.
+ */
+
+void
+NewGame(void)
+{
+ short l, c, p, max_opening_sequence;
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+#endif
+ compptr = oppptr = 0;
+ stage = 0;
+ stage2 = -1; /* the game is not yet started */
+ flag.illegal = flag.mate = flag.post = flag.quit
+ = flag.reverse = flag.bothsides = flag.onemove = flag.force
+ = false;
+ flag.material = flag.coords = flag.hash = flag.easy
+ = flag.beep = flag.rcptr
+ = true;
+ flag.stars = flag.shade = flag.back = flag.musttimeout = false;
+ flag.gamein = false;
+ flag.rv = true;
+
+ mycnt1 = mycnt2 = 0;
+ GenCnt = NodeCnt = et0 = dither = XCmore = 0;
+ znodes = ZNODES;
+ WAwindow = WAWNDW;
+ WBwindow = WBWNDW;
+ BAwindow = BAWNDW;
+ BBwindow = BBWNDW;
+ xwndw = BXWNDW;
+
+ if (!MaxSearchDepth)
+ MaxSearchDepth = MAXDEPTH - 1;
+
+ contempt = 0;
+ GameCnt = 0;
+ Game50 = 1;
+ CptrFlag[0] = TesujiFlag[0] = false;
+ hint = OPENING_HINT;
+ ZeroRPT();
+ GameType[0] = GameType[1] = UNKNOWN;
+ Pscore[0] = Tscore[0] = (SCORE_LIMIT + 3000);
+ opponent = player = black;
+ computer = white;
+
+ for (l = 0; l < TREE; l++)
+ Tree[l].f = Tree[l].t = 0;
+
+ gsrand((unsigned int) 1);
+
+ if (!InitFlag)
+ {
+ for (c = black; c <= white; c++)
+ {
+ for (p = pawn; p <= king; p++)
+ {
+ for (l = 0; l < NO_SQUARES; l++)
+ {
+ (*hashcode)[c][p][l].key
+ = (((unsigned long) urand()));
+ (*hashcode)[c][p][l].key
+ += (((unsigned long) urand()) << 16);
+ (*hashcode)[c][p][l].bd
+ = (((unsigned long) urand()));
+ (*hashcode)[c][p][l].bd
+ += (((unsigned long) urand()) << 16);
+#if SIZEOF_LONG == 8 /* 64-bit long i.e. 8 bytes */
+ (*hashcode)[c][p][l].key
+ += (((unsigned long) urand()) << 32);
+ (*hashcode)[c][p][l].key
+ += (((unsigned long) urand()) << 48);
+ (*hashcode)[c][p][l].bd
+ += (((unsigned long) urand()) << 32);
+ (*hashcode)[c][p][l].bd
+ += (((unsigned long) urand()) << 48);
+#endif
+ }
+ }
+ }
+
+ for (c = black; c <= white; c++)
+ {
+ for (p = pawn; p <= king; p++)
+ {
+ for (l = 0; l < MAX_CAPTURED; l++)
+ {
+ (*drop_hashcode)[c][p][l].key
+ = (((unsigned long) urand()));
+ (*drop_hashcode)[c][p][l].key
+ += (((unsigned long) urand()) << 16);
+ (*drop_hashcode)[c][p][l].bd
+ = (((unsigned long) urand()));
+ (*drop_hashcode)[c][p][l].bd
+ += (((unsigned long) urand()) << 16);
+#if SIZEOF_LONG == 8 /* 64-bit long i.e. 8 bytes */
+ (*drop_hashcode)[c][p][l].key
+ += (((unsigned long) urand()) << 32);
+ (*drop_hashcode)[c][p][l].key
+ += (((unsigned long) urand()) << 48);
+ (*drop_hashcode)[c][p][l].bd
+ += (((unsigned long) urand()) << 32);
+ (*drop_hashcode)[c][p][l].bd
+ += (((unsigned long) urand()) << 48);
+#endif
+ }
+ }
+ }
+ }
+
+ for (l = 0; l < NO_SQUARES; l++)
+ {
+ board[l] = Stboard[l];
+ color[l] = Stcolor[l];
+ Mvboard[l] = 0;
+ }
+
+ ClearCaptured();
+ ClearScreen();
+ InitializeStats();
+
+#ifdef HAVE_GETTIMEOFDAY
+ gettimeofday(&tv, NULL);
+ time0 = tv.tv_sec*100 + tv.tv_usec/10000;
+#else
+ time0 = time((long *) 0);
+#endif
+
+ /* resetting reference time */
+ ElapsedTime(COMPUTE_AND_INIT_MODE);
+ flag.regularstart = true;
+ Book = BOOKFAIL;
+
+ if (!InitFlag)
+ {
+ char sx[256];
+ strcpy(sx, CP[169]);
+
+ if (TCflag)
+ SetTimeControl();
+ else if (MaxResponseTime == 0)
+ SelectLevel(sx);
+
+ UpdateDisplay(0, 0, 1, 0);
+ GetOpenings();
+ GetOpeningPatterns(&max_opening_sequence);
+
+ InitFlag = true;
+ }
+
+#if ttblsz
+ if (TTadd)
+ {
+ ZeroTTable();
+ TTadd = 0;
+ }
+#endif /* ttblsz */
+
+ hashbd = hashkey = 0;
+ return;
+}
+
+
+
+int
+Initialize_data(void)
+{
+ size_t n;
+ int i;
+ char buffer[60];
+ int doit = true;
+
+ {
+ small_short x = -1;
+
+ if (x >= 0)
+ {
+ ShowMessage("datatype 'small_short' is unsigned; "
+ "check gnushogi.h\n");
+ return 1;
+ }
+ }
+
+ n = sizeof(struct leaf) * (size_t)TREE;
+ Tree = malloc(n);
+
+ if (!Tree)
+ {
+ sprintf(buffer, "Cannot allocate %ld bytes for search tree",
+ (long)n);
+ ShowMessage(buffer);
+ return 1;
+ }
+
+ n = sizeof(hashcode_array);
+ hashcode = malloc(n);
+
+ if (!hashcode)
+ {
+ sprintf(buffer, "Cannot allocate %ld bytes for hashcode", (long)n);
+ ShowMessage(buffer);
+ return 1;
+ }
+
+ n = sizeof(drop_hashcode_array);
+ drop_hashcode = malloc(n);
+
+ if (!drop_hashcode)
+ {
+ sprintf(buffer,
+ "Cannot allocate %ld bytes for drop_hashcode",
+ (long)n);
+ ShowMessage(buffer);
+ return 1;
+ }
+
+ n = sizeof(struct GameRec) * (size_t)(MAXMOVES + MAXDEPTH);
+ GameList = malloc(n);
+
+ if (!GameList)
+ {
+ sprintf(buffer,
+ "Cannot allocate %ld bytes for game record",
+ (long)n);
+ ShowMessage(buffer);
+ return 1;
+ }
+
+#if !defined SAVE_NEXTPOS
+ n = sizeof(next_array);
+
+ for (i = 0; i < NO_PTYPE_PIECES; i++)
+ {
+ nextdir[i] = use_nextpos ? malloc(n) : NULL;
+
+ if (!nextdir[i])
+ {
+ if (use_nextpos)
+ {
+ sprintf(buffer, "cannot allocate %ld space for nextdir %d",
+ (long)(n), i);
+ ShowMessage(buffer);
+ }
+
+ nextdir[i] = NULL;
+ use_nextpos = false;
+ }
+
+ nextpos[i] = use_nextpos ? malloc(n) : NULL;
+
+ if (!nextpos[i])
+ {
+ if (use_nextpos)
+ {
+ sprintf(buffer, "cannot allocate %ld space for nextpos %d",
+ (long)(n), i);
+ ShowMessage(buffer);
+ }
+
+ use_nextpos = false;
+ }
+ }
+
+ if (!use_nextpos)
+ {
+ return 1;
+ }
+#endif
+
+ n = sizeof(value_array);
+ value = malloc(n);
+
+ if (!value)
+ {
+ ShowMessage("cannot allocate value space");
+ return 1;
+ }
+
+ n = sizeof(fscore_array);
+ fscore = malloc(n);
+
+ if (!fscore)
+ {
+ ShowMessage("cannot allocate fscore space");
+ return 1;
+ }
+
+#if defined HISTORY
+ n = sizeof_history;
+ history = malloc(n);
+
+ if (!history)
+ {
+ sprintf(buffer, "Cannot allocate %ld bytes for history table",
+ (long)sizeof_history);
+ ShowMessage(buffer);
+ use_history = false;
+ }
+#endif
+
+#if defined CACHE
+ n = sizeof(struct etable) * (size_t)ETABLE;
+
+ for (i = 0; i < 2; i++)
+ {
+ etab[i] = use_etable ? malloc(n) : 0;
+
+ if (!etab[i])
+ {
+ sprintf(buffer, "Cannot allocate %ld bytes for cache table %ld",
+ (long)n, (long)i);
+ ShowMessage(buffer);
+ use_etable = false;
+ }
+ }
+#endif
+
+#if ttblsz
+
+ if (rehash < 0)
+ rehash = MAXrehash;
+
+ n = sizeof(struct hashentry)*(ttblsize + rehash);
+
+ while (doit && ttblsize > MINTTABLE)
+ {
+ ttable[0] = malloc(n); /* FIXME: cast to the correct type. */
+ ttable[1] = ttable[0] ? malloc(n) : NULL;
+
+ if (!ttable[0] || !ttable[1])
+ {
+ if (!ttable[0])
+ free(ttable[0]);
+
+ if (!ttable[1])
+ free(ttable[1]);
+
+ ttblsize = ttblsize >> 1;
+ n = sizeof(struct hashentry) * (ttblsize + rehash);
+ }
+ else
+ {
+ doit = false;
+ }
+ }
+
+ if (ttblsize <= MINTTABLE)
+ {
+ use_ttable = false;
+ }
+
+ if (use_ttable)
+ {
+ /* CHECKME: is the precedence here correct? */
+ /* ttbllimit = ttblsize << 1 - ttblsize >> 2; */
+ ttbllimit = (ttblsize << 1) - (ttblsize >> 2);
+ }
+ else
+ {
+ sprintf(buffer, "Cannot allocate %ld bytes for transposition table",
+ (long)(2 * n));
+ ShowMessage(buffer);
+ ttable[0] = ttable[1] = NULL;
+ }
+#endif /* ttblsz */
+
+#if !defined SAVE_DISTDATA
+ n = sizeof(distdata_array);
+ distdata = malloc(n);
+
+ if (!distdata)
+ {
+ ShowMessage("cannot allocate distdata space...");
+ use_distdata = false;
+ }
+#endif
+
+#if !defined SAVE_PTYPE_DISTDATA
+ n = sizeof(distdata_array);
+
+ for (i = 0; i < NO_PTYPE_PIECES; i++)
+ {
+ ptype_distdata[i] = use_ptype_distdata ? malloc(n) : 0;
+
+ if (!ptype_distdata[i])
+ {
+ sprintf(buffer,
+ "cannot allocate %ld bytes for ptype_distdata %d...",
+ (long)n, i);
+ use_ptype_distdata = false;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+
+#if defined EXTLANGFILE
+
+#ifdef OLDLANGFILE
+
+void
+InitConst(char *lang)
+{
+ FILE *constfile;
+ char s[256];
+ char sl[5];
+ char buffer[120];
+ int len, entry;
+ char *p, *q;
+ constfile = fopen(LANGFILE, "r");
+
+ if (!constfile)
+ {
+ ShowMessage("NO LANGFILE");
+ exit(1);
+ }
+
+ while (fgets(s, sizeof(s), constfile))
+ {
+ if (s[0] == '!')
+ continue;
+
+ len = strlen(s);
+
+ for (q = &s[len]; q > &s[8]; q--)
+ if (*q == '}')
+ break;
+
+ if (q == &s[8])
+ {
+ ShowMessage("{ error in cinstfile");
+ exit(1);
+ }
+
+ *q = '\0';
+
+ if ((s[3] != ':') || (s[7] != ':') || (s[8] != '{'))
+ {
+ sprintf(buffer, "Langfile format error %s", s);
+ ShowMessage(buffer);
+ exit(1);
+ }
+
+ s[3] = s[7] = '\0';
+
+ if (lang == NULL)
+ {
+ lang = sl;
+ strcpy(sl, &s[4]);
+ }
+
+ if (strcmp(&s[4], lang))
+ continue;
+
+ entry = atoi(s);
+
+ if ((entry < 0) || (entry >= CPSIZE))
+ {
+ ShowMessage("Langfile number error");
+ exit(1);
+ }
+
+ for (q = p = &s[9]; *p; p++)
+ {
+ if (*p != '\\')
+ {
+ *q++ = *p;
+ }
+ else if (*(p + 1) == 'n')
+ {
+ *q++ = '\n';
+ p++;
+ }
+ }
+
+ *q = '\0';
+
+ if ((entry < 0) || (entry > 255))
+ {
+ sprintf(buffer, "Langfile error %d\n", entry);
+ ShowMessage(buffer);
+ exit(0);
+ }
+
+ CP[entry] = (char *)GLOBAL_ALLOC((unsigned) strlen(&s[9]) + 1);
+
+ if (CP[entry] == NULL)
+ {
+ char buffer[80];
+ sprintf(buffer, "CP MALLOC, entry %d", entry);
+ perror(buffer);
+ exit(0);
+ }
+
+ strcpy(CP[entry], &s[9]);
+ }
+
+ fclose(constfile);
+}
+
+#else
+
+void
+InitConst(char *lang)
+{
+ FILE *constfile;
+ char s[256];
+ char sl[5];
+ char buffer[120];
+ int len, entry;
+ char *p, *q;
+ constfile = fopen(LANGFILE, "r");
+
+ if (!constfile)
+ {
+ ShowMessage("NO LANGFILE");
+ exit(1);
+ }
+
+ while (fgets(s, sizeof(s), constfile))
+ {
+ if (s[0] == '!')
+ continue;
+
+ len = strlen(s);
+
+ if ((len > 3) && (s[3] == ':') || (len > 7) && (s[7] == ':'))
+ {
+ ShowMessage("old Langfile error");
+ exit(1);
+ }
+
+ if (len <= 15)
+ {
+ ShowMessage("length error in Langfile");
+ exit(1);
+ }
+
+ for (q = &s[len]; q > &s[15]; q--)
+ {
+ if (*q == '"')
+ break;
+ }
+
+ if (q == &s[15])
+ {
+ ShowMessage("\" error in Langfile");
+ exit(1);
+ }
+
+ *q = '\0';
+
+ if ((s[6] != ':') || (s[10] != ':') || (s[15] != '"'))
+ {
+ sprintf(buffer, "Langfile format error %s", s);
+ ShowMessage(buffer);
+ exit(1);
+ }
+
+ s[6] = s[10] = '\0';
+
+ if (lang == NULL)
+ {
+ lang = sl;
+ strcpy(sl, &s[7]);
+ }
+
+ if (strcmp(&s[7], lang))
+ continue;
+
+ entry = atoi(&s[3]);
+
+ if ((entry < 0) || (entry >= CPSIZE))
+ {
+ ShowMessage("Langfile number error");
+ exit(1);
+ }
+
+ for (q = p = &s[16]; *p; p++)
+ {
+ if (*p != '\\')
+ {
+ *q++ = *p;
+ }
+ else if (*(p + 1) == 'n')
+ {
+ *q++ = '\n';
+ p++;
+ }
+ }
+
+ *q = '\0';
+
+ if ((entry < 0) || (entry > 255))
+ {
+ sprintf(buffer, "Langfile error %d\n", entry);
+ ShowMessage(buffer);
+ exit(0);
+ }
+
+ CP[entry] = (char *)GLOBAL_ALLOC((unsigned)strlen(&s[16]) + 1);
+
+ if (CP[entry] == NULL)
+ {
+ char buffer[80];
+ sprintf(buffer, "CP MALLOC, entry %d", entry);
+ perror(buffer);
+ exit(0);
+ }
+
+ strcpy(CP[entry], &s[16]);
+ }
+
+ fclose(constfile);
+}
+
+#endif
+
+#endif
+
+
+int
+InitMain(void)
+{
+ gsrand(starttime = ((unsigned int)time((long *)0))); /* init urand */
+
+#if ttblsz
+ ttblsize = ttblsz;
+ rehash = -1;
+#endif /* ttblsz */
+
+ if (Initialize_data() != 0)
+ return 1;
+
+#if defined EXTLANGFILE
+ InitConst(Lang);
+#endif
+
+ strcpy(ColorStr[0], CP[118]);
+ strcpy(ColorStr[1], CP[119]);
+
+ XC = 0;
+ MaxResponseTime = 0;
+
+ if (XSHOGI)
+ {
+ signal(SIGINT, TerminateSearch);
+
+ TCmoves = 40;
+ TCminutes = 5;
+ TCseconds = 0;
+ TCadd = 0;
+
+ TCflag = true;
+ OperatorTime = 0;
+ barebones = 1;
+ }
+ else
+ {
+ TCflag = false;
+ OperatorTime = 0;
+ barebones = 0;
+ }
+
+ Initialize();
+ Initialize_dist();
+ Initialize_eval();
+#if !defined SAVE_NEXTPOS
+ Initialize_moves();
+#endif
+
+ NewGame();
+
+ flag.easy = ahead;
+ flag.hash = hash;
+
+ if (xwin)
+ xwndw = atoi(xwin);
+
+#ifdef HASHFILE
+ hashfile = NULL;
+#endif
+
+#if ttblsz
+#ifdef HASHFILE
+ hashfile = fopen(HASHFILE, RWA_ACC);
+
+ if (hashfile)
+ {
+ fseek(hashfile, 0L, SEEK_END);
+ filesz = ftell(hashfile) / sizeof(struct fileentry) - 1 - MAXrehash;
+ hashmask = filesz >> 1;
+ hashbase = hashmask + 1;
+ }
+#endif /* HASHFILE */
+#endif /* ttblsz */
+
+ savefile[0] = '\0';
+ listfile[0] = '\0';
+
+ return 0;
+}
+
+
+void
+ExitMain(void)
+{
+#if ttblsz
+#ifdef HASHFILE
+ if (hashfile)
+ fclose(hashfile);
+#endif /* HASHFILE */
+#endif /* ttblsz */
+
+ ExitShogi();
+}
+