C语言自制华容道游戏代码

该博客介绍了如何使用C语言自制一款华容道游戏,参考了超级华容道的画风。程序随机生成盘面,包含自动解题功能,但不保证所有生成盘面都有解。文章提供了程序的执行效果,并分享了完整源代码。读者可以通过作者的B站号和QQ群获取更多编程资料。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

程序简介

华容道,画风参考的是手机程序:超级华容道。玩法是将大块移动至下层的中间。随机盘面,难度适中,自动解题。

程序随机了横块纵块数量,所以会有无解或难解,生成函数保证了加载出来的盘面是可玩的,但不保证每次生成的都可玩,所以需要有个等待过程。编码函数和解码函数是辅助解题的,解题思路是移动仅有的两个空格,包括两个空格移动,和一个空格移动。游戏下方从左往右是播放,重置,刷新按钮。点击播放开始输出解题过程;点击重置返回盘面初始状态,在游戏过程和播放完毕后使用;刷新即重新生成盘面。没有剪枝,面对类似横刀立马这类难解,只能分段求解才可以。这个程序直接舍弃这种题目了。

更新过加入了站内同学给出的十二张标准谱面,将求解作为按钮单独隔开,这十二关都可以解出来;因此随机生成谱面会有无解的可能,按求解会判断出来。明确了玩法,将出口标记了出来;点击棋子选中,点击相邻空格移动。

程序执行效果:

 完整源代码:


// 程序:华容道
// 编译环境:Visual C++ 2010,EasyX_20211109
// 编写日期:2023.2.18

# include <math.h>
# include <graphics.h>
# include <time.h>
# include <string>

static HWND hOut;						// 画布

// 定义一个结构体,树
struct Node1
{
	int num;							// 编号
	int num_transverse;					// 横向特征值
	int num_portrait;					// 纵向特征值
	int num_other;						// 其他特征值
	int num_father;						// 父结点
};
Node1 box[200001];						// 预制结点

// 定义一个结构体,临时存放
struct Node2
{
	int num_transverse;					// 横向特征值
	int num_portrait;					// 纵向特征值
	int num_other;						// 其他特征值
};

// 定义一个结构体,按钮
struct Node3
{
	int posx1, posy1, posx2, posy2;		// 坐标
};

// 定义一个类
class Gary
{
public:
	void carry();						// 主进程
	void initialization();				// 初始化
	void move();						// 窗口主视角函数
	void draw_scene(int num_box);		// 绘制界面函数
	void create();						// 生成函数
	void decode();						// 解码函数
	void code();						// 编码函数
	void check(int a, int b, int c);	// 检测重复函数
	void single_space(int mode);		// 单格移动函数
	void double_space();				// 双哥移动函数
	void over();						// 结束判断函数
	void game();						// 游戏函数
	void solve();						// 求解函数

	int exit_carry;						// 主循函数控制参数
	int exit_move;						// 开始界面控制参数
	int num_double[31];					// 辅助数据存入
	int num_step;						// 树层数
	int num_eat;						// 求解链长度参数
	int num_start;						// 求解起点参数
	int num_over;						// 求解终点参数
	int num_mod;						// 游戏模式
	int box_transverse[6];				// 横向
	int box_portrait[6];				// 纵向
	int box_big;						// 大格
	int box_space[2];					// 空格
	int num_transverse;					// 横向数量
	int num_portrait;					// 纵向数量
	int pan[30];						// 棋盘信息
	double num_flag;					// 树结点标记系数
	double num_flag1;					// 树结点标记系数
	IMAGE* img_transverse;				// 横块图片
	IMAGE* img_portrait;				// 纵块图片
	IMAGE* img_small;					// 小块图片
	IMAGE* img_big;						// 大块图片
	IMAGE* img_space;					// 空格图片
	ExMessage m;						// 鼠标定义
	Node2 eat[200];						// 临时存放结点
	Node3 box_button[20];				// 按钮,预制
};

// 场景绘制函数
void Gary::draw_scene(int num_box)
{
	int i, j;
	// 横向
	for(i = 0; i < num_transverse; i++)
	{
		box_transverse[i] = ( eat[num_box].num_transverse & ( num_double[i * 5 + 5] - num_double[i * 5] ) ) / num_double[i * 5];
	}
	// 纵向
	for(i = 0; i < num_portrait; i++)
	{
		box_portrait[i] = ( eat[num_box].num_portrait & ( num_double[i * 5 + 5] - num_double[i * 5] ) ) / num_double[i * 5];
	}
	// 大格
	box_big = ( eat[num_box].num_other & ( num_double[21] - num_double[16] ) ) / num_double[16];
	// 空格
	box_space[0] = ( eat[num_box].num_other & ( num_double[13] - num_double[8] ) ) / num_double[8];
	box_space[1] = ( eat[num_box].num_other & ( num_double[5] - num_double[0] ) );
	// 初始化
	for(i = 0; i < 20; i++)
	{
		pan[i] = -1;
	}
	// 横向
	for(i = 0; i < num_transverse; i++)
	{
		pan[box_transverse[i]] = 2;
		pan[box_transverse[i] + 1] = 5;
	}
	// 纵向
	for(i = 0; i < num_portrait; i++)
	{
		pan[box_portrait[i]] = 3;
		pan[box_portrait[i] + 4] = 5;

	}
	// 大格
	pan[box_big] = 1;
	pan[box_big + 1] = 5;
	pan[box_big + 4] = 5;
	pan[box_big + 5] = 5;
	// 空格
	pan[box_space[0]] = 0;
	pan[box_space[1]] = 0;
	// 小块
	for(j = 0; j < 20; j++)
	{
		if(pan[j] == -1)
		{
			pan[j] = 4;
		}
	}
	// 背景绘制
	setbkcolor(RGB(136, 192, 160));
	cleardevice();
	// 棋盘绘制
	setlinestyle(PS_SOLID, 3);
	setfillcolor(RGB(73, 130, 120));
	setlinecolor(RGB(168, 226, 195));
	fillroundrect(20, 15, 25 + 102 * 4, 30 + 102 * 5, 30, 30);
	for(i = 0; i < 20; i++)
	{
		// 根据格子类型绘制
		switch(pan[i])
		{
		case 0:putimage(25 + i % 4 * 102, 25 + i / 4 * 102, img_space); break;
		case 1:putimage(25 + i % 4 * 102, 25 + i / 4 * 102, img_big); break;
		case 2:putimage(25 + i % 4 * 102, 25 + i / 4 * 102, img_transverse); break;
		case 3:putimage(25 + i % 4 * 102, 25 + i / 4 * 102, img_portrait); break;
		case 4:putimage(25 + i % 4 * 102, 25 + i / 4 * 102, img_small); break;
		default:break;
		}
		// 出口绘制
		if(pan[i] == 0 && ( i == 13 || i == 14 || i == 17 || i == 18 ))
		{
			setlinecolor(RGB(230, 230, 230));
			setlinestyle(PS_SOLID, 10);
			setfillcolor(RGB(112, 180, 167));
			fillcircle(25 + 51 + i % 4 * 102, 25 + 51 + i / 4 * 102, 20);
			setlinecolor(RGB(168, 226, 195));
			setfillcolor(RGB(73, 130, 120));
			setlinestyle(PS_SOLID, 3);
		}
	}

	// 按钮绘制
	TCHAR s[25];
	setlinecolor(RGB(155, 195, 230));
	setfillcolor(RGB(80, 189, 222));
	settextcolor(RGB(230, 230, 230));
	settextstyle(30, 20, _T("Times New Roman"));
	setbkcolor(RGB(80, 189, 222));
	// 标准棋盘按钮
	for(i = 0; i < 12; i++)
	{
		fillroundrect(box_button[i].posx1, box_button[i].posy1, box_button[i].posx2, box_button[i].posy2, 20, 20);
		_stprintf_s(s, _T("%d"), i);
		outtextxy(box_button[i].posx1 + 13 - 11 * ( i / 10 ), box_button[i].posy1 + 10, s);
	}
	// 其他按钮
	settextstyle(100, 100, _T("Webdings"));
	settextcolor(RGB(73, 130, 120));
	setbkmode(TRANSPARENT);
	// 播放,求解
	outtextxy(102 - 50, 580 - 30, 0x34);
	// 重置,恢复初始盘面
	outtextxy(214 - 50, 580 - 30, 0x33);
	// 刷新,随机盘面按钮
	outtextxy(326 - 50, 580 - 30, 0x71);
	// 恢复填充
	setbkmode(OPAQUE);
	settextcolor(RGB(230, 230, 230));
	settextstyle(30, 20, _T("宋体"));
	setbkcolor(RGB(136, 192, 160));
	outtextxy(102 - 50, 655, _T("求解"));
	outtextxy(214 - 50, 655, _T("恢复"));
	outtextxy(326 - 50, 655, _T("刷新"));

	FlushBatchDraw();
}

// 解码
void Gary::decode()
{
	int i;
	// 根据特征值画棋面
	// 横向
	for(i = 0; i < num_transverse; i++)
	{
		box_transverse[i] = ( box[int(num_flag)].num_transverse & ( num_double[i * 5 + 5] - num_double[i * 5] ) ) / num_double[i * 5];
	}
	// 纵向
	for(i = 0; i < num_portrait; i++)
	{
		box_portrait[i] = ( box[int(num_flag)].num_portrait & ( num_double[i * 5 + 5] - num_double[i * 5] ) ) / num_double[i * 5];
	}
	// 大格
	box_big = ( box[int(num_flag)].num_other & ( num_double[21] - num_double[16] ) ) / num_double[16];
	// 空格
	box_space[0] = ( box[int(num_flag)].num_other & ( num_double[13] - num_double[8] ) ) / num_double[8];
	box_space[1] = ( box[int(num_flag)].num_other & ( num_double[5] - num_double[0] ) );
}

// 检查重复函数
void Gary::check(int a, int b, int c)
{
	int k, t;
	// 全局检测
	k = 0;
	for(t = int(num_flag1 - 1); t >= 0; t--)
	{
		if(box[t].num_transverse == a && box[t].num_portrait == b && box[t].num_other == c) { k = 1; break; }
	}
	// 不重复则生成子结点
	if(k == 0)
	{
		// 特征值录入,父结点录入
		box[int(num_flag1)].num_transverse = a;
		box[int(num_flag1)].num_portrait = b;
		box[int(num_flag1)].num_other = c;
		box[int(num_flag1)].num_father = int(num_flag);
		// 编号
		box[int(num_flag1)].num = box[box[int(num_flag1)].num_father].num + 1;
		// 层数
		if(box[int(num_flag1)].nu
package 华容道; import java.awt.*; import java.awt.event.*; //主函数 public class Main { public static void main(String[] args) { new Hua_Rong_Road(); } } //人物按钮颜色 class Person extends Button implements FocusListener{ int number; Color c=new Color(255,245,170); Person(int number,String s) { super(s); setBackground(c);//人物的颜色背景是黄色 this.number=number; c=getBackground(); addFocusListener(this);//好像是焦点监听器 } public void focusGained(FocusEvent e) { setBackground(Color.red);//只要单击该按钮则按钮变颜色 } public void focusLost(FocusEvent e) { setBackground(c);//上一个按钮回复原先的颜色 } } //华容道总类 class Hua_Rong_Road extends Frame implements MouseListener,KeyListener,ActionListener{ Person person[] = new Person[10]; Button left,right,above,below; Button restart = new Button("Start");//重新开始按钮 public Hua_Rong_Road() { init(); setBounds(100,100,320,360); setVisible(true);//设置Frame为可见,默认为不可见 validate(); addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); } public void init() { setLayout(null); add(restart); restart.setBounds(100, 320, 120, 25); restart.addActionListener(this); String name[]={"我","陆逊","姜维","陈宫","许攸","邓艾","周瑜","庞统","诸葛亮","贾诩"}; for(int k=0;k<name.length;k++) { person[k]=new Person(k,name[k]); person[k].addMouseListener(this); person[k].addKeyListener(this); add(person[k]); }//为所有的按钮注册所需的东西 person[0].setBounds(104, 54, 100, 100); person[1].setBounds(104,154, 100, 50); person[2].setBounds(54, 154, 50, 100); person[3].setBounds(204, 154, 50, 100);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值