You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1372 lines
36KB

  1. //
  2. // "$Id: checkers.cxx 8168 2011-01-02 03:55:23Z matt $"
  3. //
  4. // Checkers game for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Hours of fun: the FLTK checkers game!
  7. // Based on a very old algorithm, but it still works!
  8. //
  9. // Copyright 1998-2010 by Bill Spitzak and others.
  10. //
  11. // This library is free software; you can redistribute it and/or
  12. // modify it under the terms of the GNU Library General Public
  13. // License as published by the Free Software Foundation; either
  14. // version 2 of the License, or (at your option) any later version.
  15. //
  16. // This library is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  19. // Library General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU Library General Public
  22. // License along with this library; if not, write to the Free Software
  23. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  24. // USA.
  25. //
  26. // Please report all bugs and problems on the following page:
  27. //
  28. // http://www.fltk.org/str.php
  29. //
  30. const char* copyright =
  31. "Checkers game\n"
  32. "Copyright (C) 1997-2010 Bill Spitzak spitzak@d2.com\n"
  33. "Original Pascal code:\n"
  34. "Copyright 1978, Oregon Minicomputer Software, Inc.\n"
  35. "2340 SW Canyon Road, Portland, Oregon 97201\n"
  36. "Written by Steve Poulsen 18-Jan-79\n"
  37. "\n"
  38. "This program is free software; you can redistribute it and/or modify "
  39. "it under the terms of the GNU General Public License as published by "
  40. "the Free Software Foundation; either version 2 of the License, or "
  41. "(at your option) any later version.\n"
  42. "\n"
  43. "This program is distributed in the hope that it will be useful, "
  44. "but WITHOUT ANY WARRANTY; without even the implied warranty of "
  45. "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
  46. "GNU General Public License for more details.\n"
  47. "\n"
  48. "You should have received a copy of the GNU Library General Public "
  49. "License along with this library; if not, write to the Free Software "
  50. "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 "
  51. "USA.";
  52. // Define FLTK to get the fltk interface
  53. // Define VT100 to get the VT100 interface
  54. // Define both to get a program that takes a -t switch
  55. #define FLTK
  56. //#define VT100
  57. #undef check
  58. #include <string.h>
  59. #include <stdlib.h>
  60. #include <stdio.h>
  61. #include <stdarg.h>
  62. #include <time.h>
  63. #ifdef VT100
  64. #include <ctype.h> // toupper
  65. #endif
  66. ////////////////////////////////////////////////////////////////
  67. // The algorithim:
  68. int maxevaluate=2500; // max number of moves to examine on a turn
  69. int maxnodes = 2500; // maximum number of nodes in search tree
  70. int maxply = 20; // maximum depth to look ahead
  71. char forcejumps = 1; // is forced jumps rule in effect?
  72. // scoring parameters: (all divided by 5 from original code)
  73. // some signs seem to be backwards, marked them with (-) in comment
  74. const int spiece = 800; // value of a piece
  75. const int sking = 1200; // value of a king
  76. const int sadvan = 160; // value of mypieces/theirpieces-1
  77. // const int smobil = ? // moves *enemy* can make w/o being jumped
  78. const int sallpin = 80; // mobil == 0
  79. const int sdeny = 10; // moves enemy can make that will be jumped
  80. const int spin = 32; // enemy pieces that have no move except jumped
  81. const int sthreat = -10; // enemy pieces we can jump if not moved (-)
  82. const int sgrad = 1; // score of piece positions
  83. const int sback = 10; // back row occupied so enemy can't make king
  84. const int smoc2 = 200; // more mobility, more center
  85. const int smoc3 = -8; // less mobility, less center
  86. const int smoc4 = -80; // more mobility, less center
  87. const int smode2 = -14; // less mobility, less denied
  88. const int smode3 = -40; // more mobility, more denied (-)
  89. const int sdemmo = -20; // more denied, more moves (-)
  90. const int scent = 10; // pieces in center
  91. const int skcent = 100; // kings in center
  92. const int depthpenalty=4; // guess
  93. const int noise=2; // values less or eq to this apart are eq
  94. // const int sattackking = 4; // not used
  95. // const int sattackpiece = 3;
  96. struct node {
  97. node *father;
  98. node *son; // best son
  99. node *brother; // next brother
  100. short int value; // value of this board position to player making move
  101. unsigned char from,to; // the move to reach this board
  102. long int jump; // bit map of locations jumped
  103. unsigned char mobil;
  104. unsigned char deny;
  105. unsigned char pin;
  106. unsigned char threat;
  107. short int gradient;
  108. unsigned who:1; // 0 = black's move, 1 = white's move
  109. unsigned king:1; // 1 = move causes piece to be kinged
  110. unsigned back:1;
  111. unsigned moc2:1;
  112. unsigned moc3:1;
  113. unsigned moc4:1;
  114. unsigned mode2:1;
  115. unsigned mode3:1;
  116. unsigned demmo:1;
  117. };
  118. int nodes; // count of nodes
  119. /* Board positions: Border positions:
  120. WHITE 00 01 02 03 04
  121. 05 06 07 08 04 XX XX XX XX
  122. 09 10 11 12 XX XX XX XX 13
  123. 14 15 16 17 13 XX XX XX XX
  124. 18 19 20 21 XX XX XX XX 22
  125. 23 24 25 26 22 XX XX XX XX
  126. 27 28 29 30 XX XX XX XX 31
  127. 32 33 34 36 31 XX XX XX XX
  128. 36 37 38 39 XX XX XX XX 40
  129. BLACK 40 41 42 43 44
  130. */
  131. typedef char piece;
  132. // Piece values so that BLACK and WHITE are bit flags:
  133. #define EMPTY 0
  134. #define BLACK 1
  135. #define WHITE 2
  136. #define KING 4
  137. #define BLACKKING 5
  138. #define WHITEKING 6
  139. #define BLUE 8
  140. const piece flip[9] = {
  141. EMPTY, WHITE, BLACK, 0, 0, WHITEKING, BLACKKING, 0, BLUE};
  142. const int offset[9][4] = { // legal move directions
  143. {0,0,0,0},
  144. {-5,-4,0,0},
  145. {4,5,0,0},
  146. {0,0,0,0},
  147. {0,0,0,0},
  148. {4,5,-4,-5},
  149. {4,5,-4,-5},
  150. {0,0,0,0},
  151. {0,0,0,0}
  152. };
  153. piece b[45]; // current board position being considered
  154. int evaluated; // number of moves evaluated this turn
  155. char centralsquares[45];
  156. char is_protected[45];
  157. piece flipboard[45]; // swapped if enemy is black
  158. piece *tb; // pointer to real or swapped board
  159. #define FRIEND BLACK
  160. #define FRIENDKING BLACKKING
  161. #define ENEMY WHITE
  162. #define ENEMYKING WHITEKING
  163. char check(int target,int direction) {
  164. // see if enemy at target can be jumped from direction by our piece
  165. int dst = target-direction;
  166. if (tb[dst]) return(0);
  167. int src = target+direction;
  168. if (tb[src] == FRIENDKING);
  169. else if (direction < 0 || tb[src] != FRIEND) return(0);
  170. piece aa = tb[target]; piece bb = tb[src];
  171. tb[target] = EMPTY; tb[src] = EMPTY;
  172. int safe =
  173. ( (tb[src-4]&FRIEND && tb[src-8]&ENEMY)
  174. || (tb[src-5]&FRIEND && tb[src-10]&ENEMY)
  175. || (tb[dst-4]&ENEMY && !tb[dst+4])
  176. || (tb[dst-5]&ENEMY && !tb[dst+5])
  177. || (tb[src+4]&FRIEND && tb[src+8]==ENEMYKING)
  178. || (tb[src+5]&FRIEND && tb[src+10]==ENEMYKING)
  179. || (tb[dst+4]==ENEMYKING && !tb[dst-4])
  180. || (tb[dst+5]==ENEMYKING && !tb[dst-5]));
  181. tb[target] = aa; tb[src] = bb;
  182. return(safe);
  183. }
  184. int deniedmoves,undeniedmoves;
  185. void analyzemove(int direction,int src) {
  186. int target = src+direction;
  187. if (!tb[target]) {
  188. if (!tb[target+direction]) is_protected[target] = 1;
  189. piece a = tb[src]; tb[src] = EMPTY;
  190. if (check(target,4) || check(target,5) ||
  191. check(target,-4) || check(target,-5) ||
  192. (tb[src+4]&ENEMY && check(src+4,4)) ||
  193. (tb[src+5]&ENEMY && check(src+5,5)) ||
  194. (tb[src-4]&ENEMY && check(src-4,-4)) ||
  195. (tb[src-5]&ENEMY && check(src-5,-5)))
  196. deniedmoves++;
  197. else undeniedmoves++;
  198. tb[src] = a;
  199. }
  200. }
  201. void evaluateboard(node *n,int print) {
  202. if (!n->who) tb = b; // move was black's
  203. else {
  204. for (int i=0; i<45; i++) flipboard[44-i] = flip[(int)b[i]];
  205. tb = flipboard;
  206. }
  207. memset(is_protected,0,sizeof(is_protected));
  208. int friendpieces = 0;
  209. int enemypieces = 0;
  210. int friendkings = 0;
  211. int enemykings = 0;
  212. int friendkcent = 0;
  213. int friendcent = 0;
  214. int enemykcent = 0;
  215. int enemycent = 0;
  216. n->mobil = n->deny = n->pin = n->threat = 0;
  217. int i;
  218. for (i=5; i<40; i++) switch(tb[i]) {
  219. case ENEMYKING:
  220. enemykings++;
  221. enemykcent += centralsquares[i];
  222. deniedmoves = 0;
  223. undeniedmoves = 0;
  224. if (i>8) {
  225. analyzemove(-4,i);
  226. analyzemove(-5,i);
  227. }
  228. goto J1;
  229. case ENEMY:
  230. deniedmoves = 0;
  231. undeniedmoves = 0;
  232. J1: enemypieces++;
  233. enemycent += centralsquares[i];
  234. if (i<36) {
  235. analyzemove(4,i);
  236. analyzemove(5,i);
  237. }
  238. if (deniedmoves && !undeniedmoves) n->pin++;
  239. n->deny += deniedmoves;
  240. n->mobil += undeniedmoves;
  241. break;
  242. case FRIENDKING:
  243. friendkings++;
  244. friendkcent += centralsquares[i];
  245. if (tb[i+4]&ENEMY && !tb[i+8] && !(tb[i+4]==ENEMYKING && !tb[i-4]))
  246. n->threat++;
  247. if (tb[i+5]&ENEMY && !tb[i+10] && !(tb[i+5]==ENEMYKING && !tb[i-5]))
  248. n->threat++;
  249. case FRIEND:
  250. friendpieces++;
  251. friendcent += centralsquares[i];
  252. if (tb[i-4]&ENEMY && !tb[i-8] && tb[i+4]) n->threat++;
  253. if (tb[i-5]&ENEMY && !tb[i-10] && tb[i+5]) n->threat++;
  254. break;
  255. }
  256. int gradient[40];
  257. for (i=4; i<9; i++) gradient[i] = tb[i] ? 0 : 32;
  258. int total = 0;
  259. for (i=9; i<40; i++) {
  260. int x = (gradient[i-4]+gradient[i-5])/2;
  261. if (tb[i]==FRIEND) total += x;
  262. gradient[i] = (tb[i]&FRIEND || (!tb[i] && !is_protected[i])) ? x : 0;
  263. }
  264. n->gradient = total;
  265. n->back = tb[39]==FRIEND && tb[37]==FRIEND && !enemykings;
  266. node* f = n->father;
  267. n->moc2 = f->mobil>n->mobil && friendcent>enemycent;
  268. n->moc3 = f->mobil<=n->mobil && friendcent<enemycent;
  269. n->moc4 = f->mobil>n->mobil && friendcent<enemycent;
  270. n->mode2 = f->mobil<=n->mobil && n->deny<f->deny;
  271. n->mode3 = f->mobil>n->mobil && n->deny>f->deny;
  272. n->demmo = n->deny>f->deny && f->deny+f->mobil>n->deny+n->mobil;
  273. total =
  274. spiece * (friendpieces - enemypieces) +
  275. (sking-spiece) * (friendkings - enemykings) +
  276. // mobil?
  277. sdeny * (n->deny - f->deny) +
  278. spin * (n->pin - f->pin) +
  279. sthreat * (n->threat - f->threat) +
  280. sgrad * (n->gradient - f->gradient) +
  281. sback * (n->back - f->back) +
  282. smoc2 * (n->moc2 - f->moc2) +
  283. smoc3 * (n->moc3 - f->moc3) +
  284. smoc4 * (n->moc4 - f->moc4) +
  285. smode2 * (n->mode2 - f->mode2) +
  286. smode3 * (n->mode3 - f->mode3) +
  287. sdemmo * (n->demmo - f->demmo) +
  288. scent * (friendcent - enemycent) +
  289. (skcent-scent) * (friendkcent - enemykcent);
  290. if (!n->mobil) total += sallpin;
  291. if (!enemypieces) total = 30000;
  292. else if (friendpieces > enemypieces)
  293. total += (sadvan*friendpieces)/enemypieces-sadvan;
  294. else total -= (sadvan*enemypieces)/friendpieces-sadvan;
  295. if (print) {
  296. printf("\tParent\tNew\tScore\n");
  297. printf("pieces\t%d\t%d\t%d\n",enemypieces,friendpieces,
  298. spiece*(friendpieces-enemypieces));
  299. printf("kings\t%d\t%d\t%d\n",enemykings,friendkings,
  300. (sking-spiece)*(friendkings-enemykings));
  301. printf("mobil\t%d\t%d\n",f->mobil,n->mobil);
  302. printf("deny\t%d\t%d\t%d\n",f->deny,n->deny,sdeny*(n->deny-f->deny));
  303. printf("pin\t%d\t%d\t%d\n",f->pin,n->pin,spin*(n->pin-f->pin));
  304. printf("threat\t%d\t%d\t%d\n",f->threat,n->threat,sthreat*(n->threat-f->threat));
  305. printf("grad\t%d\t%d\t%d\n",f->gradient,n->gradient,sgrad*(n->gradient-f->gradient));
  306. printf("back\t%d\t%d\t%d\n",f->back,n->back,sback*(n->back-f->back));
  307. printf("moc2\t%d\t%d\t%d\n",f->moc2,n->moc2,smoc2*(n->moc2-f->moc2));
  308. printf("moc3\t%d\t%d\t%d\n",f->moc3,n->moc3,smoc3*(n->moc3-f->moc3));
  309. printf("moc4\t%d\t%d\t%d\n",f->moc4,n->moc4,smoc4*(n->moc4-f->moc4));
  310. printf("mode2\t%d\t%d\t%d\n",f->mode2,n->mode2,smode2*(n->mode2-f->mode2));
  311. printf("mode3\t%d\t%d\t%d\n",f->mode3,n->mode3,smode3*(n->mode3-f->mode3));
  312. printf("demmo\t%d\t%d\t%d\n",f->demmo,n->demmo,sdemmo*(n->demmo-f->demmo));
  313. printf("cent\t%d\t%d\t%dn",enemycent,friendcent,scent*(friendcent-enemycent));
  314. printf("kcent\t%d\t%d\t%d\n",enemykcent,friendkcent,skcent*(friendkcent-enemykcent));
  315. printf("total:\t\t\t%d\n",total);
  316. }
  317. else {
  318. n->value = total;
  319. evaluated++;
  320. }
  321. } // end of evaluateboard
  322. // --------------------- Tree management -----------------
  323. node *freelist;
  324. node *newnode(void) {
  325. node *n;
  326. if (freelist) {
  327. n = freelist;
  328. freelist = n->brother;
  329. }
  330. else n = (node *)malloc(sizeof(node));
  331. memset(n,0,sizeof(node));
  332. nodes++;
  333. return(n);
  334. }
  335. void extract(node *n) {
  336. node* i = n->father;
  337. if (i) {
  338. node* j = i->son;
  339. if (j==n) i->son = n->brother;
  340. else while (j) {
  341. i = j; j = j->brother;
  342. if (j==n) {i->brother = n->brother; break;}
  343. }
  344. }
  345. n->brother = 0;
  346. }
  347. void killnode(node *x) {
  348. if (!x) return;
  349. node *y;
  350. for (y = x; ; y = y->brother) {
  351. nodes--;
  352. killnode(y->son); y->son = 0;
  353. if (!y->brother) break;
  354. }
  355. y->brother = freelist;
  356. freelist = x;
  357. }
  358. int seed; // current random number
  359. void insert(node *n) {
  360. int val = n->value;
  361. node **pp;
  362. for (pp = &(n->father->son); *pp; pp = &((*pp)->brother)) {
  363. int val1 = (*pp)->value;
  364. if (abs(val-val1) <= noise) {
  365. seed = (seed*13077+5051)%0100000;
  366. if ((seed & 070) >= 060) break;
  367. }
  368. else if (val > val1) break;
  369. }
  370. n->brother = *pp;
  371. *pp = n;
  372. }
  373. // --------------------------------------------------------------
  374. void movepiece(node* f, int i, node* jnode) {
  375. static char jumphappened;
  376. for (int k=0; k<4; k++) {
  377. int direction = offset[(int)b[i]][k];
  378. if (!direction) break;
  379. int j = i+direction;
  380. if (b[j] == EMPTY) {
  381. if (!jnode && (!forcejumps || !f->son || !f->son->jump)) {
  382. node* n = newnode();
  383. n->father = f;
  384. n->who = !f->who;
  385. n->from = i;
  386. n->to = j;
  387. piece oldpiece = b[i]; b[i] = EMPTY;
  388. if (!(oldpiece&KING) && n->who ? (j>=36) : (j<=8)) {
  389. n->king = 1;
  390. b[j] = oldpiece|KING;
  391. }
  392. else b[j] = oldpiece;
  393. evaluateboard(n,0);
  394. insert(n);
  395. b[i] = oldpiece; b[j] = EMPTY;
  396. }
  397. } else if (((b[j]^b[i])&(WHITE|BLACK))==(WHITE|BLACK) && !b[j+direction]) {
  398. if (forcejumps && f->son && !f->son->jump) {
  399. killnode(f->son);
  400. f->son = 0;
  401. }
  402. int jumploc = j;
  403. j += direction;
  404. node* n = newnode();
  405. n->father = f;
  406. n->who = !f->who;
  407. n->from = i;
  408. n->to = j;
  409. n->jump = (1<<(jumploc-10));
  410. piece oldpiece = b[i]; b[i] = EMPTY;
  411. if (!(oldpiece&KING) && n->who ? (j>=36) : (j<=8)) {
  412. n->king = 1;
  413. b[j] = oldpiece|KING;
  414. }
  415. else b[j] = oldpiece;
  416. if (jnode) {
  417. n->from = jnode->from;
  418. n->jump |= jnode->jump;
  419. n->king |= jnode->king;
  420. }
  421. piece jumpedpiece = b[jumploc];
  422. b[jumploc] = EMPTY;
  423. jumphappened = 0;
  424. movepiece(f,j,n);
  425. if (forcejumps && jumphappened) killnode(n);
  426. else {evaluateboard(n,0); insert(n);}
  427. b[i] = oldpiece; b[j] = EMPTY;
  428. b[jumploc] = jumpedpiece;
  429. jumphappened = 1;
  430. }
  431. }
  432. }
  433. void expandnode(node *f) {
  434. if (f->son || f->value > 28000) return; // already done
  435. piece turn = f->who ? BLACK : WHITE;
  436. for (int i=5; i<40; i++) if (b[i]&turn) movepiece(f,i,0);
  437. if (f->son) {
  438. f->value = -f->son->value;
  439. if (f->brother) f->value -= depthpenalty;
  440. }
  441. else f->value = 30000;
  442. }
  443. void makemove(node *n) {
  444. b[n->to] = b[n->from];
  445. if (n->king) b[n->to] |= KING;
  446. b[n->from] = EMPTY;
  447. if (n->jump) for(int i=0; i<32; i++) {
  448. if (n->jump & (1<<i)) b[10+i] = EMPTY;
  449. }
  450. }
  451. int didabort(void);
  452. int fullexpand(node *f, int level) {
  453. if (didabort() || nodes > maxnodes-(maxply*10) || evaluated > maxevaluate) return(0);
  454. expandnode(f);
  455. if (!f->son) return(1);
  456. piece oldboard[45];
  457. memmove(oldboard,b,sizeof(b));
  458. node* n = f->son;
  459. if (!n->jump && n->brother) {if (level<1) return(1); level--;}
  460. int i;
  461. node* sons[32]; for (i=0; (sons[i++] = n); n = n->brother);
  462. int ret = 1;
  463. for (i=0; ret && (n = sons[i++]);) {
  464. makemove(n);
  465. ret = fullexpand(n,level);
  466. memmove(b,oldboard,sizeof(b));
  467. extract(n);
  468. insert(n);
  469. }
  470. f->value = -f->son->value;
  471. return(ret);
  472. }
  473. int descend(node *f) {
  474. static int depth;
  475. if (didabort() || nodes > maxnodes || depth >= maxply) return(0);
  476. if (f->son) {
  477. node* n = f->son;
  478. makemove(n);
  479. depth++;
  480. int ret = descend(n);
  481. depth--;
  482. extract(n);
  483. insert(n);
  484. f->value = -f->son->value;
  485. return(ret);
  486. }
  487. else {expandnode(f); return(1);}
  488. }
  489. char debug;
  490. node *calcmove(node *root) { // return best move after root
  491. expandnode(root);
  492. if (!root->son) return(0); // no move due to loss
  493. if (debug) printf("calcmove() initial nodes = %d\n",nodes);
  494. evaluated = 0;
  495. if (root->son->brother) {
  496. int x;
  497. for (x = 1; abs(root->value)<28000 && fullexpand(root,x); x++);
  498. piece saveboard[45]; memmove(saveboard,b,sizeof(b));
  499. while (abs(root->value)<28000) {
  500. x = descend(root);
  501. memmove(b,saveboard,sizeof(b));
  502. if (!x) break;
  503. }
  504. }
  505. if (debug) printf(" evaluated %d, nodes = %d\n", evaluated, nodes);
  506. return(root->son);
  507. }
  508. // the actual game state ----------------
  509. node *root,*undoroot;
  510. piece jumpboards[24][45]; // saved boards for undoing jumps
  511. int nextjump;
  512. char user; // 0 = black, 1 = white
  513. char playing;
  514. char autoplay;
  515. void newgame(void) {
  516. int n;
  517. for (n=0; n<5; n++) b[n] = BLUE;
  518. for (n=5; n<18; n++) b[n] = WHITE;
  519. for (n=18; n<27; n++) b[n] = EMPTY;
  520. for (n=27; n<40; n++) b[n] = BLACK;
  521. for (n=40; n<45; n++) b[n] = BLUE;
  522. b[13] = b[22] = b[31] = BLUE;
  523. centralsquares[15] = centralsquares[16] =
  524. centralsquares[19] = centralsquares[20] =
  525. centralsquares[24] = centralsquares[25] =
  526. centralsquares[28] = centralsquares[29] = 1;
  527. // set up initial search tree:
  528. nextjump = 0;
  529. killnode(undoroot);
  530. undoroot = root = newnode();
  531. // make it white's move, so first move is black:
  532. root->who = 1;
  533. user = 0;
  534. playing = 1;
  535. }
  536. void domove(node* move) {
  537. if (move->jump) memmove(jumpboards[nextjump++],b,sizeof(b));
  538. makemove(move);
  539. extract(move);
  540. killnode(root->son);
  541. root->son = move;
  542. root = move;
  543. if (debug) evaluateboard(move,1);
  544. }
  545. node* undomove() {
  546. node *n = root;
  547. if (n == undoroot) return 0; // no more undo possible
  548. if (n->jump) memmove(b,jumpboards[--nextjump],sizeof(b));
  549. else {
  550. b[n->from] = b[n->to];
  551. if (n->king) b[n->from] &= (WHITE|BLACK);
  552. b[n->to] = EMPTY;
  553. }
  554. root = n->father;
  555. killnode(n);
  556. root->son = 0;
  557. root->value = 0; // prevent it from thinking game is over
  558. playing = 1;
  559. if (root == undoroot) user = 0;
  560. return n;
  561. }
  562. const char _usermoves[] =
  563. "B1D1F1H1A2C2E2G2??B3D3F3H3A4C4E4G4??B5D5F5H5A6C6E6G6??B7D7F7H7A8C8E8G8??";
  564. #define usermoves(x,y) _usermoves[2*((x)-5)+(y)-1]
  565. void dumpnode(node *n, int help) {
  566. int x = n->from;
  567. int y = n->to;
  568. if (help) printf("%c%c %c%c\t- ",
  569. usermoves(x,1),usermoves(x,2),
  570. usermoves(y,1),usermoves(y,2));
  571. printf("%s %ss from %c%c to %c%c",
  572. n->who ? "White" : "Black",
  573. n->jump ? "jump" : "move",
  574. usermoves(x,1),usermoves(x,2),
  575. usermoves(y,1),usermoves(y,2));
  576. if (n->jump) {
  577. for (int i=0; i<32; i++) if (n->jump & (1<<i))
  578. printf(", %c%c",usermoves(10+i,1),usermoves(10+i,2));
  579. printf(" removed");
  580. }
  581. printf(" (%+d).\n",n->value);
  582. }
  583. int abortflag;
  584. ////////////////////////////////////////////////////////////////
  585. // VT100 Interface:
  586. #ifdef VT100
  587. void positioncursor(int i) {
  588. printf("\033[%d;%dH",
  589. usermoves(i,2)-'0'+1,
  590. 2*(usermoves(i,1)-'A')+1);
  591. }
  592. void outpiecename(piece n) {
  593. printf(n&BLACK ? "\033[1;7m" : "\033[1m");
  594. putchar(" BW??BW??"[n]);
  595. putchar(" BW??KK??"[n]);
  596. printf("\033[0m");
  597. }
  598. void VT100board(void) {
  599. printf("\033<\033[H\033[J\033[10r");
  600. int l = 0;
  601. puts(" A B C D E F G H");
  602. for (int i=0; i<4; i++) {
  603. int j = 9*i+5;
  604. int k;
  605. for (k=0; k<4; k++) {
  606. printf("\033[7m \033[0m");
  607. outpiecename(b[j+k]);
  608. }
  609. l++;
  610. printf("%d\n",l);
  611. j += 4;
  612. for (k=0; k<4; k++) {
  613. outpiecename(b[j+k]);
  614. printf("\033[7m \033[0m");
  615. }
  616. l++;
  617. printf("%d\n",l);
  618. }
  619. }
  620. void VT100move(node *n, int) {
  621. if (!n) return;
  622. printf("\0337");
  623. positioncursor(n->from);
  624. outpiecename(b[n->from]);
  625. positioncursor(n->to);
  626. outpiecename(b[n->to]);
  627. if (n->jump) for(int i=0; i<32; i++) {
  628. if (n->jump & (1<<i)) {
  629. positioncursor(10+i);
  630. outpiecename(b[10+i]);
  631. }
  632. }
  633. printf("\0338");
  634. }
  635. int decode(char *m) {
  636. int i;
  637. for(i=5; i<=40; i++)
  638. if (toupper(m[0])==usermoves(i,1) && m[1]==usermoves(i,2)) return(i);
  639. return(0);
  640. }
  641. #include <signal.h>
  642. static void sigint(...) {
  643. abortflag = 1;
  644. signal(SIGINT,sigint);
  645. }
  646. void fixexit(int x) {
  647. printf("\0337\033[r\0338");
  648. exit(x);
  649. }
  650. // Returns a son, or 0 if no move specified, or root to cause "help"
  651. node *getusermove(void) {
  652. int i,j;
  653. node *t;
  654. char line[100],*m1,*m2;
  655. if (playing)
  656. printf("\033[1m%s's move?\033[0m ",root->who ? "Black" : "White");
  657. else
  658. printf("\033[1mCommand?\033[0m ");
  659. abortflag = 0;
  660. if (!fgets(line, sizeof(line), stdin)) {
  661. putchar('\n');
  662. if (feof(stdin)) fixexit(0);
  663. return 0;
  664. }
  665. for (m1 = line; *m1 && *m1<=' '; m1++);
  666. if (!*m1) return(0);
  667. m2 = m1+1;
  668. if (*m2) m2++;
  669. for (; *m2 && *m2<'0'; m2++);
  670. if (playing && m1[1]>='0' && m1[1]<='9') {
  671. i = decode(m1);
  672. j = decode(m2);
  673. if (i && j) for (t = root->son; t; t = t->brother)
  674. if (t->from == i && t->to == j) return(t);
  675. puts("Valid moves are:");
  676. m1[0] = 'L';
  677. }
  678. switch(toupper(m1[0])) {
  679. case 0: return(0);
  680. case 'A':
  681. if (playing) autoplay = 1;
  682. return(root);
  683. case 'C':
  684. puts(copyright);
  685. break;
  686. case 'D':
  687. debug = !debug;
  688. printf("Debug is now %s.", debug ? "on" : "off");
  689. break;
  690. case 'F':
  691. forcejumps = !forcejumps;
  692. printf("Forced jumps rule is now %s.",forcejumps ? "on" : "off");
  693. killnode(root->son); root->son = 0;
  694. return(0);
  695. case 'L':
  696. expandnode(root);
  697. if (playing) for (t = root->son; t; t = t->brother) dumpnode(t,1);
  698. break;
  699. case 'M':
  700. return(playing ? root : 0);
  701. case 'N':
  702. newgame();
  703. VT100board();
  704. return(0);
  705. case 'P':
  706. printf("I expect the following moves:\n");
  707. for (t = root->son; t; t = t->son) dumpnode(t,0);
  708. break;
  709. case 'Q':
  710. fixexit(0);
  711. case 'R':
  712. VT100board();
  713. break;
  714. case 'S':
  715. user = !user;
  716. return(root);
  717. case 'U':
  718. VT100move(undomove(),1);
  719. VT100move(undomove(),1);
  720. return(0);
  721. case '+':
  722. maxevaluate = maxnodes = 2*maxevaluate;
  723. goto J2;
  724. case '-':
  725. if (maxevaluate > 1)
  726. maxevaluate = maxnodes = maxevaluate/2;
  727. J2: printf("Moves evaluated set to %d.",maxevaluate);
  728. break;
  729. default:
  730. puts(
  731. "A(utoplay)\n"
  732. "C(opyright)\n"
  733. "D(ebug on/off)\n"
  734. "F(orce jumps rule on/off)\n"
  735. "L(ist legal moves)\n"
  736. "M(ake a move for me)\n"
  737. "N(ew game)\n"
  738. "P(redict next few moves)\n"
  739. "Q(uit)\n"
  740. "R(edraw screen)\n"
  741. "S(witch sides)\n"
  742. "U(ndo)\n"
  743. "+ - smarter\n"
  744. "- - stupider");
  745. expandnode(root);
  746. for (t = root->son; t; t = t->brother) dumpnode(t,1);
  747. }
  748. return(0);
  749. }
  750. int VT100main() {
  751. signal(SIGINT,sigint);
  752. VT100board();
  753. for (;;) {
  754. if (playing) {
  755. expandnode(root);
  756. if (!root->son) {
  757. printf("%s has no move. Game over.",root->who ? "Black" : "White");
  758. playing = autoplay = 0;
  759. }
  760. }
  761. node* move;
  762. if (playing && (autoplay || root->who == user)) {
  763. move = calcmove(root);
  764. if (move->value <= -30000) {
  765. printf("%s resigns.", move->who ? "White" : "Black");
  766. move = 0;
  767. playing = autoplay = 0;
  768. }
  769. } else {
  770. move = getusermove();
  771. if (move == root) move = calcmove(root);
  772. }
  773. if (move) {
  774. dumpnode(move,0);
  775. domove(move);
  776. VT100move(move,0);
  777. }
  778. }
  779. }
  780. #endif
  781. ////////////////////////////////////////////////////////////////
  782. // fltk interface:
  783. #ifdef FLTK
  784. #include <FL/Fl.H>
  785. #include <FL/Fl_Double_Window.H>
  786. #include <FL/Fl_Bitmap.H>
  787. #include <FL/fl_draw.H>
  788. #include <FL/Fl_Menu_Item.H>
  789. #include <FL/fl_ask.H>
  790. //----------------------------------------------------------------
  791. // old 4-level NeXT images have been seperated into bitmaps so they
  792. // can be drawn with arbitrary colors and real transparency. This is
  793. // rather tedious and perhaps fltk should provide a direct support
  794. // to do this:
  795. #include "pixmaps/black_1.xbm"
  796. #include "pixmaps/black_2.xbm"
  797. #include "pixmaps/black_3.xbm"
  798. #include "pixmaps/black_4.xbm"
  799. #include "pixmaps/white_1.xbm"
  800. #include "pixmaps/white_2.xbm"
  801. #include "pixmaps/white_3.xbm"
  802. #include "pixmaps/white_4.xbm"
  803. #include "pixmaps/blackking_1.xbm"
  804. #include "pixmaps/blackking_2.xbm"
  805. #include "pixmaps/blackking_3.xbm"
  806. #include "pixmaps/blackking_4.xbm"
  807. #include "pixmaps/whiteking_1.xbm"
  808. #include "pixmaps/whiteking_2.xbm"
  809. #include "pixmaps/whiteking_3.xbm"
  810. #include "pixmaps/whiteking_4.xbm"
  811. Fl_Bitmap *bm[4][4];
  812. void make_bitmaps() {
  813. if (bm[0][0]) return;
  814. bm[0][0] = new Fl_Bitmap(black_1_bits, black_1_width, black_1_height);
  815. bm[0][1] = new Fl_Bitmap(black_2_bits, black_1_width, black_1_height);
  816. bm[0][2] = new Fl_Bitmap(black_3_bits, black_1_width, black_1_height);
  817. bm[0][3] = new Fl_Bitmap(black_4_bits, black_1_width, black_1_height);
  818. bm[1][0] = new Fl_Bitmap(white_1_bits, black_1_width, black_1_height);
  819. bm[1][1] = new Fl_Bitmap(white_2_bits, black_1_width, black_1_height);
  820. bm[1][2] = new Fl_Bitmap(white_3_bits, black_1_width, black_1_height);
  821. bm[1][3] = new Fl_Bitmap(white_4_bits, black_1_width, black_1_height);
  822. bm[2][0] = new Fl_Bitmap(blackking_1_bits, black_1_width, black_1_height);
  823. bm[2][1] = new Fl_Bitmap(blackking_2_bits, black_1_width, black_1_height);
  824. bm[2][2] = new Fl_Bitmap(blackking_3_bits, black_1_width, black_1_height);
  825. bm[2][3] = new Fl_Bitmap(blackking_4_bits, black_1_width, black_1_height);
  826. bm[3][0] = new Fl_Bitmap(whiteking_1_bits, black_1_width, black_1_height);
  827. bm[3][1] = new Fl_Bitmap(whiteking_2_bits, black_1_width, black_1_height);
  828. bm[3][2] = new Fl_Bitmap(whiteking_3_bits, black_1_width, black_1_height);
  829. bm[3][3] = new Fl_Bitmap(whiteking_4_bits, black_1_width, black_1_height);
  830. }
  831. #define ISIZE black_1_width
  832. void draw_piece(int which, int x, int y) {
  833. if (!fl_not_clipped(x,y,ISIZE,ISIZE)) return;
  834. switch (which) {
  835. case BLACK: which = 0; break;
  836. case WHITE: which = 1; break;
  837. case BLACKKING: which = 2; break;
  838. case WHITEKING: which = 3; break;
  839. default: return;
  840. }
  841. fl_color(FL_BLACK); bm[which][0]->draw(x, y);
  842. fl_color(FL_INACTIVE_COLOR); bm[which][1]->draw(x, y);
  843. fl_color(FL_SELECTION_COLOR); bm[which][2]->draw(x, y);
  844. fl_color(FL_WHITE); bm[which][3]->draw(x, y);
  845. }
  846. //----------------------------------------------------------------
  847. class Board : public Fl_Double_Window {
  848. void draw();
  849. int handle(int);
  850. public:
  851. void drag_piece(int, int, int);
  852. void drop_piece(int);
  853. void animate(node* move, int backwards);
  854. void computer_move(int);
  855. Board(int w, int h) : Fl_Double_Window(w,h) {color(15);}
  856. };
  857. #define BOXSIZE 52
  858. #define BORDER 4
  859. #define BOARDSIZE (8*BOXSIZE+BORDER)
  860. #define BMOFFSET 5
  861. static int erase_this; // real location of dragging piece, don't draw it
  862. static int dragging; // piece being dragged
  863. static int dragx; // where it is
  864. static int dragy;
  865. static int showlegal; // show legal moves
  866. int squarex(int i) {return (usermoves(i,1)-'A')*BOXSIZE+BMOFFSET;}
  867. int squarey(int i) {return (usermoves(i,2)-'1')*BOXSIZE+BMOFFSET;}
  868. void Board::draw() {
  869. make_bitmaps();
  870. // -- draw the board itself
  871. fl_draw_box(box(),0,0,w(),h(),color());
  872. // -- draw all dark tiles
  873. fl_color((Fl_Color)10 /*107*/);
  874. int x; for (x=0; x<8; x++) for (int y=0; y<8; y++) {
  875. if (!((x^y)&1)) fl_rectf(BORDER+x*BOXSIZE, BORDER+y*BOXSIZE,
  876. BOXSIZE-BORDER, BOXSIZE-BORDER);
  877. }
  878. // -- draw outlines around the fileds
  879. fl_color(FL_DARK3);
  880. for (x=0; x<9; x++) {
  881. fl_rectf(x*BOXSIZE,0,BORDER,h());
  882. fl_rectf(0,x*BOXSIZE,w(),BORDER);
  883. }
  884. for (int j = 5; j < 40; j++) if (j != erase_this) {
  885. draw_piece(b[j], squarex(j), squarey(j));
  886. }
  887. if (showlegal) {
  888. fl_color(FL_WHITE);
  889. node* n;
  890. for (n = root->son; n; n = showlegal==2 ? n->son : n->brother) {
  891. int x1 = squarex(n->from)+BOXSIZE/2-5;
  892. int y1 = squarey(n->from)+BOXSIZE/2-5;
  893. int x2 = squarex(n->to)+BOXSIZE/2-5;
  894. int y2 = squarey(n->to)+BOXSIZE/2-5;
  895. fl_line(x1,y1,x2,y2);
  896. fl_push_matrix();
  897. fl_mult_matrix(x2-x1,y2-y1,y1-y2,x2-x1,x2,y2);
  898. fl_begin_polygon();
  899. fl_vertex(0,0);
  900. fl_vertex(-.3, .1);
  901. fl_vertex(-.3, -.1);
  902. fl_end_polygon();
  903. fl_pop_matrix();
  904. }
  905. int num = 1;
  906. fl_color(FL_BLACK);
  907. fl_font(FL_BOLD,10);
  908. for (n = root->son; n; n = showlegal==2 ? n->son : n->brother) {
  909. int x1 = squarex(n->from)+BOXSIZE/2-5;
  910. int y1 = squarey(n->from)+BOXSIZE/2-5;
  911. int x2 = squarex(n->to)+BOXSIZE/2-5;
  912. int y2 = squarey(n->to)+BOXSIZE/2-5;
  913. char buf[20]; sprintf(buf,"%d",num);
  914. fl_draw(buf, x1+int((x2-x1)*.85)-3, y1+int((y2-y1)*.85)+5);
  915. num++;
  916. }
  917. }
  918. if (dragging) draw_piece(dragging, dragx, dragy);
  919. }
  920. // drag the piece on square i to dx dy, or undo drag if i is zero:
  921. void Board::drag_piece(int j, int dx, int dy) {
  922. dy = (dy&-2) | (dx&1); // make halftone shadows line up
  923. if (j != erase_this) drop_piece(erase_this); // should not happen
  924. if (!erase_this) { // pick up old piece
  925. dragx = squarex(j); dragy = squarey(j);
  926. erase_this = j;
  927. dragging = b[j];
  928. }
  929. if (dx != dragx || dy != dragy) {
  930. damage(FL_DAMAGE_ALL, dragx, dragy, ISIZE, ISIZE);
  931. damage(FL_DAMAGE_ALL, dx, dy, ISIZE, ISIZE);
  932. }
  933. dragx = dx;
  934. dragy = dy;
  935. }
  936. // drop currently dragged piece on square i
  937. void Board::drop_piece(int j) {
  938. if (!erase_this) return; // should not happen!
  939. erase_this = 0;
  940. dragging = 0;
  941. int x = squarex(j);
  942. int y = squarey(j);
  943. if (x != dragx || y != dragy) {
  944. damage(4, dragx, dragy, ISIZE, ISIZE);
  945. damage(4, x, y, ISIZE, ISIZE);
  946. }
  947. }
  948. // show move (call this *before* the move, *after* undo):
  949. void Board::animate(node* move, int backwards) {
  950. if (showlegal) {showlegal = 0; redraw();}
  951. if (!move) return;
  952. int f = move->from;
  953. int t = move->to;
  954. if (backwards) {int x = f; f = t; t = x;}
  955. int x1 = squarex(f);
  956. int y1 = squarey(f);
  957. int x2 = squarex(t);
  958. int y2 = squarey(t);
  959. const int STEPS=35;
  960. for (int j=0; j<STEPS; j++) {
  961. int x = x1+(x2-x1)*j/STEPS;
  962. int y = y1+(y2-y1)*j/STEPS;
  963. drag_piece(move->from,x,y);
  964. Fl::flush();
  965. }
  966. drop_piece(t);
  967. if (move->jump) redraw();
  968. }
  969. int busy; // causes pop-up abort menu
  970. void Board::computer_move(int help) {
  971. if (!playing) return;
  972. cursor(FL_CURSOR_WAIT);
  973. Fl::flush();
  974. busy = 1; abortflag = 0;
  975. node* move = calcmove(root);
  976. busy = 0;
  977. if (move) {
  978. if (!help && move->value <= -30000) {
  979. fl_message("%s resigns", move->who ? "White" : "Black");
  980. playing = autoplay = 0;
  981. cursor(FL_CURSOR_DEFAULT);
  982. return;
  983. }
  984. animate(move,0);
  985. domove(move);
  986. }
  987. expandnode(root);
  988. if (!root->son) {
  989. fl_message("%s has no move", root->who ? "Black" : "White");
  990. playing = autoplay = 0;
  991. }
  992. if (!autoplay) cursor(FL_CURSOR_DEFAULT);
  993. }
  994. extern Fl_Menu_Item menu[];
  995. extern Fl_Menu_Item busymenu[];
  996. int Board::handle(int e) {
  997. if (busy) {
  998. const Fl_Menu_Item* m;
  999. switch(e) {
  1000. case FL_PUSH:
  1001. m = busymenu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
  1002. if (m) m->do_callback(this, (void*)m);
  1003. return 1;
  1004. case FL_SHORTCUT:
  1005. m = busymenu->test_shortcut();
  1006. if (m) {m->do_callback(this, (void*)m); return 1;}
  1007. return 0;
  1008. default:
  1009. return 0;
  1010. }
  1011. }
  1012. node *t, *n;
  1013. static int deltax, deltay;
  1014. int dist;
  1015. const Fl_Menu_Item* m;
  1016. switch (e) {
  1017. case FL_PUSH:
  1018. if (Fl::event_button() > 1) {
  1019. m = menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0);
  1020. if (m) m->do_callback(this, (void*)m);
  1021. return 1;
  1022. }
  1023. if (playing) {
  1024. expandnode(root);
  1025. for (t = root->son; t; t = t->brother) {
  1026. int x = squarex(t->from);
  1027. int y = squarey(t->from);
  1028. if (Fl::event_inside(x,y,BOXSIZE,BOXSIZE)) {
  1029. deltax = Fl::event_x()-x;
  1030. deltay = Fl::event_y()-y;
  1031. drag_piece(t->from,x,y);
  1032. return 1;
  1033. }
  1034. }
  1035. }
  1036. return 0;
  1037. case FL_SHORTCUT:
  1038. m = menu->test_shortcut();
  1039. if (m) {m->do_callback(this, (void*)m); return 1;}
  1040. return 0;
  1041. case FL_DRAG:
  1042. drag_piece(erase_this, Fl::event_x()-deltax, Fl::event_y()-deltay);
  1043. return 1;
  1044. case FL_RELEASE:
  1045. // find the closest legal move he dropped it on:
  1046. dist = 50*50; n = 0;
  1047. for (t = root->son; t; t = t->brother) if (t->from==erase_this) {
  1048. int d1 = Fl::event_x()-deltax-squarex(t->to);
  1049. int d = d1*d1;
  1050. d1 = Fl::event_y()-deltay-squarey(t->to);
  1051. d += d1*d1;
  1052. if (d < dist) {dist = d; n = t;}
  1053. }
  1054. if (!n) {drop_piece(erase_this); return 1;} // none found
  1055. drop_piece(n->to);
  1056. domove(n);
  1057. if (showlegal) {showlegal = 0; redraw();}
  1058. if (n->jump) redraw();
  1059. computer_move(0);
  1060. return 1;
  1061. default:
  1062. return 0;
  1063. }
  1064. }
  1065. void quit_cb(Fl_Widget*, void*) {exit(0);}
  1066. int FLTKmain(int argc, char** argv) {
  1067. Fl::visual(FL_DOUBLE|FL_INDEX);
  1068. Board b(BOARDSIZE,BOARDSIZE);
  1069. b.color(FL_BACKGROUND_COLOR);
  1070. b.callback(quit_cb);
  1071. b.show(argc,argv);
  1072. return Fl::run();
  1073. }
  1074. void autoplay_cb(Fl_Widget*bp, void*) {
  1075. if (autoplay) {autoplay = 0; return;}
  1076. if (!playing) return;
  1077. Board* b = (Board*)bp;
  1078. autoplay = 1;
  1079. while (autoplay) {b->computer_move(0); b->computer_move(0);}
  1080. }
  1081. #include <FL/Fl_Box.H>
  1082. Fl_Window *copyright_window;
  1083. void copyright_cb(Fl_Widget*, void*) {
  1084. if (!copyright_window) {
  1085. copyright_window = new Fl_Window(400,270,"Copyright");
  1086. copyright_window->color(FL_WHITE);
  1087. Fl_Box *b = new Fl_Box(20,0,380,270,copyright);
  1088. b->labelsize(10);
  1089. b->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_WRAP);
  1090. copyright_window->end();
  1091. }
  1092. copyright_window->hotspot(copyright_window);
  1093. copyright_window->set_non_modal();
  1094. copyright_window->show();
  1095. }
  1096. void debug_cb(Fl_Widget*, void*v) {
  1097. debug = !debug;
  1098. ((Fl_Menu_Item*)v)->flags =
  1099. debug ? FL_MENU_TOGGLE|FL_MENU_VALUE : FL_MENU_TOGGLE;
  1100. }
  1101. void forced_cb(Fl_Widget*b, void*v) {
  1102. forcejumps = !forcejumps;
  1103. ((Fl_Menu_Item*)v)->flags =
  1104. forcejumps ? FL_MENU_TOGGLE|FL_MENU_VALUE : FL_MENU_TOGGLE;
  1105. killnode(root->son); root->son = 0;
  1106. if (showlegal) {expandnode(root); b->redraw();}
  1107. }
  1108. void move_cb(Fl_Widget*pb, void*) {
  1109. Board* b = (Board*)pb;
  1110. if (playing) b->computer_move(1);
  1111. if (playing) b->computer_move(0);
  1112. }
  1113. void newgame_cb(Fl_Widget*b, void*) {
  1114. showlegal = 0;
  1115. newgame();
  1116. b->redraw();
  1117. }
  1118. void legal_cb(Fl_Widget*pb, void*) {
  1119. if (showlegal == 1) {showlegal = 0; ((Board*)pb)->redraw(); return;}
  1120. if (!playing) return;
  1121. expandnode(root);
  1122. showlegal = 1; ((Board*)pb)->redraw();
  1123. }
  1124. void predict_cb(Fl_Widget*pb, void*) {
  1125. if (showlegal == 2) {showlegal = 0; ((Board*)pb)->redraw(); return;}
  1126. if (playing) expandnode(root);
  1127. showlegal = 2; ((Board*)pb)->redraw();
  1128. }
  1129. void switch_cb(Fl_Widget*pb, void*) {
  1130. user = !user;
  1131. ((Board*)pb)->computer_move(0);
  1132. }
  1133. void undo_cb(Fl_Widget*pb, void*) {
  1134. Board* b = (Board*)pb;
  1135. b->animate(undomove(),1);
  1136. b->animate(undomove(),1);
  1137. }
  1138. //--------------------------
  1139. #include <FL/Fl_Slider.H>
  1140. #include <FL/Fl_Value_Output.H>
  1141. Fl_Window *intel_window;
  1142. Fl_Value_Output *intel_output;
  1143. void intel_slider_cb(Fl_Widget*w, void*) {
  1144. double v = ((Fl_Slider*)w)->value();
  1145. int n = int(v*v);
  1146. intel_output->value(n);
  1147. maxevaluate = maxnodes = n;
  1148. }
  1149. void intel_cb(Fl_Widget*, void*) {
  1150. if (!intel_window) {
  1151. intel_window = new Fl_Window(200,25,"Checkers Intelligence");
  1152. Fl_Slider* s = new Fl_Slider(60,0,140,25);
  1153. s->type(FL_HOR_NICE_SLIDER);
  1154. s->minimum(1); s->maximum(500); s->value(50);
  1155. s->callback(intel_slider_cb);
  1156. intel_output = new Fl_Value_Output(0,0,60,25);
  1157. intel_output->value(maxevaluate);
  1158. intel_window->resizable(s);
  1159. }
  1160. intel_window->hotspot(intel_window);
  1161. intel_window->set_non_modal();
  1162. intel_window->show();
  1163. }
  1164. //---------------------------
  1165. void stop_cb(Fl_Widget*, void*) {abortflag = 1;}
  1166. void continue_cb(Fl_Widget*, void*) {}
  1167. Fl_Menu_Item menu[] = {
  1168. {"Autoplay", 'a', autoplay_cb},
  1169. {"Legal moves", 'l', legal_cb},
  1170. {"Move for me", 'm', move_cb},
  1171. {"New game", 'n', newgame_cb},
  1172. {"Predict", 'p', predict_cb},
  1173. {"Switch sides", 's', switch_cb},
  1174. {"Undo", 'u', undo_cb, 0, FL_MENU_DIVIDER},
  1175. {"Forced jumps rule", 'f', forced_cb, 0, FL_MENU_TOGGLE|FL_MENU_VALUE},
  1176. {"Debug", 'd', debug_cb, (void *)"d", FL_MENU_TOGGLE},
  1177. {"Intelligence...", 'i', intel_cb, 0, FL_MENU_DIVIDER},
  1178. {"Copyright", 'c', copyright_cb},
  1179. {"Quit", 'q', quit_cb},
  1180. {0}};
  1181. Fl_Menu_Item busymenu[] = {
  1182. {"Stop", '.', stop_cb},
  1183. {"Autoplay", 'a', autoplay_cb},
  1184. {"Continue", 0, continue_cb},
  1185. {"Debug", 'd', debug_cb, (void *)"d", FL_MENU_TOGGLE},
  1186. {"Intelligence...", 'i', intel_cb},
  1187. {"Copyright", 'c', copyright_cb},
  1188. {"Quit", 'q', quit_cb},
  1189. {0}};
  1190. #endif
  1191. ////////////////////////////////////////////////////////////////
  1192. // parts shared by both interface:
  1193. #ifdef FLTK
  1194. #ifdef VT100
  1195. #define BOTH
  1196. #endif
  1197. #endif
  1198. #ifdef BOTH
  1199. int terminal;
  1200. int arg(int, char **argv, int &i) {
  1201. if (argv[i][1] == 't') {terminal = 1; i++; return 1;}
  1202. return 0;
  1203. }
  1204. #endif
  1205. int didabort(void) {
  1206. #ifdef FLTK
  1207. #ifdef BOTH
  1208. if (!terminal)
  1209. #endif
  1210. Fl::check();
  1211. #endif
  1212. if (abortflag) {
  1213. autoplay = 0;
  1214. abortflag = 0;
  1215. return 1;
  1216. }
  1217. return(0);
  1218. }
  1219. int main(int argc, char **argv) {
  1220. seed = time(0);
  1221. newgame();
  1222. #ifdef BOTH
  1223. int i = 1;
  1224. if (Fl::args(argc, argv, i, arg) < argc) {
  1225. fprintf(stderr," -t : use VT100 display\n", Fl::help);
  1226. exit(1);
  1227. }
  1228. if (!getenv("DISPLAY")) terminal = 1;
  1229. if (!terminal)
  1230. #endif
  1231. #ifdef FLTK
  1232. return FLTKmain(argc,argv);
  1233. #endif
  1234. #ifdef VT100
  1235. return VT100main();
  1236. #endif
  1237. }
  1238. //
  1239. // End of "$Id: checkers.cxx 8168 2011-01-02 03:55:23Z matt $".
  1240. //