三(五)子棋实现

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

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

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

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

一.程序设计

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

                                                              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;
}

  小节

本期就到这里了,其中我们使用的思想其实非常贴合程序设计模型的一个周期,当然虽然我调试过很多次但是还是有许多不足但是值得各位借鉴的我想也会有,如果朋友们有不理解的欢迎大家私聊我,谢谢!
  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值