三(五)子棋实现

news2024/9/21 14:37:32

设计一个小游戏其实是对自己掌握一门编程语言的一个升华,几百行代码分项目进行这种很让人着迷的感觉哦!

  与五子棋游戏其实本质区别只不过是判输赢的条件不同,这里我打算写写三子棋小游戏。

代码的最后我将所有源代码整理了,大家急用可以直接复制哦不过要记得分项目哦。

  本文的三子棋代码修改只需要改一下一些关于判输赢条件即可 棋盘大小可以自由修改。

一.程序设计

  写这样的一个小游戏项目-----先要进行设计:    

                                                              1.数据结构

                                                               2.整体规划

                                                              3.接口设计

                                                            4.实现具体功能

                    

 1.1数据结构以及接口                   

     存放棋盘上的棋子我们可以用*和#来代替,所以这样了棋盘存放棋子的数据机构可以用数组 下面我用静态数组形式实现 -------形式为 char Broad[ROW][COL] ;  当棋盘对应的棋子为空格表示这个位置不就是空位置么。

1.2整体规划

2. 棋盘创建

主函数这边先给大家一下便于们理解代码过程:
enum Choice {
	Exit,
	Play


};
menu()
{
	printf("*******************\n");
	printf("*****0.exit********\n");
	printf("*****1.paly********\n");
	printf("*******************\n");
	printf("*******************\n");

}



void game()
{
	
	char Board[ROW][COL] = { 0 };
	int size = 0;// 用来后续判满
	BoardInit(Board);
	BoardPrint(Board);

}




int main() {

   enum  Choice input = 0;
	
	do
	{
		menu();
		scanf("%d", &input);

		switch (input) {
		case Exit:
			printf("hehe");
			break;
		case Play:
			game();
			break;
		default:
			printf("请输入正确选项>.");
		}


	} while (input);



	return 0;
}

总结: 对于棋盘的创建我们其实直接用了数组创建,但是实际上在展现棋盘的时候我们可以对打印过程总一些分割线的随之打印可以让你的棋盘更加美观。

3.玩家和电脑

tip:其实二者思路都很简单只需要将棋盘的数据结构修改进行 (这里是数组) 说白了就是将数组中的元素修改

4.判断输赢情况:

                                       

ISwin函数

输赢情况:             

    1.一个是对角线三子合一

     2.或者是某一行或者某一列 

      3. 满了而且和了

行列判断: 根据他的连续性  

 

 思路:根据连续性我们固定行不动 遍历列上所有点 创建一个flag 只有当棋子相同且连续才++否则就重新赋值为0 这样就可以记录输赢了。

行和列的判赢思路是类似的下面是具体实现:

对角线判断:判赢最难的就是任意棋盘大小下判对角线的了: 这里介绍一种      即任意对角线从左到下  和任意对角线从右到下。

  任意一个点都判断它关于对角线的关系:  ----要知道对角线中的元素 行和列都相差一个同样的分量 。

最后是判满条件:

最后是判满 其实判满很简单 :

1. 既然一直没赢满了就和

2. 刚好下了就满了

     我这里甚至没有单独写一个判满函数 而是直接这样是因为我提前做了逻辑判断

就两种情况 因为如果是下最后一个满棋这里是先判输赢在判满 所以赢在前 就直接结束了

如果没有结果在用判满 和了

-------------我们前面指定了一个size就是拿来判满的。

五.程序优缺以及实现状况

   1.本三子棋的创建其实有许多小细节没有做的通用,比如对于判断赢的棋子数3可以用#difine这样后期想修改为五子棋也就方便了。
   2. 本程序一开始对于电脑下棋产生的随机数没有进行限制这可能会出现一种情况,已经有棋子的位置被电脑下棋赋盖。
  缺陷 : 其实还有一个不利于美观的实现就是对于分割线的打印我们这里如果棋盘大小改变还要我们自己去修改分割线长度,但是其实也比较好修改,朋友们试试吧。(如果有疑问可以私聊我哦)
  3.优点:最为满意的是其中对角线的判断这是对于任意棋盘大小都可以使用所以这个算法是很不错的。以及使用了枚举类型便于其中的选择的理解。

实现情况:接下来我们来验证一下

尝试:

玩家下棋后电脑会立刻下棋,然后打印棋盘

行胜利情况:

列:

对角线胜利

六.项目具体实现

         朋友们需要的直接拿走吧,但是麻烦给我一个小小的赞和关注作为鼓励呢!

game.h

#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 5
#define COL 5



void BoardInit(char(*Board)[COL]);
void BoardPrint(char(*Board)[COL]);
void  PeopleMove(char(*Board)[COL], int* size);
void  ComputerMove(char(*Board)[COL],int*size);
char IsWin(char(*Board)[COL]);
int IsFull(int* size);

game.c

#include"game.h"

void BoardInit(char(*Board)[COL])
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{

			Board[i][j] = ' ';

		}


	}



}

void BoardPrint(char(*Board)[COL])
{

	for (int i = 0; i < ROW; i++)
	{
		printf("_______________________________\n");
		for (int j = 0; j < COL; j++)
		{
			printf("|  ");
			printf("%c", Board[i][j]);//   |  *  |  *  |  *  |  *  |
			printf("  ");              //  _________________________
			if (j == COL-1)
				printf("|");

		}
		printf("\n");
		if(i==ROW-1)
			printf("_______________________________\n");


	}


}

void  PeopleMove(char(*Board)[COL],int*size)
{
	int x = 0;
	int y = 0;// 坐标 
	printf("玩家输入坐标:");
	scanf("%d %d",&x,&y);
	x--;
	y--;
	if(x<ROW&&x>=0&&y<COL&&y>=0)
	Board[x][y] = '*';
	(*size)++;



}

void  ComputerMove(char(*Board)[COL],int* size)
{
	int x = 0;
	int y = 0;// 坐标 
	while (1)
	{
		x = rand() % ROW;
		y = rand() % COL;
		if (Board[x][y] == ' ') {
			Board[x][y] = '#';
			(*size)++;
			break;
		}
		
	}


}

int  Diag(char(*Board)[COL], int row,int col,int dr, int dc)
{
	char point = Board[row][col];
	if (point == ' ')
		return 0;

	int count = 0;
	for (int i = 0; i < 3; i++)
	{
		int r = row + dr * i;
		int c = col + dc * i;
		if (r < 0 || r >= ROW || c < 0 || c >= ROW || Board[r][c] != point)
			return 0;
		count++;

	}
	return count == 3;


}





char IsWin(char(*Board)[COL])
{
	// 行满
	// 方向确定为从上往下
	for (int i = 0; i < ROW; i++)
	{
		int flag = 0;
		int j = 1;
		for (j; j < COL; j++)
		{
			if (Board[i][j] != Board[i][j - 1])// * * ***
			{
				flag = 0;
			}
			if (Board[i][j] == Board[i][j - 1] && Board[i][j] != ' ')
			{

				flag++;
				if (flag == 2)
					return Board[i][j];
			}

		}
	}



	// 列
	for (int i = 0; i < COL; i++)
	{
		int flag = 0;
		int j = 1;
		for ( j ; j < ROW; j++)
		{
			if (Board[j-1][i] != Board[j][i])
			{
				flag = 0;
			}
			if (Board[j-1][i] == Board[j][i]&&Board[j][i]!=' ')
			{

				flag++;
				if (flag == 2)
					return Board[j][i];
			}
			
		}

	}


// 对角线判

	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			// 每一个点左上到右下 右上到左下
			if (Diag(Board, i, j, 1, -1) || Diag(Board, i, j, 1, 1))
			{
				return Board[i][j];
			}

		}
	}


	return ' ';





}

int IsFull(int* size)
{
	return size == COL * ROW;

}

test.c

#include"game.h"

enum Choice {
	Exit,
	Play


};
menu()
{
	printf("*******************\n");
	printf("*****0.exit********\n");
	printf("*****1.paly********\n");
	printf("*******************\n");
	printf("*******************\n");

}
void game()
{
	
	char Board[ROW][COL] = { 0 };
	int size = 0;// 用来后续判满
	BoardInit(Board);
	BoardPrint(Board);
	
	srand((unsigned int)time(NULL));
	while (1) {
		
		if (IsWin(Board)!=' ')
		{
			if (IsWin(Board) == '*')
				printf("玩家获胜\n");
			else
				printf("电脑获胜\n");
			return;
		}
		if (size == ROW * COL) {
			printf("和了\n");
			return;
			
		}
		PeopleMove(Board, &size);

		BoardPrint(Board);
		printf("\n电脑操作:\n");
		ComputerMove(Board, &size);
		BoardPrint(Board);
	}














}

int main() {

   enum  Choice input = 0;
	
	do
	{
		menu();
		scanf("%d", &input);

		switch (input) {
		case Exit:
			printf("hehe");
			break;
		case Play:
			game();
			break;
		default:
			printf("请输入正确选项>.");
		}


	} while (input);



	return 0;
}

  小节

本期就到这里了,其中我们使用的思想其实非常贴合程序设计模型的一个周期,当然虽然我调试过很多次但是还是有许多不足但是值得各位借鉴的我想也会有,如果朋友们有不理解的欢迎大家私聊我,谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2099039.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++ Primer Plus习题】8.2

问题: 解答: #include <iostream> using namespace std;typedef struct _CandyBar {string brand;float weight;int hot; }CandyBar;void fill(CandyBar& cb, const char* name"Millennium Munch", double w2.85, int h350) {cb.brand name;cb.weight w…

2222. 分糖果(candy)

代码 #include <bits/stdc.h> using namespace std; int main(){int n, l, r;cin>>n>>l>>r;cout<<(l/nr/n?r%n:n-1);return 0; } 记得点赞关注收藏&#xff01;&#xff01;&#xff01;谢谢&#xff01;&#xff01;&#xff01;

6.远程调用-OpenFeign

文章目录 1.OpenFeign介绍2.OpenFeign开发3.OpenFeign的参数传递4.OpenFeign 的最佳实践4.1继承的方式4.2抽取的方式 5.服务部署6.spring全家桶复习 大家好&#xff0c;我是晓星航。今天为大家带来的是 远程调用-OpenFeign 相关的讲解&#xff01;&#x1f600; 1.OpenFeign介…

养老院管理系统设计与实现

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装养老院管理系统软件来发挥其高效地信息处理的作用&#xff…

[问题] allegro 绑定3D 无法显示3D图像-已解决

找到原因了&#xff1a; 文件路径有中文&#xff0c;所以识别不到step文件。

C语言 | Leetcode C语言题解之第377题组合总和IV

题目&#xff1a; 题解&#xff1a; int combinationSum4(int* nums, int numsSize, int target) {int dp[target 1];memset(dp, 0, sizeof(dp));dp[0] 1;for (int i 1; i < target; i) {for (int j 0; j < numsSize; j) {if (nums[j] < i && dp[i - num…

数据结构-符号表

1.概述 符号表最主要的目的就是将一个键和一个值联系起来&#xff0c;符号表能够将存储的数据元素是一个键和一个值共同组成的键值对数据&#xff0c;我们可以根据键来查找对应的值。 符号表中&#xff0c;键具有唯一性,符号表在实际生活中的使用场景是非常广泛的&#xff0c;见…

扮猪吃老虎的电脑机箱,不到300块的追风者XT523静音版开箱赏析

扮猪吃老虎的电脑机箱&#xff0c;不到300块的追风者XT523静音版开箱赏析 哈喽小伙伴们好&#xff0c;我是Stark-C~ 最近办公室的老大需要我帮忙挑选一款电脑机箱&#xff0c;除了可以日常办公&#xff0c;闲暇之余还需要用这台电脑打打游戏&#xff0c;要求是噪音越小越好且…

Cesium加载高速公路样式线图层和利用CSS撰写高速公路样式

在ArcGIS软件中是将多个线图层叠加&#xff08;宽的叠加在下方防止遮盖其他图层&#xff09; 依照此想法在Cesium中加载高速公路线图层时 在 Cesium 中&#xff0c;直接设置线&#xff08;如 Polyline&#xff09;的样式为“高速公路样式”并不直接支持&#xff0c;因为 Cesiu…

奥yùn会节目很精彩!想看直播?

有没有可以在电视上安装&#xff0c;然后看直播的软件呢&#xff1f;答案肯定的。 资源在这&#xff08;点我&#xff09; 嗯&#xff0c;废话不多说了。 正文开始 安装教程 保证文件的后缀名为.apk 然后把它复制到U盘根目录&#xff0c;再接入到电视上。 在电视上用文件管…

解决windterm莫名其妙输入ctrl+c的问题

原来是钉钉在监控你的鼠标&#xff0c;取消设置即可 来源&#xff1a;https://github.com/kingToolbox/WindTerm/issues/2296

每一次逾越都是不可替代的成长![我是如何克服编程学习过程中的挫折感】

成长路上不孤单&#x1f60a;【14后&#xff0c;C爱好者&#xff0c;持续分享所学&#xff0c;如有需要欢迎收藏转发&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#xff01;&#xff01;&#xff01;&#xff01;&#xff…

logging | 项目开发中日志模块logging在整个工程中的应用

日志模块 日志介绍1. logging使用场景设置级别 2. 实际logging使用 - 学习版2.1 终端输出StreamHandler2.2 日志文件中输出FileHandler2.3 同时写入终端和文件2.4 .Formatter参数语句 3. 封装logging模块 - 实战版 ⭐3.1 配置config文件夹下project_config.py文件time模块 3.2 …

Linux日志-btmp日志

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux进阶部分又分了很多小的部分,我们刚讲完了Linux基础软件&#xff0c;下面是Linux日志。Linux 系统中的日志是记录系统活…

正向代理、反向代理

代理作为客户端和服务器的中间层&#xff0c;按照不同的维度可以分为不同的类型。 一种常见的划分方式是将代理分为正向代理&#xff08;forward proxy&#xff09;与反向代理&#xff08;reverse proxy&#xff09;。 根据实现代理的方式可以分为 HTTP 隧道代理、MITM 代理、…

ubuntu安装dnsmasq 做dns服务器

本文介绍在ubuntn22.04上安装dnsmasq用做自定义域名服务器&#xff0c;可以在公网上使用。 目标 准备两台不是同一个局域网内的服务器&#xff0c;其中A服务器是ubuntu22.04。在A上安装dnsmasq dns服务器&#xff0c;配置自定义域名&#xff0c;然后在B服务器上配置A做为dns服…

使用session实现单用户多端登录限制

基本流程&#xff1a; 首先获得当前浏览器访问服务器的session&#xff0c;然后根据用户的信息&#xff08;如id等&#xff09;在redis中查找&#xff0c;如果找到&#xff0c;并且和查找对应的session不同&#xff0c;则可以判断已经有其他设备登录过了&#xff0c;这个时候就…

Andorid 如何查看某个.so库的依赖

Android 手机中&#xff0c;如何查看其中某个.so 库依赖了其它哪些库&#xff1f;1.方法&#xff1a;使用android 手机中的readelf 命令.。2. 操作步骤&#xff1a;如查看libdolphin.so 的的依赖。 &#xff08;1&#xff09;adb shell 进入手机&#xff0c;进入libdolphin.so…

C++学习笔记----6、内存管理(一)---- 使用动态内存(2)

2.2、我的好朋友malloc怎么样了&#xff1f; 如果你是一个C程序员&#xff0c;对啦&#xff0c;我就是&#xff0c;你可能会想&#xff0c;malloc()函数怎么样了。在C语言中&#xff0c;malloc()用于分配一定数量的内存字节。总的来讲&#xff0c;使用malloc()简单直接。在C中m…

传统CV算法——图像特征算法之角点检测算法

文章目录 2. 角点检测2.1 角点概述2.1.1 概念2.1.2 角点的特点2.1.3 角点的检测2.1.4 角点的应用 2.2 角点检测算法2.2.1 Harris 角点2.2.1.1 Harris 角点介绍2.2.1.2 Harris计算流程1. 图像梯度2. 结构张量3. Harris响应函数4. 非极大值抑制5. 阈值化 2.2.1.3 Harris性质1. 旋…