IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> <C>.三子棋 -> 正文阅读

[C++知识库]<C>.三子棋

目录

一:先写三子棋的开始菜单逻辑

二.接下来写game()部分。

1.初始化棋盘(InItbroad)

2.打印棋盘(Dispalybroad)

3.玩家输入(player_move)

接下来实现电脑下棋:computer_move

1.实现随机,需要用?rand &&?srand && time 函数?

判断输赢(is_win)

1.判断行

2.判断列:

3.*判断对角线

4.判断平局

所以,最终我们写成:

最后



实现这个三子棋,想要他能实现:
1.先打印一个3X3的棋盘→九宫格→3X3二维数组→分割行
2.玩家下棋和电脑下棋的位置都要存储

一:先写三子棋的开始菜单逻辑

#include<stdio.h>
void menu()
{
	printf("**************************\n");
	printf("*********1.start**********\n");
	printf("*********0. exit *********\n");
	printf("**************************\n");

}
void test()
{
	int input = 0;
	do
	{
	    menu();
		printf("请输入>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			//game()
			printf("开始游戏\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("重新输入\n");
		}

	} while (input);
}
int main()
{
	test();
	return 0;
}

?逻辑没有问题

二.接下来写game()部分。

1.首先需要打印棋盘,九个位置必须是初始化为空格,且要有分割行。
我们写三个文件:
test.c→游戏逻辑
game.c→游戏的实现
game.h→函数的声明

1.首先我们要求,
row为行,col为列

这样写的优势在于:以后我如果想打印10x10的棋盘,只需要修改row,col的定义即可,这样就更方便我进行修改。


接下来的关于游戏的函数都写在test.c里的game()文件里,函数的实现写在game.c文件里


1.初始化棋盘(InItbroad)

void InItbroad(char broad[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			broad[i][j] = ' ';
		}
	}
}

2.打印棋盘(Dispalybroad)


重点在于如何添加分割行
倘若我们这样写:

void Dispalybroad(char broad[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", broad[i][j]);
		}
		printf("\n");
	}
}

那么打印的将会是全是空格,什么也看不见
?

观察可得,是_ _ _ 一个 | ,中间是我们数据。?所以我可以写成:?

void Dispalybroad(char broad[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 ", broad[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.玩家输入(player_move)


数组虽说是0开始,但是玩家输入要从1开始。所以我可以写成:

void player_move(char broad[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("玩家下棋,请输入坐标:\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//下棋
			if (broad[x - 1][y - 1] == ' ')
			{
				broad[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("坐标被占用,重输入\n");
			}
		}
		else
		{
			printf("输入非法,重新输入\n");
		}
	}
}

接下来实现电脑下棋:computer_move


1.实现随机,需要用?rand &&?srand && time 函数

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

1.使用rand函数前,需在调用game函数前调用一次srand函数。我们引用time.h和stdlib.h头文件,然后使用srand,传入time空指针。以时间为参照物实现随机。
2.为什么是rand()%row,rand()%col呢?
这涉及一个小学问题:要使余数最大,方框里分别填几?
答:余数肯定比除数要小,要想余数最大,就只能除以比余数小1的数。
例如:rand()%3,那么他的余数最大,就是2

判断输赢(is_win)

第一步,先将玩家和用户下棋的部分设为循环,再加入判断输赢的函数,决定是否需要跳出循环,打印结果,结束游戏。
game()逻辑部分我们这样设定,来实现判断:
玩家赢→'*'
电脑赢→'#'
平局→'Q'
继续→'C'

void game()
{
	char ret = 0;
	//存放下棋的数据
	char broad[ROW][COL] = { 0 };
	//初始化棋盘
	InItbroad(broad, ROW, COL);
	//打印棋盘
	Dispalybroad(broad, ROW, COL);
	//玩家下棋
	while (1)
	{
		player_move(broad, ROW, COL);
		Dispalybroad(broad, ROW, COL);
		//判断输赢
		ret = is_win(broad, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		//电脑下棋
		computer_move(broad, ROW, COL);//随机
		Dispalybroad(broad, ROW, COL);
		ret = is_win(broad, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家赢了\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else if(ret =='Q')
	{
		printf("平局\n");
	}
	Dispalybroad(broad, ROW, COL);
}

?第二步,我们来写输赢判断函数(is_win).(初学者可以先自己思考一番)

1.判断行

//判断行
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int count = 0;
		int j = 0;
		for (j = 0; j < col-1; j++)
		{
			if ( broad[i][j] == broad[i][j + 1] && broad[i][0] != ' ')
				{
				count++;
				}
		}
		if (count == col - 1)
		{
			return broad[i][0];
		}
	}

我当时写遇到的第一个问题:如果我不引用count来计数的话,就难以建立判断条件。

2.判断列:

//判断列
	for (i = 0; i < col; i++)
	{
		int count = 0;
		int j = 0;
		for (j = 0; j < row-1; j++)
		{
			if (broad[j][i] == broad[j + 1][i] && broad[0][i] != ' ')
			{
				count++;
            }
		}
		if (count == row - 1)
		{
			return broad[0][i];
		}
	}

3.*判断对角线


左斜对角线:
假若我们这样写:

//判断左斜对角线 row行, col 列
	for (i = 0; i < col-1; i++)
	{
	      int count2 = 0;
		if (broad[i][i] == broad[i + 1][i + 1] && broad[0][i] != ' ')
		{
			count2++;
		}
	  if (count2 == col - 1)
	  {
		return broad[0][0];
	  }
	}

这样写就会有一个非常明显的错误,当我条件已经不满足for语句时,我就不会进入for语句,也就不会进入判断部分。所以我们要把判断部分拿出来:

int count2 = 0;
	for (i = 0; i < col - 1; i++)
	{
		if (broad[i][i] == broad[i + 1][i + 1] && broad[0][i] != ' ')
		{
			count2++;
		}
	}
	if (count2 == col - 1)
	{
		return broad[0][0];
	}

右斜对角线:
假若我们不知道for语句可以同时对两个变量进行调整的话,我们也许会这样写:

这样写的话,他会等到 j 这个变量走完后,才调整i这个变量,j和i并不会同时变化。于是我想了办法,使用goto语句:

?这样写,最终造成了死循环。

这段代码有两个错误,其中最为严重的是goto语句的错误使用。
原因是:goto语句会直接跳到标签部分,而不会进入调整部分,i++和j--都不会被执行,因此造成了死循环。
第二个次要问题在于if在for语句里面,倘若for语句不成立了,就不会进入到判断部分。

最后询问了@^jhao^后,找到了正确的写法,应该写成这种形式:两个调整部分。

?所以,最终应该写成

	//右斜对角线row行, col 列
	int count = 0;
	for (int j = col - 1, i = 0; i < row - 1 && j>0; i++, j--)//0 1 2
	{

		if (broad[i][j] == broad[i + 1][j - 1] && broad[0][col - 1] != ' ')
		{
			count++;
		}

	}
	if (count == col - 1)
	{
		return broad[0][col - 1];
	}

4.判断平局:


我们直接写一个ping函数,来进行判断

	//判断平局
	if (ping(broad,row,col) == 1)
	{
		return 'Q';
	}

接下来实现ping函数部分
假若我们这样写:

int ping(char broad[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 (broad[i][j] != ' ')
			{
				return 0;//没满
			}
		}
	}
	return 1;
}

程序到最后会出问题,为什么?
原因在于if判断部分出了问题。
假若我们broad[ i ][ j ] ! = '? ',那就说明,他是存了东西的,但他只能证明这一个地方存了东西,而不能证明所有的格子,都存了东西。第一次写这个代码时,在这里逻辑就可能会出错,必须要多加小心。
改正方法:
法1:我可以把return改写成continue,但是这样的话要引入变量,就比较冗余。
法2:我直接把!=’ ‘,改写成 ==,即可。

所以正确写法是:

int ping(char broad[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 (broad[i][j] == ' ')
			{
				return 0;//没满
			}
		}
	}
	return 1;

当以上情况都不满足时,我们直接return 'C',继续游戏。


所以,最终我们写成:

test.c:

#include"game.h"
void menu()
{
	printf("**************************\n");
	printf("*********1.start**********\n");
	printf("*********0. exit *********\n");
	printf("**************************\n");

}
void game()
{
	char ret = 0;
	//存放下棋的数据
	char broad[ROW][COL] = { 0 };
	//初始化棋盘
	InItbroad(broad, ROW, COL);
	//打印棋盘
	Dispalybroad(broad, ROW, COL);
	//玩家下棋
	while (1)
	{
		player_move(broad, ROW, COL);
		Dispalybroad(broad, ROW, COL);
		//判断输赢
		ret = is_win(broad, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		//电脑下棋
		computer_move(broad, ROW, COL);//随机
		Dispalybroad(broad, ROW, COL);
		ret = is_win(broad, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家赢了\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else if(ret =='Q')
	{
		printf("平局\n");
	}
	Dispalybroad(broad, ROW, COL);
}
/*
什么时候赢呢?
玩家赢→'*'
电脑赢→'#'
平局→'Q'
继续→'C'
*/
void test()
{
	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");
		}
	} while (input);
}
int main()
{
	test();
	return 0;
}

game.h:

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define ROW 3
#define COL 3
#include<stdlib.h>
#include<time.h>
void InItbroad(char broad[ROW][COL], int , int );//初始化棋盘
void Dispalybroad(char broad[ROW][COL], int , int );//打印棋盘
void player_move(char broad[ROW][COL], int , int );//玩家下棋
void computer_move(char broad[ROW][COL], int, int);//电脑下棋
char is_win(char broad[ROW][COL], int, int);//判断输赢

game.c:

#include"game.h"
void InItbroad(char broad[ROW][COL], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			broad[i][j] = ' ';
		}
	}
}

void Dispalybroad(char broad[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 ", broad[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 player_move(char broad[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("玩家下棋,请输入坐标,行,列:\n");
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			//下棋
			if (broad[x - 1][y - 1] == ' ')
			{
				broad[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("坐标被占用,重输入\n");
			}
		}
		else
		{
			printf("输入非法,重新输入\n");
		}
	}
}

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

int ping(char broad[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 (broad[i][j] == ' ')
			{
				return 0;//没满
			}
		}
	}
	return 1;
}


char is_win(char broad[ROW][COL], int row, int col)
{

	int i = 0;
	for (i = 0; i < row; i++)
	{
		int count = 0;
		int j = 0;
		for (j = 0; j < col - 1; j++)
		{
			if (broad[i][j] == broad[i][j + 1] && broad[i][0] != ' ')
			{
				count++;
			}
		}
		if (count == col - 1)
		{
			return broad[i][0];
		}
	}

	//判断列
	for (i = 0; i < col; i++)
	{
		int count = 0;
		int j = 0;
		for (j = 0; j < row - 1; j++)
		{
			if (broad[j][i] == broad[j + 1][i] && broad[0][i] != ' ')
			{
				count++;
			}
		}
		if (count == row - 1)
		{
			return broad[0][i];
		}
	}
	//判断对角线 row行, col 列
	int count2 = 0;
	for (i = 0; i < col - 1; i++)
	{
		if (broad[i][i] == broad[i + 1][i + 1] && broad[0][i] != ' ')
		{
			count2++;
		}
	}
	if (count2 == col - 1)
	{
		return broad[0][0];
	}
	//row行, col 列
	int count = 0;
	for (int j = col - 1, i = 0; i < row - 1 && j>0; i++, j--)//0 1 2
	{

		if (broad[i][j] == broad[i + 1][j - 1] && broad[0][col - 1] != ' ')
		{
			count++;
		}

	}
	if (count == col - 1)
	{
		return broad[0][col - 1];
	}

	//判断平局
	if (ping(broad,row,col) == 1)
	{
		return 'Q';
	}
	//继续
	return 'C';
}


程序正常运行


最后

感谢@^jhao^。
初学者可以试写这段代码,可以加强对分支循环语句,二维数组的理解与运用。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-19 00:58:09  更:2022-02-19 00:58:17 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:52:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码