标题:强悍,300多行实现中国象棋人机对战
只看楼主
卧龙孔明
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:59
帖 子:3872
专家分:684
注 册:2006-10-13
结帖率:100%
 问题点数:0 回复次数:45 
强悍,300多行实现中国象棋人机对战

强悍,300多行实现中国象棋人机对战

vsccp.c

/*
VSCCP - Very Simple Chinese Chess Program
Written by Pham Hong Nguyen
Faculty of Information Technology - Vietnam National University, Hanoi
Office: 334 Nguyen Trai street, Thanh Xuan District, Hanoi, Vietnam
Home page: http://www.Geocities.com/SiliconValley/Grid/6544/
Email : phhnguyen@yahoo.com

Version:
-> 1.0 - basic
1.1 - add opening book
1.2 - improve eval function
1.3 - improve alphabeta search by adding iterative deepening,
quiescence, principal variation, history, killer heuristics
1.4 - add new rules and interface for tournament between 2 programs
A tournament can be controled by ROCC (Referee of Chinese Chess)
*/

#include <stdio.h>
#include <conio.h>
#include "defs10.h"


/* the board representation && the initial board state */
char color[BOARD_SIZE]= {
0, 0, 0, 0, 0, 0, 0, 0, 0,
7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 0, 7, 7, 7, 7, 7, 0, 7,
0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7,
1, 7, 1, 7, 1, 7, 1, 7, 1,
7, 1, 7, 7, 7, 7, 7, 1, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7,
1, 1, 1, 1, 1, 1, 1, 1, 1};

char piece[BOARD_SIZE]= {
5, 3, 2, 1, 6, 1, 2, 3, 5,
7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 4, 7, 7, 7, 7, 7, 4, 7,
0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 7, 7, 7, 7, 7, 7, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7,
0, 7, 0, 7, 0, 7, 0, 7, 0,
7, 4, 7, 7, 7, 7, 7, 4, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7,
5, 3, 2, 1, 6, 1, 2, 3, 5};

/* For getting information */
unsigned long nodecount, brandtotal = 0, gencount = 0;
char ply, side, xside, computerside;
move newmove;
gen_rec gen_dat[MOVE_STACK];
short gen_begin[HIST_STACK], gen_end[HIST_STACK];
hist_rec hist_dat[HIST_STACK];
short hdp;

volatile unsigned long *systicks=(unsigned long *)0x46C; /* Clock counter */
unsigned long tickstart, tickend;

/***** INTERFACE *****/
void MoveTo(short x, short y)
{
gotoxy (5*x+1, 2*y+1);
}


void DrawCell(short pos, short mode)
{
char piece_char[] = "PBENCRK+"; /*"TSVMPXT+"; /* the piece letters */

if (color[pos]==DARK) textcolor(13);
else if (color[pos]==LIGHT) textcolor(14); else textcolor(7);
if (mode==NORMAL) textbackground(0); else textbackground(1);
MoveTo(pos%9, pos/9);
cprintf("%c", piece_char[piece[pos]]);
}


void DrawBoard(void)
{
int i;
textcolor(7); textbackground(0); clrscr(); gotoxy(1,1);
printf("+----+----+----+----+----+----+----+----+ 9\n");
printf("| | | | \\ | / | | | |\n");
printf("+----+----+----+----+----+----+----+----+ 8\n");
printf("| | | | / | \\ | | | |\n");
printf("+----+----+----+----+----+----+----+----+ 7\n");
printf("| | | | | | | | |\n");
printf("+----+----+----+----+----+----+----+----+ 6\n");
printf("| | | | | | | | |\n");
printf("+----+----+----+----+----+----+----+----+ 5\n");
printf("| |\n");
printf("+----+----+----+----+----+----+----+----+ 4\n");
printf("| | | | | | | | |\n");
printf("+----+----+----+----+----+----+----+----+ 3\n");
printf("| | | | | | | | |\n");
printf("+----+----+----+----+----+----+----+----+ 2\n");
printf("| | | | \\ | / | | | |\n");
printf("+----+----+----+----+----+----+----+----+ 1\n");
printf("| | | | / | \\ | | | |\n");
printf("+----+----+----+----+----+----+----+----+ 0\n");
printf("A B C D E F G H I\n");
gotoxy(1,25); printf("Up, Down, Right, Left: cursor move Enter or Space: select ESC: escape");
gotoxy(48,1); cprintf("VERY SIMPLE CHINESE CHESS PROGRAM");
gotoxy(50,2); cprintf("(C) Pham Hong Nguyen. Ver %s", VERSION);

for (i=0; i<BOARD_SIZE; i++) DrawCell(i, NORMAL);
}


void Gen(void);

short GetHumanMove(void)
{
static short x = 4, y = 5;
short ch, from, t, i, selecting = 0;

Gen(); /* for check legal move only */

while (1) {
MoveTo (x, y);
ch = (short)getch();
switch (ch) {
case 13:
case 32: /* Enter or Spacebar */
t = x + y*SIZE_X;
if (!selecting) {
if (color[t]==side) {
selecting = 1; from = t; DrawCell(t, SELECT);
}
} else {
if (t != from) DrawCell(from, NORMAL);
if (color[t]==side) {
from = t; DrawCell(t, SELECT);
} else {
newmove.from = from; newmove.dest = t;
for (i=gen_begin[ply]; i<gen_end[ply]; i++)
if (gen_dat[i].m.from==newmove.from && gen_dat[i].m.dest==newmove.dest) return 0;
DrawCell(from, SELECT);
}
}
break;

case 27: return 1; /* ESC */

case 0:
ch = (short)getch();
switch (ch) {
case 75: if (x) x--; else x = SIZE_X-1; break; /* LEFT */
case 77: if (x<SIZE_X-1) x++; else x = 0; break; /* RIGHT */
case 72: if (y) y--; else y = SIZE_Y-1; break; /* UP */
case 80: if (y<SIZE_Y-1) y++; else y = 0; break; /* DOWN */
}
break;
} /* switch */
} /* while */
}


/**** MOVE GENERATE ****/
short offset[7][8] =
{{-1, 1,13, 0, 0, 0, 0, 0}, /* PAWN {for DARK side} */
{-12,-14,12,14,0,0,0,0}, /* BISHOP */
{-28,-24,24,28, 0, 0, 0, 0 }, /* ELEPHAN */
{-11,-15,-25,-27,11,15,25,27}, /* KNIGHT */
{-1, 1,-13,13, 0, 0, 0, 0}, /* CANNON */
{-1, 1,-13,13, 0, 0, 0, 0}, /* ROOK */
{-1, 1,-13,13, 0, 0, 0, 0}}; /* KING */

short mailbox182[182] =
{-1,-1,-1,-1,-1,-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,
-1,-1, 9,10,11,12,13,14,15,16,17,-1,-1,
-1,-1,18,19,20,21,22,23,24,25,26,-1,-1,
-1,-1,27,28,29,30,31,32,33,34,35,-1,-1,
-1,-1,36,37,38,39,40,41,42,43,44,-1,-1,
-1,-1,45,46,47,48,49,50,51,52,53,-1,-1,
-1,-1,54,55,56,57,58,59,60,61,62,-1,-1,
-1,-1,63,64,65,66,67,68,69,70,71,-1,-1,
-1,-1,72,73,74,75,76,77,78,79,80,-1,-1,
-1,-1,81,82,83,84,85,86,87,88,89,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};

short mailbox90[90] =
{28, 29, 30, 31, 32, 33, 34, 35, 36,
41, 42, 43, 44, 45, 46, 47, 48, 49,
54, 55, 56, 57, 58, 59, 60, 61, 62,
67, 68, 69, 70, 71, 72, 73, 74, 75,
80, 81, 82, 83, 84, 85, 86, 87, 88,
93, 94, 95, 96, 97, 98, 99,100,101,
106, 107,108,109,110,111,112,113,114,
119, 120,121,122,123,124,125,126,127,
132, 133,134,135,136,137,138,139,140,
145, 146,147,148,149,150,151,152,153};

short legalposition[90] =
{1, 1, 5, 3, 3, 3, 5, 1, 1,
1, 1, 1, 3, 3, 3, 1, 1, 1,
5, 1, 1, 3, 7, 3, 1, 1, 5,
1, 1, 1, 1, 1, 1, 1, 1, 1,
9, 1,13, 1, 9, 1,13, 1, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9};

short maskpiece[7] = {8, 2, 4, 1, 1, 1, 2},
knightcheck[8] = {1,-1,-9,-9,-1,1,9,9},
elephancheck[8] = {-10,-8,8,10,0,0,0,0},
kingpalace[9] = {3,4,5,12,13,14,21,22,23};


void InitGen(void)
{
gen_begin[0] = 0; ply = 0; hdp = 0;
}


short KingFace(short from, short dest)
{
short i, k, t, r = 0;
i = from % SIZE_X;
if (i>=3 && i<=5 && piece[dest]!=KING) {
t = piece[dest]; piece[dest] = piece[from]; piece[from] = EMPTY;
i = 0;
for (k=kingpalace[i]; piece[k]!=KING; k++) ;
for (k += SIZE_X; k<BOARD_SIZE && piece[k]==EMPTY; k += SIZE_X);
if (piece[k]==KING) r = 1;
piece[from] = piece[dest]; piece[dest] = t;
}
return r;
}

void Gen_push(short from, short dest)
{
if (!KingFace(from, dest)) {
gen_dat[gen_end[ply]].m.from = from;
gen_dat[gen_end[ply]].m.dest = dest;
gen_end[ply]++;
}
}


void Gen(void)
{
short i, j, k, n, p, x, y, t, fcannon;

gen_end[ply] = gen_begin[ply];

for(i=0; i < BOARD_SIZE; i++)
if (color[i]==side) {
p = piece[i];
for(j=0; j<8; j++) {
if (!offset[p][j]) break;
x = mailbox90[i]; fcannon = 0;
if (p==ROOK || p==CANNON) n = 9; else n = 1;
for (k=0; k<n; k++) {
if (p==PAWN && side==LIGHT) x -= offset[p][j]; else x += offset[p][j];

y = mailbox182[x];
if (side == DARK) t = y; else t = 89-y;
if (y==-1 || (legalposition[t] & maskpiece[p])==0) break;
if (!fcannon) {
if (color[y]!=side)
switch (p) {
case KNIGHT: if (color[i+knightcheck[j]]==EMPTY) Gen_push(i, y); break;
case ELEPHAN:if (color[i+elephancheck[j]]==EMPTY) Gen_push(i, y); break;
case CANNON: if (color[y]==EMPTY) Gen_push(i, y); break;
default: Gen_push(i, y);
}
if (color[y]!=EMPTY) { if (p==CANNON) fcannon++; else break; }
}
else { /* CANNON switch */
if (color[y] != EMPTY) {
if (color[y]==xside) Gen_push(i, y);
break;
}
}
} /* for k */
} /* for j */
}

gen_end[ply+1] = gen_end[ply]; gen_begin[ply+1] = gen_end[ply];
brandtotal += gen_end[ply] - gen_begin[ply]; gencount++;
}


/***** MOVE *****/
short MakeMove(move m)
{
short from, dest, p;
nodecount++;
from = m.from; dest = m.dest;
hist_dat[hdp].m = m; hist_dat[hdp].capture = p = piece[dest];
piece[dest] = piece[from]; piece[from] = EMPTY;
color[dest] = color[from]; color[from] = EMPTY;
hdp++; ply++; side = xside; xside = 1-xside;
return p == KING;
}


void UnMakeMove(void)
{
short from, dest;
hdp--; ply--; side = xside; xside = 1-xside;
from = hist_dat[hdp].m.from; dest = hist_dat[hdp].m.dest;
piece[from] = piece[dest]; color[from] = color[dest];
piece[dest] = hist_dat[hdp].capture;
if (piece[dest] == EMPTY) color[dest] = EMPTY; else color[dest] = xside;
}


short UpdateNewMove(void)
{
short from, dest, p;
from = newmove.from; dest = newmove.dest; p = piece[dest];
piece[dest] = piece[from]; piece[from] = EMPTY;
color[dest] = color[from]; color[from] = EMPTY;
DrawCell(from, NORMAL); DrawCell(dest, NORMAL);
return p == KING;
}


/***** EVALUATE *****/
short Eval(void)
{
static short piecevalue[7] = {10, 20, 20, 40, 45, 90, 1000};
short i, s = 0;
for (i=0; i<BOARD_SIZE; i++)
if (color[i]==side) s += piecevalue[piece[i]];
else if (color[i]==xside) s -= piecevalue[piece[i]];
return s;
}


/***** SEARCH *****/
/* Search game tree by alpha-beta algorith */
short AlphaBeta(short alpha, short beta, short depth)
{
short i, value, best;

if (!depth) return Eval();

Gen();
best = -INFINITY;

for (i=gen_begin[ply]; i<gen_end[ply] && best<beta; i++) {
if (best > alpha) alpha = best;

if (MakeMove(gen_dat[i].m)) value = 1000-ply;
else value = -AlphaBeta(-beta, -alpha, depth-1);
UnMakeMove();

if (value > best) {
best = value; if (!ply) newmove = gen_dat[i].m;
}
}

return best;
}


/***** THINK *****/
/* Call AlphaBeta short && display some information */
void ComputerThink(void)
{
short best;
tickstart = *systicks; nodecount = 0;
best = AlphaBeta(-INFINITY, INFINITY, MAX_PLY);
/* Display some information */
tickend = *systicks; textcolor(7);
gotoxy(50, 4); printf("Depth : %d", MAX_PLY);
gotoxy(50, 5); printf("Node total : %ld ", nodecount);
gotoxy(50, 6); printf("Brand factor : %.2f ", (float)brandtotal/gencount);
gotoxy(50, 7); printf("Time (second) : %.2f ", (tickend-tickstart)/18.23);
gotoxy(50, 8); printf("Nodes per second : %ld ", (long)(nodecount*18.23/(tickend-tickstart+1)));
gotoxy(50, 9); printf("Score : %d ", best);
gotoxy(50,11); printf("Computer move : %c%d%c%d ", (char)(newmove.from%SIZE_X+65), (short)(SIZE_X-newmove.from/SIZE_X),
(char)(newmove.dest%SIZE_X+65), (short)(SIZE_X-newmove.dest/SIZE_X));
}


/***** MAIN BLOCK *****/
void main(void)
{
InitGen(); DrawBoard(); side = DARK; xside = LIGHT; computerside = DARK;

do {
if (side == computerside) ComputerThink();
else if (GetHumanMove()) break;
side = xside; xside = 1-xside;
} while (!UpdateNewMove());
}

搜索更多相关主题的帖子: 中国象棋 人机 
2007-01-01 18:06
卧龙孔明
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:59
帖 子:3872
专家分:684
注 册:2006-10-13
得分:0 

DEFS10.H


#define MAX_PLY 4
#define VERSION "1.0"

#define SIZE_X 9
#define SIZE_Y 10
#define BOARD_SIZE SIZE_X*SIZE_Y

#define MOVE_STACK 4096
#define HIST_STACK 50

#define EMPTY 7
#define DARK 0
#define LIGHT 1

#define PAWN 0
#define BISHOP 1
#define ELEPHAN 2
#define KNIGHT 3
#define CANNON 4
#define ROOK 5
#define KING 6

#define INFINITY 20000
#define NORMAL 0
#define SELECT 1

typedef struct {
short from, dest;
} move;

typedef struct {
move m;
} gen_rec;

typedef struct {
move m;
int capture;
} hist_rec;


My Blog: www.aiexp.info
虽然我的路是从这里开始的,但是这里不再是乐土.感谢曾经影响过,引导过,帮助过我的董凯,飞燕,leeco,starwing,Rockcarry,soft_wind等等等等.别了,BCCN.
2007-01-01 18:06
kelifei
Rank: 1
来 自:UESTC
等 级:新手上路
帖 子:89
专家分:0
注 册:2006-5-11
得分:0 
没有注释。

-DFAE -DESS -DDVD -DMTK  -DDVR -DDECODE -DMSTAR -DPMP我决定在论坛潜水3年又3年!
2007-01-01 18:31
卧龙孔明
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:59
帖 子:3872
专家分:684
注 册:2006-10-13
得分:0 
但他的编写者思路清晰,写的程序是很好理解的

My Blog: www.aiexp.info
虽然我的路是从这里开始的,但是这里不再是乐土.感谢曾经影响过,引导过,帮助过我的董凯,飞燕,leeco,starwing,Rockcarry,soft_wind等等等等.别了,BCCN.
2007-01-01 20:44
miaomiao0403
Rank: 1
等 级:新手上路
帖 子:38
专家分:0
注 册:2006-8-22
得分:0 

没看懂啊 还要努力啊

2007-01-01 21:04
卧龙孔明
Rank: 9Rank: 9Rank: 9
等 级:贵宾
威 望:59
帖 子:3872
专家分:684
注 册:2006-10-13
得分:0 
这个程序除了界面部分外几乎就没有什么东西了,核心代码(着法生成/局面评价)都很短

My Blog: www.aiexp.info
虽然我的路是从这里开始的,但是这里不再是乐土.感谢曾经影响过,引导过,帮助过我的董凯,飞燕,leeco,starwing,Rockcarry,soft_wind等等等等.别了,BCCN.
2007-01-01 21:10
高达
Rank: 1
等 级:新手上路
威 望:1
帖 子:261
专家分:0
注 册:2006-10-27
得分:0 
你帮+点注释好么?
我看得有点迷糊

哎 时间....................
2007-01-01 21:15
ffaannggqq
Rank: 1
等 级:新手上路
帖 子:40
专家分:0
注 册:2006-12-23
得分:0 
顶一下

2007-01-02 15:03
jishuai
Rank: 1
等 级:新手上路
帖 子:97
专家分:0
注 册:2006-12-15
得分:0 
厉害

2007-01-02 16:01
死了都要C
Rank: 4
来 自:四川成都
等 级:贵宾
威 望:13
帖 子:1582
专家分:116
注 册:2006-12-7
得分:0 
~~~怎么把~上面的代码弄下来使用啊~~

我想用下看看怎么样~

女施主``我给你``送茶来了```师太``你就从了老衲吧``
代码本天成~~~妙头偶得之```
2007-01-02 16:10



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-113614-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.144318 second(s), 7 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved