checkers.cxx

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

CXX
1,360
字号
}

#define ISIZE black_1_width

void draw_piece(int which, int x, int y) {
  if (!fl_not_clipped(x,y,ISIZE,ISIZE)) return;
  switch (which) {
  case BLACK: which = 0; break;
  case WHITE: which = 1; break;
  case BLACKKING: which = 2; break;
  case WHITEKING: which = 3; break;
  default: return;
  }
  fl_color(FL_BLACK); bm[which][0]->draw(x, y);
  fl_color(FL_INACTIVE_COLOR); bm[which][1]->draw(x, y);
  fl_color(FL_SELECTION_COLOR); bm[which][2]->draw(x, y);
  fl_color(FL_WHITE); bm[which][3]->draw(x, y);
}

//----------------------------------------------------------------

class Board : public Fl_Double_Window {
  void draw();
  int handle(int);
public:
  void drag_piece(int, int, int);
  void drop_piece(int);
  void animate(node* move, int backwards);
  void computer_move(int);
  Board(int w, int h) : Fl_Double_Window(w,h) {color(15);}
};

#define BOXSIZE 52
#define BORDER 4
#define BOARDSIZE (8*BOXSIZE+BORDER)
#define BMOFFSET 5

static int erase_this;  // real location of dragging piece, don't draw it
static int dragging;	// piece being dragged
static int dragx;	// where it is
static int dragy;
static int showlegal;	// show legal moves

int squarex(int i) {return (usermoves(i,1)-'A')*BOXSIZE+BMOFFSET;}
int squarey(int i) {return (usermoves(i,2)-'1')*BOXSIZE+BMOFFSET;}

void Board::draw() {
  make_bitmaps();
  fl_draw_box(box(),0,0,w(),h(),color());
  fl_color((Fl_Color)10 /*107*/);
  int x; for (x=0; x<8; x++) for (int y=0; y<8; y++) {
    if (!((x^y)&1)) fl_rectf(BORDER+x*BOXSIZE, BORDER+y*BOXSIZE,
			     BOXSIZE-BORDER, BOXSIZE-BORDER);
  }
  fl_color(FL_DARK3 /*FL_GRAY_RAMP+4*/);
  for (x=0; x<9; x++) {
    fl_rectf(x*BOXSIZE,0,BORDER,h());
    fl_rectf(0,x*BOXSIZE,w(),BORDER);
  }
  for (int j = 5; j < 40; j++) if (j != erase_this) {
    draw_piece(b[j], squarex(j), squarey(j));
  }
  if (showlegal) {
    fl_color(FL_WHITE);
    node* n;
    for (n = root->son; n; n = showlegal==2 ? n->son : n->brother) {
      int x1 = squarex(n->from)+BOXSIZE/2-5;
      int y1 = squarey(n->from)+BOXSIZE/2-5;
      int x2 = squarex(n->to)+BOXSIZE/2-5;
      int y2 = squarey(n->to)+BOXSIZE/2-5;
      fl_line(x1,y1,x2,y2);
      fl_push_matrix();
      fl_mult_matrix(x2-x1,y2-y1,y1-y2,x2-x1,x2,y2);
      fl_begin_polygon();
      fl_vertex(0,0);
      fl_vertex(-.3, .1);
      fl_vertex(-.3, -.1);
      fl_end_polygon();
      fl_pop_matrix();
    }
    int num = 1;
    fl_color(FL_BLACK);
    fl_font(FL_BOLD,10);
    for (n = root->son; n; n = showlegal==2 ? n->son : n->brother) {
      int x1 = squarex(n->from)+BOXSIZE/2-5;
      int y1 = squarey(n->from)+BOXSIZE/2-5;
      int x2 = squarex(n->to)+BOXSIZE/2-5;
      int y2 = squarey(n->to)+BOXSIZE/2-5;
      char buf[20]; sprintf(buf,"%d",num);
      fl_draw(buf, x1+int((x2-x1)*.85)-3, y1+int((y2-y1)*.85)+5);
      num++;
    }
  }
  if (dragging) draw_piece(dragging, dragx, dragy);
}

// drag the piece on square i to dx dy, or undo drag if i is zero:
void Board::drag_piece(int j, int dx, int dy) {
  dy = (dy&-2) | dx&1; // make halftone shadows line up
  if (j != erase_this) drop_piece(erase_this); // should not happen
  if (!erase_this) { // pick up old piece
    dragx = squarex(j); dragy = squarey(j);
    erase_this = j;
    dragging = b[j];
  }
  if (dx != dragx || dy != dragy) {
    damage(FL_DAMAGE_ALL, dragx, dragy, ISIZE, ISIZE);
    damage(FL_DAMAGE_ALL, dx, dy, ISIZE, ISIZE);
  }
  dragx = dx;
  dragy = dy;
}

// drop currently dragged piece on square i
void Board::drop_piece(int j) {
  if (!erase_this) return; // should not happen!
  erase_this = 0;
  dragging = 0;
  int x = squarex(j);
  int y = squarey(j);
  if (x != dragx || y != dragy) {
    damage(4, dragx, dragy, ISIZE, ISIZE);
    damage(4, x, y, ISIZE, ISIZE);
  }
}

// show move (call this *before* the move, *after* undo):
void Board::animate(node* move, int backwards) {
  if (showlegal) {showlegal = 0; redraw();}
  if (!move) return;
  int f = move->from;
  int t = move->to;
  if (backwards) {int x = f; f = t; t = x;}
  int x1 = squarex(f);
  int y1 = squarey(f);
  int x2 = squarex(t);
  int y2 = squarey(t);
  const int STEPS=35;
  for (int j=0; j<STEPS; j++) {
    int x = x1+(x2-x1)*j/STEPS;
    int y = y1+(y2-y1)*j/STEPS;
    drag_piece(move->from,x,y);
    Fl::flush();
  }
  drop_piece(t);
  if (move->jump) redraw();
}

int busy; // causes pop-up abort menu

void Board::computer_move(int help) {
  if (!playing) return;
  cursor(FL_CURSOR_WAIT);
  Fl::flush();
  busy = 1; abortflag = 0;
  node* move = calcmove(root);
  busy = 0;
  if (move) {
    if (!help && move->value <= -30000) {
      fl_message("%s resigns", move->who ? "White" : "Black");
      playing = autoplay = 0;
      cursor(FL_CURSOR_DEFAULT);
      return;
    }
    animate(move,0);
    domove(move);
  }
  expandnode(root);
  if (!root->son) {
    fl_message("%s has no move", root->who ? "Black" : "White");
    playing = autoplay = 0;
  }
  if (!autoplay) cursor(FL_CURSOR_DEFAULT);
}

extern Fl_Menu_Item menu[];
extern Fl_Menu_Item busymenu[];

int Board::handle(int e) {
  if (busy) {
    const Fl_Menu_Item* m;
    switch(e) {
    case FL_PUSH:
      m = busymenu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
      if (m) m->do_callback(this, (void*)m);
      return 1;
    case FL_SHORTCUT:
      m = busymenu->test_shortcut();
      if (m) {m->do_callback(this, (void*)m); return 1;}
      return 0;
    default:
      return 0;
    }
  }
  node *t, *n;
  static int deltax, deltay;
  int dist;
  const Fl_Menu_Item* m;
  switch (e) {
  case FL_PUSH:
    if (Fl::event_button() > 1) {
      m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
      if (m) m->do_callback(this, (void*)m);
      return 1;
    }
    if (playing) {
      expandnode(root);
      for (t = root->son; t; t = t->brother) {
	int x = squarex(t->from);
	int y = squarey(t->from);
	if (Fl::event_inside(x,y,BOXSIZE,BOXSIZE)) {
	  deltax = Fl::event_x()-x;
	  deltay = Fl::event_y()-y;
	  drag_piece(t->from,x,y);
	  return 1;
	}
      }
    }
    return 0;
  case FL_SHORTCUT:
    m = menu->test_shortcut();
    if (m) {m->do_callback(this, (void*)m); return 1;}
    return 0;
  case FL_DRAG:
    drag_piece(erase_this, Fl::event_x()-deltax, Fl::event_y()-deltay);
    return 1;
  case FL_RELEASE:
    // find the closest legal move he dropped it on:
    dist = 50*50; n = 0;
    for (t = root->son; t; t = t->brother) if (t->from==erase_this) {
      int d1 = Fl::event_x()-deltax-squarex(t->to);
      int d = d1*d1;
      d1 = Fl::event_y()-deltay-squarey(t->to);
      d += d1*d1;
      if (d < dist) {dist = d; n = t;}
    }
    if (!n) {drop_piece(erase_this); return 1;} // none found
    drop_piece(n->to);
    domove(n);
    if (showlegal) {showlegal = 0; redraw();}
    if (n->jump) redraw();
    computer_move(0);
    return 1;
  default:
    return 0;
  }
}

void quit_cb(Fl_Widget*, void*) {exit(0);}

int FLTKmain(int argc, char** argv) {
  Fl::visual(FL_DOUBLE|FL_INDEX);
  Board b(BOARDSIZE,BOARDSIZE);
  b.callback(quit_cb);
  b.show(argc,argv);
  return Fl::run();
} 

void autoplay_cb(Fl_Widget*bp, void*) {
  if (autoplay) {autoplay = 0; return;}
  if (!playing) return;
  Board* b = (Board*)bp;
  autoplay = 1;
  while (autoplay) {b->computer_move(0); b->computer_move(0);}
}

#include <FL/Fl_Box.H>
Fl_Window *copyright_window;
void copyright_cb(Fl_Widget*, void*) {
  if (!copyright_window) {
    copyright_window = new Fl_Window(400,270,"Copyright");
    copyright_window->color(FL_WHITE);
    Fl_Box *b = new Fl_Box(20,0,380,270,copyright);
    b->labelsize(10);
    b->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
    copyright_window->end();
  }
  copyright_window->hotspot(copyright_window);
  copyright_window->set_non_modal();
  copyright_window->show();
}

void debug_cb(Fl_Widget*, void*v) {
  debug = !debug;
  ((Fl_Menu_Item*)v)->flags =
    debug ? FL_MENU_TOGGLE|FL_MENU_VALUE : FL_MENU_TOGGLE;
}

void forced_cb(Fl_Widget*b, void*v) {
  forcejumps = !forcejumps;
  ((Fl_Menu_Item*)v)->flags =
    forcejumps ? FL_MENU_TOGGLE|FL_MENU_VALUE : FL_MENU_TOGGLE;
  killnode(root->son); root->son = 0;
  if (showlegal) {expandnode(root); b->redraw();}
}

void move_cb(Fl_Widget*pb, void*) {
  Board* b = (Board*)pb;
  if (playing) b->computer_move(1);
  if (playing) b->computer_move(0);
}

void newgame_cb(Fl_Widget*b, void*) {
  showlegal = 0;
  newgame();
  b->redraw();
}

void legal_cb(Fl_Widget*pb, void*) {
  if (showlegal == 1) {showlegal = 0; ((Board*)pb)->redraw(); return;}
  if (!playing) return;
  expandnode(root);
  showlegal = 1; ((Board*)pb)->redraw();
}

void predict_cb(Fl_Widget*pb, void*) {
  if (showlegal == 2) {showlegal = 0; ((Board*)pb)->redraw(); return;}
  if (playing) expandnode(root);
  showlegal = 2; ((Board*)pb)->redraw();
}

void switch_cb(Fl_Widget*pb, void*) {
  user = !user;
  ((Board*)pb)->computer_move(0);
}

void undo_cb(Fl_Widget*pb, void*) {
  Board* b = (Board*)pb;
  b->animate(undomove(),1);
  b->animate(undomove(),1);
}

//--------------------------

#include <FL/Fl_Slider.H>
#include <FL/Fl_Value_Output.H>

Fl_Window *intel_window;
Fl_Value_Output *intel_output;

void intel_slider_cb(Fl_Widget*w, void*) {
  double v = ((Fl_Slider*)w)->value();
  int n = int(v*v);
  intel_output->value(n);
  maxevaluate = maxnodes = n;
}

void intel_cb(Fl_Widget*, void*) {
  if (!intel_window) {
    intel_window = new Fl_Window(200,25,"Checkers Intelligence");
    Fl_Slider* s = new Fl_Slider(60,0,140,25);
    s->type(FL_HOR_NICE_SLIDER);
    s->minimum(1); s->maximum(500); s->value(50);
    s->callback(intel_slider_cb);
    intel_output = new Fl_Value_Output(0,0,60,25);
    intel_output->value(maxevaluate);
    intel_window->resizable(s);
  }
  intel_window->hotspot(intel_window);
  intel_window->set_non_modal();
  intel_window->show();
}

//---------------------------

void stop_cb(Fl_Widget*, void*) {abortflag = 1;}

void continue_cb(Fl_Widget*, void*) {}

Fl_Menu_Item menu[] = {
  {"Autoplay", 'a', autoplay_cb},
  {"Legal moves", 'l', legal_cb},
  {"Move for me", 'm', move_cb},
  {"New game", 'n', newgame_cb},
  {"Predict", 'p', predict_cb},
  {"Switch sides", 's', switch_cb},
  {"Undo", 'u', undo_cb, 0, FL_MENU_DIVIDER},
  {"Forced jumps rule", 'f', forced_cb, 0, FL_MENU_TOGGLE|FL_MENU_VALUE},
  {"Debug", 'd', debug_cb, (void *)"d", FL_MENU_TOGGLE},
  {"Intelligence...", 'i', intel_cb, 0, FL_MENU_DIVIDER},
  {"Copyright", 'c', copyright_cb},
  {"Quit", 'q', quit_cb},
  {0}};

Fl_Menu_Item busymenu[] = {
  {"Stop", '.', stop_cb},
  {"Autoplay", 'a', autoplay_cb},
  {"Continue", 0, continue_cb},
  {"Debug", 'd', debug_cb, (void *)"d", FL_MENU_TOGGLE},
  {"Intelligence...", 'i', intel_cb},
  {"Copyright", 'c', copyright_cb},
  {"Quit", 'q', quit_cb},
  {0}};

#endif

////////////////////////////////////////////////////////////////
// parts shared by both interface:

#ifdef FLTK
#ifdef VT100
#define BOTH
#endif
#endif

#ifdef BOTH
int terminal;
int arg(int, char **argv, int &i) {
  if (argv[i][1] == 't') {terminal = 1; i++; return 1;}
  return 0;
}
#endif

int didabort(void) {
#ifdef FLTK
#ifdef BOTH
  if (!terminal)
#endif
    Fl::check();
#endif
  if (abortflag) {
    autoplay = 0;
    abortflag = 0;
    return 1;
  }
  return(0);
}

int main(int argc, char **argv) {
  seed = time(0);
  newgame();
#ifdef BOTH
  int i = 1;
  if (Fl::args(argc, argv, i, arg) < argc) {
    fprintf(stderr," -t : use VT100 display\n", Fl::help);
    exit(1);
  }
  if (!getenv("DISPLAY")) terminal = 1;
  if (!terminal)
#endif
#ifdef FLTK
    return FLTKmain(argc,argv);
#endif
#ifdef VT100
  return VT100main();
#endif
}

//
// End of "$Id: checkers.cxx,v 1.1.1.1 2003/06/03 22:25:47 agno Exp $".
//

⌨️ 快捷键说明

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