C语言实现简单的n*n型的三子棋及多子棋

引言

 三子棋是对于函数,数组,循环,判断,以及常量与变量的知识结合,是对于目前初阶C语言的小测试,用来巩固已学的知识和初步了解编程思想。

一、三子棋及多子棋的实现思路:

1.游戏的菜单可视化;

2.获取玩家输入的选项程序响应下一步操作;

3.在一个game()函数中的操作:

1) 获取的值为字符,且为多行多列,故通过二维数组存放棋子的位置,以及谁下的棋子;

2) 对二维数组初始化;

3) 显示棋盘;

4) 获取玩家输入的棋子坐标;

5) 显示棋盘状况;

6) 电脑下棋;

7) 显示棋盘状况;

8) 由于4~7步为循环步骤,直至哪一方获胜或者平局,故需要将4~7循环并且在每一方下完棋后判断是否继续或者胜负或者平局,即在每个显示棋盘状况后添加判断;

9) 判断完胜负或平局后,显示结果。

4.完成一局后,回到菜单,通过玩家输入时候进行下一场游戏,或退出。

二、三子棋的主要功能:

1.游戏的简易菜单menu():

图示:

 示例代码:

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

2.用户进入游戏与退出 :

        通过获取用户输入的选项来进行下一步操作,如:进入游戏,退出游戏,检测输入错误,重新输入;

 示例代码:

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);
	
	return 0;
}

 3.game()函数的功能:

进入游戏后初始化二维数组,调用函数,判断游戏结果

void game()
{
	char board[ROW][COL] = { 0 };
	InitBoard(board, ROW, COL);
	DisplayBoard(board, ROW, COL);
	char ret = 0;
	while (1)
	{
		Player(board);
		DisplayBoard(board, ROW, COL);
		ret = Determine(board);
		if (ret != 'C')
			break;
		Computer(board);
		DisplayBoard(board, ROW, COL);
		ret = Determine(board);
		if (ret != 'C')
			break;
	}
	if (ret == '*')
	{
		printf("\n");
		printf("***********\n");
		printf("玩家赢!!!!!\n");
		printf("\n");
	}
	if (ret == '#')
	{
		printf("\n");
		printf("***********\n");
		printf("电脑赢!!!!!\n");
		printf("\n");
	}
	if (ret == 'Q')
	{
		printf("\n");
		printf("***********\n");
		printf("平局!!!!!!\n");
		printf("\n");
	}
}

 4.用户选择进入游戏后,各个游戏功能介绍:

1)初始化棋盘

2)显示棋盘

3)玩家下棋

4)电脑下棋

5)判断游戏的情况

#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 3
#define COL 3

void InitBoard(char board[ROW][COL], int row, int col);//初始化棋盘

void DisplayBoard(char board[ROW][COL], int row, int col);//显示棋盘

void Player(char board[ROW][COL]);//玩家下棋

void Computer(char board[ROW][COL]);//电脑下棋

//返回值的含义:*--玩家胜  #--电脑胜 Q--退出  C--继续
char Determine(char board[ROW][COL]);//判断游戏进行的情况

5.初始化棋盘:

初始化棋盘为空格,即可默认棋盘为空

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

6.显示棋盘:

通过for循环嵌套实现棋盘的打印,以及棋子的摆放,通过下划线_以及或符号 | 来美化棋盘,一开始为一个for循环里打印每一行的棋子和如同 ___|___|___,但是过于局限性,故通过for循环嵌套优化

void DisplayBoard(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j != col - 1)
				printf("|");
		}
		printf("\n");
		for (int k = 0; k < col; k++)
		{
			printf("---");
			if (k < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
	}
}

7.玩家下棋:

通过获取玩家输入的横、纵坐标各减1来用*替换数组相应位置的空格,并且判断坐标输入的有效性

void Player(char board[ROW][COL])
{
	int i, j;
	printf("玩家下棋\n");
	while (1)
	{
		printf("请输入棋子坐标:>");
		scanf("%d %d", &i, &j);
		if (i >= 1 && i <= ROW && j <= COL && j >= 1)//合法坐标
		{
			if (board[i - 1][j - 1] == ' ')//坐标未占用
			{
				board[i - 1][j - 1] = '*';
				break;
			}
			else
				printf("输入坐标被占用\n");
		}
		else
			printf("输入坐标无效\n");
	}

}

8.电脑下棋

通过随机数函数来使电脑随机下棋,在game()函数中使用srand()函数来控制rand()函数,而srand()函数中的参数为无符号整型,参数设为(unsigned int)time(NULL)可使rand()函数生成较为随机的随机值,通过%行或列来实现坐标正确位于二维数组。

srand((unsigned int)time(NULL));
void Computer(char board[ROW][ROW])
{
	int x, y;
	printf("电脑下棋\n");
	while (1)
	{
		x = rand() % ROW;
		y = rand() % COL;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

9.判断棋盘状况:

返回char,char可为结果有‘*’,‘#’,‘C’,‘Q’,以此来在game()函数判断循环继续,以及最后结果,若为‘C’游戏继续,直至产生游戏结果。

其中的IsFull函数判断时候棋盘已满,返回0或1,以此来判断未产生胜负结果时,返回‘C’,还是‘Q’;

int IsFull(char board[ROW][COL])
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			if (board[i][j] == ' ')
				return 0;
		}
	}
	return 1;
}

char Determine(char board[ROW][COL])
{
	int i = 0;
	int count2 = 0;
	int count3 = 0;
	for (i = 0; i < ROW; i++)
	{
		int j = 0;
		int count = COL;
		int count1 = COL;


		for (j = 0; j < COL; j++)
		{
			if (board[i][j] == '*'&&board[i][0]=='*')//依据计数来统计行相同数
				count++;
			else if (board[i][j] == '#'&& board[i][0] == '#')
				count--;
			if (board[j][i] == '*'&& board[0][i] == '*')//依据计数来统计列相同数
				count1++;
			else if (board[j][i] == '#'&& board[0][i] == '#')
				count1--;
			if (board[i][j] == '*' && i == j)//统计对角线相同数
				count2++;
			else if (board[i][j] == '#' && i == j)
				count2--;
			if (board[i][j] == '*' && i + j == COL - 1 )//统计反对角线相同数
				count3++;
			else if (board[i][j] == '#' && i + j == COL - 1 )
				count3--;
		}
		if (count == 2 * COL)//判断行满足胜利条件
			return '*';
		else if (count == 0)
			return '#';
		if (count1 == COL * 2)//判断列满足胜利条件
			return '*';
		else if (count1 == 0)
			return '#';
	}
	if (count2 == COL || count3 == COL)
		return '*';
	if (count2 == -COL || count3 == -COL)
		return '#';
	if (IsFull(board) == 1)
		return 'Q';
	return 'C';
}

三、程序结果及感想:

 

 感想:这篇博客不是写的很好,第一次写,三子棋的实现也几乎是n*n的多子棋的实现,只需把宏定义的常量改为所需要的数字,而三子棋的专属实现有一部分在判断棋盘状况的函数中,只需4个for循环里if语句分别判断行,列,对角线,反对角线的三个元素是否相等且不为空格,并返回其中的某一个元素的字符类型就能判断胜负,而在改进成多子棋的过程中未保存原先的三子棋步骤,故在此不显示。在进行多子棋改进中通过多次调试,才实现多子棋,count,count1只能在最外层,不能放在for循环中,自行尝试;而count2,count3需要放在第一个for循环中,若放在最外层即不在for循环中,则会导致有些对角线和反对角线本该出现胜负的情况却没有出现,原因为count2,count3会在里层for循环中更改,而每次计数在内部的for循环中更改,故需要初始化。

四、源代码:

test.c中:

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

void game()
{
	char board[ROW][COL] = { 0 };
	InitBoard(board, ROW, COL);
	DisplayBoard(board, ROW, COL);
	char ret = 0;
	while (1)
	{
		Player(board);
		DisplayBoard(board, ROW, COL);
		ret = Determine(board);
		if (ret != 'C')
			break;
		Computer(board);
		DisplayBoard(board, ROW, COL);
		ret = Determine(board);
		if (ret != 'C')
			break;
	}
	if (ret == '*')
	{
		printf("\n");
		printf("***********\n");
		printf("玩家赢!!!!!\n");
		printf("\n");
	}
	if (ret == '#')
	{
		printf("\n");
		printf("***********\n");
		printf("电脑赢!!!!!\n");
		printf("\n");
	}
	if (ret == 'Q')
	{
		printf("\n");
		printf("***********\n");
		printf("平局!!!!!!\n");
		printf("\n");
	}
}

void menu() 
{
	printf("**********************\n");
	printf("***   1.开始游戏   ***\n");
	printf("***     0.退出     ***\n");
	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);
	
	return 0;
}

game.c中:

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"

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

void DisplayBoard(char board[ROW][COL], int row, int col)
{
	for (int i = 0; i < row; i++)
	{
		for (int j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if (j != col - 1)
				printf("|");
		}
		printf("\n");
		for (int k = 0; k < col; k++)
		{
			printf("---");
			if (k < col - 1)
			{
				printf("|");
			}
		}
		printf("\n");
	}
}

void Player(char board[ROW][COL])
{
	int i, j;
	printf("玩家下棋\n");
	while (1)
	{
		printf("请输入棋子坐标:>");
		scanf("%d %d", &i, &j);
		if (i >= 1 && i <= ROW && j <= COL && j >= 1)//合法坐标
		{
			if (board[i - 1][j - 1] == ' ')//坐标未占用
			{
				board[i - 1][j - 1] = '*';
				break;
			}
			else
				printf("输入坐标被占用\n");
		}
		else
			printf("输入坐标无效\n");
	}

}

void Computer(char board[ROW][ROW])
{
	int x, y;
	printf("电脑下棋\n");
	while (1)
	{
		x = rand() % ROW;
		y = rand() % COL;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

int IsFull(char board[ROW][COL])
{
	for (int i = 0; i < ROW; i++)
	{
		for (int j = 0; j < COL; j++)
		{
			if (board[i][j] == ' ')
				return 0;
		}
	}
	return 1;
}

char Determine(char board[ROW][COL])
{
	int i = 0;
	int count2 = 0;
	int count3 = 0;
	for (i = 0; i < ROW; i++)
	{
		int j = 0;
		int count = COL;
		int count1 = COL;


		for (j = 0; j < COL; j++)
		{
			if (board[i][j] == '*'&&board[i][0]=='*')//依据计数来统计行相同数
				count++;
			else if (board[i][j] == '#'&& board[i][0] == '#')
				count--;
			if (board[j][i] == '*'&& board[0][i] == '*')//依据计数来统计列相同数
				count1++;
			else if (board[j][i] == '#'&& board[0][i] == '#')
				count1--;
			if (board[i][j] == '*' && i == j)//统计对角线相同数
				count2++;
			else if (board[i][j] == '#' && i == j)
				count2--;
			if (board[i][j] == '*' && i + j == COL - 1 )//统计反对角线相同数
				count3++;
			else if (board[i][j] == '#' && i + j == COL - 1 )
				count3--;
		}
		if (count == 2 * COL)//判断行满足胜利条件
			return '*';
		else if (count == 0)
			return '#';
		if (count1 == COL * 2)//判断列满足胜利条件
			return '*';
		else if (count1 == 0)
			return '#';
	}
	if (count2 == COL || count3 == COL)
		return '*';
	if (count2 == -COL || count3 == -COL)
		return '#';
	if (IsFull(board) == 1)
		return 'Q';
	return 'C';
}

game.h中:

#pragma once
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 3
#define COL 3
//该程序为三子棋及多子琪小游戏

void InitBoard(char board[ROW][COL], int row, int col);//初始化棋盘

void DisplayBoard(char board[ROW][COL], int row, int col);//显示棋盘

void Player(char board[ROW][COL]);//玩家下棋

void Computer(char board[ROW][COL]);//电脑下棋

//*--玩家胜  #--电脑胜 Q--退出  C--继续
char Determine(char board[ROW][COL]);//判断游戏进行的情况

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值