本文转自: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. }
  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. }

算法分析:

分别向上,下,左,右四个方向搜索,若找到一个点且颜色与该棋子不同(敌对棋子),则将该点坐标记录在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. ];
  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. ];

这里的字符串代表每个棋子的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. }
  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.  
  10. "C0":"C","C1":"C",
  11. "M0":"M","M1":"M",
  12. "X0":"X","X1":"X",
  13. "S0":"S","S1":"S",
  14. "J0":"J",
  15. "P0":"P","P1":"P",
  16. "Z0":"Z","Z1":"Z","Z2":"Z","Z3":"Z","Z4":"Z","Z5":"Z",
  17. }

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. }
  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.  
  20. return d;
  21. }

算法分析:

当马处于一点时,可以走的最多情况有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. }
  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. }

算法分析:

因为相不能过河,所以要按颜色分情况讨论(不同颜色,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. }
  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.  
  24. }

算法分析:

士不能出九宫格,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. }
  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.  
  13. if (my===1){ //红方
  14. //下
  15. if ( y+1<= 9 && (!com.mans[map[y+1][x]] || com.mans[map[y+1][x]].my!=my)) d.push([x,y+1]);
  16. //上
  17. if ( y-1>= 7 && (!com.mans[map[y-1][x]] || com.mans[map[y-1][x]].my!=my)) d.push([x,y-1]);
  18. //老将对老将的情况
  19. if ( com.mans["j0"].x == com.mans["J0"].x &&isNull) d.push([com.mans["J0"].x,com.mans["J0"].y]); //x相等,且中间为空,push黑将的坐标
  20.  
  21. }else{
  22. //下
  23. if ( y+1<= 2 && (!com.mans[map[y+1][x]] || com.mans[map[y+1][x]].my!=my)) d.push([x,y+1]);
  24. //上
  25. if ( y-1>= 0 && (!com.mans[map[y-1][x]] || com.mans[map[y-1][x]].my!=my)) d.push([x,y-1]);
  26. //老将对老将的情况
  27. if ( com.mans["j0"].x == com.mans["J0"].x &&isNull) d.push([com.mans["j0"].x,com.mans["j0"].y]); //push红帅的坐标
  28. }
  29. //右
  30. if ( x+1<= 5 && (!com.mans[map[y][x+1]] || com.mans[map[y][x+1]].my!=my)) d.push([x+1,y]);
  31. //左
  32. if ( x-1>= 3 && (!com.mans[map[y][x-1]] || com.mans[map[y][x-1]].my!=my))d.push([x-1,y]);
  33. return d;
  34. }

算法分析:

将除了颜色不同导致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. }
  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. }

算法分析:

跟车一样,需要向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. }
  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.  
  19. return d;
  20. }

算法分析:

同样分情况讨论。且由于卒不能后退所以只用判断上,左,右三种情况。而卒由于过河后才能左右移动,所以左右的判断除了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. }
  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.  
  8. for (var i=0; i < moves.length; i++) {</span>
  9.  
  10.    //走这个走法;
  11. var move= moves[i];
  12. var key = move[4];
  13. var oldX= move[0];
  14. var oldY= move[1];
  15. var newX= move[2];
  16. var newY= move[3];
  17. var clearKey = map[ newY ][ newX ]||"";
  18.  
  19. map[ newY ][ newX ] = key; //走,赋新值,删除旧值
  20. delete map[ oldY ][ oldX ];
  21. play.mans[key].x = newX;
  22. play.mans[key].y = newY;
  23.  
  24.   <span style="color:#ff0000;">if (clearKey=="j0"||clearKey=="J0") { //被吃老将
  25. play.mans[key] .x = oldX;
  26. play.mans[key] .y = oldY;
  27. map[ oldY ][ oldX ] = key;
  28. delete map[ newY ][ newX ]; //并不是真的走,所以这里要撤销
  29. if (clearKey){
  30. map[ newY ][ newX ] = clearKey;
  31.  
  32. }
  33.  
  34. return {"key":key,"x":newX,"y":newY,"value":8888};
  35. </span>
  36.   }else {
  37.    var val = -AI.getAlphaBeta(-B, -A, depth - 1, map , -my).value; //上面代表AI,这里倒置,-my,代表人的着法,然后再从上面开始执行
  38. //val = val || val.value;
  39.  
  40.    //<span style="color:#ff0000;">撤消这个走法; 
  41. play.mans[key] .x = oldX;
  42. play.mans[key] .y = oldY;
  43. map[ oldY ][ oldX ] = key;
  44. delete map[ newY ][ newX ];
  45. if (clearKey){
  46. map[ newY ][ newX ] = clearKey;
  47. //play.mans[ clearKey ].isShow = true;
  48. }</span>
  49.    if (val >= B) {
  50. //将这个走法记录到历史表中;
  51. //AI.setHistoryTable(txtMap,AI.treeDepth-depth+1,B,my);
  52. return {"key":key,"x":newX,"y":newY,"value":B};
  53. }
  54. <span style="color:#ff0000;">if (val > A) {
  55.      A = val; //设置最佳走法,
  56. if (AI.treeDepth == depth) var rootKey={"key":key,"x":newX,"y":newY,"value":A};
  57. } </span>
  58. }
  59.   }
  60.  
  61. if (AI.treeDepth == depth) {//已经递归回根了
  62. if (!rootKey){
  63. //AI没有最佳走法,说明AI被将死了,返回false
  64. return false;
  65. }else{
  66. //这个就是最佳走法;
  67. return rootKey;
  68. }
  69. }
  70.  return {"key":key,"x":newX,"y":newY,"value":A};
  71. }

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

  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. }
  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. }

这样,简单套用上一讲讲过的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. 也说AOP

    前言 1.引言 2.Aop概念 3.Aop实践 4.总结 一.引言 对于初入行的小白来讲,aop,ioc这两个程序设计思想总是傻傻分不清,不知道是个什么东东?别人再一谈各种框架更是云里雾里...博主今 ...

  2. HttpWebRequest(System.Net)模拟HTTP发送POST

    相关参考网上很多,但需要理解并转成自己的情况 public static string HttpWebRequestPost(string url, string param) { HttpWebRe ...

  3. django 返回json

    django返回json有以下三个版本 from django.http import HttpResponse import json from django.views import View f ...

  4. 开发.NET Core NuGet包并实现CI/CD

    实际开发中我们需要对一些公共类库进行开发,并基于Jenkins进行CI/CD(CI:持续集成,CD:持续部署),其他项目通过NuGet引用.上文讲述了如何搭建本地NuGet服务器并发布NuGet包,这 ...

  5. [Perl]Windows 系统 Unicode 文件名操作(新建、重命名、枚举、复制)全攻略

    [Perl] Windows 系统 Unicode 文件名操作(新建.重命名.枚举.复制)全攻略 环境 XP/WIN7 Perl v5.16 编辑整理:PerlMonk.523066680 常见的那些 ...

  6. Chat Order (map映射)

     Chat Order Time Limit:3000MS     Memory Limit:262144KB     64bit IO Format:%I64d & %I64u Submit ...

  7. 洛谷P2462 [SDOI2007]游戏(哈希+最长路)

    题面 传送门 题解 我们把字符的出现次数哈希起来,然后把每个点向能在它之后的点连边.那么这显然是一个\(DAG\),直接求最长路就行了 //minamoto #include<bits/stdc ...

  8. SP16549 QTREE6 - Query on a tree VI(LCT)

    题意翻译 题目描述 给你一棵n个点的树,编号1~n.每个点可以是黑色,可以是白色.初始时所有点都是黑色.下面有两种操作请你操作给我们看: 0 u:询问有多少个节点v满足路径u到v上所有节点(包括)都拥 ...

  9. [Objective-C语言教程]变量(6)

    变量是程序可以操作的存储区域的名称. Objective-C中的每个变量都有一个特定的类型,它决定了变量内存的大小和布局; 可存储在内存中的值的范围; 以及可以应用于变量的操作集. 变量的名称可以由字 ...

  10. Ionic2实战——按模块划分app 创建多module

    http://www.jianshu.com/p/d94324b722af 背景 用ionic2开发过一两个小功能的朋友都会发现,每新建一个页面都需要在\src\app\app.module.ts中添 ...