三子棋————(c语言)

目录

1.输出三子棋的棋盘

 2.玩家跟电脑下棋

3.判断输赢,或者平局

源代码

结语


Hello,大家好,今天我们用c语言简单写一个三子棋,话不多说,我们开始构思整体思路。

在此之前先看看代码的效果

思路构思:

1.定义一个game.h头文件,放函数声明,game.c放实现游戏的代码,test.c放主函数,调试游戏代码

2.输出棋盘

3.玩家跟电脑下棋

4.判断输赢,是否平局

5.结束

1.输出三子棋的棋盘

如上图,我们要输出棋盘,就要先定义一个3x3的二维数组,并且里面要放的值是空格,并且想要在棋盘中插入需要的棋子,那就定义为char类型,并且全部初始为空格。先创建game,h,game.c,test.c文件

头文件中放入 要包含的头文件,.c文件中包含头文件

//game.h
#include<stdio.h>

//game.c
#include "game.h"

//test.c
#include "game.h"

 这样子,就可以在game.c跟test,c中愉快的使用库文件的函数了。

想好后高高兴兴打开代码一顿噼里啪啦,最后输出的效果如下

输出棋盘:

版本1

game.c

 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 DisplayBoard(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]);
		}
		printf("\n");
}//输出3x3棋盘

 

 与预想的三子棋棋盘完全不一样,为什么会这样?仔细想想,前面我们初始化棋盘里面全是空格,因此,我们把空格改成任意字符(如X)再看看效果

 

 OMG,原来已经把棋盘输出来了,但是还是没有达到我们预期的效果,动动小脑袋再思考,我们要达到想要的效果,看最开始的棋盘的第一行,先输出(空格+空格+竖线),第二行(横线+横线+横线+竖线),其中,边框是没有线条的,恍然大雾!!!

 抄起键盘又是一顿啪啪啪。于是,版本二就诞生了!

game.c

void DisplayBoard(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]);
		}
		printf("\n");
		printf("---|---|---\n");
	}
}//输出3x3棋盘

心想,不就是简简单单的棋盘吗,不就是在输出棋盘的时候,先打印(空格+初始化棋盘内容+空格+竖线)-->( %c |),这还不简单,其次就是到下面的竖线,只需要在他打印完第一行就直接输出---|---|---不就ok?然而你在运行代码时

WTF? 怎么边边也有横线跟竖线啊,跟我想的棋盘不一样啊,

 看了半天,原来是循环里面,我们只需要打印两次竖线跟横线就可以了,而且在优化一下代码,我们先打印棋盘内容,在打印边边角角,并且给边边角角订上规则,你只能打印两次。

抄起键盘开干
game.c

void DisplayBoard(char board[ROW][COL], int row, int col) {
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++) {
		//1.打印数据
		for (j = 0; j < col; j++) {
			printf(" %c ", board[i][j]);
			if (j < col - 1)打印两次竖线
				printf("|");
		}
		printf("\n");
		//2.打印分割线
		if (i < row - 1) {
			//printf("---|---|---\n");
			for (j = 0; j < col; j++) {
				printf("---");
				if (j < col - 1)//打印两次分割线
					printf("|");
			}
			printf("\n");
		}
	}//版本三		
}//打印棋盘

ohohohoh!!!棋盘打印出来了 ,再把初始化棋盘内容改成空格,就可以达到预期效果了


 2.玩家跟电脑下棋

棋盘做好了,那也得有人来下啊,因此我们可以先跟电脑solo一下。

思考:

1.玩家的坐标是怎么样的?(1~3)

2.如何让玩家在正确的位置下棋,下错地方了会怎么样?

3.如何判断改地方已经有棋子了,不能在下?

4.玩家可以下多少次?

玩家下棋

game.c

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);
		if (x >= 1 && x <= row && y >= 1 && y <= col) {//限定为1~3的坐标
			if (board[x - 1][y - 1] == ' ') {
				board[x - 1][y - 1] = 'X';
				break;
			}//要落子的地方都必须是棋盘初始化为空格的键盘内
			//玩家棋子为'X'	
			//在输入数组的坐标中落子
			else {
				printf("坐标被占用,不能落子,请重新输入坐标\n");
				//如果不是空格,就是该坐标已经有棋子了
				//没有这个条件就会造成落子重复
			}
		}//坐标合法
		else {
			printf("坐标错误,重新输入!\n");
		}//坐标非法
	}//循环的目的是让玩家可以一直落子
}//玩家落子

test.c

void game() {
	char board[ROW][COL] = { 0 };
	char ret = 0;
	//初始化棋盘
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);

	while (1) {
		//玩家下棋
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
    }
}//游戏代码
int main() {
	int input = 0;
	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);
}//主函数测试游戏代码

 

OK兄弟们,辛辛苦苦写完的代码测试一下

 Nice!!!没有问题进行下一步

电脑下棋

电脑下棋嘛,由于是实现简单的三子棋,主打就就是随意下,因此有什么方法可以实现生成随机坐标呢,在c语言中,生成动态的随机数,可以使用rand()函数跟srand()函数,对于这两个函数的用法不多bb。在写之前,我们先想想电脑如何下棋

1.电脑的坐标跟玩家的坐标是否一致?

2.电脑下棋能不能随便乱下,是不是跟我家鸽鸽随地下蛋一样?

3.三子棋的坐标就是3x3的,怎么不让电脑生成的随机坐标不超过棋盘坐标?

4.电脑是不是可以多下几次?

 game,c

void ComputerMove(char board[ROW][COL], int row, int col) {
	printf("电脑下棋:>\n");
	int x = 0;//0~row-1
	int y = 0;//0~col-1
	while (1) {
		x = rand() % row;//求余最大随机值小于row,符号数组下标
		y = rand() % col;
		if (board[x][y] == ' ') {
			board[x][y] = 'O';//定义电脑的棋子为'O'
			break;
		}//可以落子
	}//不能落子就继续返回生成新的随机坐标
}//循环实现电脑落子

OK兄弟们,目光向代码看齐

void game() {
	char board[ROW][COL] = { 0 };
	char ret = 0;
	//初始化棋盘
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);

	while (1) {
		//玩家下棋
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
        //电脑下棋
        ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
    }
}

 

芜湖!!,有惊无险,终于把玩家跟电脑下棋给完成了 ,但是我都赢了,怎么没有判断我赢啊???少年(少女),你想得太简单了,你认为的赢,是电脑认为的赢吗?

 电脑不认得你所谓的赢啊。因此,我们要写一些条件让电脑判断谁赢了,或者平局了。

3.判断输赢,或者平局

 写之前,先思考一下

1.三子棋中一共有多少个条件能赢?

2.平局的条件是什么?

3.如何将输赢,或者平局让电脑知道

 game.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;//没有满就返回1
}//判断棋盘是否满了

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

	//判断行
	//那个赢就返回那个的值
	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];
	}
	//if内条件错误示范:board[i][0] == board[i][1] && board[i][1]== board[i][0] != ' '
	//牢记这个错误,让博主找了一个多小时的错误,条件判断不能这样子连续相等
	// 可以添加括号的方式,也可以这样子写
	//判断列
	for (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];
	}
	//判断对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
		return board[0][0];

	if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
		return board[0][2];

	//平局
	//平局返回'Y'
	//否则游戏继续返回'C'
	if (IsFull(board, row, col) == 1)
		return 'Y';
	return 'C';//没有赢或平局继续
}

 test.c

void game() {
	char board[ROW][COL] = { 0 };
	char ret = 0;
	//初始化棋盘
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);

	while (1) {
		//玩家下棋
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);

		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C') {
			break;
		}//判断游戏是否结束
		//电脑下棋
		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);

		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C') {
			break;
		}
	}
	if (ret == 'X')
		printf("玩家赢!\n");
	else if (ret == 'O')
		printf("电脑赢!\n");
	else
		printf("平局!\n");//巧妙运用返回值来判断输赢
}

这里,我们巧妙运用了返回值的关系,如果判断为赢则在调用游戏函数void game()中用ret接收返回值,其中每下一个棋就要判断是否继续,如果不等于‘C’,就直接退出循环判断输赢还有平局,这种函数调用跟返回值的关系,还有很多巧妙的运用关系,我们还需要不断努力学习才能达到预期效果。

源代码

//game.h
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
//头文件声明函数
//菜单
void menu();
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int low);
//输出棋盘
void DisplayBoard(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);
//判断输赢
//玩家赢 返回 'X'
//电脑赢 返回 'O'
//平局 返回'Y'
//继续 返回'C'
char IsWin(char board[ROW][COL], int row, int col);
//判断棋盘是否满了
int IsFull(char board[ROW][COL], int row, int col);

//game.c
#pragma warning (disable:4996)
#include "game.h"
void menu() {
	printf("*****************************\n");
	printf("********  1 . Play  *********\n");
	printf("********  0 . Exit  *********\n");
	printf("*****************************\n");
}//菜单

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 DisplayBoard(char board[ROW][COL], int row, int col) {
	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++) {
		//1.打印数据
		for (j = 0; j < col; j++) {
			printf(" %c ", board[i][j]);
			if (j < col - 1)
				printf("|");
		}
		printf("\n");
		//2.打印分割线
		if (i < row - 1) {
			//printf("---|---|---\n");
			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);
		if (x >= 1 && x <= row && y >= 1 && y <= col) {//限定为1~3的坐标
			if (board[x - 1][y - 1] == ' ') {
				board[x - 1][y - 1] = 'X';
				break;
			}//要落子的地方都必须是棋盘初始化为空格的键盘内
			//玩家棋子为'X'
			//在输入数组的坐标中落子
			else {
				printf("坐标被占用,不能落子,请重新输入坐标\n");
				//如果不是空格,就是该坐标已经有棋子了
				//没有这个条件就会造成落子重复
			}
		}//坐标合法
		else {
			printf("坐标错误,重新输入!\n");
		}//坐标非法
	}//循环的目的是让玩家可以一直落子
}
//电脑随机下棋
void ComputerMove(char board[ROW][COL], int row, int col) {
	printf("电脑下棋:>\n");
	int x = 0;//0~row-1
	int y = 0;//0~col-1
	while (1) {
		x = rand() % row;//求余最大随机值小于row,符号数组下标
		y = rand() % col;
		if (board[x][y] == ' ') {
			board[x][y] = 'O';
			break;
		}//可以落子
	}
}

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;//没有满就返回1
}

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

	//判断行
	//那个赢就返回那个的值
	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];
	}
	//if内条件错误示范:board[i][0] == board[i][1] && board[i][1]== board[i][0] != ' '
	//牢记这个错误,让博主找了一个多小时的错误,条件判断不能这样子连续相等
	// 可以添加括号的方式,也可以这样子写
	//判断列
	for (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];
	}
	//判断对角线
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
		return board[0][0];

	if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
		return board[0][2];

	//平局
	//平局返回'Y'
	//否则游戏继续返回'C'
	if (IsFull(board, row, col) == 1)
		return 'Y';
	return 'C';//没有赢或平局继续
}

 

//test.c
#pragma warning (disable:4996)
#include "game.h"

void game() {
	char board[ROW][COL] = { 0 };
	char ret = 0;
	//初始化棋盘
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);

	while (1) {
		//玩家下棋
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);

		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C') {
			break;
		}//判断游戏是否结束
		//电脑下棋
		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);

		//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C') {
			break;
		}
	}
	if (ret == 'X')
		printf("玩家赢!\n");
	else if (ret == 'O')
		printf("电脑赢!\n");
	else
		printf("平局!\n");//巧妙运用返回值来判断输赢
}

int main() {
	int input = 0;
	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);
}

 

最后乱杀电脑


 

结语

总结:代码的可读性还是挺好的,当然博主在写的时候,遇到了某些致命的低级错误,找了一个多小时,总之,代码基础还是不够好,还需要不断继续练习。

  • 16
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吃椰子不吐壳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值