先看效果:

思路:
一共定义了8个函数:

  • 菜单打印函数
  • 棋盘打印函数
  • 玩家下棋函数
  • 电脑下棋函数
  • 赢家判断函数
  • 判断棋盘是否满了函数
  • 游戏函数
  • 主函数

菜单打印:
这个没什么好说的,printf 输出就行,写成什么样都可以

棋盘打印:
我们的棋盘实际上就是 3x3 的数组,数组中的元素有:| — X(代表人下的棋) o(代表电脑下的棋)空格(棋盘初始化需要),用 for 循环打印就行

玩家下棋
输入两个值作为二维数组的下标,要对值进行判断,一是判断位置是否正确,二是判断位置是否为空,所以有可能你得再下一次,直接把下棋写成死循环,如果下棋成功则break就行。同样的,若成功下棋,下一步一定要判断有没有产生赢家,产生就结束游戏,没产生的话就电脑下棋,注意:在电脑下棋之前还得检测现在棋盘内是否还有位置,没有位置就意味着平局,有位置则电脑下棋。

电脑下棋
电脑下棋是自动的,所以得为电脑产生两个随机值作为二维数组的下标,因为有可能你要下棋的地方已经被占了,所以你得再下一次,所以直接把电脑下棋写成死循环,如果下棋成功则break就行。若成功下棋,下一步一定要判断有没有产生赢家,产生就结束游戏,没产生的话就玩家下棋,注意:在玩家下棋之前还得检测现在棋盘内是否还有位置,没有位置就意味着平局,有位置则玩家下棋。

赢家判断
对于 3x3 的矩阵来说,若是有赢家一共有八种情况(3横3竖2交叉),判断这8条线上的字符是否相同,若字符相同且不是空格,则说明赢家产生,当赢家产生时,通过判断字符是’X’ 还是 ‘o’ 就可以得知到底是人赢了还是电脑赢了,若没有赢家产生判断棋盘是会否满了,满了则输出平局,否则继续

棋盘是否满了
这个很简单,循环遍历棋盘看有没有空格存在,有就没满

游戏函数
游戏函数主要是调用上面函数来实现游戏,但是在此之前要先初始化棋盘,即给数组对应的位置放入空格(因为现在定义的棋盘是 3x3 的,以后可能会改,不妨把它们定义成全局变量),然后按照自己的逻辑来调用函数,因为一般的游戏只要你不退出哪怕游戏输了也会从头开始,所以用 循环 来实现。

代码:
为了显得正式一点,特意分了三个文件:

  1. test.c
  2. game.c
  3. game.h

game.h

#ifndef __GAME_H__
#define __GAME_H__


#define ROW 3
#define COL 3

void InitBoard(char map[ROW][COL], int row, int col);
void DisplayBoard(char map[ROW][COL], int row, int col);
void PlayerMove(char map[ROW][COL], int row, int col);
void Computermove(char map[ROW][COL], int row, int col);
char IsWin(char map[ROW][COL], int row, int col);//有返回值的原因是要根据返回值的字符来看看是人赢了还是电脑
char is_full(char map[ROW][COL], int row, int col);//棋盘是否已满

#endif  //__GAME_H__

game.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

void InitBoard(char map[ROW][COL], int row, int col)
{
	/*int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			map[i][j] = '*';
		}
	}*/

	memset(map, ' ', row*col*sizeof(map[0][0]));
}


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

void PlayerMove(char map[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	
	//下的位置可能有旗,得重复下,死循环
	while (1)
	{
		printf("请玩家输入坐标:");
		scanf("%d%d", &x, &y);
		if (1 <= x && row >= x && 1 <= y && col >= y) //坐标界限
		{
			//先判断这个位置是否有元素
			if (map[x - 1][y - 1] == ' ')//为空
			{
				map[x - 1][y - 1] = 'X';//X代表玩家下的
				break; //如果下了元素记得跳出循环
			}
			else 
			{
				printf("该坐标已经有棋,请重新输入!\n");
			}
		}
		else
		{
			printf("坐标输入有误,请重新输入!\n");
		}
	}

}


void Computermove(char map[ROW][COL], int row, int col) 
{
	int x = 0;
	int y = 0;
	printf("该电脑走了\n");
	while (1)
	{
		x = rand() % row;
		y = rand() % col;

		if (map[x][y] == ' ')
		{
			map[x][y] = 'o';
			break;
		}
	}
}


char is_full(char map[ROW][COL], int row, int col) {
	int count = row*col;
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			if (map[i][j] == ' ')//有空格就返回t
			{
				return 't';
			}
		}
	}
	return 'f';//没有空格返回f
}


char IsWin(char map[ROW][COL], int row, int col)
{
	char ret = is_full(map, ROW, COL);

	for (int i = 0; i < row; i++) {
		//判断每一行
		if (map[i][0] == map[i][1] && map[i][0] == map[i][2] && map[i][0] != ' ') 
		{
			return map[i][0];
		}
	}

	for (int i = 0; i < col; i++) {
		//判断每一列是否相等
		if (map[0][i] == map[1][i] && map[0][i] == map[2][i] && map[0][i] != ' ')
		{
			return map[0][i];
		}
	}

	//对角线判断
	if (map[0][0] == map[1][1] && map[1][1] == map[2][2] && map[1][1] != ' ') {
		return map[0][0];
	}
	if (map[0][2] == map[1][1] && map[1][1] == map[2][0] && map[1][1] != ' ') {
		return map[1][1];
	}

	if ('f' == ret) {
		return 'p';
	}
	if ('t' == ret) {
		return 't';
	}
	
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "game.h"


//菜单打印函数
void menu()
{
	printf("**********************************\n");
	printf("****** 欢迎来到三子棋游戏 ********\n");
	printf("**********************************\n");
	printf("******   1 play  0 exit   ********\n");
	printf("**********************************\n");
}

void game()
{
	char tmp;
	char ret;
	char map[ROW][COL] = { 0 };
	//第一步:画出棋盘
	InitBoard(map,ROW,COL);
	//DisplayBoard(map, ROW, COL);
	system("cls");//清屏

	while (1)
	{
		PlayerMove(map, ROW, COL);
		DisplayBoard(map, ROW, COL);
		//每下完一次后都判断一下是否有赢家
		tmp = IsWin(map,ROW,COL);
		if (tmp == 'X')
		{
			printf("玩家赢!\n");
			break;
		}
		else if (tmp ==  'o')
		{
			printf("电脑赢!\n");
			break;
		}
		//谁都没赢,先判断棋盘是不是满了,没满再下一步
		else if (tmp == 'p')
		{
			printf("平局!\n");
			break;
		}
		else
			;
		

		Computermove(map, ROW, COL);
		DisplayBoard(map, ROW, COL);
		//每下完一次后都判断一下是否有赢家
		tmp = IsWin(map, ROW, COL);
		if (tmp == 'X')
		{
			printf("玩家赢!\n");
			break;
		}
		else if (tmp == 'o')
		{
			printf("电脑赢!\n");
			break;
		}
		//谁都没赢,先判断棋盘是不是满了,没满再下一步
		else if (tmp == 'p')
		{
			printf("平局!\n");
			break;
		}
		else
			;

	}
}


//主函数
int main()
{
	int input = 0;
	srand((unsigned)time(NULL));
	//用do while循环这样的话,在最初就会执行一次
	do {
		menu();
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("您的输出有误,请重新输入!\n");
		}

	} while (input);



	system("pause");
	return 0;	
}

有了上面的思路,再来写五子棋就很简单了,只需要修改三部分

  • 1,修改棋盘大小
#define ROW 5
#define COL 5
  • 2,修改输赢判断条件
char IsWin(char map[ROW][COL], int row, int col)
{
	char ret = is_full(map, ROW, COL);

	for (int i = 0; i < row; i++) {
		//判断每一行
		if (map[i][0] == map[i][1] && map[i][0] == map[i][2] && map[i][0] == map[i][3]  && map[i][0]  == map[i][4] && map[i][0] != ' ')
		{
			return map[i][0];
		}
	}

	for (int i = 0; i < col; i++) {
		//判断每一列是否相等
		if (map[0][i] == map[1][i] && map[0][i] == map[2][i] && map[0][i] == map[3][i] && map[0][i] == map[4][i] && map[0][i] != ' ')
		{
			return map[0][i];
		}
	}

	//对角线判断
	if (map[0][0] == map[1][1] && map[1][1] == map[2][2] && map[2][2] == map[3][3] && map[3][3] == map[4][4] && map[2][2] != ' ') {
		return map[2][2];
	}
	if (map[0][4] == map[1][3] && map[1][3] == map[2][2] && map[2][2] == map[3][1] && map[3][1] == map[4][0] && map[2][2] != ' ') {
		return map[2][2];
	}

	if ('f' == ret) {
		return 'p';
	}
	if ('t' == ret) {
		return 't';
	}
	
}
  • 3,修改打印棋盘的函数
void menu()
{
	printf("**********************************\n");
	printf("****** 欢迎来到五子棋游戏 ********\n");
	printf("**********************************\n");
	printf("******   1 play  0 exit   ********\n");
	printf("**********************************\n");
}