手把手教你C语言五子棋的实现(双玩家对战)

Posted 小赵小赵福星高照~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手教你C语言五子棋的实现(双玩家对战)相关的知识,希望对你有一定的参考价值。

五子棋的实现


我们依然分以下三个文件来实现五子棋:

test.c - 主函数 - 设计整个游戏过程

游戏的逻辑

game.c - 函数的实现

game.h - 函数的声明

五子棋和三子棋十分像,仅仅是输赢的检查不一样,我们这次设计成两个玩家对着下的游戏模式

成品展示

image-20210501231744261

首先我们打印一个菜单,让玩家选择,选择后会出现棋盘界面,然后让玩家1输入坐标下棋。

image-20210501231830729

然后玩家2再输入坐标,之后实现玩家1走和玩家2走,直到一方横竖左斜右斜连成五子则获得胜利,游戏结束。

image-20210501232115927

首先讲一讲我们整体的思路框架,我们设计这个游戏,让玩家想玩的时候可以一直玩,所以我们采用do…while循环语句,然后打印菜单,写一个菜单函数,让玩家进行选择,这里我们采用switch分支语句,当我们选择1时进入游戏,此时需要写一个游戏函数,选择0时退出游戏,选择其他时,告诉他选择错误,重新输入,我们发现当选择1和选择错误时我们需要循环继续,退出游戏是我们退出循环的时候,所以我们将while()里的循环条件设置成玩家输入的选择。

我们的整体逻辑框架如下代码:

test.c

void game()
{
	//游戏的实现,这里先不写  
}
void menu()
{
    printf("********************\\n");
    printf("*******1.play*******\\n");
    printf("*******0.exit*******\\n");
    printf("********************\\n");
}
int main()
{
    int input=0;
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d",&input);
        switch(input)
        {
        case 1:
        		game();
                break;
        case 2:
                printf("退出游戏\\n");
                break;
        default:
                printf("选择错误,重新选择\\n");
                break;
        }
    }while(input)
    return 0;
}

那么游戏的实现,我们该怎么弄呢?

从刚开始我们进行成品展示时,实现这个游戏,我们需要:

1、创建一个存储数据的字符数组

行列的元素个数我们用#define在game.h中定义常量,这样我们需要修改棋盘行列时就很简单,使我们的游戏程序更加灵活多变。

char board[ROW][COL] = { 0 };

image-20210501232327319

2、初始化数据

首先打印的界面数据为空的,我们需要初始化数据为空格

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] = ' ';
		}
	}
}

3、打印棋盘

image-20210501232454064

打印棋盘代码:

这里我们打印棋盘的代码与上篇三子棋文章一样,这就看到前面用#define定义行和列的好处了,当我们想打印10*10的棋盘时,直接将ROW,COL改为10就好了。

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

这里以3*3棋盘讲解为例:

image-20210425210310094

我们把打印棋盘分成了打印数据行和打印分割行,我们发现分割行我们只打印两次,最后一行我们不需要分割行,所以我们将判断条件设置为i<row-1时我们才打印分割行,我们再看列,最后一行我们不打印|,所以|的打印我们给判断条件j<col-1。

4、玩家走棋

玩家走的函数代码如下:

void PlayerMove(int num, char board[ROW][COL], int row, int col, char set)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("玩家%d走,请输入下棋的坐标:>", num);
		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] = set;
				break;
			}
			else
			{
				printf("该坐标已被占用,请重新选择坐标\\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\\n");
		}
	}
}

玩家走的函数参数我们给定5个,分别是显示哪个玩家的参数、棋盘数组、行、列、每个玩家要下后的展示字符(好比黑白棋),首先我们需要判断该玩家输入的下棋坐标是否合法,我们的棋盘是十行十列,所以玩家输入的坐标需要在范围内,如果坐标合法了,我们再判断该坐标是否被占用,如果没有被占用,则将该坐标所对应数组下标数据赋值为传进来的参数set(因为我们玩家玩游戏时输入(1,1)坐标时,对应的数组下标为board[0] [0],所以我们判断条件的数组下标需要设置为x-1,y-1)。

5、判断输赢

首先我们看一下判断输赢的基本框架:

我们设定判断输赢函数的返回值

1.玩家1赢,返回*
2.玩家2赢,返回#
3.平局,返回Q
4.游戏继续,返回C

ret = IsWin(board, ROW, COL);
//用ret来接收判断输赢函数的返回值
//1.玩家1赢,返回*
//2.玩家2赢,返回#
//3.平局,返回Q
//4.游戏继续,返回C

我们在每个玩家走后判断输赢,在循环内部判断,如果返回的不是C,则说明游戏结束,则跳出循环判断其他三种情况

if (ret != 'C')//游戏已结束
{
    break;
}

循环外面判断:

	if (ret == '*')
	{
		printf("玩家1赢\\n");
	}
	else if (ret == '#')
	{
		printf("玩家2赢\\n");
	}
	else if (ret == 'Q')
	{
		printf("平局\\n");
	}

判断输赢函数代码:

char IsWin(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] == ' ')
			{
				continue;
			}
			else if ((board[i][j] == board[i][j + 1] && board[i][j] == board[i][j + 2] && board[i][j] == board[i][j + 3] && board[i][j] == board[i][j + 4]) ||
				//横
				(board[i][j] == board[i + 1][j] && board[i][j] == board[i + 2][j] && board[i][j] == board[i + 3][j] && board[i][j] == board[i + 4][j]) ||
				//竖
				(board[i][j] == board[i + 1][j + 1] && board[i][j] == board[i + 2][j + 2] && board[i][j] == board[i + 3][j + 3] && board[i][j] == board[i + 4][j + 4]) ||
				//右斜
				(board[i][j] == board[i + 1][j - 1] && board[i][j] == board[i + 2][j - 2] && board[i][j] == board[i + 3][j - 3] && board[i][j] == board[i + 4][j - 4]))
				//左斜
			{
				return board[i][j];
			}
			else
			{
				continue;
			}
		}
	}
	if (IsFull(board, row, col) == 1)
	{
		return 'Q';
	}
	return 'C';
}

我们需要判断行、列、左斜,右斜是否形成五个一样的字符,以及棋盘是否满,来判断游戏是否结束,因为我们设定1.玩家1赢,返回*,2.玩家2赢,返回#。所以我们判断行、列、左斜、右斜时可以直接return里面任意一个字符就可以知道是谁赢了,或者是平局,平局我们需要写一个判断棋盘是否满的函数,如果返回值为1,则表示满–平局,如果玩家1赢,玩家2赢,平局这三个都不满足,则游戏继续,return字符‘C’。
判断棋盘是否满的代码

//判断棋盘是否满
int IsFull(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。

需要注意每个玩家走后都要进行判断输赢

test.c中的游戏函数代码如下:

void game()
{
	//1.创建存储数据的字符数组,行列的元素我们用#define定义,这样我们需要修改棋盘行列时就很简单
	char board[ROW][COL] = { 0 };
	//2.首先打印的界面数据为空的,我们需要初始化数据为空格
	InitBoard(board, ROW, COL);
	//3.打印棋盘
	DispalyBoard(board, ROW, COL);
	char ret = 0;
	while (1)
	{
		//4.玩家1走
		PlayerMove(1, board, ROW, COL, '*');
		//判断输赢
		ret = IsWin(board, ROW, COL);
		//1.玩家1赢,返回*
		//2.玩家2赢,返回#
		//3.平局,返回Q
		//4.游戏继续,返回C
		DispalyBoard(board, ROW, COL);
		if (ret != 'C')//游戏已结束
		{
			break;
		}

		//玩家2走
		PlayerMove(2, board, ROW, COL, '#');
		//ComputerMove(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		DispalyBoard(board, ROW, COL);
		if (ret != 'C')//游戏已结束
		{
			break;
		}

	}
	if (ret == '*')
	{
		printf("玩家1赢\\n");
	}
	else if (ret == '#')
	{
		printf("玩家2赢\\n");
	}
	else if (ret == 'Q')
	{
		printf("平局\\n");
	}

}

游戏的实现中用到的函数我们在game.h文件中声明

game.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 10
#define COL 10

//初始化数组数据函数声明
void InitBoard(char board[ROW][COL], int row, int col);
//打印棋盘函数声明
void DispalyBoard(char board[ROW][COL], int row, int col);
//玩家走函数声明
void PlayerMove(int num, char board[ROW][COL], int row, int col, char set);
//检查输赢函数声明
char IsWin(char board[ROW][COL], int row, int col);

我们在game.c中写函数的定义

game.c

#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 DispalyBoard(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");
		if (i < row - 1)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\\n");
		}
	}
}
//玩家走函数定义
void PlayerMove(int num, char board[ROW][COL], int row, int col, char set)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("玩家%d走,请输入下棋的坐标:>", num);
		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] = set;
				break;
			}
			else
			{
				printf("该坐标已被占用,请重新选择坐标\\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\\n");
		}
	}
}
//判断棋盘是否满
int IsFull(char board[ROW][以上是关于手把手教你C语言五子棋的实现(双玩家对战)的主要内容,如果未能解决你的问题,请参考以下文章

双人小游戏—五子棋(c语言)

C语言实现五子棋三子棋人机对战,包含电脑人工智能对战(可攻可守)(非标题党)

C语言 AI智能,五子棋 人机对战,人人对战

实现一个Java五子棋

Java五子棋课程设计

五子棋人机对战