C语言小游戏——井字棋

前言:在我们小时候经常上课开小差,与同桌下“井字棋”---也叫“三子棋”,想不想在vs上重温小时候的快乐,往下看看吧!

 

目录

完整代码


今天要完成一个相对于之前学习更有挑战性的小程序——三子棋。

相信我们大部分人都接触过三子棋,这是一款操作简单易上手的小游戏。

C语言小游戏——井字棋

先简单介绍一下三子棋的规则,方便我们接下来的编程和理解。规则如下:

在九宫格棋盘上,只要将自己的三个棋子走成一条线(横、竖、对角线),对方就算输了。

规则很简单,但是我们应该从哪里入手完成这个三子棋程序呢?

首先,我们的游戏程序应该先有个菜单页面,这个菜单页面用来让用户操作选择玩游戏,或是退出。

界面可以很简单,只需要几条 printf 语句即可。

这里我们尽可能用函数来完成游戏的功能:

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

这就是一个简单的主菜单界面,效果如下:

C语言小游戏——井字棋

既然菜单中有选项,我们就必须要设计一个变量用来接收用户的选择。

而且游戏程序本身应该允许用户反复进行玩耍,所以在主函数中,我们需要用一个循环来完成这个功能。

do-while循环在调用时会先运行循环体,而后在进行判断,所以这里我们选择使用do-while循环:

int main()
{
    int input;
    do
    {
        menu();
        printf("请选择是否(1/0)开始游戏");
        scanf("%d", &input);
        switch (choice)
        {
        case 1:
            game();
            break;
        case 0:
            printf("退出游戏!\n");
            break;
        default:
            printf("输入错误,请重新输入!\n");
            break;
        }
    } while (input);
    return 0;
}

由于用户选择选项1时我们需要为用户启动游戏程序,所以这里我们使用一个switch语句来接受用户的选择。

选择0时退出程序,所以我们只需要跳出循环,即可退出。

而输入0、1之外的值时,我们应该向用户报输入错误,所以在default中输出一条报错信息。

接下来就是我们程序的重点——三子棋游戏本身了。

先创建一个实现三子棋的game()函数,里面的内容我们一步步来填充。

void game()
{

}

在程序开始阶段,我们首先要创建一个3*3的二维字符数组,

由于长和宽我们要经常用到,为了后续修改方便,我们采用宏定义方式:

#define ROWS 3
#define COLS 3

接下来在game()函数中创建数组:

char board[ROWS][COLS];

并将这个数组进行初始化,因为这个数组在后续需要输出展示在用户面前,所以我们将值初始化为空格“ ”。

初始化用函数进行完成:


void init_board(char board[ROWS][COLS], int rows, int cols)
{
    //对棋盘初始化
    int i, j;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            board[i][j] = ' ';
        }
    }
}

接下来,我们应该输出这个数组棋盘,来检查一下是否初始化完成,

但我们没有展示棋盘的函数,所以我们需要完成这个显示棋盘函数:

void show_board(char board[ROWS][COLS], int rows, int cols)
{
    int i;
    for (int i = 0; i < rows; i++)
    {
        printf("  %c | %c | %c  \n",board[i][0],board[i][1],board[i][2]);
        if (i != rows - 1)
            printf(" ---|---|--- \n");
    }    
}//棋盘的打印有两种方法
//这是简单粗暴的方法
//我会在后面介绍另一种

这里需要利用循环来输出我们棋盘的格式,格式不统一,可以根据自己的喜好进行修改。

下面展示一下我这个代码所输出的棋盘:

C语言小游戏——井字棋

上面已经看出我的棋盘初始化已经完成,所以接下来我们需要考虑如何让电脑或用户进行下棋操作了。

电脑走需要让电脑产生随机坐标,然后在数组的这个坐标位置放入一个 ‘#’ 作为电脑的棋子。

所以代码如下:

void ComputerMove(char board[ROWS][COLS], int rows, int cols)
{

    int x, y;
    printf("电脑走:\n");
    while (1)
    {
        x = rand() % rows;
        y = rand() % cols;
        if (board[x][y] == ' ')
        {
            board[x][y] = '#';
            break;
        }
    }
}

rand()是用来生成随机数的,这里我们还需要在主函数main中加上一行代码;

由于我们不希望他多次生成随机数,生成一次就足够用了,所以直接在创建choice变量的下一行加上下面这个代码即可:

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

注意生成随机数需要引用time.h这个头文件。

电脑下完棋后,需要轮到我们的用户进行下棋操作,这个函数和电脑下棋大同小异;

玩家下的棋,用 '*' 记录;

但是要注意人的习惯不会输入(0,0)这个坐标,而是输入(1,1);

所以这里我们要给传过去的参数-1。

解决这个问题后的代码如下:

void player_move(char board[ROWS][COLS], int rows, int cols)
{
    int x, y;
    printf("玩家走:\n");
    while (1)
    {
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= rows && y >= 1 && y <= cols)
        {
            if (board[x - 1][y - 1] == ' ')
            {
                board[x - 1][y - 1] = 'O';
                break;
            }
            else printf("坐标被占用,请重新输入!\n");
        }
        else printf(" 坐标非法,请重新输入!\n");
    }
}

在双方走完后,我们需要判断是否胜利,也就是判断之前我们提到的规则,

这时我们需要编写一个is_win()函数来检测并返回一个值来判断谁获胜。

代码如下:

char is_win(char board[ROWS][COLS], int rows, int cols)
{
    int i;
    for (i = 0; i < rows; 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 < cols; 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];
    else if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
        return board[1][1];
    else if (is_full(board, rows, cols))
        return 'q';
    return 0;
}

由于可能出现棋盘下满,却没人获胜的情况,
所以我们需要在其中判断一下平局的情况,

这里我们编写了一个is_full()函数,用来判断棋盘是否下满:

int is_full(char board[ROWS][COLS], int rows, int cols)
{
    int i, j;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            if (board[i][j] == ' ')
                return 0;
        }
    }
    return 1;
}

        这时程序的雏形已经基本完成,我们只需要按我们自己理解的游戏步骤来完成game()函数即可。

所以完成后的game()函数如下所示:

void game()
{
    char win = 0;
    char arr[ROWS][COLS];
    init_board(board, ROWS, COLS);
    do
    {
        computer_move(board, ROWS, COLS);
        show_board(board, ROWS, COLS);
        win = is_win(board, ROWS, COLS);
        if (win != 0)
            break;
        player_move(board, ROWS, COLS);
        show_board(board, ROWS, COLS);
        win = is_win(board, ROWS, COLS);
    } while (win == 0);
    if (win == '#')
        printf("恭喜,电脑赢了!\n");
    if (win == '*')
        printf("恭喜,你赢了!\n");
    if (win == 'q')
        printf("平局!\n");
}

这样,将上面各个部分合在一起,这个程序就被我们完成了。

完整代码

下面放上我自己写的,比较丑陋的代码:

我的代码分为三部分,

第一部分是game.h头文件:

#pragma once

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

#define ROWS 3
#define COLS 3

void show_board(char board[ROWS][COLS], int rows, int cols);
void init_board(char board[ROWS][COLS], int rows, int cols);
void computer_move(char board[ROWS][COLS], int rows, int cols);
void player_move(char board[ROWS][COLS], int rows, int cols);
char is_win(char board[ROWS][COLS], int rows, int cols);

为了方便我们随时改变棋盘大小,所以我们在game.h头文件中,定义棋盘行(ROWS)和列(COLS)的大小。 

第二部分是game.c源文件的函数部分:

#include"game.h"

//方法1:
void show_board(char board[ROWS][COLS], int rows, int cols)
{
    int i;
    for (int i = 0; i < rows; i++)
    {
        printf("  %c | %c | %c  \n",board[i][0],board[i][1],board[i][2]);
        if (i != rows - 1)
            printf(" ---|---|--- \n");
    }    
}
//方法2
//void show_board(char board[ROWS][COLS], int rows, int cols)
//{
//	int i = 0;
//	int j = 0;
//	for (i = 0; i < rows; i++)
//	{
//		for (j = 0; j < cols; j++)
//		{
//			printf(" %c ", board[i][j]);
//			if (j < cols - 1)
//				printf("|");
//		}
//		printf("\n");
//		if (i < rows - 1)
//		{
//			for (j = 0; j < cols; j++)
//			{
//				printf("---");
//				if (j < cols - 1)
//					printf("|");
//			}
//		}
//		printf("\n");
//	}
//}
void init_board(char board[ROWS][COLS], int rows, int cols)
{
    int i, j;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            board[i][j] = ' ';
        }
    }
}

void computer_move(char board[ROWS][COLS], int rows, int cols)
{
    int x, y, i;
    printf("电脑走:\n");
    while (1)
    {
        x = rand() % rows;
        y = rand() % cols;    
        for (i = 0; i < rows; i++)
        {
            if (board[i][0] == board[i][1] && board[i][0] == '#' && board[i][2] == ' ')
            {
                board[i][2] = '#';
                goto flag1;
            }
            else if (board[i][1] == board[i][2] && board[i][1] == '#' && board[i][0] == ' ')
            {
                board[i][0] = '#';
                goto flag1;
            }
            else if (board[i][0] == board[i][2] && board[i][2] == '#' && board[i][1] == ' ')
            {
                board[i][1] = '#';
                goto flag1;
            }
            else if (board[0][i] == board[1][i] && board[0][i] == '#' && board[2][i] == ' ')
            {
                board[2][i] = '#';
                goto flag1;
            }
            else if (board[1][i] == board[2][i] && board[1][i] == '#' && board[0][i] == ' ')
            {
                board[0][i] = '#';
                goto flag1;
            }
            else if (board[0][i] == board[2][i] && board[2][i] == '#' && board[1][i] == ' ')
            {
                board[1][i] = '#';
                goto flag1;
            }
            else if (board[0][0] == board[1][1] && board[0][0] == '#' && board[2][2] == ' ')
            {
                board[2][2] = '#';
                goto flag1;
            }
            else if (board[1][1] == board[2][2] && board[1][1] == '#' && board[0][0] == ' ')
            {
                board[0][0] = '#';
                goto flag1;
            }
            else if (board[0][0] == board[2][2] && board[0][0] == '#' && board[1][1] == ' ')
            {
                board[1][1] = '#';
                goto flag1;
            }
            else if (board[0][2] == board[1][1] && board[1][1] == '#' && board[2][0] == ' ')
            {
                board[2][0] = '#';
                goto flag1;
            }
            else if (board[1][1] == board[2][0] && board[1][1] == '#' && board[0][2] == ' ')
            {
                board[0][2] = '#';
                goto flag1;
            }
            else if (board[2][0] == board[0][2] && board[2][0] == 'X' && board[1][1] == ' ')
            {
                board[1][1] = '#';
                goto flag1;
            }
        }
        for (i = 0; i < rows; i++)
        {
            if (board[i][0] == board[i][1] && board[i][0] == 'O' && board[i][2] == ' ')
            {
                board[i][2] = '#';
                goto flag1;
            }
            else if (board[i][1] == board[i][2] && board[i][1] == 'O' && board[i][0] == ' ')
            {
                board[i][0] = '#';
                goto flag1;
            }
            else if (board[i][0] == board[i][2] && board[i][2] == 'O' && board[i][1] == ' ')
            {
                board[i][1] = '#';
                goto flag1;
            }
            else if (board[0][i] == board[1][i] && board[0][i] == 'O' && board[2][i] == ' ')
            {
                board[2][i] = '#';
                goto flag1;
            }
            else if (board[1][i] == board[2][i] && board[1][i] == 'O' && board[0][i] == ' ')
            {
                board[0][i] = '#';
                goto flag1;
            }
            else if (board[0][i] == board[2][i] && board[2][i] == 'O' && board[1][i] == ' ')
            {
                board[1][i] = '#';
                goto flag1;
            }
            else if (board[0][0] == board[1][1] && board[0][0] == 'O' && board[2][2] == ' ')
            {
                board[2][2] = '#';
                goto flag1;
            }
            else if (board[1][1] == board[2][2] && board[1][1] == 'O' && board[0][0] == ' ')
            {
                board[0][0] = '#';
                goto flag1;
            }
            else if (board[0][0] == board[2][2] && board[0][0] == 'O' && board[1][1] == ' ')
            {
                board[1][1] = '#';
                goto flag1;
            }
            else if (board[0][2] == board[1][1] && board[1][1] == 'O' && board[2][0] == ' ')
            {
                board[2][0] = '#';
                goto flag1;
            }
            else if (board[1][1] == board[2][0] && board[1][1] == 'O' && board[0][2] == ' ')
            {
                board[0][2] = '#';
                goto flag1;
            }
            else if (board[2][0] == board[0][2] && board[2][0] == 'O' && board[1][1] == ' ')
            {
                board[1][1] = '#';
                goto flag1;
            }
        }
        if (board[x][y] == ' ')
        {
            board[x][y] = '#';
            goto flag1;
        }
    }
flag1:;
}

void player_move(char board[ROWS][COLS], int rows, int cols)
{
    int x, y;
    printf("玩家走:\n");
    while (1)
    {
        scanf("%d %d", &x, &y);
        if (x >= 1 && x <= rows && y >= 1 && y <= cols)
        {
            if (board[x - 1][y - 1] == ' ')
            {
                board[x - 1][y - 1] = 'O';
                break;
            }
            else printf("坐标被占用,请重新输入:>\n");
        }
        else printf(" 坐标非法,请重新输入:>\n");
    }
}

int is_full(char board[ROWS][COLS], int rows, int cols)
{
    int i, j;
    for (i = 0; i < rows; i++)
    {
        for (j = 0; j < cols; j++)
        {
            if (board[i][j] == ' ')
                return 0;
        }
    }
    return 1;
}

char is_win(char board[ROWS][COLS], int rows, int cols)
{
    int i;
    for (i = 0; i < rows; 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 < cols; 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];
    else if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
        return board[1][1];
    else if (is_full(board, rows, cols))
        return 'q';
    return 0;
}

这一部分是经过发挥的,让电脑更智能,但代码部分我并没有想出简化的写法,只好一步步的用if语句进行完成了。

第三部分是test.c源文件的游戏测试部分:

#include"game.h"
void menu()
{
    printf("***************************************\n");
    printf("*      1.play             0.exit      *\n");
    printf("***************************************\n");
}
void first_move()
{
    printf("***************************************\n");
    printf("*  1.computer first   2.player first  *\n");
    printf("***************************************\n");
}
void game()
{
    int input_1, win;
    char board[ROWS][COLS];
    init_board(board, ROWS, COLS);
    first_move();
again:
    printf("请选择谁先走:>");
    scanf("%d", &input_1);
    switch (input_1)//选择谁先走~
    {
    case 1:
        do
        {
            computer_move(board, ROWS, COLS);
            show_board(board, ROWS, COLS);
            win = is_win(board, ROWS, COLS);//每走一步,我们需要判断是否输赢
            if (win != 0)
                break;
            player_move(board, ROWS, COLS);
            show_board(board, ROWS, COLS);
            win = is_win(board, ROWS, COLS);//每走一步,我们需要判断是否输赢
        } while (win == 0);
        if (win == '#')
            printf("恭喜,电脑赢了!\n");
        if (win == '*')
            printf("恭喜,你赢了!\n");
        if (win == 'q')
            printf("平局!\n");
        break;
    case 2:
        do
        {
            show_board(board, ROWS, COLS);
            player_move(board, ROWS, COLS);
            show_board(board, ROWS, COLS);
            win = is_win(board, ROWS, COLS);
            if (win != 0)
                break;
            computer_move(board, ROWS, COLS);
            win = is_win(board, ROWS, COLS);
        } while (win == 0);
        if (win == '*')
            printf("恭喜!电脑赢了!\n");
        if (win == '#')
            printf("恭喜!你赢了!\n");
        if (win == 'q')
            printf("平局!\n");
        break;
    default:
        printf(" 输入错误,请重新输入!\n");
        goto again;
    }
}
int main()
{
    int input;
    srand((unsigned int)time(NULL));
    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;
}

上一篇:(初阶版本)扫雷游戏(C语言)娱乐教程


下一篇:C语言学习笔记-二维数组之扫雷