checkers.cxx

来自「SRI international 发布的OAA框架软件」· CXX 代码 · 共 1,360 行 · 第 1/3 页

CXX
1,360
字号
      if (jnode) {
	n->from = jnode->from;
	n->jump |= jnode->jump;
	n->king |= jnode->king;
      }
      piece jumpedpiece = b[jumploc];
      b[jumploc] = EMPTY;
      jumphappened = 0;
      movepiece(f,j,n);
      if (forcejumps && jumphappened) killnode(n);
      else {evaluateboard(n,0); insert(n);}
      b[i] = oldpiece; b[j] = EMPTY;
      b[jumploc] = jumpedpiece;
      jumphappened = 1;
    }
  }
}

void expandnode(node *f) {
  if (f->son || f->value > 28000) return;	// already done
  piece turn = f->who ? BLACK : WHITE;
  for (int i=5; i<40; i++) if (b[i]&turn) movepiece(f,i,0);
  if (f->son) {
    f->value = -f->son->value;
    if (f->brother) f->value -= depthpenalty;
  }
  else f->value = 30000;
}

void makemove(node *n) {
  b[n->to] = b[n->from];
  if (n->king) b[n->to] |= KING;
  b[n->from] = EMPTY;
  if (n->jump) for(int i=0; i<32; i++) {
    if (n->jump & (1<<i)) b[10+i] = EMPTY;
  }
}

int didabort(void);

int fullexpand(node *f, int level) {
  if (didabort() || nodes > maxnodes-(maxply*10) || evaluated > maxevaluate) return(0);
  expandnode(f);
  if (!f->son) return(1);
  piece oldboard[45];
  memmove(oldboard,b,sizeof(b));
  node* n = f->son;
  if (!n->jump && n->brother) {if (level<1) return(1); level--;}
  int i;
  node* sons[32]; for (i=0; (sons[i++] = n); n = n->brother);
  int ret = 1;
  for (i=0; ret && (n = sons[i++]);) {
    makemove(n);
    ret = fullexpand(n,level);
    memmove(b,oldboard,sizeof(b));
    extract(n);
    insert(n);
  }
  f->value = -f->son->value;
  return(ret);
}

int descend(node *f) {
  static int depth;
  if (didabort() || nodes > maxnodes || depth >= maxply) return(0);
  if (f->son) {
    node* n = f->son;
    makemove(n);
    depth++;
    int ret = descend(n);
    depth--;
    extract(n);
    insert(n);
    f->value = -f->son->value;
    return(ret);
  }
  else {expandnode(f); return(1);}
}

char debug;

node *calcmove(node *root) {	// return best move after root
  expandnode(root);
  if (!root->son) return(0);	// no move due to loss
  if (debug) printf("calcmove() initial nodes = %d\n",nodes);
  evaluated = 0;
  if (root->son->brother) {
    int x;
    for (x = 1; abs(root->value)<28000 && fullexpand(root,x); x++);
    piece saveboard[45]; memmove(saveboard,b,sizeof(b));
    while (abs(root->value)<28000) {
      x = descend(root);
      memmove(b,saveboard,sizeof(b));
      if (!x) break;
    }
  }
  if (debug) printf(" evaluated %d, nodes = %d\n", evaluated, nodes);
  return(root->son);
}

// the actual game state ----------------

node *root,*undoroot;

piece jumpboards[24][45];	// saved boards for undoing jumps
int nextjump;

char user;	// 0 = black, 1 = white
char playing;
char autoplay;

void newgame(void) {

  int n;
  for (n=0; n<5; n++) b[n] = BLUE;
  for (n=5; n<18; n++) b[n] = WHITE;
  for (n=18; n<27; n++) b[n] = EMPTY;
  for (n=27; n<40; n++) b[n] = BLACK;
  for (n=40; n<45; n++) b[n] = BLUE;
  b[13] = b[22] = b[31] = BLUE;

  centralsquares[15] = centralsquares[16] =
    centralsquares[19] = centralsquares[20] =
    centralsquares[24] = centralsquares[25] =
    centralsquares[28] = centralsquares[29] = 1;

  // set up initial search tree:
  nextjump = 0;
  killnode(undoroot);
  undoroot = root = newnode();

  // make it white's move, so first move is black:
  root->who = 1;
  user = 0;
  playing = 1;
}

void domove(node* move) {
  if (move->jump) memmove(jumpboards[nextjump++],b,sizeof(b));
  makemove(move);
  extract(move);
  killnode(root->son);
  root->son = move;
  root = move;
  if (debug) evaluateboard(move,1);
}

node* undomove() {
  node *n = root;
  if (n == undoroot) return 0; // no more undo possible
  if (n->jump) memmove(b,jumpboards[--nextjump],sizeof(b));
  else {
    b[n->from] = b[n->to];
    if (n->king) b[n->from] &= (WHITE|BLACK);
    b[n->to] = EMPTY;
  }
  root = n->father;
  killnode(n);
  root->son = 0;
  root->value = 0;	// prevent it from thinking game is over
  playing = 1;
  if (root == undoroot) user = 0;
  return n;
}

const char _usermoves[] =
"B1D1F1H1A2C2E2G2??B3D3F3H3A4C4E4G4??B5D5F5H5A6C6E6G6??B7D7F7H7A8C8E8G8??";
#define usermoves(x,y) _usermoves[2*((x)-5)+(y)-1]

void dumpnode(node *n, int help) {
  int x = n->from;
  int y = n->to;
  if (help) printf("%c%c %c%c\t- ",
		   usermoves(x,1),usermoves(x,2),
		   usermoves(y,1),usermoves(y,2));
  printf("%s %ss from %c%c to %c%c",
	 n->who ? "White" : "Black",
	 n->jump ? "jump" : "move",
	 usermoves(x,1),usermoves(x,2),
	 usermoves(y,1),usermoves(y,2));
  if (n->jump) {
    for (int i=0; i<32; i++) if (n->jump & (1<<i))
      printf(", %c%c",usermoves(10+i,1),usermoves(10+i,2));
    printf(" removed");
  }
  printf(" (%+d).\n",n->value);
}

int abortflag;

////////////////////////////////////////////////////////////////
// VT100 Interface:
#ifdef VT100

void positioncursor(int i) {
  printf("\033[%d;%dH",
	 usermoves(i,2)-'0'+1,
	 2*(usermoves(i,1)-'A')+1);
}

void outpiecename(piece n) {
  printf(n&BLACK ? "\033[1;7m" : "\033[1m");
  putchar(" BW??BW??"[n]);
  putchar(" BW??KK??"[n]);
  printf("\033[0m");
}

void VT100board(void) {
  printf("\033<\033[H\033[J\033[10r");
  int l = 0;
  puts(" A B C D E F G H");
  for (int i=0; i<4; i++) {
    int j = 9*i+5;
    int k;
    for (k=0; k<4; k++) {
      printf("\033[7m  \033[0m");
      outpiecename(b[j+k]);
    }
    l++;
    printf("%d\n",l);
    j += 4;
    for (k=0; k<4; k++) {
      outpiecename(b[j+k]);
      printf("\033[7m  \033[0m");
    }
    l++;
    printf("%d\n",l);
  }
}

void VT100move(node *n, int) {
  if (!n) return;
  printf("\0337");
  positioncursor(n->from);
  outpiecename(b[n->from]);
  positioncursor(n->to);
  outpiecename(b[n->to]);
  if (n->jump) for(int i=0; i<32; i++) {
    if (n->jump & (1<<i)) {
      positioncursor(10+i);
      outpiecename(b[10+i]);
    }
  }
  printf("\0338");
}

int decode(char *m) {
  int i;
  for(i=5; i<=40; i++)
    if (toupper(m[0])==usermoves(i,1) && m[1]==usermoves(i,2)) return(i);
  return(0);
}

#include <signal.h>

static void sigint(...) {
  abortflag = 1;
  signal(SIGINT,sigint);
}

void fixexit(int x) {
  printf("\0337\033[r\0338");
  exit(x);
}

// Returns a son, or 0 if no move specified, or root to cause "help"
node *getusermove(void) {
  int i,j;
  node *t;
  char line[100],*m1,*m2;

  if (playing)
    printf("\033[1m%s's move?\033[0m ",root->who ? "Black" : "White");
  else
    printf("\033[1mCommand?\033[0m ");
  abortflag = 0;
  if (!gets(line)) {
    putchar('\n');
    if (feof(stdin)) fixexit(0);
    return 0;
  }
  for (m1 = line; *m1 && *m1<=' '; m1++);
  if (!*m1) return(0);
  m2 = m1+1;
  if (*m2) m2++;
  for (; *m2 && *m2<'0'; m2++);
  if (playing && m1[1]>='0' && m1[1]<='9') {
    i = decode(m1);
    j = decode(m2);
    if (i && j) for (t = root->son; t; t = t->brother)
      if (t->from == i && t->to == j) return(t);
    puts("Valid moves are:");
    m1[0] = 'L';
  }
  switch(toupper(m1[0])) {
  case 0: return(0);
  case 'A':
    if (playing) autoplay = 1;
    return(root);
  case 'C':
    puts(copyright);
    break;
  case 'D':
    debug = !debug;
    printf("Debug is now %s.", debug ? "on" : "off");
    break;
  case 'F':
    forcejumps = !forcejumps;
    printf("Forced jumps rule is now %s.",forcejumps ? "on" : "off");
    killnode(root->son); root->son = 0;
    return(0);
  case 'L':
    expandnode(root);
    if (playing) for (t = root->son; t; t = t->brother) dumpnode(t,1);
    break;
  case 'M':
    return(playing ? root : 0);
  case 'N':
    newgame();
    VT100board();
    return(0);
  case 'P':
    printf("I expect the following moves:\n");
    for (t = root->son; t; t = t->son) dumpnode(t,0);
    break;
  case 'Q':
    fixexit(0);
  case 'R':
    VT100board();
    break;
  case 'S':
    user = !user;
    return(root);
  case 'U':
    VT100move(undomove(),1);
    VT100move(undomove(),1);
    return(0);
  case '+':
    maxevaluate = maxnodes = 2*maxevaluate;
    goto J2;
  case '-':
    if (maxevaluate > 1)
      maxevaluate = maxnodes = maxevaluate/2;
  J2: printf("Moves evaluated set to %d.",maxevaluate);
    break;
  default:
    puts(
	 "A(utoplay)\n"
	 "C(opyright)\n"
	 "D(ebug on/off)\n"
	 "F(orce jumps rule on/off)\n"
	 "L(ist legal moves)\n"
	 "M(ake a move for me)\n"
	 "N(ew game)\n"
	 "P(redict next few moves)\n"
	 "Q(uit)\n"
	 "R(edraw screen)\n"
	 "S(witch sides)\n"
	 "U(ndo)\n"
	 "+	- smarter\n"
	 "-	- stupider");
    expandnode(root);
    for (t = root->son; t; t = t->brother) dumpnode(t,1);
  }
  return(0);
}

int VT100main() {
  signal(SIGINT,sigint);
  VT100board();
  for (;;) {
    if (playing) {
      expandnode(root);
      if (!root->son) {
	printf("%s has no move.  Game over.",root->who ? "Black" : "White");
	playing = autoplay = 0;
      }
    }
    node* move;
    if (playing && (autoplay || root->who == user)) {
      move = calcmove(root);
      if (move->value <= -30000) {
 	printf("%s resigns.", move->who ? "White" : "Black");
 	move = 0;
 	playing = autoplay = 0;
      }
    } else {
      move = getusermove();
      if (move == root) move = calcmove(root);
    }
    if (move) {
      dumpnode(move,0);
      domove(move);
      VT100move(move,0);
    }
  }
}

#endif

////////////////////////////////////////////////////////////////
// fltk interface:
#ifdef FLTK

#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/Fl_Bitmap.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Menu_Item.H>
#include <FL/fl_ask.H>

//----------------------------------------------------------------
// old 4-level NeXT images have been seperated into bitmaps so they
// can be drawn with arbitrary colors and real transparency.  This is
// rather tedious and perhaps fltk should provide a direct support
// to do this:

#include "black_1.xbm"
#include "black_2.xbm"
#include "black_3.xbm"
#include "black_4.xbm"
#include "white_1.xbm"
#include "white_2.xbm"
#include "white_3.xbm"
#include "white_4.xbm"
#include "blackking_1.xbm"
#include "blackking_2.xbm"
#include "blackking_3.xbm"
#include "blackking_4.xbm"
#include "whiteking_1.xbm"
#include "whiteking_2.xbm"
#include "whiteking_3.xbm"
#include "whiteking_4.xbm"

Fl_Bitmap *bm[4][4];

void make_bitmaps() {
  if (bm[0][0]) return;
  bm[0][0] = new Fl_Bitmap(black_1_bits, black_1_width, black_1_height);
  bm[0][1] = new Fl_Bitmap(black_2_bits, black_1_width, black_1_height);
  bm[0][2] = new Fl_Bitmap(black_3_bits, black_1_width, black_1_height);
  bm[0][3] = new Fl_Bitmap(black_4_bits, black_1_width, black_1_height);
  bm[1][0] = new Fl_Bitmap(white_1_bits, black_1_width, black_1_height);
  bm[1][1] = new Fl_Bitmap(white_2_bits, black_1_width, black_1_height);
  bm[1][2] = new Fl_Bitmap(white_3_bits, black_1_width, black_1_height);
  bm[1][3] = new Fl_Bitmap(white_4_bits, black_1_width, black_1_height);
  bm[2][0] = new Fl_Bitmap(blackking_1_bits, black_1_width, black_1_height);
  bm[2][1] = new Fl_Bitmap(blackking_2_bits, black_1_width, black_1_height);
  bm[2][2] = new Fl_Bitmap(blackking_3_bits, black_1_width, black_1_height);
  bm[2][3] = new Fl_Bitmap(blackking_4_bits, black_1_width, black_1_height);
  bm[3][0] = new Fl_Bitmap(whiteking_1_bits, black_1_width, black_1_height);
  bm[3][1] = new Fl_Bitmap(whiteking_2_bits, black_1_width, black_1_height);
  bm[3][2] = new Fl_Bitmap(whiteking_3_bits, black_1_width, black_1_height);
  bm[3][3] = new Fl_Bitmap(whiteking_4_bits, black_1_width, black_1_height);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?