2012-05-04 3 views
1

Прежде всего, это часть дополнительной домашней домашней работы, поэтому, пожалуйста, не дайте мне ответа. Пожалуйста, просто помогите мне понять, где у меня может быть проблема с тем, что происходит. Это генератор Tic-Tac-Toe, где игра проходит рекурсивно, чтобы определить лучший ход, основанный на игроке. (Профессор использует белые «W» и черные «B» вместо X и O)Почему моя рекурсия не возвращается, но заканчивается переполнением стека?

Мой основной рекурсивный метод возвращает оценку состояния на основе входной позиции на плате TTT; 1, если белый заставит выиграть от этой позиции, 0, если это ничья, и -1, если черный заставит выиграть от этой позиции:

public int stateScore(boolean whiteMove, int[] BestMove) { 
    return stateScore(whiteMove,BestMove,TTTBoard); 
} 

который называет мой основной метод частной рекурсии:

private int stateScore(boolean whiteMove, int[] BestMove,char[][] TestBoard) { 
    char [][] newTestBoard = new char [3][3]; 
    for(int rowVal = 0; rowVal < 3; rowVal++){ 
     for(int colVal = 0; colVal < 3; colVal++){ 
      newTestBoard[rowVal][colVal] = TestBoard[rowVal][colVal]; 
     } 
    } 

    int [] bestMove = new int [2]; 

    for(int rowVal = 0; rowVal < 3; rowVal++){ 
     for(int colVal = 0; colVal < 3; colVal++){ 
      if(isFull(newTestBoard) == true){ 
       return 0; 
      } 
      else if(newTestBoard[rowVal][colVal] == '-'){ 
       bestMove[0] = rowVal; 
       bestMove[1] = colVal; 

       //if boolean is white 
       if(whiteMove == true){ 
        newTestBoard = testEntry(rowVal,colVal,'W',newTestBoard); 
        if(threeInRow(newTestBoard) == 1){ 
         return 1; 
        } 
        else if(threeInRow(newTestBoard) == 0 && isFull(newTestBoard) == true){ 
         return 0; 
        } 
        else if(threeInRow(newTestBoard) == -1 && isFull(newTestBoard) == true){ 
         return -1; 
        } 
        else{ 
         return stateScore(!whiteMove,bestMove,newTestBoard); 
        } 
       } 
       //if boolean is black 
       else{ 
        newTestBoard = testEntry(rowVal,colVal,'B',newTestBoard); 
        if(threeInRow(newTestBoard) == -1){ 
         return -1; 
        } 
        else if(threeInRow(newTestBoard) == 0 && isFull(newTestBoard) == true){ 
         return 0; 
        } 
        else if(threeInRow(newTestBoard) == 1 && isFull(newTestBoard) == true){ 
         return 1; 
        } 
        else{ 
         return stateScore(!whiteMove,bestMove); 
        } 
       } 
      } 
     } 
    } 
    return 0; 
} 

Логическое значение для whiteMove истинно, если оно является белым, а false, если оно черное. Вторичные методы в рамках функции включают threeInRow:

public int threeInRow(char[][] TTTBoard){ 
    boolean whiteIs = false; 
    boolean blackIs = false; 
     //Horizontal? 
     char [] colChar = new char [3]; 
     for(int rowVal = 0; rowVal < 3; rowVal ++){ 
      for(int colVal = 0; colVal < 3; colVal++){ 
       colChar[colVal] = TTTBoard[rowVal][colVal]; 
      } 
      if(colChar[0] == colChar[1] && colChar[1] == colChar[2]){ 
       if(colChar[0] == 'W'){ 
        whiteIs = true; 
       } 
       if(colChar[0] == 'B'){ 
        blackIs = true; 
       } 
      } 
     } 

     //Vertical? 
     char [] rowChar = new char [3]; 
     for(int colVal = 0; colVal < 3; colVal ++){ 
      for(int rowVal = 0; rowVal < 3; rowVal++){ 
       rowChar[colVal] = TTTBoard[rowVal][colVal]; 
      } 
      if(rowChar[0] == rowChar[1] && rowChar[1] == rowChar[2]){ 
       if(rowChar[0] == 'W'){ 
        whiteIs = true; 
       } 
       else if(rowChar[0] == 'B'){ 
        blackIs = true; 
       } 
      } 
     } 

     //Diagonal 
      //topLeft to bottomRight 
      if(TTTBoard[0][0] == TTTBoard[1][1] && TTTBoard[1][1] == TTTBoard[2][2]){ 
       if(TTTBoard[0][0] == 'W'){ 
        whiteIs = true; 
       } 
       else if(TTTBoard[0][0] == 'B'){ 
        blackIs = true; 
       } 
      } 

      //topRight to bottomLeft 
      if(TTTBoard[0][2] == TTTBoard[1][1] && TTTBoard[1][1] == TTTBoard [2][0]){ 
       if(TTTBoard[1][1] == 'W'){ 
        whiteIs = true; 
       } 
       else if(TTTBoard[1][1] == 'B'){ 
        blackIs = true; 
       } 
      } 


    //Return Vals 
    if(whiteIs == true && blackIs == true){ 
     return 0; 
    } 
    else if(blackIs == true && whiteIs == false){ 
     return -1; 
    } 
    else if(blackIs == false && whiteIs == true){ 
     return 1; 
    } 
    else if(blackIs == false && whiteIs == false){ 
     return 0; 
    } 
    else{ 
     return 0; 
    } 

} 

и testEntry:

public char[][] testEntry(int row,int col,char newChar, char[][] TestBoard){ 

    char [][] returnBoard = new char[3][3]; 
    for(int rowVal = 0; rowVal < 3; rowVal++){ 
     for(int colVal = 0; colVal < 3; colVal++){ 
      returnBoard[rowVal][colVal] = TestBoard[rowVal][colVal]; 
     } 
    } 
    returnBoard[row][col] = newChar; 
    return returnBoard; 

} 

Я не понимаю, где переполнение стека происходит из. Кажется, что мои возвращения охватывают все случаи и что мои методы имеют соответствующую доходность. Я никогда не использовал цикл for с рекурсией, я что-то испортил с этим. Кроме того, я правильно говорю, что type [] name = name (тот же тип) НЕ работает, не так ли? Вот почему я сделал цикл for в этом случае.

+0

Это много кода, пожалуйста, уменьшить его минимальная компиляционная привязка, которая все еще покрывает проблему. – amit

+0

Жаль не могу сопротивляться: странная игра. Единственный выигрышный ход - не играть. Как насчет хорошей игры в шахматы? – flolo

+0

Я второй Марко здесь, Зак. Не могли бы вы занять пару минут, чтобы просмотреть свои шесть предыдущих вопросов? У всех есть ответы (хотя в том случае, если вы считаете, что ответ не помог, не преминуть принять признание в конкретном случае). – halfer

ответ

4

В вашей черной ветке ваше возвращение неверно.

Вы возвращаетесь

return stateScore(!whiteMove,bestMove); 

который перезапускает рекурсию. Вы хотите вернуть

return stateScore(!whiteMove,bestMove,newTestBoard); 

Советы:

  • Исправьте булевы:

    if(whiteMove == true) -> if (whiteMove) 
    
  • Использование UpperCase для классов, lowerCamelCase для переменных.

  • Если вы вернетесь в ветку if, вам не понадобится другое.

    Вместо:

    if (condition) { 
        ... 
        return ...; 
    } 
    else 
    { 
        ... 
    } 
    

    Лучше написать:

    if (condition) { 
        ... 
        return ...; 
    } 
    ... 
    

    Сохраняет вложенности ниже и упрощает код, чтобы следовать.

  • Refactor общий код: Обе ветви возвращают один и тот же результат:

    return stateScore(!whiteMove,bestMove,newTestBoard); 
    

    Почему бы не перенести это снаружи, если (whiteMove)

+0

Большое спасибо, подсказки включены. –

+0

Где ты был всю мою жизнь. –

0

Опубликовать трассировку стека, но я бы сказал, что когда вы вызываете stateScore рекурсивно, вы получаете бесконечную рекурсию.