Минимаксная проблема с обрезкой альфа-бета Java в Connect 4 Game - PullRequest
0 голосов
/ 28 января 2020

Я разрабатываю игру connect 4 с javafx для экзамена в университете, используя минимаксный алгоритм с отсечкой альфа-бета ... но иногда cra sh (возвращая значение столбца -1), и алгоритм кажется глупым

Здесь алгоритмы: (aBoard - это матрица доски (6x7), а фигуры 1 для игрока и 2 для процессора)

Здесь минимакс:

private int[] minimax_alpha_beta(int [][] aBoard,int iDepth, int iAlpha, int iBeta, boolean bMaximize) 
{
    ArrayList<Integer> aValidLocations = getValidLocations(aBoard);
    int aClonedMatrix[][];
    int iValue;
    int iNewScore;
    int iBestColumn;
    int aReturnValue[] = new int[2];
    aReturnValue[0] = -1;
    int iGameOver = _oGameClass.getGameOver(aBoard);
    if (iGameOver != 0) 
    {
        if (iGameOver == PLAYER_PIECE) 
        {
            aReturnValue[1] = -1000000; 
            return aReturnValue;
        }else if (iGameOver == AI_PIECE) 
        {
            aReturnValue[1] = 1000000; 
            return aReturnValue;
        }else 
        {
            aReturnValue[1] = 0; 
            return aReturnValue;
        }
    }else if (iDepth == 0) 
    {
        aReturnValue[1] = getScore(aBoard, AI_PIECE);
        return aReturnValue;
    }


    if (bMaximize) 
    {
        iValue = Integer.MIN_VALUE;
        iBestColumn = aValidLocations.get(0);
        for (int i = 0;i<aValidLocations.size();i++) 
        {
            int iRow = _oGameClass.getFirstFreeCellInAColumn(aBoard, aValidLocations.get(i));
            if (iRow != -1) 
            {
                aClonedMatrix = aBoard.clone();
                aClonedMatrix[aValidLocations.get(i)][iRow] = AI_PIECE;
                iNewScore = minimax_alpha_beta(aClonedMatrix,iDepth-1, iAlpha, iBeta, false)[1];
                if (iNewScore > iValue) 
                {
                    iValue = iNewScore;
                    iBestColumn = aValidLocations.get(i);
                }
                iAlpha = Math.max(iAlpha, iValue);
                if (iAlpha >= iBeta)
                    break;
            }
        }
        aReturnValue[0] = iBestColumn;
        aReturnValue[1] = iValue;
        return aReturnValue;
    }else 
    {
        iValue = Integer.MAX_VALUE;
        iBestColumn = aValidLocations.get(0);
        for (int i = 0;i<aValidLocations.size();i++) 
        {
            int iRow = _oGameClass.getFirstFreeCellInAColumn(aBoard, aValidLocations.get(i));
            if (iRow != -1) 
            {
                aClonedMatrix = aBoard.clone();
                aClonedMatrix[aValidLocations.get(i)][iRow] = PLAYER_PIECE;
                iNewScore = minimax_alpha_beta(aClonedMatrix,iDepth-1, iAlpha, iBeta, true)[1];
                if (iNewScore < iValue) 
                {
                    iValue = iNewScore;
                    iBestColumn = aValidLocations.get(i);
                }
                iBeta = Math.min(iBeta, iValue);
                if (iAlpha >= iBeta)
                    break;
            }
        }
        aReturnValue[0] = iBestColumn;
        aReturnValue[1] = iValue;
        return aReturnValue;
    }
}

Функция оценки:

private int getScore(int[][] aBoard,int iPiece) 
{
    int iScore = 0;
    int aWindowArray[] = new int[4];

    int aCenterColumn[] = new int[7];

    for (int i=0;i<7;i++) 
    {
        aCenterColumn[i] = aBoard[2][i]; 
    }

    iScore+= getOccurrencesInIntArray(aCenterColumn, iPiece) * 3;

    for (int i=0;i<7;i++) 
    {
        aCenterColumn[i] = aBoard[3][i]; 
    }

    iScore+= getOccurrencesInIntArray(aCenterColumn, iPiece) * 3;

    //Check Horizontal
    int aRowArray[] = new int[6];
    for (int j=0;j<7;j++) 
    {
        for (int i=0;i<6;i++) 
        {
            aRowArray[i] = aBoard[i][j];
        }
        for (int i=0; i<3;i++) 
        {
            aWindowArray[0] = aBoard[i][j];
            aWindowArray[1] = aBoard[i+1][j];
            aWindowArray[2] = aBoard[i+2][j];
            aWindowArray[3] = aBoard[i+3][j];

            iScore += getValueFromWindow(aWindowArray, iPiece);
        }
    }

    //Check Vertical
    int aColumnArray[] = new int[7];
    for (int i=0;i<6;i++) 
    {
        for (int j=0;j<7;j++) 
        {
            aColumnArray[j] = aBoard[i][j];
        }
        for (int j=0;j<4;j++) 
        {
            aWindowArray[0] = aBoard[i][j];
            aWindowArray[1] = aBoard[i][j+1];
            aWindowArray[2] = aBoard[i][j+2];
            aWindowArray[3] = aBoard[i][j+3];

            iScore += getValueFromWindow(aWindowArray, iPiece);
        }
    }


    //Check Diagonal Up Right
    ArrayList<Integer> aDiagonalUpRightArray = new ArrayList<>();
    for (int k = 0; k<= (6+7-2); k++)
    {
      for (int j = 0; j<= k; j++)
      {
        int i= k-j;
        if (i < 6 && j < 7)
        {
            aDiagonalUpRightArray.add(aBoard[i][j]);
        }
      }
      if (aDiagonalUpRightArray.size() >= 4) 
      {
          for (int j=0;j<3;j++) 
          {
              if (j+3 < aDiagonalUpRightArray.size()) 
              {
                  aWindowArray[0] = aDiagonalUpRightArray.get(j);
                  aWindowArray[1] = aDiagonalUpRightArray.get(j+1);
                  aWindowArray[2] = aDiagonalUpRightArray.get(j+2);
                  aWindowArray[3] = aDiagonalUpRightArray.get(j+3);

                  iScore += getValueFromWindow(aWindowArray, iPiece);
              }
          }
      }
      aDiagonalUpRightArray.clear();
    }

    //Check Diagonal UpLeft

    ArrayList<Integer> aDiagonalUpLeftArray = new ArrayList<>();
    int aMatrixDiagonal2[][] = new int[7][6];
    for (int i = 0;i < 6; i++)
    {
      for (int j =0; j<7;j++)
      {
        aMatrixDiagonal2[j][6-1-i] = aBoard[i][j];
      }
    }

    for (int k = 0; k<= (6+7-2); k++)
    {
      for (int j = 0; j<= k; j++)
      {
        int i= k-j;
        if (i < 7 && j < 6)
        {
            aDiagonalUpLeftArray.add(aMatrixDiagonal2[i][j]);
        }
      }
      if (aDiagonalUpLeftArray.size() >= 4) 
      {
          for (int j=0;j<3;j++) 
          {
              if (j+3 < aDiagonalUpLeftArray.size()) 
              {
                  aWindowArray[0] = aDiagonalUpLeftArray.get(j);
                  aWindowArray[1] = aDiagonalUpLeftArray.get(j+1);
                  aWindowArray[2] = aDiagonalUpLeftArray.get(j+2);
                  aWindowArray[3] = aDiagonalUpLeftArray.get(j+3);

                  iScore += getValueFromWindow(aWindowArray, iPiece);
              }
          }
      }
      aDiagonalUpLeftArray.clear();
    }


    return iScore;
}

getValueFromWindow ()

    private int getValueFromWindow(int[] aWindow, int iPiece) 
{
    int iScore = 0;
    int iOpponentPiece = PLAYER_PIECE;
    if (iPiece == PLAYER_PIECE)
        iOpponentPiece = AI_PIECE;

    if (getOccurrencesInIntArray(aWindow, iPiece) == 4) 
        iScore += 100;
    else if (getOccurrencesInIntArray(aWindow, iPiece) == 3 && getOccurrencesInIntArray(aWindow, EMPTY) == 1)
        iScore += 5;
    else if (getOccurrencesInIntArray(aWindow, iPiece) == 2 && getOccurrencesInIntArray(aWindow, EMPTY) == 2)
        iScore += 2;

    if (getOccurrencesInIntArray(aWindow, iOpponentPiece) == 3 && getOccurrencesInIntArray(aWindow, EMPTY) == 1)
        iScore -= 4;

    return iScore;
}

getValidLocations ()

private ArrayList<Integer> getValidLocations(int [][] aBoard)
{
    ArrayList<Integer> aList = new ArrayList<>();

    for (int i=0;i<6;i++) 
    {
        if (_oGameClass.getFirstFreeCellInAColumn(aBoard, i) != -1) 
        {
            aList.add(i);
        }
    }

    return aList;
}

getFirstFreeCellInAColumn ()

public int getFirstFreeCellInAColumn(int[][] aBoard,int iColumn) 
{
    int iCell = 6;
    while (iCell != -1) 
    {
        if (aBoard[iColumn][iCell] == 0) 
            return iCell;
        iCell--;
    }
    return -1;
}

getGameOver ( )

public int getGameOver(int[][] aPrimitiveBoard) //Check GameOver 0 = Not Ended / 1 = Player Win / 2 = CpuWin / 3 = Tie.
{   
    boolean bDraw = true;

    for (int i=0;i<6;i++) 
    {
        for (int j=0;j<7;j++) 
        {
            if (aPrimitiveBoard[i][j] != 0 && (
                    verticalCheckGameOver(aPrimitiveBoard[i][j], aPrimitiveBoard[i], j) != 0 ||
                    horizontalCheckGameOver(aPrimitiveBoard[i][j], aPrimitiveBoard, i, j) != 0 ||
                    diagonalUpLeftCheckGameOver(aPrimitiveBoard[i][j], aPrimitiveBoard, i, j) != 0 ||
                    diagonalUpRightCheckGameOver(aPrimitiveBoard[i][j], aPrimitiveBoard, i, j) != 0)) 
            {
                return aPrimitiveBoard[i][j];
            }
        }
    }

    for (int i=0;i<6;i++) 
    {
        for (int j=0;j<7;j++) 
        {
            if (aPrimitiveBoard[i][j] == 0) 
            {
                bDraw = false;
                break;
            }
        }
        if (!bDraw)
            break;
    }

    if (bDraw)
        return 3;


    return 0;
}
...