“纯C”实现——三子棋小游戏

简介: 文章目录三子棋实现思路棋盘实现玩家下棋电脑下棋判断输赢小结语⚡text.c文件⚡game.c文件⚡game.h⚓三子棋实现思路三子棋游戏就是玩家和电脑之间轮流下棋,首先它的棋盘为3X3,我们玩家先下棋,然后到电脑,只要其中一方下的棋子连成了一条线即为胜利。那么要实现游戏的前提首先是得有一个棋盘显示出来,然后把我们每一次下的棋到显示在屏幕上直到一方胜利或者和局。所以我们第一步是要打印棋盘:打印棋盘的前提是有数据可以打印,所以我们需要用到一个3X3的二维数组.

在这里插入图片描述

文章目录

⚡text.c文件
⚡game.c文件
⚡game.h


⚓三子棋实现思路

三子棋游戏就是玩家和电脑之间轮流下棋,首先它的棋盘为3X3,我们玩家先下棋,然后到电脑,只要其中一方下的棋子连成了一条线即为胜利。 那么要实现游戏的前提首先是得有一个棋盘显示出来,然后把我们每一次下的棋到显示在屏幕上直到一方胜利或者和局。所以

我们第一步是要打印棋盘:

打印棋盘的前提是有数据可以打印,所以我们需要用到一个3X3的二维数组,刚开始里面没有数据,我们先初始化成空格,这样打印出来就是空白的形式,为了方便区分玩家和电脑下棋,我们可以规定
玩家下棋就用符号" *"填补
电脑下棋就用符号"# "填补

那么第二步:

棋盘打印出来屏幕后,就是玩家下棋,那么我们需要一个玩家下棋的独立函数,用来接收玩家输入的坐标,而且要判断坐标是否合法

第三步:

玩家下完棋后,就是电脑下棋,电脑下棋我们可以用随机值进行下棋
此时我们又可以实现一个电脑下棋的独立函数

第四步:

玩家和电脑每下一次棋,我们都需要判断一下是否有一方已经胜利了,或者棋盘是否满了,所以我们又需要一个独立函数用来判断

第五步:

把上述的所有函数用循环连接起来即可,下面直接看我操作
在这里插入图片描述
image.png

⚓棋盘实现

下面的图就是我们要实现的棋盘,首先要创建一个3X3的二维数组

#define ROW 3        //行
#define COL 3        //列
char board[ROW][COL]

我们用宏定义来定义行列,方便以后要打印成其他4X4,10X10的棋盘
而且我们要把它初始化成空格

//初始化成空格
void InitBoard(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++)
        {
            board[i][j] = ' ';
        }
    }
}

可以看一个下的棋下面都有三个“-”符号,因为我们的“ # ”,和“ * ”都只占一个位置,所以我们打印的时候要用空格隔开
image.png

用宏定义的好处,如果把ROW和COL改成10,那么它可以直接打印成下面的10X10格子 注意我们下面是基于3X3格子进行实现的三子棋,只适用于3x3格子
image.png

下面我们就实现一下打印棋盘的代码
实现代码:

//打印棋盘
void BoardPrint(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++)
        {
            printf(" %c ",board[i][j]);
            //可以看到图片里的最后一列是没有竖杆的,所以这里要判断一下
            //如果是最后一列就不必打印竖杆
            if(j<col-1)
            printf("|");
        }
        printf("\n");
        for (j = 0; j < col; j++)
        {
            printf("---");
            //这里跟上面用一个意思
            if (j < col - 1)
                printf("|");
        }
        printf("\n");
    }
}

⚓玩家下棋

玩家下棋的方式是输入坐标 ,所以需要接收玩家输入的数据,我们要考虑到

**用户友好性**

因为我们使用的是二维数组,下标都是从0开始的,而玩家不一定是程序员,是不知道的这件事的,所以用户输入的数据时要注意处理

image.png

处理用户输入的数据只需将它-1即可,
比如玩家输入坐标"3 3",在后台改变数组的时候就将它减1变成“2 2”
同时还有判断当前坐标是否已经被占用了,如果被占用了还需要提醒玩家重新输入,直到输入正确为止,所以我们要使用到循环结构 坐标没有被占用,我们就可以将数组对应的位置放字符“ * ”

void PlayerMove(char board[ROW][COL], int row, int col)
{
    while (1)
    {
        printf("请输入坐标>:");
        int x = 0;
        int y = 0;
        scanf("%d %d", &x, &y);
        //判断坐标是否合法
        if (x <= 3 && x > 0 && y <= 3 && y > 0)
        {
            if (board[x - 1][y - 1] == ' ')
            {
                board[x - 1][y - 1] = '*';
                break;
            }
            else
            {
                printf("坐标被占用,不能下棋,请选择其他位置\n");
            }
        }
        else
        {
            printf("坐标非法,请重新输入\n");
        }
    }
}

⚓电脑下棋

电脑下棋使用rand函数获取随机值,将它坐标按行和列取模,比如随机值是100,那么取模行row之后,就为1,
电脑下棋就不用判断坐标是否合法了,只需要确定它取模后的数字范围在0~2之间即可
还需要注意获取的坐标是否被占用即可

因为我们是使用随机值的方式让电脑下棋,使用这样的方式下棋,电脑是很“笨”的,不会对我们下的棋进行拦截,简而言之就是不够“智能”,当然如果, 你感兴趣的话,可以对它进行一些算法处理,比如穷举一些玩家可能性下的棋,对它进行预判等等,让它变得更加“智能”一些,但本文章就不做优化了,留给你们自行处理!
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
    while (1)
    {
        int x = rand() % row;
        int y = rand() % col;
        if (board[x][y] == ' ')
        {
            board[x][y] = '#';
            break;
        }
    }
}

image.png

⚓判断输赢

判断输赢大概就以下几种,我们可以使用枚举的方式,也可以使用循环的方式去判断,下面我给出两个版本,一个是枚举的,一个是循环的

我们规定玩家赢返回“ * ”,电脑赢返回“ # ”,平局返回“Q”,进行游戏返回“0”

image.png

枚举

//版本1.0枚举
//玩家赢返回"*",电脑赢返回""#,棋盘满了返回"Q"
char  DetermineEnd1(char board[ROW][COL])
{
    //玩家赢的情况
    if ((board[0][0] == board[0][1]  && board[0][1] == board[0][2]&&board[0][0]=='*')
        || (board[1][0] == board[1][1]  && board[1][1] == board[1][2] && board[1][0] == '*')
        || (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '*')
        || (board[0][0] == board[1][0]  && board[1][0] == board[2][0]&&board[0][0] == '*')
        || (board[0][1] == board[1][1]  && board[1][1] == board[2][1] && board[0][1] == '*')
        || (board[0][2] == board[1][2]  && board[1][2] == board[2][2] && board[0][2] == '*')
        || (board[0][0] == board[1][1]  && board[1][1] == board[2][2] && board[0][0] == '*')
        || (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] == '*'))
    {
        
        return '*';
    }
    //电脑赢的情况
    else if ((board[0][0] == board[0][1] && board[0][1] == board[0][2]&&board[0][0]=='#')
        || (board[1][0] == board[1][1] && board[1][1] == board[1][2] && board[1][0] == '#')
        || (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '#')
        || (board[0][0] == board[1][0]  && board[1][0] == board[2][0]&&board[0][0] == '#')
        || (board[0][1] == board[1][1] && board[1][1] == board[2][1] && board[0][1] == '#')
        || (board[0][2] == board[1][2] && board[1][2] == board[2][2] && board[0][2] == '#')
        || (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] == '#')
        || (board[0][2] == board[1][1]  && board[1][1] == board[2][0] && board[0][02] == '#'))
    {
        
        return '#';
    }
    else
    {
        //判断棋盘是否满了
        for (int i = 0; i < ROW; i++)
        {
            for (int j = 0; j < COL; j++)
            {
                if (board[i][j] == ' ')
                    return '0';
            }
        }
    }
    //程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
    return 'Q';
}
其实循环和枚举在这里都是大同小异。

循环

//版本2.0循环
// 判断游戏是否结束     玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char  DetermineEnd2(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][1] != ' '))
        {
            return board[i][1];
        }
    }
    //判断列
    for (i = 0; i < row; i++)
    {
        if ((board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '))
        {
            return board[1][i];
        }
    }
    //判断对角
    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];
    }
    //判断棋盘是否满了
    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < COL; j++)
        {
            //其中有一个空格就说明还没满,返回"0"
            if (board[i][j] == ' ')
                return '0';
        }
    }
    //程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
    return 'Q';
}

⚓小结语
其实不管是猜数字小游戏,还是前面实现的顺序表和单链表,看似代码很大,其实如果理解其中的思想,就知道他们都有一个共同点,都是一些基本操作组装起来。

接下来才是最关键的一步,就是将它们组装起来,形成一个可以运行的程序
我把它实现在text.c文件中。
在这里插入图片描述

⚡text.c文件
text.c为工程测试文件
#define _CRT_SECURE_NO_WARNINGS

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

void game()
{
    
    char board[ROW][COL] = { 0 };
    //先初始化棋盘
    InitBoard(board, ROW, COL);
    //打印棋盘让玩家下棋
    BoardPrint(board, ROW, COL);
    char ret;
    while (1)
    {
        printf("玩家下棋\n");
        PlayerMove(board, ROW, COL);
        ret= DetermineEnd2(board,ROW,COL);
        if (ret != '0')
        {
            break;
        }
        BoardPrint(board, ROW, COL);
        printf("电脑下棋\n");
        ComputerMove(board, ROW, COL);
        ret = DetermineEnd2(board, ROW, COL);
        if (ret != '0')
        {
            break;
        }
        BoardPrint(board, ROW, COL);
    }
    if (ret == '*')
    {
        printf("玩家赢\n");
    }
    else if (ret == '#')
    {
        printf("电脑赢\n");
    }
    else
    {
        printf("平局\n");
    }
    BoardPrint(board, ROW, COL);

}
int main()
{
    //初始化随机值
    srand((unsigned int)time(NULL));
    //接收用户选择开始游戏,或者退出游戏的变量
    int input = 0;
    do 
    {
        menu();
        printf("请选择>:");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            game();
            break;
        case 0:
            printf("退出成功\n");
            break;
        default:
            printf("无此选项,请重新选择\n");
            break;
        }

    } while (input);
    return 0;
}

⚡game.c文件
game.c为工程函数实现文件
#define _CRT_SECURE_NO_WARNINGS

#include"game.h"


//初始化成空格
void InitBoard(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++)
        {
            board[i][j] = ' ';
        }
    }
}

//打印棋盘
void BoardPrint(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++)
        {
            printf(" %c ",board[i][j]);
            if(j<col-1)
            printf("|");
        }
        printf("\n");
        for (j = 0; j < col; j++)
        {
            printf("---");
            if (j < col - 1)
                printf("|");
        }
        printf("\n");
    }
}


void PlayerMove(char board[ROW][COL], int row, int col)
{
    while (1)
    {
        printf("请输入坐标>:");
        int x = 0;
        int y = 0;
        scanf("%d %d", &x, &y);
        //判断坐标是否合法
        if (x <= 3 && x > 0 && y <= 3 && y > 0)
        {
            if (board[x - 1][y - 1] == ' ')
            {
                board[x - 1][y - 1] = '*';
                break;
            }
            else
            {
                printf("坐标被占用,不能下棋,请选择其他位置\n");
            }
        }
        else
        {
            printf("坐标非法,请重新输入\n");
        }
    }
}

//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
    while (1)
    {
        int x = rand() % row;
        int y = rand() % col;
        if (board[x][y] == ' ')
        {
            board[x][y] = '#';
            break;
        }
    }
//}
////版本1.0
////玩家赢返回"*",电脑赢返回""#,棋盘满了返回"Q"
//char  DetermineEnd1(char board[ROW][COL])
//{
//    //玩家赢的情况
//    if ((board[0][0] == board[0][1]  && board[0][1] == board[0][2]&&board[0][0]=='*')
//        || (board[1][0] == board[1][1]  && board[1][1] == board[1][2] && board[1][0] == '*')
//        || (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '*')
//        || (board[0][0] == board[1][0]  && board[1][0] == board[2][0]&&board[0][0] == '*')
//        || (board[0][1] == board[1][1]  && board[1][1] == board[2][1] && board[0][1] == '*')
//        || (board[0][2] == board[1][2]  && board[1][2] == board[2][2] && board[0][2] == '*')
//        || (board[0][0] == board[1][1]  && board[1][1] == board[2][2] && board[0][0] == '*')
//        || (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] == '*'))
//    {
//        
//        return '*';
//    }
//    //电脑赢的情况
//    else if ((board[0][0] == board[0][1] && board[0][1] == board[0][2]&&board[0][0]=='#')
//        || (board[1][0] == board[1][1] && board[1][1] == board[1][2] && board[1][0] == '#')
//        || (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '#')
//        || (board[0][0] == board[1][0]  && board[1][0] == board[2][0]&&board[0][0] == '#')
//        || (board[0][1] == board[1][1] && board[1][1] == board[2][1] && board[0][1] == '#')
//        || (board[0][2] == board[1][2] && board[1][2] == board[2][2] && board[0][2] == '#')
//        || (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] == '#')
//        || (board[0][2] == board[1][1]  && board[1][1] == board[2][0] && board[0][02] == '#'))
//    {
//        
//        return '#';
//    }
//    else
//    {
//        //判断棋盘是否满了
//        for (int i = 0; i < ROW; i++)
//        {
//            for (int j = 0; j < COL; j++)
//            {
//                if (board[i][j] == ' ')
//                    return '0';
//            }
//        }
//    }
//    //程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
//    return 'Q';
//}

//版本2.0
// 判断游戏是否结束     玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char  DetermineEnd2(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][1] != ' '))
        {
            return board[i][1];
        }
    }
    //判断列
    for (i = 0; i < row; i++)
    {
        if ((board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '))
        {
            return board[1][i];
        }
    }
    //判断对角
    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];
    }
    //判断棋盘是否满了
    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < COL; j++)
        {
            //其中有一个空格就说明还没满,返回"0"
            if (board[i][j] == ' ')
                return '0';
        }
    }
    //程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
    return 'Q';
}

⚡game.h
game.h为工程的函数和变量声明的头文件
#pragma once

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

#define ROW 3        //行
#define COL 3        //列

//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘
void BoardPrint(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);

//  版本1.0     判断游戏是否结束     玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char  DetermineEnd1(char board[ROW][COL]);


//版本2.0    判断游戏是否结束     玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char  DetermineEnd2(char board[ROW][COL],int row,int col);



不要让舒适夺走了你本可以拥有的东西!!
相关文章
|
7月前
|
C语言
简易三子棋的实现
简易三子棋的实现
|
7月前
|
存储
三子棋游戏的实现
三子棋游戏的实现
60 0
|
7月前
|
C语言
三子棋游戏(详解+代码)
三子棋游戏(详解+代码)
78 2
|
7月前
|
人工智能 C语言
三子棋小游戏
三子棋小游戏
|
7月前
|
算法 C语言
三子棋小游戏(可改棋盘大小)
三子棋小游戏(可改棋盘大小)
77 0
简单三子棋的实现
简单三子棋的实现
65 0
|
程序员 C语言
三子棋(超详细)
三子棋(超详细)
三子棋游戏
三子棋游戏
77 0
|
C语言
C/【三子棋】
C/【三子棋】

相关实验场景

更多