本文转自:http://blog.csdn.net/u012723995/article/details/47143569

参考文献http://bbs.blueidea.com/thread-3047030-1-1.html

前言

原文大神是用html5+js写的关于象棋AI的博客,里面重点讲了棋子的着法,自己设计的评估函数和简单的Minmax理论,没有具体的讲搜索算法,本文是对原文的学习和分析补充

一,棋子的着法 com.bylaw ={}      首先创建一个数组,用于存储该棋子处于某一点时所能走到着点

(1)车:

  1. com.bylaw.c = function (x,y,map,my){
  2. var d=[];
  3. //左侧检索 若存在棋子且颜色不同则push过去并结束循环,否则一步步push <span style="color:#ff0000;"> </span>
  4. for (var i=x-1; i>= 0; i--){
  5. if (map[y][i]) {
  6. if (com.mans[map[y][i]].my!=my) d.push([i,y]);
  7. break
  8. }else{
  9. d.push([i,y])
  10. }
  11. }
  12. //右侧检索
  13. for (var i=x+1; i <= 8; i++){
  14. if (map[y][i]) {
  15. if (com.mans[map[y][i]].my!=my) d.push([i,y]);
  16. break
  17. }else{
  18. d.push([i,y])
  19. }
  20. }
  21. //上检索
  22. for (var i = y-1 ; i >= 0; i--){
  23. if (map[i][x]) {
  24. if (com.mans[map[i][x]].my!=my) d.push([x,i]);
  25. break
  26. }else{
  27. d.push([x,i])
  28. }
  29. }
  30. //下检索
  31. for (var i = y+1 ; i<= 9; i++){
  32. if (map[i][x]) {
  33. if (com.mans[map[i][x]].my!=my) d.push([x,i]);
  34. break
  35. }else{
  36. d.push([x,i])
  37. }
  38. }
  39. return d;
  40. }
com.bylaw.c = function (x,y,map,my){
var d=[];
//左侧检索 若存在棋子且颜色不同则push过去并结束循环,否则一步步push <span style="color:#ff0000;"> </span>
for (var i=x-1; i>= 0; i--){
if (map[y][i]) {
if (com.mans[map[y][i]].my!=my) d.push([i,y]);
break
}else{
d.push([i,y])
}
}
//右侧检索
for (var i=x+1; i <= 8; i++){
if (map[y][i]) {
if (com.mans[map[y][i]].my!=my) d.push([i,y]);
break
}else{
d.push([i,y])
}
}
//上检索
for (var i = y-1 ; i >= 0; i--){
if (map[i][x]) {
if (com.mans[map[i][x]].my!=my) d.push([x,i]);
break
}else{
d.push([x,i])
}
}
//下检索
for (var i = y+1 ; i<= 9; i++){
if (map[i][x]) {
if (com.mans[map[i][x]].my!=my) d.push([x,i]);
break
}else{
d.push([x,i])
}
}
return d;
}

算法分析:

分别向上,下,左,右四个方向搜索,若找到一个点且颜色与该棋子不同(敌对棋子),则将该点坐标记录在d数组中,若某一方向上没有其他棋子,将这一方向上所有坐标都记录在d数组中。简单来讲:就是将以车这个棋子为中心的十字上的坐标都记录在d数组中(你早这样说多好~,开始说那么多)

前提补充:

1,代码中的map:

  1. com.initMap = [
  2. ['C0','M0','X0','S0','J0','S1','X1','M1','C1'],
  3. [    ,    ,    ,    ,    ,    ,    ,    ,    ],
  4. [    ,'P0',    ,    ,    ,    ,    ,'P1',    ],
  5. ['Z0',    ,'Z1',    ,'Z2',    ,'Z3',    ,'Z4'],
  6. [    ,    ,    ,    ,    ,    ,    ,    ,    ],
  7. [    ,    ,    ,    ,    ,    ,    ,    ,    ],
  8. ['z0',    ,'z1',    ,'z2',    ,'z3',    ,'z4'],
  9. [    ,'p0',    ,    ,    ,    ,    ,'p1',    ],
  10. [    ,    ,    ,    ,    ,    ,    ,    ,    ],
  11. ['c0','m0','x0','s0','j0','s1','x1','m1','c1']
  12. ];
com.initMap = [
['C0','M0','X0','S0','J0','S1','X1','M1','C1'],
[ , , , , , , , , ],
[ ,'P0', , , , , ,'P1', ],
['Z0', ,'Z1', ,'Z2', ,'Z3', ,'Z4'],
[ , , , , , , , , ],
[ , , , , , , , , ],
['z0', ,'z1', ,'z2', ,'z3', ,'z4'],
[ ,'p0', , , , , ,'p1', ],
[ , , , , , , , , ],
['c0','m0','x0','s0','j0','s1','x1','m1','c1']
];

这里的字符串代表每个棋子的key值:

  1. com.keys = {                                       //设定每类棋子的key值
  2. "c0":"c","c1":"c",
  3. "m0":"m","m1":"m",
  4. "x0":"x","x1":"x",
  5. "s0":"s","s1":"s",
  6. "j0":"j",
  7. "p0":"p","p1":"p",
  8. "z0":"z","z1":"z","z2":"z","z3":"z","z4":"z","z5":"z",
  9. "C0":"C","C1":"C",
  10. "M0":"M","M1":"M",
  11. "X0":"X","X1":"X",
  12. "S0":"S","S1":"S",
  13. "J0":"J",
  14. "P0":"P","P1":"P",
  15. "Z0":"Z","Z1":"Z","Z2":"Z","Z3":"Z","Z4":"Z","Z5":"Z",
  16. }
com.keys = {                                       //设定每类棋子的key值
"c0":"c","c1":"c",
"m0":"m","m1":"m",
"x0":"x","x1":"x",
"s0":"s","s1":"s",
"j0":"j",
"p0":"p","p1":"p",
"z0":"z","z1":"z","z2":"z","z3":"z","z4":"z","z5":"z", "C0":"C","C1":"C",
"M0":"M","M1":"M",
"X0":"X","X1":"X",
"S0":"S","S1":"S",
"J0":"J",
"P0":"P","P1":"P",
"Z0":"Z","Z1":"Z","Z2":"Z","Z3":"Z","Z4":"Z","Z5":"Z",
}

2,my:

标记值:1代表红色方(这里指人。玩家永远操纵红色)   ;          -1代表AI

3,map[y][i]与d.push([i][y])

左方向上搜索,y坐标不变,x坐标遍历,而体现在map当中(向上翻第一点),仔细看就会发现:第一个下标代表y值,第二个下标代表x值,其与坐标值正好相反

其他方向上以此类推。。。

(2)马

  1. com.bylaw.m = function (x,y,map,my){
  2. var d=[];
  3. //1点钟方向  不绊马脚  1点不存在棋子或1点棋子颜色不同  push
  4. if ( y-2>= 0 && x+1<= 8 && !play.map[y-1][x] &&(!com.mans[map[y-2][x+1]] || com.mans[map[y-2][x+1]].my!=my)) d.push([x+1,y-2]);
  5. //2点
  6. if ( y-1>= 0 && x+2<= 8 && !play.map[y][x+1] &&(!com.mans[map[y-1][x+2]] || com.mans[map[y-1][x+2]].my!=my)) d.push([x+2,y-1]);
  7. //4点
  8. if ( y+1<= 9 && x+2<= 8 && !play.map[y][x+1] &&(!com.mans[map[y+1][x+2]] || com.mans[map[y+1][x+2]].my!=my)) d.push([x+2,y+1]);
  9. //5点
  10. if ( y+2<= 9 && x+1<= 8 && !play.map[y+1][x] &&(!com.mans[map[y+2][x+1]] || com.mans[map[y+2][x+1]].my!=my)) d.push([x+1,y+2]);
  11. //7点
  12. if ( y+2<= 9 && x-1>= 0 && !play.map[y+1][x] &&(!com.mans[map[y+2][x-1]] || com.mans[map[y+2][x-1]].my!=my)) d.push([x-1,y+2]);
  13. //8点
  14. if ( y+1<= 9 && x-2>= 0 && !play.map[y][x-1] &&(!com.mans[map[y+1][x-2]] || com.mans[map[y+1][x-2]].my!=my)) d.push([x-2,y+1]);
  15. //10点
  16. if ( y-1>= 0 && x-2>= 0 && !play.map[y][x-1] &&(!com.mans[map[y-1][x-2]] || com.mans[map[y-1][x-2]].my!=my)) d.push([x-2,y-1]);
  17. //11点
  18. if ( y-2>= 0 && x-1>= 0 && !play.map[y-1][x] &&(!com.mans[map[y-2][x-1]] || com.mans[map[y-2][x-1]].my!=my)) d.push([x-1,y-2]);
  19. return d;
  20. }
com.bylaw.m = function (x,y,map,my){
var d=[];
//1点钟方向 不绊马脚 1点不存在棋子或1点棋子颜色不同 push
if ( y-2>= 0 && x+1<= 8 && !play.map[y-1][x] &&(!com.mans[map[y-2][x+1]] || com.mans[map[y-2][x+1]].my!=my)) d.push([x+1,y-2]);
//2点
if ( y-1>= 0 && x+2<= 8 && !play.map[y][x+1] &&(!com.mans[map[y-1][x+2]] || com.mans[map[y-1][x+2]].my!=my)) d.push([x+2,y-1]);
//4点
if ( y+1<= 9 && x+2<= 8 && !play.map[y][x+1] &&(!com.mans[map[y+1][x+2]] || com.mans[map[y+1][x+2]].my!=my)) d.push([x+2,y+1]);
//5点
if ( y+2<= 9 && x+1<= 8 && !play.map[y+1][x] &&(!com.mans[map[y+2][x+1]] || com.mans[map[y+2][x+1]].my!=my)) d.push([x+1,y+2]);
//7点
if ( y+2<= 9 && x-1>= 0 && !play.map[y+1][x] &&(!com.mans[map[y+2][x-1]] || com.mans[map[y+2][x-1]].my!=my)) d.push([x-1,y+2]);
//8点
if ( y+1<= 9 && x-2>= 0 && !play.map[y][x-1] &&(!com.mans[map[y+1][x-2]] || com.mans[map[y+1][x-2]].my!=my)) d.push([x-2,y+1]);
//10点
if ( y-1>= 0 && x-2>= 0 && !play.map[y][x-1] &&(!com.mans[map[y-1][x-2]] || com.mans[map[y-1][x-2]].my!=my)) d.push([x-2,y-1]);
//11点
if ( y-2>= 0 && x-1>= 0 && !play.map[y-1][x] &&(!com.mans[map[y-2][x-1]] || com.mans[map[y-2][x-1]].my!=my)) d.push([x-1,y-2]); return d;
}

算法分析:

当马处于一点时,可以走的最多情况有8种方向,分别讨论每个方向:如果不绊马脚,且该方向上那着点没有棋子或棋子颜色不同,则记录该着点

图例分析:

有点丑,用画图做的,不要在意这些细节

(三)相

  1. com.bylaw.x = function (x,y,map,my){
  2. var d=[];
  3. if (my===1){ //红方  颜色不同,y的取值范围不同,且不能过河
  4. //4点半  不绊象脚   4.5位置没子或棋子颜色不同   push
  5. if ( y+2<= 9 && x+2<= 8 && !play.map[y+1][x+1] && (!com.mans[map[y+2][x+2]] || com.mans[map[y+2][x+2]].my!=my)) d.push([x+2,y+2]);
  6. //7点半
  7. if ( y+2<= 9 && x-2>= 0 && !play.map[y+1][x-1] && (!com.mans[map[y+2][x-2]] || com.mans[map[y+2][x-2]].my!=my)) d.push([x-2,y+2]);
  8. //1点半
  9. if ( y-2>= 5 && x+2<= 8 && !play.map[y-1][x+1] && (!com.mans[map[y-2][x+2]] || com.mans[map[y-2][x+2]].my!=my)) d.push([x+2,y-2]);
  10. //10点半
  11. if ( y-2>= 5 && x-2>= 0 && !play.map[y-1][x-1] && (!com.mans[map[y-2][x-2]] || com.mans[map[y-2][x-2]].my!=my)) d.push([x-2,y-2]);
  12. }else{
  13. //4点半
  14. if ( y+2<= 4 && x+2<= 8 && !play.map[y+1][x+1] && (!com.mans[map[y+2][x+2]] || com.mans[map[y+2][x+2]].my!=my)) d.push([x+2,y+2]);
  15. //7点半
  16. if ( y+2<= 4 && x-2>= 0 && !play.map[y+1][x-1] && (!com.mans[map[y+2][x-2]] || com.mans[map[y+2][x-2]].my!=my)) d.push([x-2,y+2]);
  17. //1点半
  18. if ( y-2>= 0 && x+2<= 8 && !play.map[y-1][x+1] && (!com.mans[map[y-2][x+2]] || com.mans[map[y-2][x+2]].my!=my)) d.push([x+2,y-2]);
  19. //10点半
  20. if ( y-2>= 0 && x-2>= 0 && !play.map[y-1][x-1] && (!com.mans[map[y-2][x-2]] || com.mans[map[y-2][x-2]].my!=my)) d.push([x-2,y-2]);
  21. }
  22. return d;
  23. }
com.bylaw.x = function (x,y,map,my){
var d=[];
if (my===1){ //红方 颜色不同,y的取值范围不同,且不能过河
//4点半 不绊象脚 4.5位置没子或棋子颜色不同 push
if ( y+2<= 9 && x+2<= 8 && !play.map[y+1][x+1] && (!com.mans[map[y+2][x+2]] || com.mans[map[y+2][x+2]].my!=my)) d.push([x+2,y+2]);
//7点半
if ( y+2<= 9 && x-2>= 0 && !play.map[y+1][x-1] && (!com.mans[map[y+2][x-2]] || com.mans[map[y+2][x-2]].my!=my)) d.push([x-2,y+2]);
//1点半
if ( y-2>= 5 && x+2<= 8 && !play.map[y-1][x+1] && (!com.mans[map[y-2][x+2]] || com.mans[map[y-2][x+2]].my!=my)) d.push([x+2,y-2]);
//10点半
if ( y-2>= 5 && x-2>= 0 && !play.map[y-1][x-1] && (!com.mans[map[y-2][x-2]] || com.mans[map[y-2][x-2]].my!=my)) d.push([x-2,y-2]);
}else{
//4点半
if ( y+2<= 4 && x+2<= 8 && !play.map[y+1][x+1] && (!com.mans[map[y+2][x+2]] || com.mans[map[y+2][x+2]].my!=my)) d.push([x+2,y+2]);
//7点半
if ( y+2<= 4 && x-2>= 0 && !play.map[y+1][x-1] && (!com.mans[map[y+2][x-2]] || com.mans[map[y+2][x-2]].my!=my)) d.push([x-2,y+2]);
//1点半
if ( y-2>= 0 && x+2<= 8 && !play.map[y-1][x+1] && (!com.mans[map[y-2][x+2]] || com.mans[map[y-2][x+2]].my!=my)) d.push([x+2,y-2]);
//10点半
if ( y-2>= 0 && x-2>= 0 && !play.map[y-1][x-1] && (!com.mans[map[y-2][x-2]] || com.mans[map[y-2][x-2]].my!=my)) d.push([x-2,y-2]);
}
return d;
}

算法分析:

因为相不能过河,所以要按颜色分情况讨论(不同颜色,y坐标不同)

而每种颜色的相都有四种可能着法,与马类似:如果不绊象脚, 着点没有棋子或棋子颜色不同,记录

图例分析:

(四)士

  1. com.bylaw.s = function (x,y,map,my){
  2. var d=[];
  3. if (my===1){ //红方
  4. //4点半
  5. if ( y+1<= 9 && x+1<= 5 && (!com.mans[map[y+1][x+1]] || com.mans[map[y+1][x+1]].my!=my)) d.push([x+1,y+1]);
  6. //7点半
  7. if ( y+1<= 9 && x-1>= 3 && (!com.mans[map[y+1][x-1]] || com.mans[map[y+1][x-1]].my!=my)) d.push([x-1,y+1]);
  8. //1点半
  9. if ( y-1>= 7 && x+1<= 5 && (!com.mans[map[y-1][x+1]] || com.mans[map[y-1][x+1]].my!=my)) d.push([x+1,y-1]);
  10. //10点半
  11. if ( y-1>= 7 && x-1>= 3 && (!com.mans[map[y-1][x-1]] || com.mans[map[y-1][x-1]].my!=my)) d.push([x-1,y-1]);
  12. }else{
  13. //4点半
  14. if ( y+1<= 2 && x+1<= 5 && (!com.mans[map[y+1][x+1]] || com.mans[map[y+1][x+1]].my!=my)) d.push([x+1,y+1]);
  15. //7点半
  16. if ( y+1<= 2 && x-1>= 3 && (!com.mans[map[y+1][x-1]] || com.mans[map[y+1][x-1]].my!=my)) d.push([x-1,y+1]);
  17. //1点半
  18. if ( y-1>= 0 && x+1<= 5 && (!com.mans[map[y-1][x+1]] || com.mans[map[y-1][x+1]].my!=my)) d.push([x+1,y-1]);
  19. //10点半
  20. if ( y-1>= 0 && x-1>= 3 && (!com.mans[map[y-1][x-1]] || com.mans[map[y-1][x-1]].my!=my)) d.push([x-1,y-1]);
  21. }
  22. return d;
  23. }
com.bylaw.s = function (x,y,map,my){
var d=[];
if (my===1){ //红方
//4点半
if ( y+1<= 9 && x+1<= 5 && (!com.mans[map[y+1][x+1]] || com.mans[map[y+1][x+1]].my!=my)) d.push([x+1,y+1]);
//7点半
if ( y+1<= 9 && x-1>= 3 && (!com.mans[map[y+1][x-1]] || com.mans[map[y+1][x-1]].my!=my)) d.push([x-1,y+1]);
//1点半
if ( y-1>= 7 && x+1<= 5 && (!com.mans[map[y-1][x+1]] || com.mans[map[y-1][x+1]].my!=my)) d.push([x+1,y-1]);
//10点半
if ( y-1>= 7 && x-1>= 3 && (!com.mans[map[y-1][x-1]] || com.mans[map[y-1][x-1]].my!=my)) d.push([x-1,y-1]);
}else{
//4点半
if ( y+1<= 2 && x+1<= 5 && (!com.mans[map[y+1][x+1]] || com.mans[map[y+1][x+1]].my!=my)) d.push([x+1,y+1]);
//7点半
if ( y+1<= 2 && x-1>= 3 && (!com.mans[map[y+1][x-1]] || com.mans[map[y+1][x-1]].my!=my)) d.push([x-1,y+1]);
//1点半
if ( y-1>= 0 && x+1<= 5 && (!com.mans[map[y-1][x+1]] || com.mans[map[y-1][x+1]].my!=my)) d.push([x+1,y-1]);
//10点半
if ( y-1>= 0 && x-1>= 3 && (!com.mans[map[y-1][x-1]] || com.mans[map[y-1][x-1]].my!=my)) d.push([x-1,y-1]);
}
return d; }

算法分析:

士不能出九宫格,x,y值都有限制。按颜色分情况讨论。每种颜色各有4中可能着法:如果该着点没棋子或棋子颜色不同,记录

图例分析:

这个简单了,就不画图了~ ~ ~ ~

(五)将

  1. com.bylaw.j = function (x,y,map,my){
  2. var d=[];
  3. var isNull=(function (y1,y2){
  4. var y1=com.mans["j0"].y;         //红帅的y
  5. var x1=com.mans["J0"].x;         //黑将的x
  6. var y2=com.mans["J0"].y;         //黑将的y
  7. for (var i=y1-1; i>y2; i--){
  8. if (map[i][x1]) return false;       //将与将之间非空,有子
  9. }
  10. return true;
  11. })();
  12. if (my===1){ //红方
  13. //下
  14. if ( y+1<= 9  && (!com.mans[map[y+1][x]] || com.mans[map[y+1][x]].my!=my)) d.push([x,y+1]);
  15. //上
  16. if ( y-1>= 7 && (!com.mans[map[y-1][x]] || com.mans[map[y-1][x]].my!=my)) d.push([x,y-1]);
  17. //老将对老将的情况
  18. if ( com.mans["j0"].x == com.mans["J0"].x &&isNull) d.push([com.mans["J0"].x,com.mans["J0"].y]);      //x相等,且中间为空,push黑将的坐标
  19. }else{
  20. //下
  21. if ( y+1<= 2  && (!com.mans[map[y+1][x]] || com.mans[map[y+1][x]].my!=my)) d.push([x,y+1]);
  22. //上
  23. if ( y-1>= 0 && (!com.mans[map[y-1][x]] || com.mans[map[y-1][x]].my!=my)) d.push([x,y-1]);
  24. //老将对老将的情况
  25. if ( com.mans["j0"].x == com.mans["J0"].x &&isNull) d.push([com.mans["j0"].x,com.mans["j0"].y]);        //push红帅的坐标
  26. }
  27. //右
  28. if ( x+1<= 5  && (!com.mans[map[y][x+1]] || com.mans[map[y][x+1]].my!=my)) d.push([x+1,y]);
  29. //左
  30. if ( x-1>= 3 && (!com.mans[map[y][x-1]] || com.mans[map[y][x-1]].my!=my))d.push([x-1,y]);
  31. return d;
  32. }
com.bylaw.j = function (x,y,map,my){
var d=[];
var isNull=(function (y1,y2){
var y1=com.mans["j0"].y; //红帅的y
var x1=com.mans["J0"].x; //黑将的x
var y2=com.mans["J0"].y; //黑将的y
for (var i=y1-1; i>y2; i--){
if (map[i][x1]) return false; //将与将之间非空,有子
}
return true;
})(); if (my===1){ //红方
//下
if ( y+1<= 9 && (!com.mans[map[y+1][x]] || com.mans[map[y+1][x]].my!=my)) d.push([x,y+1]);
//上
if ( y-1>= 7 && (!com.mans[map[y-1][x]] || com.mans[map[y-1][x]].my!=my)) d.push([x,y-1]);
//老将对老将的情况
if ( com.mans["j0"].x == com.mans["J0"].x &&isNull) d.push([com.mans["J0"].x,com.mans["J0"].y]); //x相等,且中间为空,push黑将的坐标 }else{
//下
if ( y+1<= 2 && (!com.mans[map[y+1][x]] || com.mans[map[y+1][x]].my!=my)) d.push([x,y+1]);
//上
if ( y-1>= 0 && (!com.mans[map[y-1][x]] || com.mans[map[y-1][x]].my!=my)) d.push([x,y-1]);
//老将对老将的情况
if ( com.mans["j0"].x == com.mans["J0"].x &&isNull) d.push([com.mans["j0"].x,com.mans["j0"].y]); //push红帅的坐标
}
//右
if ( x+1<= 5 && (!com.mans[map[y][x+1]] || com.mans[map[y][x+1]].my!=my)) d.push([x+1,y]);
//左
if ( x-1>= 3 && (!com.mans[map[y][x-1]] || com.mans[map[y][x-1]].my!=my))d.push([x-1,y]);
return d;
}

算法分析:

将除了颜色不同导致y值不同外,还有种特殊情况:即老将见面。所以开始先写个函数,判断将与帅之间是否有其他棋子

接下来按颜色不同分情况讨论上下两种着法:重点 是y值的界定。以帅为例:帅在棋盘下方,y坐标只能取7,8,9.如果向下走,则取7,8,所以y值最大为8.上与其类似。而判断完着法之后还要判断是否老将见面的特殊情况:如果两者x坐标相等且中间没其他棋子,之间闪现过去抢人头~ ~ ~然后victory

(六),炮

  1. com.bylaw.p = function (x,y,map,my){
  2. var d=[];
  3. //左侧检索
  4. var n=0;
  5. for (var i=x-1; i>= 0; i--){
  6. if (map[y][i]) {                  //碰到子
  7. if (n==0){                    //若是第一个子,不用管,跳出本次循环,标记位加1
  8. n++;
  9. continue;
  10. }else{                       //若不是第一个子,判断颜色若不同,push过去并结束循环
  11. if (com.mans[map[y][i]].my!=my) d.push([i,y]);
  12. break
  13. }
  14. }else{                          //若一直碰不到子,将子走到最左
  15. if(n==0) d.push([i,y])
  16. }
  17. }
  18. //右侧检索
  19. var n=0;
  20. for (var i=x+1; i <= 8; i++){
  21. if (map[y][i]) {
  22. if (n==0){
  23. n++;
  24. continue;
  25. }else{
  26. if (com.mans[map[y][i]].my!=my) d.push([i,y]);
  27. break
  28. }
  29. }else{
  30. if(n==0) d.push([i,y])
  31. }
  32. }
  33. //上检索
  34. var n=0;
  35. for (var i = y-1 ; i >= 0; i--){
  36. if (map[i][x]) {
  37. if (n==0){
  38. n++;
  39. continue;
  40. }else{
  41. if (com.mans[map[i][x]].my!=my) d.push([x,i]);
  42. break
  43. }
  44. }else{
  45. if(n==0) d.push([x,i])
  46. }
  47. }
  48. //下检索
  49. var n=0;
  50. for (var i = y+1 ; i<= 9; i++){
  51. if (map[i][x]) {
  52. if (n==0){
  53. n++;
  54. continue;
  55. }else{
  56. if (com.mans[map[i][x]].my!=my) d.push([x,i]);
  57. break
  58. }
  59. }else{
  60. if(n==0) d.push([x,i])
  61. }
  62. }
  63. return d;
  64. }
com.bylaw.p = function (x,y,map,my){
var d=[];
//左侧检索
var n=0;
for (var i=x-1; i>= 0; i--){
if (map[y][i]) { //碰到子
if (n==0){ //若是第一个子,不用管,跳出本次循环,标记位加1
n++;
continue;
}else{ //若不是第一个子,判断颜色若不同,push过去并结束循环
if (com.mans[map[y][i]].my!=my) d.push([i,y]);
break
}
}else{ //若一直碰不到子,将子走到最左
if(n==0) d.push([i,y])
}
}
//右侧检索
var n=0;
for (var i=x+1; i <= 8; i++){
if (map[y][i]) {
if (n==0){
n++;
continue;
}else{
if (com.mans[map[y][i]].my!=my) d.push([i,y]);
break
}
}else{
if(n==0) d.push([i,y])
}
}
//上检索
var n=0;
for (var i = y-1 ; i >= 0; i--){
if (map[i][x]) {
if (n==0){
n++;
continue;
}else{
if (com.mans[map[i][x]].my!=my) d.push([x,i]);
break
}
}else{
if(n==0) d.push([x,i])
}
}
//下检索
var n=0;
for (var i = y+1 ; i<= 9; i++){
if (map[i][x]) {
if (n==0){
n++;
continue;
}else{
if (com.mans[map[i][x]].my!=my) d.push([x,i]);
break
}
}else{
if(n==0) d.push([x,i])
}
}
return d;
}

算法分析:

跟车一样,需要向4个方向上搜索

若该方向上没棋子,则记录该方向所有点坐标

若走着走着发现一个棋子,先冷静一下(跳出本次循环),偷偷地看接下来该方向上有没有敌方棋子,有,就可以越塔gank了。然后把敌方死的位置记录下来留作纪念~ ~ ~

(七)卒

  1. com.bylaw.z = function (x,y,map,my){
  2. var d=[];
  3. if (my===1){ //红方
  4. //上
  5. if ( y-1>= 0 && (!com.mans[map[y-1][x]] || com.mans[map[y-1][x]].my!=my)) d.push([x,y-1]);
  6. //右
  7. if ( x+1<= 8 && y<=4  && (!com.mans[map[y][x+1]] || com.mans[map[y][x+1]].my!=my)) d.push([x+1,y]);    //y<4,即过河之后,才能左右移动
  8. //左
  9. if ( x-1>= 0 && y<=4 && (!com.mans[map[y][x-1]] || com.mans[map[y][x-1]].my!=my))d.push([x-1,y]);
  10. }else{
  11. //下
  12. if ( y+1<= 9  && (!com.mans[map[y+1][x]] || com.mans[map[y+1][x]].my!=my)) d.push([x,y+1]);
  13. //右
  14. if ( x+1<= 8 && y>=6  && (!com.mans[map[y][x+1]] || com.mans[map[y][x+1]].my!=my)) d.push([x+1,y]);
  15. //左
  16. if ( x-1>= 0 && y>=6 && (!com.mans[map[y][x-1]] || com.mans[map[y][x-1]].my!=my))d.push([x-1,y]);
  17. }
  18. return d;
  19. }
com.bylaw.z = function (x,y,map,my){
var d=[];
if (my===1){ //红方
//上
if ( y-1>= 0 && (!com.mans[map[y-1][x]] || com.mans[map[y-1][x]].my!=my)) d.push([x,y-1]);
//右
if ( x+1<= 8 && y<=4 && (!com.mans[map[y][x+1]] || com.mans[map[y][x+1]].my!=my)) d.push([x+1,y]); //y<4,即过河之后,才能左右移动
//左
if ( x-1>= 0 && y<=4 && (!com.mans[map[y][x-1]] || com.mans[map[y][x-1]].my!=my))d.push([x-1,y]);
}else{
//下
if ( y+1<= 9 && (!com.mans[map[y+1][x]] || com.mans[map[y+1][x]].my!=my)) d.push([x,y+1]);
//右
if ( x+1<= 8 && y>=6 && (!com.mans[map[y][x+1]] || com.mans[map[y][x+1]].my!=my)) d.push([x+1,y]);
//左
if ( x-1>= 0 && y>=6 && (!com.mans[map[y][x-1]] || com.mans[map[y][x-1]].my!=my))d.push([x-1,y]);
} return d;
}

算法分析:

同样分情况讨论。且由于卒不能后退所以只用判断上,左,右三种情况。而卒由于过河后才能左右移动,所以左右的判断除了x的界定还有y值的界定。最后跟车一样如果该着点没有棋子或该棋子颜色不同,记录该点

二 ,使用alpha-beta在所有着法当中搜索最佳着法

  1. AI.getAlphaBeta = function (A, B, depth, map ,my) {
  2. if (depth == 0) {
  3. return {"value":AI.evaluate(map , my)}; //当搜索深度为0是时调用局面评价函数;
  4.     }
  5.     var moves = AI.getMoves(map , my ); //生成全部走法;
  6.     <span style="color:#ff0000;">//这里排序以后会增加效率
  7. for (var i=0; i < moves.length; i++) {</span>
  8.     //走这个走法;
  9. var move= moves[i];
  10. var key = move[4];
  11. var oldX= move[0];
  12. var oldY= move[1];
  13. var newX= move[2];
  14. var newY= move[3];
  15. var clearKey = map[ newY ][ newX ]||"";
  16. map[ newY ][ newX ] = key;                   //走,赋新值,删除旧值
  17. delete map[ oldY ][ oldX ];
  18. play.mans[key].x = newX;
  19. play.mans[key].y = newY;
  20.   <span style="color:#ff0000;">if (clearKey=="j0"||clearKey=="J0") {        //被吃老将
  21. play.mans[key]  .x = oldX;
  22. play.mans[key]  .y = oldY;
  23. map[ oldY ][ oldX ] = key;
  24. delete map[ newY ][ newX ];      //并不是真的走,所以这里要撤销
  25. if (clearKey){
  26. map[ newY ][ newX ] = clearKey;
  27. }
  28. return {"key":key,"x":newX,"y":newY,"value":8888};
  29. </span>
  30.   }else {
  31.     var val = -AI.getAlphaBeta(-B, -A, depth - 1, map , -my).value;        //上面代表AI,这里倒置,-my,代表人的着法,然后再从上面开始执行
  32. //val = val || val.value;
  33.     //<span style="color:#ff0000;">撤消这个走法; 
  34. play.mans[key]  .x = oldX;
  35. play.mans[key]  .y = oldY;
  36. map[ oldY ][ oldX ] = key;
  37. delete map[ newY ][ newX ];
  38. if (clearKey){
  39. map[ newY ][ newX ] = clearKey;
  40. //play.mans[ clearKey ].isShow = true;
  41. }</span>
  42.     if (val >= B) {
  43. //将这个走法记录到历史表中;
  44. //AI.setHistoryTable(txtMap,AI.treeDepth-depth+1,B,my);
  45. return {"key":key,"x":newX,"y":newY,"value":B};
  46. }
  47. <span style="color:#ff0000;">if (val > A) {
  48.         A = val; //设置最佳走法,
  49. if (AI.treeDepth == depth) var rootKey={"key":key,"x":newX,"y":newY,"value":A};
  50. } </span>
  51. }
  52.     }
  53. if (AI.treeDepth == depth) {//已经递归回根了
  54. if (!rootKey){
  55. //AI没有最佳走法,说明AI被将死了,返回false
  56. return false;
  57. }else{
  58. //这个就是最佳走法;
  59. return rootKey;
  60. }
  61. }
  62.  return {"key":key,"x":newX,"y":newY,"value":A};
  63. }
AI.getAlphaBeta = function (A, B, depth, map ,my) {
if (depth == 0) {
return {"value":AI.evaluate(map , my)}; //当搜索深度为0是时调用局面评价函数;
  }
  var moves = AI.getMoves(map , my ); //生成全部走法;
  <span style="color:#ff0000;">//这里排序以后会增加效率 for (var i=0; i < moves.length; i++) {</span>    //走这个走法;
var move= moves[i];
var key = move[4];
var oldX= move[0];
var oldY= move[1];
var newX= move[2];
var newY= move[3];
var clearKey = map[ newY ][ newX ]||""; map[ newY ][ newX ] = key; //走,赋新值,删除旧值
delete map[ oldY ][ oldX ];
play.mans[key].x = newX;
play.mans[key].y = newY;   <span style="color:#ff0000;">if (clearKey=="j0"||clearKey=="J0") { //被吃老将
play.mans[key] .x = oldX;
play.mans[key] .y = oldY;
map[ oldY ][ oldX ] = key;
delete map[ newY ][ newX ]; //并不是真的走,所以这里要撤销
if (clearKey){
map[ newY ][ newX ] = clearKey; } return {"key":key,"x":newX,"y":newY,"value":8888};
</span>
  }else {
   var val = -AI.getAlphaBeta(-B, -A, depth - 1, map , -my).value; //上面代表AI,这里倒置,-my,代表人的着法,然后再从上面开始执行
//val = val || val.value;    //<span style="color:#ff0000;">撤消这个走法; 
play.mans[key] .x = oldX;
play.mans[key] .y = oldY;
map[ oldY ][ oldX ] = key;
delete map[ newY ][ newX ];
if (clearKey){
map[ newY ][ newX ] = clearKey;
//play.mans[ clearKey ].isShow = true;
}</span>
   if (val >= B) {
//将这个走法记录到历史表中;
//AI.setHistoryTable(txtMap,AI.treeDepth-depth+1,B,my);
return {"key":key,"x":newX,"y":newY,"value":B};
}
<span style="color:#ff0000;">if (val > A) {
     A = val; //设置最佳走法,
if (AI.treeDepth == depth) var rootKey={"key":key,"x":newX,"y":newY,"value":A};
} </span>
}
  } if (AI.treeDepth == depth) {//已经递归回根了
if (!rootKey){
//AI没有最佳走法,说明AI被将死了,返回false
return false;
}else{
//这个就是最佳走法;
return rootKey;
}
}
 return {"key":key,"x":newX,"y":newY,"value":A};
}

简化后的伪代码(与上面代码一一对应):

  1. int AlphaBeta(int vlAlpha, int vlBeta, int nDepth) {
  2.  if (nDepth == 0) {
  3.   return 局面评价函数;
  4.  }
  5.  生成全部走法;
  6.  <span style="color:#ff0000;">按历史表排序全部走法;</span>
  7.  for (每个生成的走法) {
  8.   走这个走法;
  9.   <span style="color:#ff0000;">if (被将军) {
  10.    撤消这个走法;
  11.   } else</span> {
  12.    int vl = -AlphaBeta(-vlBeta, -vlAlpha, nDepth - 1);
  13.    <span style="color:#ff0000;">撤消这个走法;</span> 
  14.    if (vl >= vlBeta) {
  15.     <span style="color:#ff0000;">将这个走法记录到历史表中;</span>
  16.     return vlBeta;
  17.    }
  18.    if (vl > vlAlpha) {
  19.     <span style="color:#ff0000;">设置最佳走法;</span>
  20.     vlAlpha = vl;
  21.    }
  22.   }
  23.  }
  24.  if (没有走过任何走法) {                 //AI被将死
  25.   return 杀棋的分数;
  26.  }
  27.  将最佳走法记录到历史表中;
  28.  if (根节点) {
  29.   最佳走法就是电脑要走的棋;
  30.  }
  31.  return vlAlpha;
  32. }
int AlphaBeta(int vlAlpha, int vlBeta, int nDepth) {
 if (nDepth == 0) {
  return 局面评价函数;
 }
 生成全部走法;
 <span style="color:#ff0000;">按历史表排序全部走法;</span>
 for (每个生成的走法) {
  走这个走法;
  <span style="color:#ff0000;">if (被将军) {
   撤消这个走法;
  } else</span> {
   int vl = -AlphaBeta(-vlBeta, -vlAlpha, nDepth - 1);
   <span style="color:#ff0000;">撤消这个走法;</span> 
   if (vl >= vlBeta) {
    <span style="color:#ff0000;">将这个走法记录到历史表中;</span>
    return vlBeta;
   }
   if (vl > vlAlpha) {
    <span style="color:#ff0000;">设置最佳走法;</span>
    vlAlpha = vl;
   }
  }
 }
 if (没有走过任何走法) { //AI被将死
  return 杀棋的分数;
 }
 将最佳走法记录到历史表中;
 if (根节点) {
  最佳走法就是电脑要走的棋;
 }
 return vlAlpha;
}

这样,简单套用上一讲讲过的alpha-beta算法,就能搜索出相对来说最佳路径来~ ~ ~

最后设置坐标就可以实现AI自动走棋或吃子了

[转]象棋AI算法(二)的更多相关文章

  1. 象棋AI算法(二)

    原文大神是用html5+js写的关于象棋AI的博客,里面重点讲了棋子的着法,自己设计的评估函数和简单的Minmax理论,没有具体的讲搜索算法,本文是对原文的学习和分析补充 一,棋子的着法com.byl ...

  2. 象棋AI算法(一)

    最近想做一个象棋游戏,但是AI把我难住了.这是这几天的成果: 象棋程序通过使用“搜索”函数来寻找着法.搜索函数获得棋局信息,然后寻找对于程序一方来说最好的着法. 一,最小-最大搜索Minimax Se ...

  3. [转]象棋AI算法(一)

    本文转自:http://blog.csdn.net/u012723995/article/details/47133693 参考文献:http://www.xqbase.com/computer/se ...

  4. AI佳作解读系列(二)——目标检测AI算法集杂谈:R-CNN,faster R-CNN,yolo,SSD,yoloV2,yoloV3

    1 引言 深度学习目前已经应用到了各个领域,应用场景大体分为三类:物体识别,目标检测,自然语言处理.本文着重与分析目标检测领域的深度学习方法,对其中的经典模型框架进行深入分析. 目标检测可以理解为是物 ...

  5. 【中国象棋人机对战】引入了AI算法,学习低代码和高代码如何混编并互相调用

    以低代码和高代码(原生JS代码)混编的方式引入了AI算法,学习如何使用表达式调用原生代码的.整个过程在众触低代码应用平台进行,适合高阶学员. AI智能级别演示 AI算法分三个等级,体现出来的智能水平不 ...

  6. AI算法测评(二)--算法测试流程

    根据算法测试过程中遇到的一些问题和管理规范, 梳理出算法测试工作需要关注的一些点: 编号 名称 描述信息 备注 1 明确算法测试需求 明确测试目的 明确测试需求, 确认测试需要的数据及场景 明确算法服 ...

  7. 聊聊找AI算法岗工作

    https://blog.csdn.net/weixin_42137700/article/details/81628028 首先,本文不是为了增加大家的焦虑感,而是站在一名学生的角度聊聊找AI算法岗 ...

  8. 游戏人工智能 读书笔记 (四) AI算法简介——Ad-Hoc 行为编程

    本文内容包含以下章节: Chapter 2 AI Methods Chapter 2.1 General Notes 本书英文版: Artificial Intelligence and Games ...

  9. 浅析初等贪吃蛇AI算法

    作为小学期程序设计训练大作业的一部分,也是自己之前思考过的一个问题,终于利用小学期完成了贪吃蛇AI的一次尝试,下作一总结. 背景介绍: 首先,我针对贪吃蛇AI这一关键词在百度和google上尽心了检索 ...

随机推荐

  1. sublime 插件安装之sublime highlight 如何优雅拷贝代码到word

      首先:打开preference => Package Control,输入 Add Repository ,用它来为Sublime 添加插件安装源, https://github.com/n ...

  2. 【05】循序渐进学 docker:系统资源和网络

    写在前面的话 在上一篇学习 Dockerfile 的时候其实还有几个相当重要得关键中没有谈到,但没关系,在后面的内容会单独提出来一个一个的学习.这里就先谈谈关于资源的控制个容器的网络~ 资源限制 其实 ...

  3. Android应用-底部导航栏的使用

    目录 1. 设计底部导航栏页面 1.1. 创建必须的文件夹 1.2. 设计主页面 2. 设计逻辑函数 3. 项目展示 底部导航栏是基于Bottom Navigation Bar 插件使用的 这个插件包 ...

  4. VSM(Virtual Storage Manager) add new osd 代码分析

    vsm add new osd 流程 后台获取可用设备 | 选择可用设备及osd相关信息等 | 点击add按钮,把准备部署的osd信息添加到需要部署的item列表中 | 点击submit按钮,添加it ...

  5. idea maven新建struts2项目

    环境: IDEA java1.8 struts2-core  2.5.18 一路下一步,名字自己随便填, 项目建好后修改pom.xml文件,加入struts2-core 添加tomcat: +号添加w ...

  6. POJ - 2421 Constructing Roads (最小生成树)

    There are N villages, which are numbered from 1 to N, and you should build some roads such that ever ...

  7. [Maven实战-许晓斌]-[第二章]-2.7-2.8 Mave安装的最优建议和安装小结

    2.7

  8. DHCP应用案列

    环境:centos7 需求:让员工实现0配置即可接入网络,但公司内部的若干文件服务器和打印机服务器需要使用固定的ip 部署dhcp服务很简单,首先安装dhcp,yum -y install dhcp. ...

  9. centos下部署NFS

        一. NFS简介   NFS---Network File System:主要功能是通过网络让不同的linux主机系统间可以彼此共享文件和目录.NFS客户端可以通过挂载的方式将NFS服务器端共 ...

  10. The input file was not found

    错误位置: File file= new File("/report/_test/test.xls");Workbook wb1 = jxl.Workbook.getWorkboo ...