适合新手写的小游戏--------三子棋(附新手常犯错误和源代码!)有源代码!!!

写了一个三子棋小游戏检验最近的学习成果,还有自己在写的过程中遇到的一些错误和警告,以及解决办法。
1:函数传参时,要确保数据类型相同,否则会出现数据类型不兼容的警告
2:要返回函数值时,声明函数时的类型,就是返回的数据类型,尽量使各个代码块内的数据类型保持一致。
3:写循环语句时,注意循环能否顺利结束而不影响使用,注意每次循环完成跳出后执行的动作,否则会形成死循环。以这次代码为例,

```c
 while (1)

{
    
    

     player(arr);

     board(arr);

      computer(arr);

     board(arr);

     result = victory(arr);

     if (result != NEXT)//每一次下完棋子后,都要判断是否有人胜利或平局。不是NEXT代表有结果,结束比赛。

     {
    
    

         break;

     }

}

这样写时会发生什么呢?
玩家先下棋字,如果前8颗棋子都没有分出胜负,当第九颗由人落下后,棋盘已经满了,但是电脑不知道,循环也没有结束,就在电脑落子的函数里为了找到一个能下子的位置死循环了,你问为什么死循环?小笨蛋,当然是因为找不到落子的位置,又没有判断出结果。
4:函数有返回值时,考虑到每一种情况,对应的分支语句要加return。否则会出现warning C4715: “victory”: 不是所有的控件路径都返回值。

代码头文件game.h:

#ifndef _GAME_H

#define _GAME_H

 

#include <stdio.h>

#include <windows.h>

#include <time.h>

#pragma warning(disable:4996)

 

#define ROW 3

#define COL 3

 

#define PLAYER 'X'//玩家用X

#define COMP 'O'//电脑用O

#define DRAW 'D'//平局

#define NEXT 'N'//

 

void game();

void menu();

 

#endif

 

 

 

 2. List item

代码main.c文件:

#include "game.h"

void game();

void menu();

int main()

{
    
    

    int quit = 0;

    int select = 0;

    while (quit == 0)

    {
    
    

         menu();

         scanf("%d", &select);

         switch (select)

         {
    
    

         case 1:

             game();

             printf("再来?\n");

             break;

         case 2:

             quit = 1;

             printf("byebye!\n");

             break;

         default:

             printf("输入有误!请重新输入!\n");

             continue;

         }

    }

    system("pause");

}

 

 

 

 3. List item

代码game.c文件:

#include "game.h"

void menu()

{
    
    

    printf("*****************************\n");

    printf("**** 
1:play      2:exit ****\n");

    printf("*****************************\n");

}

void board(char arr[][COL])//数组传参发生降维,二维数组可以省略第一个[]的数字。

{
    
    

    int i = 0, j = 0;

    printf("   | 1
| 2 | 3 | \n");

    for (i = 1; i <= COL; i++)//玩家使用棋盘时候,确定位置从1开始 ,COL结束。

    {
    
    

         printf("---------------\n");

         printf(" %d |", i);

         for (j = 1; j <= COL; j++)

         {
    
    

             printf(" %c |",arr[i-1][j-1]);//由于数组名下标(0-2)和玩家(1-3)使用的差别,i和j分别减一。

         }

         printf("\n");

    }

    printf("\n");

}

void player(char arr[][COL])

{
    
    

    int a = 0, b = 0;

    while (1)

    {
    
    

         printf("请输入你要下的位置!\n");

         scanf("%d %d", &a, &b);

         if (a<1 || a>3 || b<1 || b>3)

         {
    
    

             printf("输入有误,请重新输入!");

             continue;

         }

         else

         {
    
    

             if (arr[a - 1][b - 1] != ' ')

             {
    
    

                  printf("该位置已有棋子,请重新选择位置!\n");

                  continue;

             }

             else

             {
    
    

                  arr[a - 1][b - 1] = PLAYER;

                  break;

             }

         }

    }

}

void computer(char arr[][COL])

{
    
    

    while (1)

    {
    
    

         int r = rand() % ROW;

         int q = rand() % COL;

         if (arr[r][q] == ' ')

         {
    
    

             arr[r][q] = COMP;

             break;

         }

    }

}

char victory(char arr[][COL])

{
    
    

    int i = 0, j = 0;

    for (i = 0; i < 3; i++)//判断行是否三连

    {
    
    

         if (arr[i][0] == arr[i][1] &&\

            
arr[i][0] == arr[i][2] &&\

            
arr[i][0] != ' ')//另外判断三个是否同样时,不可以写成 arr[i][0] ==
arr[i][1] == arr[i][2]==arr[i][0] != ' '// 因为'=='是个逻辑运算符,运算后结果为1或0,第一个“==”完成后变成了“1或者0”==arr[i][2],明显失真。

         {
    
    

             return arr[i][0];

         }

    }

    for (i = 0; i < 3; i++)//判断列是否三连

    {
    
    

         if (arr[0][i] == arr[1][i]&&\

             arr[0][i] == arr[2][i]&&\

             arr[0][i] != ' ')

         {
    
    

             return arr[0][i];

         }

    }

         if (arr[0][0] == arr[1][1]&&\

            
arr[1][1] == arr[2][2]&&\

             arr[1][1] != ' ')//↘方向的三连判断

    {
    
    

         return arr[1][1];

    }

    if ((arr[0][2] == arr[1][1] &&\

          arr[1][1] == arr[2][0])&&\

          arr[1][1] != ' ')//↙方向的三连判断,上面的“\”起到承接下一行代码的作用提高可读性。

    {
    
    

         return arr[1][1];

    }

    for (i = 0; i < 3; i++)//用来判断尚未分出胜负时,棋盘是否下满,没满则下一步NEXT,已满则平局。

    {
    
    

         for (j = 0; j < 3; j++)

         {
    
    

             if (arr[i][j] == ' ')

             {
    
    

                  return NEXT;

             }

         }

    }

         return DRAW;//函数有返回值时,考虑到每一种情况,对应的分支语句要加return。否则会出现warning C4715: “victory”: 不是所有的控件路径都返回值。

}

void game ()

{
    
       

    char arr[ROW][COL];

    //InitBoard(board, ROW, COL)

    memset(arr,' ', sizeof(arr));

    srand((unsigned long)time(NULL));

    board(arr);

    while (1)

    {
    
    

         player(arr);

         board(arr);

         char result = victory(arr);//用一个外部变量取代函数的返回值,提高可读性,确保数据类型相同。

         if (result != NEXT)//每一次下完棋子后,都要判断是否有人胜利或平局。不是NEXT代表有结果,结束比赛。

         {
    
    

             break;

         }

         computer(arr);

         board(arr);

         result = victory(arr);

         if (result != NEXT)//每一次下完棋子后,都要判断是否有人胜利或平局。不是NEXT代表有结果,结束比赛。

         {
    
    

             break;

         }

    }

    char result = victory(arr);

    if (result == PLAYER)

    {
    
    

         printf("你赢了!\n");

    }

    else

    {
    
    

         if (result == COMP)

         {
    
    

             printf("你输了!\n");

         }

         else

         {
    
    

             printf("平局!\n");

         }

    }

}


猜你喜欢

转载自blog.csdn.net/Zhou000815/article/details/109408092
今日推荐