首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >零和交叉版本2

零和交叉版本2
EN

Code Review用户
提问于 2019-02-15 21:29:02
回答 1查看 67关注 0票数 3

这款游戏比以前的版本更方便用户--它有一个示例网格来演示输入,现在使用的是Xs和Os。

游戏现在可以检测到抽签。

改变了算法来检测胜利者,虽然游戏结束时仍然有一些组合错误地决定了胜利者或输家--但不知道如何解决这个问题,也不知道是什么原因造成的。

我很想知道如何改进游戏和代码的结构,以及如何避免提到的错误。

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// Struct with all game state variables.
struct game_data {
    int win; // Either 0 or 1.
    int turns; // Ranges from 1 to 9(game end).
    int turn; // Either 0 or 1 where 0 is human player
    char grid[3][3];
};

//Initialising game state variables
struct game_data game = {
    0,
    1,
    0,
    { { ' ', ' ', ' ' },
      { ' ', ' ', ' ' },
      { ' ', ' ', ' ' } }
    };

void intro(void){

    printf("Welcome to NOUGHTS AND CROSSES\n\n");
    printf("The grid you will be playing on is 3x3 and your input will be determined by the co ordinates you put in, in the form 'row column'.\n\n");
    printf("For example an input of '1 1' will put a 'Z' on the first row on the first column. Like so:\n\n");

    printf(
        "+---+---+---+\n"
        "| Z |   |   |\n"
        "+---+---+---+\n"
        "|   |   |   |\n"
        " ---+---+---|\n"
        "|   |   |   |\n"
        "+---+---+---+\n"
        "\n");
}

void player_one_move(struct game_data* game)
{
    int y_val, x_val;
    printf("You are 'Crosses'. Please input co-ordinates in the form 'row column' for the 3x3 grid:\n");
    scanf(" %d %d", &y_val, &x_val);

    if (game->grid[y_val - 1][x_val - 1] == ' ') {
        game->grid[y_val - 1][x_val - 1] = 'X';
        printf("\nYour turn:\n\n");
    }
    else {
        player_one_move(game);
    }
}

void computer_move(struct game_data* game)
{
    int x_val = rand() % 3;
    int y_val = rand() % 3;

    if (game->grid[y_val][x_val] == ' ') {
        game->grid[y_val][x_val] = 'O';
        printf("\nComputer turn:\n\n");
    }
    else {
        computer_move(game);
    }
}

void update(struct game_data* game)
{

    printf(

        "+---+---+---+\n"
        "| %c | %c | %c |\n"
        "+---+---+---+\n"
        "| %c | %c | %c |\n"
        "----+---+---|\n"
        "| %c | %c | %c |\n"
        "+---+---+---+\n"
        "\n",
        game->grid[0][0], game->grid[0][1], game->grid[0][2],
        game->grid[1][0], game->grid[1][1], game->grid[1][2],
        game->grid[2][0], game->grid[2][1], game->grid[2][2]);
}

void game_event_won(struct game_data* game)
{

    int count;

    //BUGGY
    /*char current_mark;

    if (game->turn == 0) {  
        current_mark = 'X';}
    else{
        current_mark = 'O';
    }*/

    for (int y_val = 0; y_val < 3; y_val++) {
        for (int x_val = 0; x_val < 3; x_val++) {
            count = 0;
            while (game->grid[y_val][x_val] == 'X') {
                x_val++;
                count++;

            //BUGGY
            /*if (count == 3 && current_mark == 'X') {   
                game->win = 1;
                printf("You have WON\n");
            }
            if (count == 3 && current_mark == 'O') {
                game->win = 1;
                printf("You have LOST\n");
            }*/

            if (count == 3) {
                game->win = 1;
                printf("You have WON\n");
            }
          }
        }
    }
    for (int x_val = 0; x_val < 3; x_val++) {
         for (int y_val = 0; y_val < 3; y_val++) {
             count = 0;
             while (game->grid[y_val][x_val] == 'X') {
                 y_val++;
                 count++;

                 if (count == 3) {
                     game->win = 1;
                     printf("You have WON\n");
                 }
             }
         }
     }
     for (int y_val = 0; y_val < 3; y_val++) {
         count = 0;
         while (game->grid[y_val][y_val] == 'X') {
             count++;
             y_val++;

             if (count == 3) {
                  game->win = 1;
                  printf("You have won\n");
             }
         }
     }
     for (int y_val = 0; y_val < 3; y_val++) {
         count = 0;
         while (game->grid[y_val][2 - y_val] == 'X') {
             count++;
             y_val++;

             if (count == 3) {
                 game->win = 1;
                 printf("You have won\n");
             }
         }
     }
 }


 // Repetition of previous function but for 'O's. Less concise but less buggy than previous implementation.
 void game_event_lost(struct game_data* game)
 {

      int count;

      for (int y_val = 0; y_val < 3; y_val++) {
           for (int x_val = 0; x_val < 3; x_val++) {
               count = 0;
               while (game->grid[y_val][x_val] == 'O') {
                    x_val++;
                    count++;


                    if (count == 3) {
                         game->win = 1;
                         printf("You have LOST\n");
                    }
              }
         }
     }
     for (int x_val = 0; x_val < 3; x_val++) {
     for (int y_val = 0; y_val < 3; y_val++) {
        count = 0;
        while (game->grid[y_val][x_val] == 'O') {
            y_val++;
            count++;

            if (count == 3) {
                game->win = 1;
                printf("You have LOST\n");
            }
        }
    }
  }
for (int y_val = 0; y_val < 3; y_val++) {
    count = 0;
    while (game->grid[y_val][y_val] == 'O') {
        count++;
        y_val++;

        if (count == 3) {
            game->win = 1;
            printf("You have LOST\n");
        }
    }
}
for (int y_val = 0; y_val < 3; y_val++) {
    count = 0;
    while (game->grid[y_val][2 - y_val] == 'O') {
        count++;
        y_val++;

        if (count == 3) {
            game->win = 1;
            printf("You have LOST\n");
            }
        }
    }
}


int main(void)
{

    srand((unsigned)time(0));

    intro();

    while (game.win == 0 ) {
        if (game.turn == 0) {
            player_one_move(&game);
            game.turns++;
            game.turn = 1;
        }

        else {
            game.turn = 0;
            computer_move(&game);
            game.turns++;
        }
        if (game.turns == 9 && game.win == 0){
            game.win = 1;
            printf("You have drawn\n");
            break;
        }
        update(&game);


        game_event_won(&game);
        game_event_lost(&game);

    }

    return 0;
}

编辑:

我已经更改了game_event_won函数。据我所知,它简单得多,没有bug,即使它更丑。可能会让它变短。

代码语言:javascript
复制
 void game_event_won(struct game_data* game)
    {

      if( ((game->grid[0][0] == game->grid[0][1]) && (game->grid[0][1] == game->grid[0][2]) && (game->grid[0][2] == 'X')) ||
          ((game->grid[1][0] == game->grid[1][1]) && (game->grid[1][1] == game->grid[1][2]) && (game->grid[1][2] == 'X')) ||
          ((game->grid[2][0] == game->grid[2][1]) && (game->grid[2][1] == game->grid[2][2]) && (game->grid[2][2] == 'X')) ||
          ((game->grid[0][0] == game->grid[1][0]) && (game->grid[1][0] == game->grid[2][0]) && (game->grid[2][0] == 'X')) ||
          ((game->grid[0][1] == game->grid[1][1]) && (game->grid[1][1] == game->grid[2][1]) && (game->grid[2][1] == 'X')) ||
          ((game->grid[0][2] == game->grid[1][2]) && (game->grid[1][2] == game->grid[2][2]) && (game->grid[2][2] == 'X')) ||
          ((game->grid[0][0] == game->grid[1][1]) && (game->grid[1][1] == game->grid[2][2]) && (game->grid[2][2] == 'X')) ||
          ((game->grid[0][2] == game->grid[1][1]) && (game->grid[1][1] == game->grid[2][0]) && (game->grid[2][0] == 'X')) ){
             game->win = 1;
             printf("You have WON\n");
       }

       if( ((game->grid[0][0] == game->grid[0][1]) && (game->grid[0][1] == game->grid[0][2]) && (game->grid[0][2] == 'O')) ||
           ((game->grid[1][0] == game->grid[1][1]) && (game->grid[1][1] == game->grid[1][2]) && (game->grid[1][2] == 'O')) ||
           ((game->grid[2][0] == game->grid[2][1]) && (game->grid[2][1] == game->grid[2][2]) && (game->grid[2][2] == 'O')) ||
           ((game->grid[0][0] == game->grid[1][0]) && (game->grid[1][0] == game->grid[2][0]) && (game->grid[2][0] == 'O')) ||
           ((game->grid[0][1] == game->grid[1][1]) && (game->grid[1][1] == game->grid[2][1]) && (game->grid[2][1] == 'O')) ||
           ((game->grid[0][2] == game->grid[1][2]) && (game->grid[1][2] == game->grid[2][2]) && (game->grid[2][2] == 'O')) ||
           ((game->grid[0][0] == game->grid[1][1]) && (game->grid[1][1] == game->grid[2][2]) && (game->grid[2][2] == 'O')) ||
           ((game->grid[0][2] == game->grid[1][1]) && (game->grid[1][1] == game->grid[2][0]) && (game->grid[2][0] == 'O')) ){
             game->win = 1;
             printf("You have LOST\n");
       }

  }

我还更改了主循环以适应它,防止错误绘制:

代码语言:javascript
复制
    int main(void)
    {

        srand((unsigned)time(0));

        intro();

        while (game.win == 0 ) {
        if (game.turn == 0) {
            player_one_move(&game);
            game.turns++;
            game.turn = 1;
        }

        else {
            game.turn = 0;
            computer_move(&game);
            game.turns++;
        }

        update(&game);

        game_event_won(&game);

        if (game.turns == 10 && game.win == 0){
            game.win = 1;
            printf("You have DRAWN\n");
            break;
        }


    }



    return 0;
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2019-02-16 19:52:13

输入验证

用户输入是邪恶的--不管它是邪恶的还是错误的。花费一些精力来验证它。

代码语言:javascript
复制
printf("You are 'Crosses'. Please input co-ordinates ...\n");
// scanf(" %d %d", &y_val, &x_val);
if (scanf(" %d %d", &y_val, &x_val) != 2) {
  puts("Invalid input");
  exit(EXIT_FAILURE);
}
if (y_val < 1 || y_val > 3 || x_val < 1 || x_val > 3) {
  puts("Out of range input");
  exit(EXIT_FAILURE);
}

更好的代码将有选择地允许重新输入。

删除//BUGGY注释

在这里张贴工作代码。对于您在解决问题时遇到的错误,请考虑堆栈溢出

使用const

不改变其指向数据的函数使用const编写得更好。这允许更清晰的功能界面,更广泛的应用,更多的编译器时间检查和潜在的更好的优化。

代码语言:javascript
复制
// void update(struct game_data* game)
void update(const struct game_data* game)

重用代码

而不是使用if( ((game->grid[0][0] == game->grid[0][1]) ...使用'X'的8行代码,然后再用'O'生成8行类似的代码,形成一个辅助函数。

代码语言:javascript
复制
 char three_in_row(const char g[][3]) {
   if(g[0][0] != ' ' && g[0][0] == g[0][1] && g[0][1] == g[0][2]) return g[0][0];
   if(g[1][0] != ' ' && g[1][0] == g[1][1] && g[1][1] == g[1][2]) return g[1][0];
   if(g[2][0] != ' ' && g[2][0] == g[2][1] && g[2][1] == g[2][2]) return g[2][0];
   if(g[0][0] != ' ' && g[0][0] == g[1][0] && g[1][0] == g[2][0]) return g[0][0];
   if(g[0][1] != ' ' && g[0][1] == g[1][1] && g[1][1] == g[2][1]) return g[0][1];
   if(g[0][2] != ' ' && g[0][2] == g[1][2] && g[1][2] == g[2][2]) return g[0][2];
   if(g[0][0] != ' ' && g[0][0] == g[1][1] && g[1][1] == g[2][2]) return g[0][0];
   if(g[0][2] != ' ' && g[0][2] == g[1][1] && g[1][1] == g[2][0]) return g[0][2];
   return ' ';
 }

void game_event_won(struct game_data* game) {
  switch (three_in_row(game->grid)) {
    case 'X': game->win = 1; printf("You have WON\n"); break;
    case 'O': game->win = 1; printf("You have LOST\n"); break;
  }
}

状态评估

而不是game_event_won(),考虑一个从-100到100的TTT_rate(game)函数。

代码语言:javascript
复制
0: tie
100: X won
-100: O won
1...99: X winning
-1...-99: O winning

不需要递归

computer_move(struct game_data* game)中使用循环

注释和代码doe非jibe

看起来范围是1.10。

代码语言:javascript
复制
int turns; // Ranges from 1 to 9(game end).
if (game.turns == 10 && game.win == 0){

格式

我希望while块会缩进。

提示:使用自动格式化程序。手动格式化是无效的。

代码语言:javascript
复制
    while (game.win == 0 ) {
    // if (game.turn == 0) {
      if (game.turn == 0) {
      ...

不需要全局数据

struct game_data game从全局移动到main()内部。

为什么用户总是首先使用?

考虑允许用户或计算机先行。

高级

XO移动调用一个函数。函数对可以来自user_move()computer_move()smarter_computer_move1()smarter_computer_move2()等,这将允许2播放,计算机算法1与算法2,用户与不同级别的游戏,等等。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/213547

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档