首页 > 其他分享 >数组应用实例-三子棋

数组应用实例-三子棋

时间:2024-08-11 12:58:25浏览次数:19  
标签:int 三子 game 实例 board 数组 printf COL ROW

目录

1. 文件组织

2. test.c 文件的架构

2.1 主函数

2.2 菜单

2.3 游戏

2.3.1 棋盘初始化:

2.3.2 下棋过程

2.3.3 判断输赢

3. 具体函数声明与实现

3.1 初始化棋盘

3.2 打印棋盘

3.3 玩家下棋

3.4 判断输赢

3.5 棋盘占满

3.6 电脑下棋

4. 最后调整


1. 文件组织

采用多文件组织的方式:
test.c : 测试的逻辑(程序主要进程)

game.h : 函数的声明(在test.c中用到的函数的声明),以及#difine定义的常量,和所有用到的头文件

game.c : 函数的实现(函数的定义)

2. test.c 文件的架构

2.1 主函数

我们都知道,在进入一个游戏时,会先出现一个充满选项的菜单页面,而这个菜单是打开游戏就会有的,不需要进行选择,所以我们可以选择使用do...while语句,先进入循环,打印一个菜单,然后再判断怎么执行,故而有:

int main()
{
    int input = 0;
    do
    {
        menu();
        printf("please choose:");
        scanf("%d",&input);
        switch(input)
        {
            case 1:
                game();
                break;
            case 0:
                printf("exit game\n");
                break;
            default:
                printf("input error,plase input again");
                break;
        }
    }while(input);
    return 0;
}

当玩家输入1时进入游戏,输入0时退出游戏,并且do...while循环判断条件为玩家输入的数字,当输入0时则退出循环,不再打印菜单。那么菜单该如何显示呢:

2.2 菜单

菜单的创建其实非常简单,只需要将信息显示出来就可以了:

void menu()
{
    printf("**************************\n");
    printf("**********1.game**********\n");
    printf("**********0.exit**********\n");
    printf("**************************\n");
}

2.3 游戏

接下来我们先说明游戏的具体流程:

2.3.1 棋盘初始化:

在我们创建game()函数后,首先要创建棋盘,我们这里是三子棋,所以需要一个3*3的二维数组

char board[3][3];

但是我们可以发现,这个程序已经写死了,因为如果有一天,我们不想要3*3的棋盘了,我们想玩五子棋,甚至十子棋,这个时候我们需要把程序中所有的3都改掉,未免太过麻烦,所以我们将行定义为3,将列定义为3

#define ROW 3
#define COL 3

这个时侯,我们创建的棋盘就可以改写成:

char board[ROW][COL];

同理,接下来需要写行和列的地方,都可以写成ROW和COL

创建好棋盘后,我们需要对棋盘初始化,让其中的空位都是空格:

void game()
{

    char board[ROW][COL];
    init_board(board,ROW,COL);
}

然后打印出棋盘,让玩家看到:

void game()
{

    char board[ROW][COL];
    init_board(board,ROW,COL);
    print_board(board,ROW,COL);
}

这两个函数的具体实现会在后文中的game.c实现中详细介绍

2.3.2 下棋过程

玩家下棋→打印棋盘→判断输赢→游戏继续→电脑下棋→打印棋盘→判断输赢→游戏继续......

对这个流程明确以后,我们需要设计的函数就很清晰了:

玩家下棋

player_move(board,ROW,COL);

判断输赢

ret = is_win(board,ROW,COL);

电脑下棋

computer_move(board,ROW,COL);
2.3.3 判断输赢

电脑赢:#,因为电脑执#,判断函数返回值用所执棋子类型

玩家赢:*,同理

平局:Q,棋盘占满,但没有返回任何一种类型的棋子

游戏继续:C

ret为判断输赢函数的返回值

    if (ret == '#')
        printf("computer win\n");
    else if (ret == '*')
        printf("player win\n");
    else if (ret == 'Q')
        printf("draw\n");

至此,主函数构架完成,最终结果为:

#include "game.h"

void menu()
{
    printf("**************************\n");
    printf("**********1.game**********\n");
    printf("**********0.exit**********\n");
    printf("**************************\n");
}

void game()
{

    char board[ROW][COL];
    char ret = 0;
    init_board(board,ROW,COL);
    print_board(board,ROW,COL);

    while(1)
    {
        player_move(board,ROW,COL);
        print_board(board,ROW,COL);
        ret = is_win(board,ROW,COL);
        if (ret != 'C')
        {
            break;
        }

        computer_move(board,ROW,COL);
        print_board(board,ROW,COL);
        ret = is_win(board,ROW,COL);
        if (ret != 'C')
        {
            break;
        }
    }

    if (ret == '#')
        printf("computer win\n");
    else if (ret == '*')
        printf("player win\n");
    else if (ret == 'Q')
        printf("draw\n");
}

int main()
{
    int input = 0;
    do
    {
        menu();
        printf("please choose:");
        scanf("%d",&input);
        switch(input)
        {
            case 1:
                game();
                break;
            case 0:
                printf("exit game\n");
                break;
            default:
                printf("input error,plase input again");
                break;
        }
    }while(input);
    return 0;
}

接下来我们开始详细介绍每个函数怎么声明和实现

3. 具体函数声明与实现

3.1 初始化棋盘

在game.h中声明函数:

void init_board(char board[ROW][COL],int row,int col);

在game.c中定义函数:

还记得我们的目的是把空位都初始化为空格

void init_board(char board[ROW][COL],int row,int col)
{
    int i = 0;
    for(i=0;i<row;i++)
    {
        int j = 0;
        for (j=0;j<col;j++)
        {
            board[i][j]=' ';
        }
    }
}

注意在声明函数时最后有 ';'  但在函数定义时没有。

3.2 打印棋盘

同样在game.h中声明:

void print_board(char board[ROW][COL],int row,int col);

在game.c中定义:

void print_board(char board[ROW][COL],int row,int col)
{
    int i = 0;
    for(i=0;i<row;i++)//every row
    {
        int j = 0;
        for(j=0;j<col;j++)//printf("   |   |   \n");
        {
            printf(" %c ",board[i][j]);//先打印棋盘中字符
            if(j<col-1)
                printf("|");//后打印分隔的'|',直到最后一个字符打印完就不用打印分隔符了
        }
        printf("\n");//打印完一行,然后换行
        if(i<row-1)//printf("---|---|---\n");
        {
            for(j=0;j<col;j++)
            {
                printf("---");
                if(j<col-1)
                    printf("|");
            }
            printf("\n");
        }
    }
}

核心思路为在一行中打印每一列的内容,然后换行打印下一行中每一列的内容

打印每一列时,先打印棋盘中的字符,然后打印分隔符,再打印字符,再打印分隔符,最后一列不需要分隔符.

注意此时打印完一列后,这里的一列只是一半,因为我们在换行后还要打印横向的分隔符---,每一行需要呈现---|---|---的效果,如果不这样多做一行,上面的3个字符的空位就会被占用来打印横向分隔,所以我们需要加上一行,这时完整的一组应该是,这才算是完整的一大行

   |   |   
---|---|---

同理横向分割在最后一行也不需要打印,所以才会有if(i<row-1)

需要说明的是我们一大行之中的i是不变的,只是用printf("\n")换的行

最后的效果呈现为:

   |   |   
---|---|---
   |   |   
---|---|---
   |   |   

3.3 玩家下棋

首先要确保输入的坐标在合法的范围内,否则的话输出:输入做错误,请重试

玩家下棋是通过输入坐标,但是我们程序员都知道数组是从下标0开始的,但是普通人输入坐标肯定是从1,1这种开始输入的,所以我们在编写代码时要注意这一点,在下文中我也是使用x-1,y-1去指向真正数组中的位置

在坐标合法的情况下,如果该位置没有被下过棋,那么则放入*,否则则输出这个坐标已经被占用

void player_move(char board[ROW][COL],int row,int col)
{
    printf("player move\n");
    while(1)
    {
        printf("please input the coordinate:");
        int x = 0;
        int y = 0;
        scanf("%d %d",&x,&y);
        if(x>=1 && x<=row && y>=1 && y<=col)
        {
            if(board[x-1][y-1]==' ')
            {
                board[x-1][y-1]='*';
                break;
            }
            else
                printf("the coordinate are already occupied,plase input again\n");
        }
        else
        {
            printf("coordinate error\n");
        }
    }
}

3.4 判断输赢

在玩家下完棋后我们需要加一个判断输赢的程序,我们现在看来好像不需要,因为电脑还没下,但是当程序真正运行起来,下过几步后就需要判断了,所以在玩家和电脑下棋后都要各自判断一遍输赢

三子棋赢的方法也就是三个同样的棋子连成一条直线,当然这三个棋不能为空格

那么就有三行  三列  两条对角线这几种情况,返回符合情况的*或者#

char is_win(char board[ROW][COL],int row,int col)
{
    int i = 0;
    for(i=0;i<row;i++)//判断三行
    {
        if(board[i][0]==board[i][1] && board[i][1]==board[i][2] && board[i][0]!=' ')
            return board[i][0];
    }
    int j = 0;
    for (j=0;j<col;j++)//判断三列
    {
        if(board[0][j]==board[1][j] && board[1][j]==board[2][j] && board[0][j]!=' ')
            return board[0][j];
    }
    //对角线
    if (board[0][0]==board[1][1] && board[1][1]==board[2][2] && board[1][1]!= ' ')
    {
        return board[1][1];
    }
    if (board[0][2]==board[1][1] && board[1][1]==board[2][0] && board[1][1]!= ' ')
    {
        return board[1][1];
    }
    //平局
    if(is_full(board,row,col)==1)
        return 'Q';
    //没有玩家或者电脑赢,也没有平局,游戏继续
    return 'C';
}

当棋盘中棋子皆不符合上述情况,并且棋盘位置被全部占用时,则为平局,返回Q

当棋盘中棋子皆不符合上述情况,并且棋盘位置还有空余时,则继续,返回C

当然我们还需要一个判断棋盘是否占满的函数:

3.5 棋盘占满

int is_full(char board[ROW][COL],int row,int col)
{
    int i = 0;
    int j = 0;
    for(i=0;i<row;i++)
    {
        for(j=0;j<col;j++)
        {
            if (board[i][j] == ' ')
                return 0;
        }
    }
    return 1;
}

不满返回0, 占满返回1

3.6 电脑下棋

void computer_move(char board[ROW][COL],int row,int col)
{
    printf("computer move\n");
    while(1)
    {
        int x = rand()%row;
        int y = rand()%col;

        if(board[x][y]==' ')
        {
            board[x][y]='#';
            break;
        }
    }
}

电脑下棋就比较简单了,因为我们只考虑它下的地方合不合法,而不考虑它下的合不合理,毕竟只是一个非常简单的例子

那么核心思路和玩家下棋是一样的,空就填入#,唯一不同的地方在于我们要用到rand--srand,这组创造随机数的函数,在之前我们也是使用过的

int main()
{
    int input = 0;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
......

4. 最后调整

至此,我们已经实现了这个小游戏,最后把所有头文件都放到"game.h",并且.c文件都包含上这个头文件

最后我们看一下各个文件的内容:

test.c:

#include "game.h"

void menu()
{
    printf("**************************\n");
    printf("**********1.game**********\n");
    printf("**********0.exit**********\n");
    printf("**************************\n");
}

void game()
{

    char board[ROW][COL];
    char ret = 0;
    init_board(board,ROW,COL);
    print_board(board,ROW,COL);

    while(1)
    {
        player_move(board,ROW,COL);
        print_board(board,ROW,COL);
        ret = is_win(board,ROW,COL);
        if (ret != 'C')
        {
            break;
        }

        computer_move(board,ROW,COL);
        print_board(board,ROW,COL);
        ret = is_win(board,ROW,COL);
        if (ret != 'C')
        {
            break;
        }
    }

    if (ret == '#')
        printf("computer win\n");
    else if (ret == '*')
        printf("player win\n");
    else if (ret == 'Q')
        printf("draw\n");
}

int main()
{
    int input = 0;
    srand((unsigned int)time(NULL));
    do
    {
        menu();
        printf("please choose:");
        scanf("%d",&input);
        switch(input)
        {
            case 1:
                game();
                break;
            case 0:
                printf("exit game\n");
                break;
            default:
                printf("input error,plase input again");
                break;
        }
    }while(input);
    return 0;
}

game.c:
 

#include "game.h"

void init_board(char board[ROW][COL],int row,int col)
{
    int i = 0;
    for(i=0;i<row;i++)
    {
        int j = 0;
        for (j=0;j<col;j++)
        {
            board[i][j]=' ';
        }
    }
}

void print_board(char board[ROW][COL],int row,int col)
{
    int i = 0;
    for(i=0;i<row;i++)//every row
    {
        int j = 0;
        for(j=0;j<col;j++)//printf("   |   |   \n");
        {
            printf(" %c ",board[i][j]);//先打印棋盘中字符
            if(j<col-1)
                printf("|");//后打印分隔的'|',直到最后一个字符打印完就不用打印分隔符了
        }
        printf("\n");//打印完一行,然后换行
        if(i<row-1)//printf("---|---|---\n");
        {
            for(j=0;j<col;j++)
            {
                printf("---");
                if(j<col-1)
                    printf("|");
            }
            printf("\n");
        }
    }
}

void player_move(char board[ROW][COL],int row,int col)
{
    printf("player move\n");
    while(1)
    {
        printf("please input the coordinate:");
        int x = 0;
        int y = 0;
        scanf("%d %d",&x,&y);
        if(x>=1 && x<=row && y>=1 && y<=col)
        {
            if(board[x-1][y-1]==' ')
            {
                board[x-1][y-1]='*';
                break;
            }
            else
                printf("the coordinate are already occupied,plase input again\n");
        }
        else
        {
            printf("coordinate error\n");
        }
    }
}

void computer_move(char board[ROW][COL],int row,int col)
{
    printf("computer move\n");
    while(1)
    {
        int x = rand()%row;
        int y = rand()%col;

        if(board[x][y]==' ')
        {
            board[x][y]='#';
            break;
        }
    }
}

int is_full(char board[ROW][COL],int row,int col)
{
    int i = 0;
    int j = 0;
    for(i=0;i<row;i++)
    {
        for(j=0;j<col;j++)
        {
            if (board[i][j] == ' ')
                return 0;
        }
    }
    return 1;
}

char is_win(char board[ROW][COL],int row,int col)
{
    int i = 0;
    for(i=0;i<row;i++)//判断三行
    {
        if(board[i][0]==board[i][1] && board[i][1]==board[i][2] && board[i][0]!=' ')
            return board[i][0];
    }
    int j = 0;
    for (j=0;j<col;j++)//判断三列
    {
        if(board[0][j]==board[1][j] && board[1][j]==board[2][j] && board[0][j]!=' ')
            return board[0][j];
    }
    //对角线
    if (board[0][0]==board[1][1] && board[1][1]==board[2][2] && board[1][1]!= ' ')
    {
        return board[1][1];
    }
    if (board[0][2]==board[1][1] && board[1][1]==board[2][0] && board[1][1]!= ' ')
    {
        return board[1][1];
    }
    //平局
    if(is_full(board,row,col)==1)
        return 'Q';
    //没有玩家或者电脑赢,也没有平局,游戏继续
    return 'C';
}

game.h

#include <stdio.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>


#define ROW 3
#define COL 3

void init_board(char board[ROW][COL],int row,int col);

void print_board(char board[ROW][COL],int row,int col);

void player_move(char board[ROW][COL],int row,int col);

char is_win(char board[ROW][COL],int row,int col);

void computer_move(char board[ROW][COL],int row,int col);

标签:int,三子,game,实例,board,数组,printf,COL,ROW
From: https://blog.csdn.net/2401_83634908/article/details/141101741

相关文章

  • 解决LocalDateTime返回前端数据为数组结构的问题
    问题现象解决办法如下1、使用@JsonFormat@JsonFormat(pattern="yyyy-MM-ddHH:mm:ss",timezone="GMT+8")结果2、使用SpringMVC提供的ExtendMessageConverters@Slf4j@ConfigurationpublicclassWebMvcConfigextendsWebMvcConfigurationSupport{/**......
  • 25版王道数据结构课后习题详细分析 第三章栈、队列和数组 3.2 队列 选择题部分
    一、单项选择题————————————————————————————————————————解析:栈和队列的逻辑结构都是线性结构,都可以采用顺序存储或链式存储,C显然也错误。只有D才是栈和队列的本质区别,限定表中插入和删除操作位置的不同。正确答案:D—————......
  • Java 入门探索者09(数组)
    Java的数组是一种固定大小、有序且相同类型元素的集合。它可以存储同一种数据类型的多个元素,并按照索引顺序访问这些元素。Java数组的特点包括:1.长度固定:一旦数组被创建,其长度就不能修改。可以通过数组的length属性来获取数组的长度。2.有序性:数组中的元素按照索引顺序排......
  • 两数之和Ⅱ——输入有序的数组
    给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1<=index1<index2<=numbers.length 。以长度为2的整数......
  • 010.Vue3入门,数组变化侦听,实时在界面显示变化后的数据
    1、代码如下:<template><h3>数组变化侦听</h3><button@click="addListHandle">添加数据</button><ul><liv-for="(item,index)ofnames":key="index">{{item}}</li></ul>&l......
  • C语言指针变量详解(函数指针,函数指针数组,转移表)
    指针变量 1.字符指针变量在指针的类型中我们知道有⼀种指针类型为字符指针char*;⼀般使⽤:intmain(){charch='w';char*pc=&ch;*pc='w';return0;}还有⼀种使⽤⽅式如下:intmain(){const......
  • C语言指针与数组详解(指针数组,数组指针,⼆级指针)
    指针与数组1.数组名的理解1.1结论:数组名是数组⾸元素的地址,但是有2个例外。      •sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表⽰整个数组,计算的是整个数组的⼤⼩     •&数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数......
  • Java--实例化
    目录五种方法构造器定义特点作用构造方法种this的使用五种方法无论哪一种方式必须经过的一步---调用构造方法。无论怎样构造函数作为初始化类的意义怎样都不会改变。new语句创建对象,最常用创建对象的方法工厂方法返回对象,如:Stringstr=String.valueOf();反射,调用java......
  • 指针数组、回调函数
    指针+二维字符型数组char s[][10]={"hello","world","china"};        char(*p)[10]=s;  //p指向二维数组s ----- *(*(p+i)+j) <=> s[i][j]        char[10] s[3];  //此时二维数组的元素是一个一维数组,定义了一个存放字......
  • 编写类 MyTools 类,编写一个方法可以打印二维数组的数据。 2) 编写一个方法 copyPerson
    1publicclassMethodExercise02{2publicstaticvoidmain(String[]args){34Personp=newPerson();5p.name="milan";6p.age=100;7//创建tools8MyToolstools=newMyTools();9......