井字棋(C语言)

本文详细介绍了使用C语言开发三子棋游戏的步骤。首先设置三个文件,接着布置菜单,进入菜单可选择开始或退出。构建game()函数逻辑,包括初始化数组、打印棋盘、玩家和电脑下棋及判断输赢等。还对game函数各部分进行详细解释,最后总结代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三子棋的思维导图


第一步,设置三个文件

这里面是设置三个文件:

test.c//测试文件(函数的大体都放在这里)

game.c//实现文件(主要是实现函数的逻辑)

game.h//头文件(函数的头文件一般放在这里面)


第二步,布置菜单

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
 
void menu()
{
	printf("*****************************\n");
	printf("*******输入对应的数字********\n");
	printf("*********1.开始游戏**********\n");
	printf("*********0.退出游戏**********\n");
	printf("*****************************\n");
}
 
 
 
 
int main()
{
	menu();          //这里直接调用函数,下面一样 不过多赘述
	return 0;
}

这里面采取调用函数,也就是调用菜单


第三步,进入菜单(1 是开始 ,0 是退出)

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
 
void menu()
{
	printf("*****************************\n");
	printf("*******输入对应的数字********\n");
	printf("*********1.开始游戏**********\n");
	printf("*********0.退出游戏**********\n");
	printf("*****************************\n");
}
 
void test()
{
 
	int input = 0;
	scanf("%d", &input);
 
switch (input)        
	{
	case 1:          //这里的意思是,输入一个数字 如果是1 则进入game()函数。
		game();
		break;
	case 0:         //如果是0则打印退出函数,并且跳出函数
		printf("退出游戏。");
		break;
	default:       //如果输入其他数字,则打印输入错误,请重新输入,并且跳出函数
		printf("输入错误,请重新输入");
		break;
	}
 
}
 
 
 
int main()
{
	menu();
	test();
	return 0;
}

当然你也可以写成这样,但是要注意的,这样写需要把main里面的menu()去掉,免得多此一举。

do
	{
		menu();
		printf("请选择:");
		scanf("%d", &input);  
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束,退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);
 

第四步,构建逻辑,game()函数的构建;(逻辑讲解)

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
	printf("*****************************\n");
	printf("*******输入对应的数字********\n");
	printf("*********1.开始游戏**********\n");
	printf("*********0.退出游戏**********\n");
	printf("*****************************\n");
}

void game()
{
	//创建数组


	//初始化数组


	//打印棋盘


	//玩家下棋


	//电脑下棋


	//判断输赢

}

void test()
{
	int input = 0;
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		game();
		break;
	case 0:
		printf("退出游戏。");
		break;
	default:
		printf("输入错误请重新输入。");
		break;
	}

}


int main()
{
	menu();
    test();
	return 0;
}

1.初始化数组

创建一个数组我们对其进行命名


2. 打印棋盘

这里的打印棋盘是有三种情况

逻辑

a.只打印出数据(不采取)

b.打印出固定的棋盘,如图(不采取)

c.这里的棋盘是具备可延长性质(采取)

也就是随着数组大小的改变棋盘的大小也会发生变化


   

3.玩家下棋

逻辑

这里的玩家下棋是令玩家先手进行下棋,如果想进行修改也就是电脑进行先下棋,只需要吧电脑下棋的函数放到玩家的前面就可以,这里不进行过多的赘述。

1.玩家下棋这里面肯定是循环

2.需要知道这里玩家的下棋是有一个限制的

3.此时我们还要进行完善 


4.  电脑下棋

逻辑

这里的电脑下棋

1,。需要用到时间戳

2.这是一个循环

3.只有当存在空格字符的时候才可以往里面放置地雷,也就是#,并且跳出循环,在主函数里面的玩家下棋下面打印棋盘


5. 判断输赢

逻辑

1.这里判断输赢需要对玩家下棋进行输赢的判断

2.需要对电脑的对局进行输赢的判断

3.我们可以令这些的返回值进行对照,防止冗余,然后设置一个参数接收判断输赢的函数IsWin就可以

//判断输赢
// 
// 注释
//在判断输赢里面
//'*'玩家胜利
//'#'电脑胜利
//'Q'平局
//'C'继续
//IsWin(board, ROW, COL);

第五步,对game函数的详细解释(同时对每一次进行一次代码的总结,进行对照,方便学习)

1.关于初始化棋盘的详细解释

这里的初始化棋盘是很简单的一件事情就是两个循环进行二维数组的初始化

代码实现

test,c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
	printf("*****************************\n");
	printf("*******输入对应的数字********\n");
	printf("*********1.开始游戏**********\n");
	printf("*********0.退出游戏**********\n");
	printf("*****************************\n");
}

void game()
{
	//创建数组
	char board[ROW][COL] = { 0 };

	//初始化数组
	Intboard(board, ROW, COL);

	//打印棋盘


	//玩家下棋


	//电脑下棋


	//判断输赢

}

void test()
{
	int input = 0;
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		game();
		break;
	case 0:
		printf("退出游戏。");
		break;
	default:
		printf("输入错误请重新输入。");
		break;
	}

}


int main()
{
	menu();
    test();
	return 0;
}

game,c

board[i][j] = ' ';这个不能写成char board

在C语言中,数组定义中的大小写是有区别的。char board 表示定义了一个字符类型的变量 board,而 char board[ROW][COL] 表示定义了一个二维字符数组,数组的维度由 ROW 和 COL 决定。

这里 board[i][j] = ' '; 是正确的。这行代码的意思是将二维数组 board 中第 i 行第 j 列的元素初始化为空格字符 ' '。
如果你写成 char board,则意味着你试图将整个二维数组赋值为一个单一的字符变量,这显然不是你的意图,也会导致编译错误。正确的做法是使用数组的形式,即 char board[ROW][COL],以便为棋盘的每个位置分配空间。
请确保在包含 game.h 头文件之前定义了 ROW 和 COL,否则编译器无法确定数组的大小。

这里需要知道=和==是不一样的。=是进行赋值,==是对比

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"



//初始化棋盘
void Intboard(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] = ' ';
		}
	}
}


game.h

#pragma once
#include<stdio.h>
#include<time.h>//time头文件
#include<stdlib.h>//rand头文件

//数组的行和列
#define ROW 3
#define COL 3



//初始化棋盘
void Intboard(char board[ROW][COL], int row, int col);


2.关于打印棋盘的详细解释

这里的打印棋盘是有三种情况

逻辑

a.只打印出数据(不采取)

简单说就是打印出来是无法分辨坐标是多少多少的(也是最简单的打印方法)

这里看着是空白的,其实棋盘已经打印出来,但是我们不采取这一种,不便于观察

 game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"



//初始化棋盘
void Intboard(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 DiaplayBoard(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]);
		}
		printf("\n");
	}


	//版本二



	//版本三



}

打印出来的效果图

b.打印出固定的棋盘,如图(不采取)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"



//初始化棋盘
void Intboard(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 DiaplayBoard(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]);
	//	}
	//	printf("\n");
	//}


	////版本二
	for (int i = 0; i < row; i++)
	{
		printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
		if (i < row - 1)
			printf("---|---|---\n");
	}


	//版本三



}

        printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
        if (i < row - 1)
            printf("---|---|---\n");

这里之所以是小于row-1是因为为了美观井字棋的最后一行是不打印的,所以是当小于三行-1的时候,停止打印最后一行

c.这里的棋盘是具备可延长性质(采取)

也就是随着数组大小的改变棋盘的大小也会发生改变


这里令二维数组是5*5 就会打印新的棋盘 不需要再次更改

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"



//初始化棋盘
void Intboard(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 DiaplayBoard(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]);
	//	}
	//	printf("\n");
	//}


	////版本二
	//for (int i = 0; i < row; i++)
	//{
	//	printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
	//	if (i < row - 1)
	//		printf("---|---|---\n");
	//}


	//版本三
	
	for (int i = 0; i < row; i++)
	{
		//打印数据
		for (int j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			//if (i < row - 1)
				printf("|");

		}
		printf("\n");

		//打印分割线
		for (int i = 0; i < row; i++)
		{
			printf("---");
			printf("|");

		}
		printf("\n");


	}

	


}

对其进行修改

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"



//初始化棋盘
void Intboard(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 DiaplayBoard(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]);
	//	}
	//	printf("\n");
	//}


	////版本二
	//for (int i = 0; i < row; i++)
	//{
	//	printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
	//	if (i < row - 1)
	//		printf("---|---|---\n");
	//}


	//版本三
	
	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");
		}

	}

	


}

 这里解释一下

1.打印数据

简单的逻辑就是首先把空的棋盘打印出来,也就是数据棋盘,然后下面加一个打印|,这个是打印棋盘的每一行的|,此时会出现三列|,也就是一行会出现三个|,所以我们加一个判断条件,小于col-1,因为此时打印的是每一行的数据,但是实际是是有col列,所以要-1.、

简单解释一下就是,首先打印一个空格+|,然后循环col次数,结束之后换行以此类推循环row次数,所以打印的时候要--1.不需要最后的|打印出来

2.打印分割线

这里是依旧采取的是一个一个打印的,不给固定,给更多的可操作性。

此时我们的数据和数据后面的|已经打印好,就差每一行的分割线,所以此时我们只需要在下面加一个循环,循环打印---,然后此时会发现上下连接存在缝隙,下面加一个打印|,但是此时发现分割线打印三行,但是我们只需要两行,所以row-1.要小于这个。同理,里面的|打印了三列,所以是col-1。

代码实现

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
	printf("*****************************\n");
	printf("*******输入对应的数字********\n");
	printf("*********1.开始游戏**********\n");
	printf("*********0.退出游戏**********\n");
	printf("*****************************\n");
}

void game()
{
	//创建数组
	char board[ROW][COL] = { 0 };

	//初始化数组
	Intboard(board, ROW, COL);

	//打印棋盘
	DiaplayBoard(board, ROW, COL);


	//玩家下棋


	//电脑下棋


	//判断输赢

}

void test()
{
	int input = 0;
	printf("输入对应的数字:");
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		game();
		break;
	case 0:
		printf("退出游戏。");
		break;
	default:
		printf("输入错误请重新输入。");
		break;
	}

}


int main()
{
	menu();
	test();
	return 0;
}

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"



//初始化棋盘
void Intboard(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 DiaplayBoard(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]);
	//	}
	//	printf("\n");
	//}


	////版本二
	//for (int i = 0; i < row; i++)
	//{
	//	printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
	//	if (i < row - 1)
	//		printf("---|---|---\n");
	//}


	//版本三
	
	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");
		}

	}

	


}

game.h

#pragma once
#include<stdio.h>
#include<time.h>//time头文件
#include<stdlib.h>//rand头文件

//数组的行和列
#define ROW 3
#define COL 3



//初始化棋盘
void Intboard(char board[ROW][COL], int row, int col);

//打印棋盘
void DiaplayBoard(char board[ROW][COL], int row, int col);

3.关于玩家下棋的详细解释

逻辑

这里的玩家下棋是令玩家先手进行下棋,如果想进行修改也就是电脑进行先下棋,只需要吧电脑下棋的函数放到玩家的前面就可以,这里不进行过多的赘述。

1.需要知道首先不管谁进行下棋这里可肯定是循环,因为一次的对局肯定不能导致对局的结束所以这里肯定是一个循环

2.需要知道这里玩家的下棋是有一个限制的也就是必须小于设定的棋盘大小大于等于1,因为这里有一个很重要的一点就是我们设定游戏的时候是从0开始的,而且电脑的计算也是从0开始的,但是玩家并不是这样,玩家眼睛里面的棋盘是1开始的,所以我们进行设定的时候我们需要进行坐标-1,但是输入的坐标必须大于等于1,小于等于3

3.此时我们还要进行完善 就是坐标的输入不能重复输入,如果重复输入则判断为错误坐标请重新输入,并且电脑也不会进行输入,这种情况下玩家下棋的逻辑算是完成了。

代码的实现步骤

1.开始逻辑

//玩家下棋
void PlayerMover(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	DiaplayBoard(board, ROW, COL);
	printf("请输入坐标,中间用空格键隔开:");
	scanf("%d %d", &x, &y);



}

2. 判断是否在区间内

//玩家下棋
void PlayerMover(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入坐标,中间用空格键隔开:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标是否在区间内
		{

		}
		else
		{
			printf("坐标输入不合法,请重新输入。");
		}
	}


}

 3.进行坐标的输入

//需要知道==是对比 =是赋值 这里是如果输入的坐标 ==字符空格 那么可以赋值为# 然后打印棋盘跳出循环

//玩家下棋
void PlayerMover(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入坐标,中间用空格键隔开:");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断坐标是否在区间内
		{
			if (board[x][y] == ' ')//需要知道==是对比 =是赋值 这里是如果输入的坐标 ==字符空格 那么可以赋值为# 然后打印棋盘跳出循环
			{
				board[x][y] = '#';
				DiaplayBoard(board, ROW, COL);
				break;
			}
			else
			{
				printf("坐标重复请重新输入。");
			}
		}
		else
		{
			printf("坐标输入不合法,请重新输入。");
		}
	}


}

此时如图

4.改变玩家坐标输入

//玩家下棋
void PlayerMover(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	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] = '#'; //*这里是用#进行实验 注意是*就行
				DiaplayBoard(board, ROW, COL);
				break;
			}
			else
			{
				printf("坐标重复请重新输入。");
			}
		}
		else
		{
			printf("坐标输入不合法,请重新输入。");
		}
	}


}

这里是关键的一步,因为之前说过,玩家的输入坐标是从1 开始的 但是电脑计算是从0开始的,所以我们需要进行xy各自-1,然后进行电脑的计算值

board[x-1][y-1] = '#'; //*这里是用#进行测试 注意是*就行 也就是实际的玩家下棋我们的符号是*

此时如图

代码实现

test,c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
	printf("*****************************\n");
	printf("*******输入对应的数字********\n");
	printf("*********1.开始游戏**********\n");
	printf("*********0.退出游戏**********\n");
	printf("*****************************\n");
}

void game()
{
	//创建数组
	char board[ROW][COL] = { 0 };

	//初始化数组
	Intboard(board, ROW, COL);

	//打印棋盘
	DiaplayBoard(board, ROW, COL);


	//玩家下棋
	PlayerMover(board, ROW, COL);

	//电脑下棋


	//判断输赢

}

void test()
{
	int input = 0;
	printf("输入对应的数字:");
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		game();
		break;
	case 0:
		printf("退出游戏。");
		break;
	default:
		printf("输入错误请重新输入。");
		break;
	}

}


int main()
{
	menu();
	test();
	return 0;
}

game,c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"



//初始化棋盘
void Intboard(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 DiaplayBoard(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]);
	//	}
	//	printf("\n");
	//}


	////版本二
	//for (int i = 0; i < row; i++)
	//{
	//	printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
	//	if (i < row - 1)
	//		printf("---|---|---\n");
	//}


	//版本三
	
	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 PlayerMover(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	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] = '*';
				DiaplayBoard(board, ROW, COL);
				break;
			}
			else
			{
				printf("坐标重复请重新输入。");
			}
		}
		else
		{
			printf("坐标输入不合法,请重新输入。");
		}
	}


}

game.h

#pragma once
#include<stdio.h>
#include<time.h>//time头文件
#include<stdlib.h>//rand头文件

//数组的行和列
#define ROW 3
#define COL 3



//初始化棋盘
void Intboard(char board[ROW][COL], int row, int col);

//打印棋盘
void DiaplayBoard(char board[ROW][COL], int row, int col);

//玩家下棋
void PlayerMover(char board[ROW][COL], int row, int col);

4.关于电脑下棋的详细解释

这里的电脑下棋

1,。需要用到时间戳,这里因为是三子棋比较简单,不需要更多的进行ai模型训练什么的,所以我们直接简化,进行时间戳和电脑进行下棋

2.这是一个循环

3.这里的电脑下棋是当玩家下棋之后,我们需要利用时间戳布置地雷的时候,需要知道只有当存在空格字符的时候才可以往里面放置地雷,也就是#,并且跳出循环,在主函数里面的玩家下棋下面打印棋盘

代码的实现步骤

1.利用时间戳,设置几个地雷 并且随机布置上去,头文件在.h里面有标注

test.c

void test()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	printf("输入对应的数字:");
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		game();
		break;
	case 0:
		printf("退出游戏。");
		break;
	default:
		printf("输入错误请重新输入。");
		break;
	}

}
//电脑下棋
void  ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋");
	x = rand() % row;
	y = rand() % col;
	while (1)
	{

	}




}

 2.这里解释一下  为什么      

if (board[x][y] == ' ')
        {
            board[x][y] = '#'; 
            DiaplayBoard(board, ROW, COL);
            break;
        }

因为这是电脑的下棋,不是玩家的下棋,玩家下棋的时候考虑的坐标是有取值范围的,往往是从1开始的,而不是从0开始,但是电脑计算的时候是从0开始的,所以要-1这个时候就变成了和电脑计算的取值范围一样 

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




}

代码实现

test,c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
	printf("*****************************\n");
	printf("*******输入对应的数字********\n");
	printf("*********1.开始游戏**********\n");
	printf("*********0.退出游戏**********\n");
	printf("*****************************\n");
}

void game()
{
	//创建数组
	char board[ROW][COL] = { 0 };

	//初始化数组
	Intboard(board, ROW, COL);

	//打印棋盘
	DiaplayBoard(board, ROW, COL);


	//玩家下棋
	PlayerMover(board, ROW, COL);

	//电脑下棋
	ComputerMove(board, ROW, COL);

	//判断输赢

}

void test()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	printf("输入对应的数字:");
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		game();
		break;
	case 0:
		printf("退出游戏。");
		break;
	default:
		printf("输入错误请重新输入。");
		break;
	}

}


int main()
{
	menu();
	test();
	return 0;
}

game,c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"



//初始化棋盘
void Intboard(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 DiaplayBoard(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]);
	//	}
	//	printf("\n");
	//}


	////版本二
	//for (int i = 0; i < row; i++)
	//{
	//	printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
	//	if (i < row - 1)
	//		printf("---|---|---\n");
	//}


	//版本三
	
	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 PlayerMover(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	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] = '*';
				DiaplayBoard(board, ROW, COL);
				break;
			}
			else
			{
				printf("坐标重复请重新输入。");
			}
		}
		else
		{
			printf("坐标输入不合法,请重新输入。");
		}
	}


}


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




}

game.h

#pragma once
#include<stdio.h>
#include<time.h>//time头文件
#include<stdlib.h>//rand头文件

//数组的行和列
#define ROW 3
#define COL 3



//初始化棋盘
void Intboard(char board[ROW][COL], int row, int col);

//打印棋盘
void DiaplayBoard(char board[ROW][COL], int row, int col);

//玩家下棋
void PlayerMover(char board[ROW][COL], int row, int col);

//电脑下棋
void  ComputerMove(char board[ROW][COL], int row, int col);

——————————————————————————————————————————————————————————————————————————————————————

5.关于判断输赢的详细解释

接下来对打印棋盘进行一定的修改,把打印棋盘在里面放在外面,其实没有区别,但是为了独立性,进行修改。

逻辑

1.首先需要知道在主函数里面这里面是一个循环,而不是只是在实现里面是循环,因为要实现循环的打印棋盘

2.这里判断输赢需要对玩家下棋进行输赢的判断,同时判断输赢里面直接返回输赢的数组就可以,

3.需要对电脑的对局进行输赢的判断

4.这里的判断输赢包括 行 列 对角线,我们可以令这些的返回值进行对照,防止冗余,然后设置一个参数接收判断输赢的函数IsWin就可以

4.判断是否是平局

5.判断是继续游戏还是跳出游戏,那么我们可以在主函数里面的循环里面加一个判断语句,如果是继续C那么不跳出循环,如果!=C那么久跳出循环,外面承接判断语句进行打印。

//判断输赢
// 
// 注释
//在判断输赢里面
//'*'玩家胜利
//'#'电脑胜利
//'Q'平局
//'C'继续
//IsWin(board, ROW, COL);

代码的实现步骤

1.这是一个循环

test,c

void game()
{
	//创建数组
	char board[ROW][COL] = { 0 };

	//初始化数组
	Intboard(board, ROW, COL);

	//打印棋盘
	DiaplayBoard(board, ROW, COL);


//在判断输赢里面
//'*'玩家胜利
//'#'电脑胜利
//'Q'平局
//'C'继续
	int ret = 0;
	while (1)
	{
	
		PlayerMover(board, ROW, COL);//玩家下棋
		DiaplayBoard(board, ROW, COL);//打印棋盘 这里我们把打印棋盘从里面拿到外面
		ret = IsWin(board, ROW, COL);//判断输赢


		ComputerMove(board, ROW, COL);//电脑下棋
		DiaplayBoard(board, ROW, COL);//打印棋盘
		ret = IsWin(board, ROW, COL);//判断输赢


		
	}


}

game.c

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

//判断输赢
char IsWin(char board[ROW][COL], int row, int col)
{

}

game.h

//电脑下棋
void  ComputerMove(char board[ROW][COL], int row, int col);

//判断输赢
////判断输赢
// 
// 注释
//在判断输赢里面
//'*'玩家胜利
//'#'电脑胜利
//'Q'平局
//'C'继续
//IsWin(board, ROW, COL);
char IsWin(char board[ROW][COL], int row, int col);

2.

test,c

此时在判断输赢里面 主函数只负责接收数值,防止函数产生冗余

void menu()
{
	printf("*****************************\n");
	printf("*******输入对应的数字********\n");
	printf("*********1.开始游戏**********\n");
	printf("*********0.退出游戏**********\n");
	printf("*****************************\n");
}

void game()
{
	//创建数组
	char board[ROW][COL] = { 0 };

	//初始化数组
	Intboard(board, ROW, COL);

	//打印棋盘
	DiaplayBoard(board, ROW, COL);


//在判断输赢里面
//'*'玩家胜利
//'#'电脑胜利
//'Q'平局
//'C'继续
	char ret = 0;
	while (1)
	{
	
		PlayerMover(board, ROW, COL);//玩家下棋
		DiaplayBoard(board, ROW, COL);//打印棋盘 这里我们把打印棋盘从里面拿到外面
		ret = IsWin(board, ROW, COL);//判断输赢

		if (ret!='C')//返回值不继续,跳出循环
		{
			break;
		}

		ComputerMove(board, ROW, COL);//电脑下棋
		DiaplayBoard(board, ROW, COL);//打印棋盘
		ret = IsWin(board, ROW, COL);//判断输赢

		if (ret != 'C')//返回值不继续,跳出循环
		{
			break;
		}
		
	}
	if (ret == '*')//返回值是*玩家胜利
	{
		printf("玩家胜利。");
	}
	else if(ret=='#')//返回值是#电脑胜利
	{
		printf("电脑胜利。");
	}
	else           //返回值是Q 也就是其他情况 此时平局
	{
		printf("平局。");
	}
}

game,c

//判断输赢
char IsWin(char board[ROW][COL], int row, int col)
{
	//赢
	//判断 行三子 列三子 对角线三子 




	//平局


	//继续




}

game.h

char IsWin(char board[ROW][COL], int row, int col);

3.这里采取如果的判断形势,利用坐标判断一行或者一列或者对角线三子的字符是否相等,如果相等直接返回其中一个字符,在test里面进行判断从而进行打印

test,c

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void menu()
{
	printf("*****************************\n");
	printf("*******输入对应的数字********\n");
	printf("*********1.开始游戏**********\n");
	printf("*********0.退出游戏**********\n");
	printf("*****************************\n");
}

void game()
{
	//创建数组
	char board[ROW][COL] = { 0 };

	//初始化数组
	Intboard(board, ROW, COL);

	//打印棋盘
	DiaplayBoard(board, ROW, COL);


//在判断输赢里面
//'*'玩家胜利
//'#'电脑胜利
//'Q'平局
//'C'继续
	char ret = 0;
	while (1)
	{
	
		PlayerMover(board, ROW, COL);//玩家下棋
		DiaplayBoard(board, ROW, COL);//打印棋盘 这里我们把打印棋盘从里面拿到外面
		ret = IsWin(board, ROW, COL);//判断输赢

		if (ret!='C')//返回值不继续,跳出循环
		{
			break;
		}

		ComputerMove(board, ROW, COL);//电脑下棋
		DiaplayBoard(board, ROW, COL);//打印棋盘
		ret = IsWin(board, ROW, COL);//判断输赢

		if (ret != 'C')//返回值不继续,跳出循环
		{
			break;
		}
		
	}
	if (ret == '*')//返回值是*玩家胜利
	{
		printf("玩家胜利。");
	}
	else if(ret=='#')//返回值是#电脑胜利
	{
		printf("电脑胜利。");
	}
	else           //返回值是Q 也就是其他情况 此时平局
	{
		printf("平局。");
	}
}

void test()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	printf("输入对应的数字:");
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		game();
		break;
	case 0:
		printf("退出游戏。");
		break;
	default:
		printf("输入错误请重新输入。");
		break;
	}

}


int main()
{
	menu();
	test();
	return 0;
}

game,c

这里的列和行的判断需要进行循环判断,不然会产生大量的冗余

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"



//初始化棋盘
void Intboard(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 DiaplayBoard(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]);
	//	}
	//	printf("\n");
	//}


	////版本二
	//for (int i = 0; i < row; i++)
	//{
	//	printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
	//	if (i < row - 1)
	//		printf("---|---|---\n");
	//}


	//版本三
	
	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 PlayerMover(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	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] = '*';
				//DiaplayBoard(board, ROW, COL);
				break;
			}
			else
			{
				printf("坐标重复请重新输入。");
			}
		}
		else
		{
			printf("坐标输入不合法,请重新输入。");
		}
	}


}


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

//判断输赢
char IsWin(char board[ROW][COL], int row, int col)
{
	//赢
	//判断 行三子 列三子 对角线三子 

	//行
	for (int i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][0];
		}
	}
	//列
	for (int i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[0][i];
		}
	}

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

	//平局


	//继续 这个想要提前测试就需要先把这个继续的返回值写上去就可以初步运行了
	return 'C';



}

game.h

#pragma once
#include<stdio.h>
#include<time.h>//time头文件
#include<stdlib.h>//rand头文件

//数组的行和列
#define ROW 3
#define COL 3



//初始化棋盘
void Intboard(char board[ROW][COL], int row, int col);

//打印棋盘
void DiaplayBoard(char board[ROW][COL], int row, int col);

//玩家下棋
void PlayerMover(char board[ROW][COL], int row, int col);

//电脑下棋
void  ComputerMove(char board[ROW][COL], int row, int col);

//判断输赢
////判断输赢
// 
// 注释
//在判断输赢里面
//'*'玩家胜利
//'#'电脑胜利
//'Q'平局
//'C'继续
//IsWin(board, ROW, COL);
char IsWin(char board[ROW][COL], int row, int col);

4.下面的代码只有game.c才会变,所以只写game.c里面的代码变化

game.c

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"



//初始化棋盘
void Intboard(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 DiaplayBoard(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]);
	//	}
	//	printf("\n");
	//}


	////版本二
	//for (int i = 0; i < row; i++)
	//{
	//	printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
	//	if (i < row - 1)
	//		printf("---|---|---\n");
	//}


	//版本三
	
	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 PlayerMover(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	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] = '*';
				//DiaplayBoard(board, ROW, COL);
				break;
			}
			else
			{
				printf("坐标重复请重新输入。");
			}
		}
		else
		{
			printf("坐标输入不合法,请重新输入。");
		}
	}


}


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

//判断平局
//判断平局 这里判断平局采取逆向思维 也就是先判断不是平局的时候
int IsFull(char board[ROW][COL], int row, int col)
{

	for (int i = 0; i < row; i++)
	{
		for (int j = 0; i < col; i++)
		{
			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++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][0];
		}
	}
	//列
	for (int i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[0][i];
		}
	}

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

	//平局
	if (IsFull(board, row, col) == 1)
	{
		return 'Q';
	}

	//继续
	return 'C';



}

到这里就是总结代码,但是因为已经是最后一步了,就不进行二次总结了,直接看最下面。


第六步,总结代码

这里总结代码,一个是总结到一个文件里面,一个是总结到三个文件里面,这里因为我直接是最后把三个文件直接合并的,所以可能会有瑕疵。当然要是学习的话,最好还是看这个三个文件的代码

放到一个文件里面的总结

1.这个是两个玩家的对战

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

char board[3][3]; // 棋盘

// 初始化棋盘
void init_board() {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            board[i][j] = ' ';
        }
    }
}

// 打印棋盘
void print_board() {
    printf("  1 2 3\n");
    for (int i = 0; i < 3; i++) {
        printf("%d ", i + 1);
        for (int j = 0; j < 3; j++) {
            printf("%c", board[i][j]);
            if (j < 2) {
                printf("|");
            }
        }
        printf("\n");
        if (i < 2) {
            printf("  ---\n");
        }
    }
}

// 判断是否有玩家获胜
int check_win(char player) {
    // 检查行
    for (int i = 0; i < 3; i++) {
        if (board[i][0] == player && board[i][1] == player && board[i][2] == player) {
            return 1;
        }
    }
    // 检查列
    for (int j = 0; j < 3; j++) {
        if (board[0][j] == player && board[1][j] == player && board[2][j] == player) {
            return 1;
        }
    }
    // 检查对角线
    if (board[0][0] == player && board[1][1] == player && board[2][2] == player) {
        return 1;
    }
    if (board[0][2] == player && board[1][1] == player && board[2][0] == player) {
        return 1;
    }
    return 0;
}

// 进行游戏
void play_game() {
    int row, col;
    char player = 'X';
    int moves = 0;

    init_board();

    while (1) {
        printf("玩家 %c,请输入行号和列号(以空格分隔):", player);
        scanf("%d %d", &row, &col);

        if (row < 1 || row > 3 || col < 1 || col > 3) {
            printf("输入无效,请重新输入!\n");
            continue;
        }

        if (board[row - 1][col - 1] != ' ') {
            printf("该位置已经有棋子,请重新输入!\n");
            continue;
        }

        board[row - 1][col - 1] = player;
        moves++;
        print_board();

        if (check_win(player)) {
            printf("玩家 %c 获胜!\n", player);
            break;
        }

        if (moves == 9) {
            printf("平局!\n");
            break;
        }

        player = (player == 'X') ? 'O' : 'X';
    }
}

int main() {
    printf("欢迎来到井字棋游戏!\n");
    play_game();
    return 0;
}

2.玩家和电脑下棋

#define _CRT_SECURE_NO_WARNINGS 1

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


char board[3][3]; // 棋盘

void initBoard() 
{
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            board[i][j] = ' ';
        }
    }
}

void printBoard() 
{
    for (int i = 0; i < 3; i++)
    {
    	//1.打印数据 这里是固定的列 也就是不打印列 但是给出了列
    	printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
    	//2.打印分割线 最外层是不打印|的
    	if (i < 2)
    	{
    		printf("---|---|---\n");
    	}
    }
}

int isBoardFull()
{
    for (int i = 0; i < 3; i++) 
    {
        for (int j = 0; j < 3; j++) 
        {
            if (board[i][j] == ' ') 
            {
                return 0; // 棋盘未满
            }
        }
    }
    return 1; // 棋盘已满
}

int isGameOver() {
    // 检查行
    for (int i = 0; i < 3; i++) 
    {
        if (board[i][0] != ' ' && board[i][0] == board[i][1] && board[i][1] == board[i][2]) 
        {
            return 1; // 游戏结束
        }
    }
    // 检查列
    for (int j = 0; j < 3; j++) 
    {
        if (board[0][j] != ' ' && board[0][j] == board[1][j] && board[1][j] == board[2][j]) 
        {
            return 1; // 游戏结束
        }
    }
    // 检查对角线
    if (board[0][0] != ' ' && board[0][0] == board[1][1] && board[1][1] == board[2][2]) 
    {
        return 1; // 游戏结束
    }
    if (board[0][2] != ' ' && board[0][2] == board[1][1] && board[1][1] == board[2][0]) 
    {
        return 1; // 游戏结束
    }
    // 检查平局
    if (isBoardFull()) 
    {
        return 2; // 平局
    }
    return 0; // 游戏未结束
}

void playerMove()
{
    int x = 0;
    int y = 0;
    printf("玩家下棋:\n");
    while (1)
    {
        printf("输入下棋的坐标,中间使用空格:");
        scanf("%d %d", &x, &y);
        //这里的坐标是大于1 是因为玩家输入的坐标是从1开始的(合法坐标)
        if (x >= 1 && x <= 3 && y >= 1 && y <= 3)
        {
            if (board[x - 1][y - 1] == ' ')//可以落子(这里-1是因为数组的索引是从0开始的 不是从1开始的 但是玩家看到的是从1开始的) 
            {
                board[x - 1][y - 1] = '*';
                break;
            }
            else//不能落子
            {
                printf("坐标已经存在请重新输入。");
            }
        }
        else//非法坐标
        {
            printf("您输入的坐标有误,请重新输入。");
        }

    }
}

void computerMove() 
{
    int row, col;
    do 
    {
        row = rand() % 3;
        col = rand() % 3;
    } while (board[row-1][col-1] != ' ');
    board[row-1][col-1] = 'O';
}

int main() 
{
    int gameOver = 0;
    initBoard();
    while (!gameOver) 
    {
        printBoard();
        playerMove();
        gameOver = isGameOver();
        if (gameOver) 
        {
            break;
        }
        computerMove();
        gameOver = isGameOver();
    }
    printBoard();
    if (gameOver == 1) 
    {
        printf("游戏结束,玩家胜利!\n");
    }
    else if (gameOver == 2) 
    {
        printf("游戏结束,平局!\n");
    }
    else 
    {
        printf("游戏结束,电脑胜利!\n");
    }
    return 0;
}

放到三个文件里面的总结

//源文件

//test,c 源文件

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"


void menu()
{
	printf("**********************************\n");
	printf("*********  1.开始游戏   **********\n");
	printf("*********  0.退出游戏   **********\n");
	printf("**********************************\n");

}

void game()
{ 
	//创建数组
	char board[ROW][COL] = { 0 };

	//初始化数组 
	InitBoard(board, ROW, COL);

	//打印棋盘
	DiaplayBoard(board, ROW, COL);

	//这里给一个参数变量ret  同时需要知道每次的落子都需要判断一下输赢 保证公平
	char ret = 0;
	while (1)
	{
		//玩家下棋
		PlayerMove(board, ROW, COL);
		DiaplayBoard(board, ROW, COL);

		//判断输赢
		ret= IsWin(board, ROW, COL);//判断输赢 这里需要一个变量接受参数
		if (ret != 'C')//如果不继续就跳出循环 也就是结束 同时循环外接一个if
			break;

		//电脑下棋
		ComputerMove(board, ROW, COL);
		DiaplayBoard(board, ROW, COL);

		//判断输赢
		ret = IsWin(board, ROW, COL);//判断输赢 这里需要一个变量接受参数
		if (ret != 'C')//如果不继续就跳出循环 也就是结束 同时循环外接一个if
			break;
	}
	if (ret == '*')//这里和循环里面的if形成对应 同时更要知道 代码的运行是从上往下运行的
		printf("玩家胜利。\n");
	else if (ret == '#')
		printf("电脑胜利。\n");	
	else 
		printf("平局。\n");
}

void test()
{
	srand((unsigned int)time(NULL));
	printf("输入数字开始或者退出游戏:");
	int input = 0;
	scanf("%d", &input);
	switch (input)
	{
	case 1:
		game();
		break;
	case 0:
		printf("游戏结束,退出游戏");
		break;
	default:
		printf("输入错误请重新输入。");
		break;
	}

}



int main()
{
	menu();
	test();
	return 0;
}

//game.h头文件

//game.h头文件

#pragma once
#include<stdio.h>
#include<time.h>//time
#include<stdlib.h>//rand

//棋盘的大小
//行 列
#define ROW 3
#define COL 3

//初始化数组
void InitBoard(char board[ROW][COL], int row, int col);

//打印棋盘
void DiaplayBoard(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);


//判断输赢
// 
// 注释
//在判断输赢里面
//'*'玩家胜利
//'#'电脑胜利
//'Q'平局
//'C'继续
//IsWin(board, ROW, COL);
char IsWin(char board[ROW][COL], int row, int col);








//game.c文件的定义(运行)

//game.c文件的定义(运行)

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

//初始化数组 这里让数组初始化等于空格
void InitBoard(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++)
		{
			board[i][j] = ' ';
		}
	}
}



//打印棋盘
void DiaplayBoard(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]);
	//	}
	//	printf("\n");
	//}

	////第二种棋盘 包含分分割线 但是导致是固定的 (版本二)
	//int i = 0;
	//for (i = 0; i < row; i++)
	//{
	//	//1.打印数据 这里是固定的列 也就是不打印列 但是给出了列
	//	printf(" %c  | %c  | %c \n", board[i][0], board[i][1], board[i][2]);
	//	//2.打印分割线 最外层是不打印|的
	//	if (i < row - 1)
	//	{
	//		printf("---|---|---\n");
	//	}
	//}

	//第三种情况 随着定义数字的改变长度也进行改变(版本三)
	int i = 0;
	for (i = 0; i < row; i++)
	{
		//打印数据
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			//这里是最后一个不打印 所以小于-1 其实也可以打印出来 因为更加美观
			//打印 竖分割线
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		//打印 横向 分割线 最后一行不打印
		if (i < row - 1)
		{
			int j = 0;
			for (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;
	int y = 0;
	printf("玩家下棋:\n");
	while (1)
	{
		printf("输入下棋的坐标,中间使用空格:");
		scanf("%d %d", &x, &y);
		//这里的坐标是大于1 是因为玩家输入的坐标是从1开始的(合法坐标)
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board[x-1][y-1] == ' ')//可以落子(这里-1是因为数组的索引是从0开始的 不是从1开始的 但是玩家看到的是从1开始的) 
			{
				board[x-1][y-1] = '*';
				break;
			}
			else//不能落子
			{
				printf("坐标已经存在请重新输入。");
			}
		}
		else//非法坐标
		{
			printf("您输入的坐标有误,请重新输入。");
		}

	}

}


//电脑下棋 依旧是利用时间戳
void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;//0~row-1
	int y = 0;//0~col-1

	printf("电脑下棋:\n");
	
	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y]==' ')
		{
			board[x][y] = '#'; //这里是=而不是==的原因是 这里是如果这个是空格则赋值为'#' 如果是==则无法赋值,比较运算符 (==): 用于比较两个值是否相等 赋值运算符 (=):用于将一个值赋给变量
			break;//这里给一个跳出 也就是电脑随机下棋 不然就会像布置地雷一样直接全部布置上去
		}
	}


}

 
//判断平局  这里判断平局采取逆向思维 也就是先判断不是平局的时候 然后返回 但是不满足这个条件的情况下就是平局了
//简单的说就是 循环里面只要还有空格那就说明没有下完棋 就依旧不能判断为是平局 所以跳出循环 跳出循环之后就进行函数的下一步 也就是跳出这个函数 返回'C'然后继续运行游戏  也就是继续主函数test里面的while
int IsFull(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++)
		{
			if (board[i][j] == ' ')//只要存在空格的情况下 直接返回函数
			{
				return 0;
			}
		}
	}
	return 1;

}


//判断输赢
// 
// 注释
//在判断输赢里面
//'*'玩家胜利
//'#'电脑胜利
//'Q'平局
//'C'继续
char IsWin(char board[ROW][COL], int row, int col)
{
	//赢了(这里分电脑胜利和玩家胜利)
	//这里也需要对 行 列 对角线进行判断 这里判断的时候不是按照玩家的逻辑  所以开始是0 而不是1 所以在玩家下棋里面也是-1从而进行判断
	// 使用循环而不是直接的if语句是因为您需要对棋盘上的每一行和每一列都进行独立的检查。对于每一行或每一列,您需要判断三个连续的棋子是否相同,并且这三个棋子不能是空格。如果找到这样的行或列,就可以直接返回胜利的符号(无论是*还是#)。
	//判断行
	int i = 0;
	for ( i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			//这里的返回值已经形成对照 也就是不管是玩家'*'还是'#'返回的只能一个 而主函数里面已经接收返回值 从而进行判断
			return board[i][0];
		}
	}
	//判断列 
	for (i = 0; i < row; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][2] && board[0][i] != ' ')
		{
			return board[0][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];
	


	//平局
	if (IsFull(board, row, col) == 1)
	{
		return 'Q';
	}


	//继续对局
	return 'C';
}












评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值