三子棋小游戏(C语言)

简介: 三子棋小游戏(C语言)

简介

三子棋,相信大家很多人小时候都玩过,横竖各画两线,在9个格子里面✔或者×,看谁先连成一线谁就胜利。在这里,我们的对手是电脑。

这个小游戏结合了数组,循环语句两大主要内容进行编写程序。再加上分文件编程,最后就能构成。

大体思路

分文件编程,好处就是程序简洁,分工有序,方便调试。这里,分成三个文件。分别是

game.h:头文件,把各个函数封装在一起,方便调用

game.c:游戏函数的定义

test.c:测试文件,用来实现最终效果


那么最主要的就是这个game.c文件了。思路主要为:初始化,打印棋盘,玩家下棋,电脑下棋,判断输赢(包含判断棋盘为满),这五个函数来写。

初始化以及打印

一般我们都是从主函数入手,首先要给出玩家一个菜单,明白要怎么操作,那么直接就打印出来即可。

void menu()
{
    printf("**********************\n");
    printf("********1.PLAY********\n");
    printf("********0.EXIT********\n");
    printf("**********************\n");
    printf("**********************\n");
}


由于游戏简单,所以我们设定可以多次玩这个小游戏,将游戏决定权交给玩家,那么我们就用do-while语句进行封装再加上switch封装选择即可。

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);


进入游戏我们相先对棋盘进行初始化,初始化用空格字符即可。

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


接下来就是将棋盘打印出来;上面我们说过,只有画出线将它分成9个格子,这样子给玩家才有一种明朗的感觉。三子棋,很明显有三行三列,而分隔线只有2条横竖,所以我们还要进行-1,不必画出多余的线条。利用两个for循环就能打印出一个二维平面。

void BoardPrint(char board[ROW][COL], int row, int col)
{
    for (int i = 0; i < row; i++)
    {
        //打印数据内容和竖列的分隔线
        for (int j = 0; j < col; j++)
        {
            printf(" %c ",board[i][j]);
            if (j < col - 1)
            {
                printf("|");
            }
        }
        //打完记得换行
        printf("\n");
        //打印横列的分隔线
        if (i < row - 1)
        {
            for (int j = 0; j < col; j++)
            {
                printf("---");
                if (j < col - 1)
                {
                    printf("|");
                }
            }
            printf("\n");
        }
    }
}


效果:

玩家和电脑下棋

接下来就是开始下棋了。先从玩家下棋开始,在玩家眼中,下标0对应的是坐标1,所以在输入坐标时,需要对玩家输入值进行-1的操作。在棋盘中,我们要判断玩家输入坐标是否超过范围,不超过范围时,该坐标是否被占领。这些问题想清楚,我们就可以编写代码了。

void PlayerMove(char board[ROW][COL], int row, int col)
{
    int x = 0, y = 0;
    printf("玩家下棋:\n");
    while (1)
    {
        printf("请输入下棋位置坐标,用空格隔开");
        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("当前位置已有,请重新输入。\n");
            }
        }
        else//棋盘范围外
        {
            printf("超出输入范围,请重新输入。\n");
        }
    }
}

电脑下棋,我们要知道怎么让电脑自动下棋,在这里,我们利用随机数来进行随机下棋,只需将随机数进行取模即可。再判断是否为空的。

//随机数种子

srand((unsigned int)time(NULL));

void ComputerMove(char board[ROW][COL], int row, int col)
{
    int x=0, y=0;
    printf("电脑下棋:\n");
    while (1)
    {
    //rand()代表随机数
        x = rand() % row;
        y = rand() % col;
        if (board[x][y] == ' ')
        {
            board[x][y] = '#';
            break;
        }
    }
}


判断是否连成一条线

我们都知道,连成一条线一般分为三种,横,竖,斜。我们只需要统计行或列以及对角线的相同字符个数即可。

char IsWin(char board[ROW][COL], int row, int col)
{
    //行项
    for (int i = 0; i < row; i++)
    {
        //Ni记录人,电脑,空
        char NI = board[i][0];
        //num记录相同的
        int num = 0;
        if (NI != ' ')
        {
            num = 1;
        }
        for (int j = 1; j < col; j++)
        {
            if (NI != ' '&&board[i][j]==NI)
            {
                num++;
            }
            if (num == row)
            {
                return NI;
            }
        }
    }
    //列项
    for (int i = 0; i < col; i++)
    {
        //Ni记录人,机,空
        char NI = board[0][i];
        //num记录相同的
        int num = 0;
        if (NI != ' ')
        {
            num = 1;
        }
        for (int j = 1; j < row; j++)
        {
            if (NI != ' ' && board[j][i] == NI)
            {
                num++;
            }
            if (num == row)
            {
                return NI;
            }
        }
    }
    //正对角线
    char NI1 = board[0][0];
    int num1 = 0;
    if (NI1 != ' ')
    {
        num1 = 1;
    }
    for (int i = 1; i < row; i++)
    {
        if (NI1 != ' ' && board[i][i] == NI1)
        {
            num1++;
        }
        if (num1 == row)
        {
            return NI1;
        }
    }
    //反对角线
    char NI2 = board[0][row - 1];
    int num2 = 0;
    if (NI2 != ' ')
    {
        num2 = 1;
    }
    for (int i = 1,j=1; i < row,j<col; i++,j++)
    {
            if (NI2 != ' ' && board[i][row - 1 - j]==NI2)
            {
                num2++;
            }
            if (num2 == row)
            {
                return NI2;
            }
    }
    //平局
    if (IsFull(board, row, col) == 1)
    {
        return 'Q';
    }
    //继续
    return 'C';
}


在这里,我们根据返回值的形式判断输赢,

当棋盘满时,即为平局。

最后的封装

进入游戏后,我们进入的是game()函数,我们先定义一个二维数组,对它进行初始化,打印,接着就是玩家和电脑下棋,下棋时,我们用循环进行多次下棋,并根据上面的返回值进行判断即可。

在这里,我们用了宏定义定义了行数和列数,

这样做,我们只需修改这两个宏变量的值,就能改变棋盘的大小。


原代码

//test.c
#include"game.h"
void menu()
{
    printf("**********************\n");
    printf("********1.PLAY********\n");
    printf("********0.EXIT********\n");
    printf("**********************\n");
    printf("**********************\n");
}
void game()
{
    char board[ROW][COL] = { 0 };
    //初始化
    BoardInit(board, ROW, COL);
    //打印
    BoardPrint(board, ROW, COL);
    //开始下棋
    char ret = 0;
    while (1)
    {
        //人
        PlayerMove(board, ROW, COL);
        BoardPrint(board, ROW, COL);
        //进行判断输赢
        ret = IsWin(board, ROW, COL);
        //非继续就退出循环
        if (ret != 'C')
        {
            break;
        }
        //电脑
        ComputerMove(board, ROW, COL);
        BoardPrint(board, ROW, COL);
        //判断
        ret = IsWin(board, ROW, COL);
        if (ret != 'C')
        {
            break;
        }
    }
    if (ret == '*')
    {
        printf("你赢了。\n");
    }
    else if (ret == '#')
    {
        printf("电脑赢了。\n");
    }
    else
    {
        printf("平局。\n");
    }
}
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.h
#pragma once//防止头文件重复包含
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
//行数和列数,可改变
#define ROW 3
#define COL 3
//初始化
void BoardInit(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);
//判断
char IsWin(char board[ROW][COL], int row, int col);
//game.c
#include"game.h"
//初始化
void BoardInit(char board[ROW][COL], int row, int col)
{
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            board[i][j] = ' ';
        }
    }
}
//打印
void BoardPrint(char board[ROW][COL], int row, int col)
{
    for (int i = 0; i < row; i++)
    {
        //打印数据内容和竖列的分隔线
        for (int j = 0; j < col; j++)
        {
            printf(" %c ",board[i][j]);
            if (j < col - 1)
            {
                printf("|");
            }
        }
        //打完记得换行
        printf("\n");
        //打印横列的分隔线
        if (i < row - 1)
        {
            for (int j = 0; j < col; j++)
            {
                printf("---");
                if (j < col - 1)
                {
                    printf("|");
                }
            }
            printf("\n");
        }
    }
}
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
    int x = 0, y = 0;
    printf("玩家下棋:\n");
    while (1)
    {
        printf("请输入下棋位置坐标,用空格隔开");
        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("当前位置已有,请重新输入。\n");
            }
        }
        else//棋盘范围外
        {
            printf("超出输入范围,请重新输入。\n");
        }
    }
}
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
    int x=0, y=0;
    printf("电脑下棋:\n");
    while (1)
    {
        x = rand() % row;
        y = rand() % col;
        if (board[x][y] == ' ')
        {
            board[x][y] = '#';
            break;
        }
    }
}
//判断棋盘是否已经满了
int IsFull(char board[ROW][COL], int row, int col)
{
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            if (board[i][j] == ' ')
            {
                return 0;
            }
        }
    }
    return 1;
}
//判断是否赢了
char IsWin(char board[ROW][COL], int row, int col)
{
    //行项
    for (int i = 0; i < row; i++)
    {
        //Ni记录人,机,空
        char NI = board[i][0];
        //num记录相同的
        int num = 0;
        if (NI != ' ')
        {
            num = 1;
        }
        for (int j = 1; j < col; j++)
        {
            if (NI != ' '&&board[i][j]==NI)
            {
                num++;
            }
            if (num == row)
            {
                return NI;
            }
        }
    }
    //列项
    for (int i = 0; i < col; i++)
    {
        //Ni记录人,机,空
        char NI = board[0][i];
        //num记录相同的
        int num = 0;
        if (NI != ' ')
        {
            num = 1;
        }
        for (int j = 1; j < row; j++)
        {
            if (NI != ' ' && board[j][i] == NI)
            {
                num++;
            }
            if (num == row)
            {
                return NI;
            }
        }
    }
    //正对角线
    char NI1 = board[0][0];
    int num1 = 0;
    if (NI1 != ' ')
    {
        num1 = 1;
    }
    for (int i = 1; i < row; i++)
    {
        if (NI1 != ' ' && board[i][i] == NI1)
        {
            num1++;
        }
        if (num1 == row)
        {
            return NI1;
        }
    }
    //反对角线
    char NI2 = board[0][row - 1];
    int num2 = 0;
    if (NI2 != ' ')
    {
        num2 = 1;
    }
    for (int i = 1,j=1; i < row,j<col; i++,j++)
    {
            if (NI2 != ' ' && board[i][row - 1 - j]==NI2)
            {
                num2++;
            }
            if (num2 == row)
            {
                return NI2;
            }
    }
    //平局
    if (IsFull(board, row, col) == 1)
    {
        return 'Q';
    }
    //继续
    return 'C';
}



相关文章
|
2月前
|
C语言 C++
【C语言】编写“猜数字“小游戏
【C语言】编写“猜数字“小游戏
103 1
|
3月前
|
定位技术 API C语言
C语言——实现贪吃蛇小游戏
本文介绍了一个基于Windows控制台的贪吃蛇游戏的实现方法。首先,需调整控制台界面以便更好地显示游戏。接着,文章详细描述了如何使用Win32 API函数如`COORD`、`GetStdHandle`、`GetConsoleCursorInfo`等来控制控制台的光标和窗口属性。此外,还介绍了如何利用`GetAsyncKeyState`函数实现键盘监听功能。文中还涉及了`&lt;locale.h&gt;`库的使用,以支持本地化字符显示。
78 1
C语言——实现贪吃蛇小游戏
|
3月前
|
存储 安全 算法
C 语言——实现扫雷小游戏
本文介绍了使用二维数组创建棋盘并实现扫雷游戏的方法。首先,通过初始化数组创建一个9x9的棋盘,并添加行列标识以便操作。接着,利用随机数在棋盘上布置雷。最后,通过判断玩家输入的坐标来实现扫雷功能,包括显示雷的数量和处理游戏胜利或失败的情况。文中提供了完整的代码实现。
56 1
C 语言——实现扫雷小游戏
|
2月前
|
存储 API C语言
【C语言】实践:贪吃蛇小游戏(附源码)(一)
【C语言】实践:贪吃蛇小游戏(附源码)
|
6月前
|
C语言
C语言实现2048小游戏---粤嵌GE6818嵌入式系统实训
C语言实现2048小游戏---粤嵌GE6818嵌入式系统实训
|
2月前
|
C语言 定位技术 API
【C语言】实践:贪吃蛇小游戏(附源码)(二)
【C语言】实践:贪吃蛇小游戏(附源码)
【C语言】实践:贪吃蛇小游戏(附源码)(二)
|
2月前
|
C语言 开发者
C语言实现猜数字小游戏(详细教程)
C语言实现猜数字小游戏(详细教程)
|
2月前
|
C语言
【C语言】实践:贪吃蛇小游戏(附源码)(三)
【C语言】实践:贪吃蛇小游戏(附源码)
|
2月前
|
C语言
C语言贪吃蛇小游戏来啦!
C语言贪吃蛇小游戏来啦!
36 0
|
5月前
|
存储 编译器 C语言