实践出真知———三子棋游戏

一、制作目的

      综合运用基础知识以及数组来求解问题,巩固夯实基础,思维扩展提升能力。

二、制作思路

       利用二维数组的二维性在平面内能产生坐标来实现棋子的落定。运用循环以及字符制作一个伪棋盘。

难点:二维数组的运用以及循环制作棋盘过程

三、制作步骤

1、菜单(menu)

代码:

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

分析:制作游戏菜单,用printf函数输出打印,能让游戏操作性提高,玩家更容易上手。

2、初始化数组(Initboard)

代码:

void Initboard(char board[][3], int row, int col)//初始化
{
	int i;
	int j;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}

}

分析:利用双重循环遍历二维数组对其值赋字符空格,即实现棋盘空的操作。row控制行,col控制列。亦可以用memset库函数来实现上述操作,memset(board,' ',row*col*sizeof(char));参数设置分别是数组,打印字符,打印的数目。

3、打印棋盘(Showboard)

代码:

void Showboard(char board[][3], int row, int col)//打印棋盘
{
	int i;
	int j;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[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");
		}
	}
}

分析:首先依然是双重循环来实现字符的“井”字型打印,分别利用“|”实现列的分隔,“---”来实现行的分隔。

注意:打印输出 board[i][j]的时候注意为%c腾出相应的空间(代码中用空格实现)以便与“---”对其更加美观。

而输出打印“|”的时候注意条件是列减一。使用if (i< row - 1)可防止输出三行“---”。最后需每打印一行换行。

4、玩家输入,电脑输入( PlayMove,ComputerMove)

代码:

void PlayMove(char board[][3], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请输入1~3的坐标:");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= 3 && y >= 1 && y <= 3)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = 'X';
				break;
			}
			else
			{
				printf("此位置已经被占用!\n");
			}
		}
		else
		{
			printf("憨憨!坐标输错了!\n");
		}

	}
}
void ComputerMove(char board[][3], int row, int col)
{
	printf("电脑移动\n");
	while (1)
	{
		int x = rand() % row + 1;//  [0-3)   [1-4)
		int y = rand() % col + 1;
		if (board[x - 1][y - 1] == ' ')
		{
			board[x - 1][y - 1] ='O';
			break;
		}
	}
}

分析:利用x,y二维坐标控制落子。利用条件判断输入是否合法。

注意:当条件合法时,落子后需用break跳出条件。用空格判断此处是否落子。使用是需结合打印函数实现,不然后面看不到你落子的结果。其次在主函数定义随机数种子让电脑随机刷数。 x = rand() % row 此时x的范围是0·3的左开右闭区间。要显示1·3需加一实现。

5、判断胜负(IsWin)

代码:

static int IsFull(char board[][3], int row, int col)//static修饰只能在game.c中使用。判断棋盘下满否。
{
	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;
}
char IsWin(char board[][3], 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[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[0][2] == board[1][1] && board[1][1] == board[2][0]
			&& board[0][0] != ' ')
		{
			return board[0][2];
		}

		//平局
		if (IsFull(board, row, col) == 1)
		{
			return 'Q';//棋盘下满,平局
		}
	}
	//棋盘未满,胜负未分
	return ' ';
}

分析:胜负的八种情况,行一样,列一样,斜着一样两种。然后依次返回里面的值,判断棋子判别胜负。棋盘未满胜负未分时继续游戏。棋盘已满胜负未分时平局。

注意:static定义的函数只在此文件中能使用。理清胜利情况,不要搞混。


6、主函数

代码:

void game() 
{
	char r;
	char board[3][3] = { 0 };
	Initboard(board, 3, 3);
	Showboard(board, 3, 3);
	while (1)
	{
		PlayMove(board, 3, 3);
		 r=IsWin(board, 3, 3);
		 if (r != ' ')
		 {
			 break;
		 }
		 Showboard(board, 3, 3);
		ComputerMove(board, 3, 3);
		r = IsWin(board, 3, 3);
		if (r != ' ')
		{
			break;
		}
		Showboard(board, 3, 3);
		}
	if (r == 'Q')
	{
		printf("平局!\n");
	}
	else if (r == 'X')
	{
		printf("哈哈!我赢了!!\n");
	}
	else if (r == 'O')
	{
		printf("尴尬,我输了!!\n");
	}
}


int main()
{   
	int in = 0;
	do{
		menu();
		srand((unsigned int)time(NULL));
		printf("请输入操作:");
		scanf("%d", &in);
		switch (in)
		{
		case 1:
			game();
			break;
		case 0:
			printf("游戏结束:\n");
			break;
		default:
			printf("憨憨!你输入错了!\n");
			break;
		}
	} while (in);
	return 0;

分析:主函数运用switch函数调用不同的输入操作,利用game函数实现其他子函数的功能,思路清晰。

7、头文件

代码:

#ifndef __GAME_H__
#define __GAME_H__
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void Initboard(char board[][3], int row, int col);
void Showboard(char board[][3], int row, int col);
void PlayMove(char board[][3], int row, int col);
char IsWin(char board[][3], int row, int col);
void ComputerMove(char board[][3], int row, int col);

#endif

         分析:利用头文件,对函数进行库存然后只需在主函数调用自己写的game.h即可。创建game.h的同时创建game.c文件用于存放函数,将所写的函数放入其中,思路清晰,尽量保持test.c测试文件存放主函数来测试程序执行,代码少更加易懂。

三、总结

        从这次实践中,我掌握了数组,函数,循环的基本用法,也学到了如何解决一个实际问题,以及如何让逻辑更加清晰,代码更加简练易懂。代码量虽然很大,但是细分成小块慢慢消化,还是很容易没明白其逻辑的。尤其注意一些特殊的细节,让程序更加精细,更加准确。在编写的过程中,尽量逐步调试,写好一个函数就去验证其功能,这样改bug起来将会变的轻松,避免一股脑写完发现一堆bug,改起来太吃力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值