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

三子棋

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);
相关推荐
谭光志21 分钟前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..25 分钟前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects31 分钟前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰31 分钟前
一些基础和问题解决
后端
陈随易1 小时前
前端项目部署只要30秒
前端·后端·程序员
YIAN1 小时前
从零手写文件读取 MCP 服务:一文吃透 Model Context Protocol 全链路通信原理
前端·后端·mcp
Imchendiana1 小时前
《狂人日记NO.9》— 前后端一把梭,我的全栈实录
前端·后端
学渣超1 小时前
记一次分布式事务数据不一致的排查之旅:从超时到索引,层层剥茧
java·后端·架构
北冥you鱼1 小时前
Go 语言读取链上数据:从基础到实战
开发语言·后端·golang
程序员cxuan2 小时前
Claude Code 为了封禁中国用户,竟然在代码里下毒
人工智能·后端·程序员