优化点线博弈

Optimization dots&line game

提问人:A TECH 提问时间:11/11/2023 最后编辑:Professor AbronsiusA TECH 更新时间:11/11/2023 访问量:23

问:

我刚刚用 minimax 算法构建了点和线游戏,用户可以在其中玩 AI,但不幸的是,即使在深度 4 中也太慢了。那么有什么优化技术吗?

这里我的代码,

class Maze {
  constructor(gridX, gridY, sideSize) {
    this.board = Array.from({ length: gridY }, 
        (a) => a = Array.from({ length: gridX },
        (b) => b = Array.from({ length: 4 }, 
        c => c = 0)
    ));
    this.visited = [];
    this.gap = Math.floor(sideSize / 8);
    this.x = gridX;
    this.y = gridY;
    this.winPointX = 0;
    this.winPointY = 0;
    this.row = gridX * this.gap;
    this.column = gridY * this.gap;
    this.sideSize = sideSize;
  };
  drawGrid(ctx) {
    console.log(this.row, this.column)
    ctx.clearRect(0, 0, canv.width, canv.height);
    for (let x = 0; x < this.row; x += this.x)
      for (let y = 0; y < this.column; y += this.y) {
        ctx.fillStyle = 'red';
        ctx.fillRect(x * this.gap, y * this.gap, this.gap, this.gap);
      }
  };

  ai(depth, alpha, beta, player, advantage, y, x, tile_Y, tile_X) {
    if (y !== undefined && x !== undefined) {
      let winPoint = this.boxForm(y, x)
      if (tile_X > -1 && tile_X < 8 && tile_Y > -1 && tile_Y < 8) {
        winPoint = winPoint || this.boxForm(tile_Y, tile_X)
      }


      if (winPoint && player == 'O') {
        player = 'X';
        advantage += 10
      } else if (winPoint && player == 'X') {
        player = 'O';
        advantage -= 10;
        // console.log('Human bonus',y,x)
      }
    }


    if (depth === 0) {
      return {
        score: advantage
      }
    }

    var pieceArr = [];

    for (var i = 0; i < this.board.length; i++) {
      for (var j = 0; j < this.board[0].length; j++) {
        for (let b = 0; b < 4; b++) {
          if (this.board[i][j][b]) {
            continue;
          };
          let tileX = j;
          let tileY = i;
          let best = {}
          this.change(i, j, b)
          best.bestmove = [i, j, b];
          let neghdir;
          if (b == 2) {
            neghdir = 0;
            tileX++
          } else if (b == 0) {
            neghdir = 2;
            tileX--
          } else if (b == 3) {
            neghdir = 1;
            tileY--
          } else {
            neghdir = 3;
            tileY++
          };
          if (tileX > -1 && tileX < 8 && tileY > -1 && tileY < 8) {
            this.change(tileY, tileX, neghdir);
          }
          var g = this.ai(depth - 1, alpha, beta, player == 'X' ? 'O' : 'X', advantage, i, j, tileY, tileX);

          /*     if (tileX>-1&&tileX<8&&tileY>-1&&tileY<8) {
                if (this.boxForm(i,j)||this.boxForm(tileY,tileX)) {
                 console.log(player,tileX,tileY,i,j,depth)
                }
               } */
          best.score = g.score;

          if (player === 'X') {
            if (best.score > alpha) {
              alpha = best.score;
            }
          } else {
            if (best.score < beta) {
              beta = best.score
            }
          };
          if (tileX > -1 && tileX < 8 && tileY > -1 && tileY < 8) {
            this.board[tileY][tileX][neghdir] = 0;
          }
          this.board[i][j][b] = 0;
          pieceArr.push(best)

          if (alpha >= beta) {
            break;
          }
        }
      }
    };
    pieceArr.sort((a, b) => {
      return Math.random() - 0.5;
    })
    var bestMove;
    if (player === 'X') {
      var bestScore = -10000;
      for (var i = 0; i < pieceArr.length; i++) {
        if (pieceArr[i].score > bestScore) {
          bestScore = pieceArr[i].score;
          bestMove = i;
        }
      }
    } else {
      var bestScore = 10000;
      for (var i = 0; i < pieceArr.length; i++) {
        if (pieceArr[i].score < bestScore) {
          bestScore = pieceArr[i].score;
          bestMove = i;
        }
      }
    }
    return pieceArr[bestMove];
  };
  rmSide(side, dir, col) {
    let vertex;
    if (dir == 'w') {
      vertex = [side[0] * this.x, this.y * side[1]];
    } else if (dir == 'e') {
      vertex = [(side[0] + 1) * this.x, this.y * side[1]];
    } else if (dir == 'n') {
      vertex = [this.x * side[1], (side[0]) * this.y];
    } else if (dir == 's') {
      vertex = [this.x * (side[1] + 1), (side[0]) * this.y];
    }
    if (!vertex) {
      return null
    }

    let x = vertex[0];
    for (let y = vertex[1] + 1; y < vertex[1] + this.y; y++) {
      ctx.fillStyle = col;
      if (dir == 'n' || dir == 's') {
        ctx.fillRect((y) * this.gap, (x) * this.gap, this.gap, this.gap);
      } else {
        ctx.fillRect((x) * this.gap, (y) * this.gap, this.gap, this.gap);
      }
    };
  }
  change(y, x, dir, player) {
    this.board[y][x][dir] = 'X';
  }
  boxForm(y, x) {
    for (let i = 0; i < 4; i++) {
      if (!this.board[y][x][i]) {
        return false
      }
    };
    return true
  }
};






//dots and line
const canv = document.getElementById('canv');
const ctx = canv.getContext('2d');
const size = Math.min(window.innerWidth, window.innerHeight) * 0.7;
canv.width = size;
canv.height = size
const sideSize = size / 8;
console.log(sideSize)
let turn = 'X'

const maze = new Maze(8, 8, sideSize);
maze.drawGrid(ctx);





function mve(tileX, tileY, dir, player) {
  if (tileX < 8 && tileY > -1 && tileX > -1 && tileY < 8) {
    turn = player == 'O' ? 'X' : 'O'

    let n = null;
    if (dir == 'n') {
      n = 3
    } else if (dir == 's') {
      n = 1
    } else if (dir === 'e') {
      n = 2
    } else {
      n = 0
    }

    if (dir) {

      maze.rmSide([tileX, tileY], dir, player == 'O' ? 'yellow' : 'blue');
      maze.change(tileY, tileX, n);
      if (maze.boxForm(tileY, tileX)) {
        turn = player;
      }
      let neghdir;
      if (n == 2) {
        neghdir = 0;
        tileX++
      } else if (n == 0) {
        neghdir = 2;
        tileX--
      } else if (n == 3) {
        neghdir = 1;
        tileY--
      } else {
        neghdir = 3;
        tileY++
      };
      if (tileX > -1 && tileX < 8 && tileY > -1 && tileY < 8) {
        maze.change(tileY, tileX, neghdir);
        if (maze.boxForm(tileY, tileX)) {
          turn = player;
        }
      };
      if (turn == "O") {
        console.log(maze.board)
        playAI()
      }
    }
  }
}




function playAI() {

  let aimove = maze.ai(4, -Infinity, Infinity, 'X', 0);
  let dir1 = undefined;
  if (aimove.bestmove[2] == 0) {
    dir1 = 'w'
  } else if (aimove.bestmove[2] == 1) {
    dir1 = 's'
  } else if (aimove.bestmove[2] == 2) {
    dir1 = 'e'
  } else {
    dir1 = 'n'
  };
  console.log(aimove)
  mve(aimove.bestmove[1], aimove.bestmove[0], dir1, 'O')
}

canv.addEventListener('click', (e) => {
  const rect = canv.getBoundingClientRect()
  let tileX = Math.floor((e.clientX - rect.x) / sideSize);
  let tileY = Math.floor((e.clientY - rect.y) / sideSize);
  let dir = prompt('direction');

  mve(tileX, tileY, dir, 'X');
});
<canvas id='canv'></canvas>

HTML CSS 节点.js

评论


答: 暂无答案