零基础手把手实现小游戏三子棋

三子棋

TOC

bash 复制代码
 本文使用C语言从零开始写一个三子棋程序,本程序功能是我们利用坐标在3X3的棋盘上填入"*"键,然后电脑自动填入"#",最后输出玩家赢还是电脑赢,本文最后附加完整代码和源代码文件。

编程软件使用VS 2019,可以百度到官网下载。

markdown 复制代码
    三子棋程序的编写一共分为7个步骤:
  • 框架搭建:任何程序在写之前都需要先把大致的结构固定好,再把核心的内容填进去
  • 文件分配:本程序比较简单所以只需要把整个程序拆分为三个文件,分别是game.c(核心代码) 、 game.h(函数声明和符号的定义)、test.c(测试该程序)
  • 初始化棋盘:我们需要往棋盘填星号和井号,就需要先把棋盘初始化为空格,否则一开始就是其他符号很乱。
  • 打印棋盘:把棋盘的架构打印出来,方便我们调试
  • 玩家下棋:编写玩家利用坐标把星号填到棋盘中
  • 电脑下棋:利用随机数使得电脑自动填写井号
  • 判断输赢:在玩家和电脑下棋过程中编写判断输赢的代码

1.框架搭建

先把总体的框架搭建好,后面再把核心的代码写好。

实现输入1,开始游戏;输入0,退出游戏。

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
//测试三子棋游戏的逻辑
void menu()
{
	printf("*******************************\n");
	printf("********* 1.play       ********\n");
	printf("********* 0.exit       ********\n");
	printf("*******************************\n");
}

void test()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d",&input);
		switch (input)
		{
		case 1:
			printf("三子棋\n");
			break;
		case 0:
			printf("退出游戏!");
			break;
		default:
			printf("选择错误\n");
			break;

		}

	} while (input);
}

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

我们实现了输入1,输出三子棋;输入0,退出游戏。

2.文件分配

  • 我们把整个程序的源代码分为三大块:

    • test.c用于测试代码的逻辑。

    • game.c用于游戏功能的实现。

    • game.h用于函数的声明和符号的定义。

3.初始化棋盘

这一步我们实现把3x3的棋盘每个格子都初始化为空格。

把行列都#define为ROW和COL方便升级行数和列数。

c 复制代码
//game.c
void InitBoard(char board[ROW][COL],int row,int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}

	}
}
c 复制代码
//game.h
#define ROW 3
#define COL 3

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

4.打印棋盘框架

利用循环把三子棋盘的框架打印出来,我们框架使用 | - 这两个符合组合实现的。

c 复制代码
//game.h
void DisplayBoard(char board[3][3], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		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");

		}
		
	}
}
c 复制代码
//game.h
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);

这就是我们利用 | - 这两种符合通过循环组合实现的棋盘。

5.玩家下棋

上一步我们已经把棋盘打印出来了,这一步实现我们输入坐标把星号写入棋盘中。

c 复制代码
//game.c
void player_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋\n");
	while (1)
	{
		printf("请输入坐标:>\n");
		scanf("%d %d", &x, &y);

		if (x >= 1 && x <= row && y >= 1 && y <= col)//如果在这个棋盘范围才能输入
		{
			if (board[x - 1][y - 1] == ' ')//在棋盘范围内,是空格才能输入
			{
				board[x - 1][y - 1] = '*';
				break;
			 }
			else
			{
				printf("改坐标被占用重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}

我们输入2 2 ,就是在棋盘的第二行和第二列输入一个星号,如果输入了 3 7 ,我们初始化棋盘时只是弄了3x3的棋盘,所以7太大了,我们就输出它是错误的坐标。

6.电脑下棋

上一步实现了玩家下棋,这一步是电脑下棋,电脑怎么下棋?我们利用srand()函数生成随机数,再把这个随机数模上棋盘的范围就可以得到一个随机的坐标,让它输入井号。

c 复制代码
//game.c
void computer_move(char board[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 (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}

	}

}
c 复制代码
//test.c
srand((unsigned int)time(NULL));
arduino 复制代码
//game.h
#include <stdlib.h>
#include <time.h>

电脑随机输入井号键。

7.判断输赢

三个星号或者三个井号连在一起就是赢,所以我们用了下面代码的四种情况来判断电脑赢还是玩家赢。

c 复制代码
static int  if_full(char board[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 (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	 return 1;
}

char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	//判断每一行的赢法
	for (i = 0; i < row; i++)
	{
		if (board[i][1] == board[i][0] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][1];
		}
	}
	//判断每一列的赢法
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[1][i];
		}
	}
	//判断对角线赢法
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	//判断平局
	if (if_full(board, row, col)==1)
	{
		return 'Q';
	}
	//继续
	return 'C';
}

总结:完整代码

test.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"
//测试三子棋游戏的逻辑
void menu()
{
	printf("*******************************\n");
	printf("********* 1.play       ********\n");
	printf("********* 0.exit       ********\n");
	printf("*******************************\n");
}
void game()
{
	char ret = 0;
	//存放下棋的数据
	char board[ROW][COL] = { 0 };
	//初始化棋盘为空格
	InitBoard(board, ROW, COL);
	//打印棋盘
	DisplayBoard(board, ROW, COL);
	while (1)
	{
		//玩家下棋
		player_move(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		//判断输赢
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		//电脑下棋
		computer_move(board, ROW, COL);//智能的应该知道该从哪里堵,有点复杂,我们目前先来个随机版本的
		DisplayBoard(board, ROW, COL);
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		


	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
	//DisplayBoard(board, 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("退出游戏!");
			break;
		default:
			printf("选择错误\n");
			break;

		}

	} while (input);
}




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

game.c

c 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

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

	}
}

void DisplayBoard(char board[3][3], int row, int col)
{
	int i = 0;
	for (i = 0; i < row; i++)
	{
		int j = 0;
		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");

		}
		
	}
}

void player_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋\n");
	while (1)
	{
		printf("请输入坐标:>\n");
		scanf("%d %d", &x, &y);

		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			 }
			else
			{
				printf("改坐标被占用重新输入\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入\n");
		}
	}
}


void computer_move(char board[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 (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}

	}



}

static int  if_full(char board[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 (board[i][j] == ' ')
			{
				return 0;
			}
		}

		

	}
	 return 1;
}

char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	//判断每一行的赢法
	for (i = 0; i < row; i++)
	{
		if (board[i][1] == board[i][0] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][1];
		}
	}
	//判断每一列的赢法
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[1][i];
		}
	}
	//判断对角线赢法
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	//判断平局
	if (if_full(board, row, col)==1)
	{
		return 'Q';
	}
	//继续
	return 'C';
}

game.h

c 复制代码
#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_move(char board[ROW][COL], int row, int col);
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);
//判断输赢
char is_win(char board[ROW][COL],int row, int col);
相关推荐
神奇小汤圆7 小时前
浅析二叉树、B树、B+树和MySQL索引底层原理
后端
文艺理科生7 小时前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
千寻girling7 小时前
主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“
前端·后端·面试
南极企鹅7 小时前
springBoot项目有几个端口
java·spring boot·后端
Luke君607977 小时前
Spring Flux方法总结
后端
define95277 小时前
高版本 MySQL 驱动的 DNS 陷阱
后端
忧郁的Mr.Li7 小时前
SpringBoot中实现多数据源配置
java·spring boot·后端
暮色妖娆丶8 小时前
SpringBoot 启动流程源码分析 ~ 它其实不复杂
spring boot·后端·spring
Coder_Boy_8 小时前
Deeplearning4j+ Spring Boot 电商用户复购预测案例中相关概念
java·人工智能·spring boot·后端·spring
Java后端的Ai之路8 小时前
【Spring全家桶】-一文弄懂Spring Cloud Gateway
java·后端·spring cloud·gateway