【问题标题】:How can I convert my `winnerCheck` function to work recursively? - C如何将我的 `winnerCheck` 函数转换为递归工作? - C
【发布时间】:2019-04-24 08:16:30
【问题描述】:

问题:我很难建立对递归的理解(学习缓慢),每当我负责创建 recursive 函数时,我总是通过 @987654322 创建它@ 第一的。

然后我尽我所能达到递归的一些基本规则,但通常最终感觉有点筋疲力尽。

我要做的就是将我的 winnerCheck 函数转换为工作 recursively

另外,我听说使用global variables 是不受欢迎的。这是真的?我应该将我的数组square 移动到本地工作吗?

感谢您提供的任何指导和意见。

代码:

#include<stdio.h>
#include<conio.h>

char square[10] = {'o', '1', '2', '3', '4', '5', '6', '7', '8', '9'};

int winnerCheck();

void board();

int main() {

    /*
    char board[3][3] = {
    };

    printf("\t|\t|\t\n");
    printf("\t|\t|\t\n");
    printf("________|_______|________\n");
    printf("\t|\t|\t\n");
    printf("\t|\t|\t\n");
    printf("________|_______|________\n");
    printf("\t|\t|\t\n");
    printf("\t|\t|\t\n");
    printf("\t|\t|\t\n");

*/

    int player = 1, i, choice;
    char mark;
    do {
        board();
        player = player % 2 ? 1 : 2;

        printf("Player %d, enter a number: ", player);
        scanf("%d", &choice);

        //mark = (player == 1) ? 'X' : 'O';

        if (player == 1) {
            mark = 'X';
        } else {
            mark = '0';
        }

        if (choice == 1)
            square[1] = mark;
        else if (choice == 2)
            square[2] = mark;
        else if (choice == 3)
            square[3] = mark;
        else if (choice == 4)
            square[4] = mark;
        else if (choice == 5)
            square[5] = mark;
        else if (choice == 6)
            square[6] = mark;
        else if (choice == 7)
            square[7] = mark;
        else if (choice == 8)
            square[8] = mark;
        else if (choice == 9)
            square[9] = mark;


        i = winnerCheck();
        player++;
    } while (i == -1);
    board();

    if (i == 1)
        printf("==>\aPlayer %d win ", --player);
    else
        printf("==>\aGame draw");
    getch();

    return 0;
}

int winnerCheck() {
    if (square[1] == square[2] && square[2] == square[3])
        return 1;
    else if (square[4] == square[5] && square[5] == square[6])
        return 1;
    else if (square[7] == square[8] && square[8] == square[9])
        return 1;
    else if (square[1] == square[4] && square[4] == square[7])
        return 1;
    else if (square[2] == square[5] && square[5] == square[8])
        return 1;
    else if (square[3] == square[6] && square[6] == square[9])
        return 1;
    else if (square[1] == square[5] && square[5] == square[9])
        return 1;
    else if (square[3] == square[5] && square[5] == square[7])
        return 1;
    else if (square[1] != '1' && square[2] != '2' && square[3] != '3' && square[4]
                                                                         != '4' && square[5] != '5' &&
             square[6] != '6' && square[7] != '7' && square[8]
                                                     != '8' && square[9] != '9')
        return 0;
    else
        return -1;

}

void board() {
    printf("\n\n\tTic Tac Toe\n\n");
    printf("Player 1 (X) - Player 2 (O)\n\n\n");

//prints the board after every input

    printf("    |     |    \n");
    printf("  %c |  %c  |  %c  \n", square[1], square[2],square[3]);
    printf("____|_____|____\n");
    printf("    |     |    \n");
    printf("  %c |  %c  |  %c  \n", square[4], square[5],square[6]);
    printf("____|_____|____\n");
    printf("    |     |    \n");
    printf("  %c |  %c  |  %c  \n", square[7], square[8],square[9]);
    printf("    |     |    \n");
}

【问题讨论】:

  • 为什么要递归?我看不出有什么特别的理由来做这个递归。
  • 这不是一个尝试递归解决的好问题。递归主要用于嵌套结构。例如,如果您正在搜索一个文件,您可能会调用一个函数来扫描目录以查找它。如果该函数在其中看到一个目录,该函数也会调用自身来检查该目录。对于平面数组,您几乎总是要使用迭代;递归方法通常没有意义。
  • @Broman 不幸的是,这是一个分配要求......我认为这也没有多大意义。
  • 你首先必须想出一个递归算法。我认为您正试图在一条直线上找到三个具有相同值的正方形。所以,1)检查当前方块的值,2)然后递归检查所有相邻方块的值,3)然后检查下一个相邻方块的值,方向与步骤 2 相同。你看过这样做吗?
  • @contrapants 我完全同意,但这是一个分配要求,所以我必须确保递归适合该函数。

标签: c recursion iteration global-variables


【解决方案1】:

winnerCheck 函数测试是否满足任何可能的获胜条件。这包括检查某些三元组是否都由同一玩家提交。

您可以用所有保证获胜的三元组对数组进行硬编码。然后检查是否获胜意味着遍历该数组,这可以很容易地递归完成。

编辑

所以有 8 个可能的“获胜位置”三元组,例如,您可以声明为,

const int numwinpos = 8;

const int winpos[8][3] = {{1,2,3},
                          {4,5,6},
                          {7,8,9},
                          {1,4,7},
                          {2,5,8},
                          {3,6,9},
                          {1,5,9},
                          {3,5,7}};

这里的递归检查过程是一个示例,用于检查大小为n 的向量v 的任何元素是否满足属性p

// returns -1 if no v[i] satisfies p
// returns  i if v[i] satisfies p (picks largest i)
// (i>=0) and (i<n)

int recTest(const int v[], const int n){

  if( (n>0) && (!p(v[n-1])) )
    return recTest(v,n-1);
  else
    return n-1;
}

EDIT2:

所以winnersCheck 可以是这样的形式,

int winnerCheck(char square[], int winseq[][3], int n){
  // there's n winning sequences to test, 0 .. n-1
  // let's check sequence n-1
  int pos0 = winseq[n-1][0];
  int pos1 = winseq[n-1][1];
  int pos2 = winseq[n-1][2];
  if( (n>0) && !(squares in positions pos1, pos2 and pos2 marked by same player) )

    // game does not contain winning sequence n-1
    // so test the other n-1 positions, i.e. 0 .. n-2 
    return winnerCheck(square,winseq,n-1);  
  else
    // either n = 0 and there's no more positions to test 
    // or game contains winning sequence n-1 
    return n-1;
}

当然,您需要填写的条件可能有点大,无法内联 if。您可能希望以不同的方式组织或定义辅助功能来完成这项工作。

此外,这里对您的主要代码进行了一些修改,以显示您所做的某些事情如何更清晰。

int main() {

  // Game Board: there's 9 squares in the game
  // 0 1 2
  // 3 4 5
  // 6 7 8

  // ' ' represents "nothing" in a square
  char square[9]={' ',' ',' ',' ',' ',' ',' ',' ',' '}; 

  // There are 8 possible ways of winning the game
  int nwinseq = 8;
  int winseq[8][3] = {{0,1,2},
                      {3,4,5},
                      {6,7,8},
                      {0,3,6},
                      {1,4,7},
                      {2,5,8},
                      {0,4,8},
                      {2,4,6}};

   // there's player 1 and player 2
   // player 1 goes first  
   int player = 1;   

   // current play
   // at most 9 plays in a game
   int i = 1;

   // winning sequence
   // 8 possibilities (0 to 7)
   // no winning sequence found when game starts
   int w = -1;

   // execute game until it's over
   bool gameOver = false;

   while(!gameOver){    
    // print board  
    board(square);

    // ask player for his move of choice
    int choice; 
    printf("Player %d, enter a number: ", player);
    scanf("%d", &choice);

    // change the square according to player's move
    move(player, square, choice);

    // check for win
    w = winnerCheck(square, winseq, nwinseq);

    gameOver = (w >= 0) // found winning sequence i
            || (i == 9); // or made 9 plays already

    // update play number and player
    // obs: maybe update it only if game is not over
    // matter of taste
    i++;

    if (player == 1)
      player = 2;
    else // player == 2 
      player = 1;
  }

  // Game is over 
  // Print the end result 
  // ...
}

和,

void move(int player, char square[], int choice){
   if (player == 1)
    square[choice] = 'X';
  else
    square[choice] = 'O';
}

【讨论】:

  • 你能举个例子吗?因为如果我对数组进行硬编码,我不确定如何正确递归地运行超过 1 个。
  • 我弄错了,我不确定将什么传递给 recTest 函数,什么满足'property' p。你能再解释一下吗?无法连接点。
  • @user7823016 当然可以。因此,那段代码recTest 是作为使用递归来检查维度为n 的数组v 中的任何元素是否满足属性p 的示例。您想检查数组winpos 中任何可能的“获胜配置”是否与您游戏的当前状态相匹配。当然你需要修改代码,特别是应该将游戏状态作为参数传递。但整体递归方案是一样的。
  • 我真的很讨厌痛苦,但我不知道如何正确地将这些部分组合在一起。我是大一新生,我正在努力学习……但这似乎比我预期的要复杂一些。您是否看到将您的解决方案集成到我的(可怕的)代码中的清晰方法?另外,我非常感谢您迄今为止提供的所有帮助。
  • 用添加的winnerCheck 编辑了代码。现在差不多完成了,但你应该完成自己。另请参阅对代码的一些修改,这些修改可能有助于您更好地组织事情。
猜你喜欢
  • 1970-01-01
  • 2020-03-18
  • 2023-04-05
  • 2013-06-22
  • 2016-01-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-03
相关资源
最近更新 更多