angular onDrop 上的 Ai chess.js 丑陋

问题描述

无法读取未定义的属性“移动”

你好,我目前正在用 Angular 制作一个国际象棋游戏

你好,我不能让人工智能工作,这件作品一直卡在老鼠身上

我目前使用 chess.js 和 chessboard 库 但问题是AI主要是用jquery写的

如果我评论那几行,这行得通,但 Ai 不行

onDrop: onDrop,onMouSEOutSquare: onMouSEOutSquare,onMouSEOverSquare: onMouSEOverSquare,onSnapEnd: onSnapEnd,

角度代码

import { Component,OnInit } from '@angular/core';
import * as ChessBoard from 'chessboardjs/www/js/chessboard';
declare var $: any;

declare var ChessBoard: any;
declare var Chess: any;
@Component({
  selector: 'app-chess',templateUrl: './chess.component.html',styleUrls: ['./chess.component.scss']
})
export class ChessComponent implements OnInit {
  board: any;
  game: any;

  constructor() { }



  ngOnInit() {
////////////////////////// 7


      let minimaxDepth = 2;
      initGame();

    function setDepth(depth){
      console.log("este es el "+depth);
      document.getElementById('difficulty').style.display = 'none';
      document.getElementById('chessboard').style.display = 'block';
      document.getElementById('restart').style.display = 'block';
      console.log(depth);
      minimaxDepth = depth;
    }

      function initGame(){
       //document.getElementById('chessboard').style.display = 'none';
        document.getElementById('gameover').style.display = 'none';
        document.getElementById('restart').style.display = 'none';
        document.getElementById('difficulty').style.display = 'block';

        $('.easy').click(function(){
          setDepth(0);
        });
        $('.medium').click(function(){
          setDepth(1);
        });
        $('.hard').click(function(){
          setDepth(2);
        });


      }


      $('.restartGame').click(function(){
        this.board.clear();
        this.board.start();
        this.game.reset();
        initGame();
      });



        // game = new Chess();
    this.game = new Chess();

      let removeGreySquares = function() {
        $('#chessboard .square-55d63').css('background','');
      };


      let greySquare = function(square) {
        let squareEl = $('#chessboard .square-' + square);

        let background = '#a9a9a9';
        if (squareEl.hasClass('black-3c85d') === true) {
          background = '#696969';
        }

        squareEl.css('background',background);
      };




      // uses the minimax algorithm with alpha beta pruning to caculate the best move
      let calculateBestMove = function() {

        let possibleNextMoves = this.game.moves();
        let bestMove = -9999;
        let bestMoveFound;

        for (let i = 0; i < possibleNextMoves.length; i++) {
          let possibleNextMove = possibleNextMoves[i];
          this.game.move(possibleNextMove);
          let value = minimax(minimaxDepth,-10000,10000,false);
          this.game.undo();
          if (value >= bestMove) {
            bestMove = value;
            bestMoveFound = possibleNextMove;
          }
        }
        return bestMoveFound;
      };


      // minimax with alhpha-beta pruning and search depth d = 3 levels
      let minimax = function(depth,alpha,beta,isMaximisingPlayer) {
        if (depth === 0) {
          return -evaluateBoard(this.game.board());
        }

        let possibleNextMoves = this.game.moves();
        let numPossibleMoves = possibleNextMoves.length;
        let bestMove = -9999;
        if (isMaximisingPlayer) {

          for (let i = 0; i < numPossibleMoves; i++) {
            this.game.move(possibleNextMoves[i]);
            bestMove = Math.max(bestMove,minimax(depth - 1,!isMaximisingPlayer));
            this.game.undo();
            alpha = Math.max(alpha,bestMove);
            if (beta <= alpha){
              return bestMove;
            }
          }

        } else {
          let bestMove = 9999;
          for (let i = 0; i < numPossibleMoves; i++) {
            this.game.move(possibleNextMoves[i]);
            bestMove = Math.min(bestMove,!isMaximisingPlayer));
            this.game.undo();
            beta = Math.min(beta,bestMove);
            if (beta <= alpha){
              return bestMove;
            }
          }
        }

        return bestMove;
      };


      // the evaluation function for minimax
      let evaluateBoard = function(board) {
        let totalEvaluation = 0;
        for (let i = 0; i < 8; i++) {
          for (let j = 0; j < 8; j++) {
            totalEvaluation = totalEvaluation + getPieceValue(board[i][j],i,j);
          }
        }
        return totalEvaluation;
      };


      let reverseArray = function(array) {
        return array.slice().reverse();
      };

      let whitePawnEval =
        [
          [0.0,0.0,0.0],[5.0,5.0,5.0],[1.0,1.0,2.0,3.0,1.0],[0.5,0.5,2.5,0.5],[0.0,-0.5,-1.0,-2.0,0.0]
        ];

      let blackPawnEval = reverseArray(whitePawnEval);

      let knightEval =
        [
          [-5.0,-4.0,-3.0,-5.0],[-4.0,-4.0],[-3.0,1.5,-3.0],[-5.0,-5.0]
        ];

      let whiteBishopEval = [
        [ -2.0,-2.0],[ -1.0,-1.0],[ -2.0,-2.0]
      ];

      let blackBishopEval = reverseArray(whiteBishopEval);

      let whiteRookEval = [
        [  0.0,[  0.5,[ -0.5,-0.5],[  0.0,0.0]
      ];

      let blackRookEval = reverseArray(whiteRookEval);

      let evalQueen = [
        [ -2.0,-2.0]
      ];

      let whiteKingEval = [

        [ -3.0,-5.0,[ -3.0,[  2.0,2.0 ],2.0 ]
      ];

      let blackKingEval = reverseArray(whiteKingEval);


      let getPieceValue = function(piece,x,y) {
        if (piece === null) {
          return 0;
        }

        let absoluteValue = getAbsoluteValue(piece,piece.color === 'w',y);

        if (piece.color === 'w'){
          return absoluteValue;
        } else {
          return -absoluteValue;
        }
      };


      let getAbsoluteValue = function(piece,isWhite,y) {
        if (piece.type === 'p') {
          return 10 + ( isWhite ? whitePawnEval[y][x] : blackPawnEval[y][x] );
        } else if (piece.type === 'r') {
          return 50 + ( isWhite ? whiteRookEval[y][x] : blackRookEval[y][x] );
        } else if (piece.type === 'n') {
          return 30 + knightEval[y][x];
        } else if (piece.type === 'b') {
          return 30 + ( isWhite ? whiteBishopEval[y][x] : blackBishopEval[y][x] );
        } else if (piece.type === 'q') {
          return 90 + evalQueen[y][x];
        } else if (piece.type === 'k') {
          return 900 + ( isWhite ? whiteKingEval[y][x] : blackKingEval[y][x] );
        }
      };


      let makeaimove = function() {
        let bestMove = calculateBestMove();
        this.game.move(bestMove);
        this.board.position(this.game.fen());
      };


      let onDrop = function(source,target) {
        removeGreySquares();

        // see if the move is legal
        var move = this.game.move({
          from: source,to: target,promotion: 'q'
        });

        // illegal move
        if (move === null) { return 'snapback'; }

        // make legal move for black AI player
        window.setTimeout(makeaimove,250);
      };


    var onMouSEOverSquare = function(square,piece) {
      // get list of possible moves for this square
      var moves = this.game.moves({
        square: square,verbose: true
      });

      // exit if there are no moves available for this square
      if (moves.length === 0) return;

      // highlight the square they moused over
      greySquare(square);

      // highlight the possible squares for this piece
      for (var i = 0; i < moves.length; i++) {
        greySquare(moves[i].to);
      }
    };

      let onMouSEOutSquare = function(square,piece) {
        removeGreySquares();
      };


      // update the board position after the piece snap
      // for castling,en passant,pawn promotion
      let onSnapEnd = function() {
        this.board.position(this.game.fen());
      };

     /* var cfg = {
        draggable: true,position: 'start',onDragStart: onDragStart,onDrop: onDrop,onSnapEnd: onSnapEnd
      };
      board = ChessBoard('board',cfg);*/


///////////////////////////////
      let config = {
      orientation: 'white',draggable: true,moveSpeed: 'fast',snapbackSpeed: 100,snapSpeed: 100,pieceTheme: 'img/chesspieces/wikipedia/{piece}.png',showNotation: false,onDragStart: this.onDragStart.bind( this )
    };


      this.board = new ChessBoard( 'chessboard',config );

      //this.game = new Chess();

      console.log('color of g5: ' + this.game.square_color('g5'));

     //this.board.move('e2-e4');

      this.updateStatus();

  }


  // do not pick up pieces if the game is over
  // only pick up pieces for White
/*
  var onDragStart = (source,piece,position,orientation) => {
    if (this.game.in_checkmate() === true || this.game.in_draw() === true || this.game.game_over() === true ) {
      $('#gameover').show();
      $("#gameover").html('Game over!');
      return false;
    }
  };
*/



  onDragStart(source,orientation) {
    if (this.game.in_checkmate() === true || this.game.in_draw() === true || this.game.game_over() === true ) {
      document.getElementById('gameover').style.display="block";
      $('#gameover').html('Game over!');
      return false;
    }
    /*// do not pick up pieces if the game is over
    if (this.game.game_over()) {return false};

    // only pick up pieces for the side to move
    if ((this.game.turn() === 'w' && piece.search(/^b/) !== -1) ||
      (this.game.turn() === 'b' && piece.search(/^w/) !== -1)) {
      return false
    };

    return true;*/
  }


  updateStatus() {
    let status = '';

    let moveColor = 'White';
    if (this.game.turn() === 'b') {
      moveColor = 'Black';
    }

    // checkmate?
    if (this.game.in_checkmate()) {
      status = 'Game over,' + moveColor + ' is in checkmate.';
    }

    // draw?
    else if (this.game.in_draw()) {
      status = 'Game over,drawn position';
    }

    // game still on
    else {
      status = moveColor + ' to move';

      // check?
      if (this.game.in_check()) {
        status += ',' + moveColor + ' is in check';
      }
    }

    console.log(status);
  }




/*
 dropOffBoard: 'snapback',// this is the default
      position: 'start'
* */
}
<div class=" alert alerta-game alert-warning alert-dismissible fade show" role="alert" >

  <p>
    <strong>Attention: </strong>this game is in development.
  </p>
</div>



<div class="menu" id="difficulty">
  <br>
  <h1>Select Difficulty:</h1>
  <hr><br>
  <button type="button" class="btn easy btn-success btn-xlarge">Easy</button>
  <br><br>
  <button type="button" class="btn medium btn-warning btn-xlarge">Medium</button>
  <br><br>
  <button type="button" class="btn hard btn-danger btn-xlarge">Hard</button>
</div>

<div id="chessboard" role="main"style="margin:0px auto; max-width: 600px;"></div>

<div id="gameover" class="alert alert-primary hide" role="alert"><strong></strong></div>
<div id="restart" class="restartGame">
  <button type="button" class="btn medium btn-danger btn-xlarge">Restart</button>
</div>

解决方法

似乎您刚刚在组件中复制粘贴了一个 Javascript 文件……好吧……这根本行不通。

  1. 尽量避免“getElementById”,这些是 Vanilla JS,而您可以使用响应式表单(Angular 方式)

  2. 您正在将“点击”事件作为普通 JS 处理,您应该使用 Angular 方法,通过附加到元素的方法,该方法在用户在视图中执行“点击”时执行。

  3. 同样的情况发生在你的“onDrag”和“orDrop”......等等。

  4. 不要使用匿名函数,而是使用粗箭头“=>”,这样可以避免绑定 this(大多数情况下)。

TLTR; Vanilla JS 如果你只是把它的代码扔到 ngOnInit 方法中是行不通的。你需要调整代码,主要是关于事件控制和视图重绘的逻辑。似乎您正在尝试移植/包装一个主要用于事件控制和视图渲染的 JS 库......(除了 2-3 个 AI 方法)所以这并不容易。