每天一个C语言小项目,提升自己的编程能力!
点灯游戏是一个十分有趣的智力游戏:有一行N行N列的灯,开始时全部是灭的,当你点击其中一盏灯时他的上下左右(若存在的话)状态全部改变,现在要求你在限定的时间内以最少地步数,将全部的灯点亮。
例如一开始有5×5共25盏灯,都处于关的状态,现在要想办法把25盏灯全打开,每次只能开/关一盏灯,但由于电路原因,和它相邻的四盏灯也会改变开/关状态,于是想把25盏灯全打开就有一定难度。
效果展示如下:
(本期代码有两个版本)
编译环境:Visual C 6.0 / VS2019/2022,EasyX插件
代码版本一:
#include <graphics.h>
#include <conio.h>
#define MaxNum 14 //单边最大格子数
#define G_length 30 //格子边长
#define USER_LBUTTONDOWN 101
#define USER_RBUTTONDOWN 102
#define USER_MBUTTONDOWN 103
///////////////////////////////////////////////
void PaintGrid(int Mid_x, int Mid_y, int num, int color); // 绘制游戏格子,初始化格子
void OnLButtonDown(MOUSEMSG m, int num); // 左键按下
void OnRButtonDown(int num); // 右键按下
void OnMButtonDown(); // 中键按下*暂无定义*
void welcome(); // 显示游戏主界面
void goodbye(int num); // 显示结束画面
void NextLevel(int num); // 下一关
int GetMessage(MOUSEMSG m); // 获取鼠标信息
int DispatchMessage(MOUSEMSG m, int opt); // 分发鼠标信息
int JudgeFull(int num, int array[MaxNum][MaxNum]); // 格子是否填满
///////////////////////////////////////////////
// 定义游戏格子结构体
struct Grid
{
int left; // 游戏区域边界
int right;
int top;
int bottom;
int array[MaxNum][MaxNum]; // 记录格子状态
int num; // 记录边界格子数目
}grid;
///////////////////////////////////////////////
void main()
{
int opt, end=0;
grid.num=4;
welcome();
PaintGrid(320, 240, grid.num, RGB(0,255,0));
MOUSEMSG m;
while(end!=1)
{
m = GetMouseMsg();
opt = GetMessage(m);
end=DispatchMessage(m, opt);
}
goodbye(grid.num);
closegraph();
}
///////////////////////////////////////////////
// 获取鼠标信息
int GetMessage(MOUSEMSG m)
{
//鼠标循环
switch(m.uMsg)
{
case WM_LBUTTONDOWN:
return USER_LBUTTONDOWN;
case WM_RBUTTONDOWN:
return USER_RBUTTONDOWN;
case WM_MBUTTONDOWN:
return USER_MBUTTONDOWN;
}
return 0;
}
///////////////////////////////////////////////
// 分发消息
int DispatchMessage(MOUSEMSG m, int opt)
{
switch(opt)
{
case USER_LBUTTONDOWN:
// 左键填色
OnLButtonDown(m, grid.num);
// 判断是否填满
if(JudgeFull(grid.num, grid.array)==1)
{
grid.num ;
// 格子数目超过最大值通关
if(grid.num>MaxNum)
{
return 1;
break;
}
else
NextLevel(grid.num);
}
break;
case USER_RBUTTONDOWN:
// 右键清除
OnRButtonDown(grid.num);
break;
case USER_MBUTTONDOWN:
return 1;
break;
}
return 0;
}
///////////////////////////////////////////////
// 左键按下
void OnLButtonDown(MOUSEMSG m, int num)
{
int nx, ny, x, y;
if(m.x>grid.left && m.x<grid.right && m.y>grid.top && m.y<grid.bottom)
{
// 计算位置
nx=(int)(m.x - grid.left)/G_length;
ny=(int)(m.y - grid.top )/G_length;
// 转换格子状态
grid.array[nx][ny] = -grid.array[nx][ny];
if(nx >= 0 && nx < num-1) grid.array[nx 1][ny] = -grid.array[nx 1][ny];
if(nx > 0 && nx <= num-1) grid.array[nx-1][ny] = -grid.array[nx-1][ny];
if(ny >= 0 && ny < num-1) grid.array[nx][ny 1] = -grid.array[nx][ny 1];
if(ny > 0 && ny <= num-1) grid.array[nx][ny-1] = -grid.array[nx][ny-1];
// 扫描填色
for(nx=0; nx<num; nx )
for(ny=0; ny<num; ny )
{
if(grid.array[nx][ny] == 1)
setfillcolor(GREEN);
else
setfillcolor(BLACK);
x= nx * G_length grid.left;
y= ny * G_length grid.top;
solidrectangle(x 1, y 1, x G_length-1, y G_length-1);
}
}
}
///////////////////////////////////////////////
// 右键按下清空
void OnRButtonDown(int num)
{
int x, y, nx, ny;
for(x=0; x<num; x )
for(y=0; y<num; y )
grid.array[x][y] = -1;
for(nx=0; nx<num; nx )
for(ny=0; ny<num; ny )
{
setfillcolor(BLACK);
x= nx*G_length grid.left;
y= ny*G_length grid.top;
solidrectangle(x 1, y 1, x G_length-1, y G_length-1);
}
}
///////////////////////////////////////////////
// 显示下一关
// 参数:
// num: 下一关的边界格子数
void NextLevel(int num)
{
// 清屏
BeginBatchDraw();
for(int y=0; y<=480; y =5)
{
setlinecolor(RGB(0, 255, 0));
settextcolor(RGB(0, 255, 0));
line(0, y, 640, y);
line(0, 480-y, 640, 480-y);
outtextxy(300, y, "下一关");
FlushBatchDraw();
Sleep(16);
setfillcolor(BLACK);
solidrectangle(0, y 4, 640, y-5);
solidrectangle(0, 480-y, 640, 480-y 5);
}
EndBatchDraw();
// 绘制下一关格子
PaintGrid(320, 240, num, RGB(0,255,0));
}
///////////////////////////////////////////////
// 判断格子是否填满
// 参数:
// num: 单边格子数目
// array: 生成数组接收实参
int JudgeFull(int num, int array[MaxNum][MaxNum])
{
int c=-1;
int nx=0, ny=0;
while(nx<num && ny<num)
{
for(nx=0; nx<num; nx )
for(ny=0; ny<num; ny )
if(array[nx][ny]==1)
continue;
else
return c;
}
c=1;
return c;
}
///////////////////////////////////////////////
// 绘制游戏格子,初始化格子
// 参数:
// Mid_x: 屏幕中心 x 坐标
// Mid_y: 屏幕中心 y 坐标
// num: 单边格子数目
// color: 格子线条颜色
void PaintGrid(int Mid_x, int Mid_y, int num, int color)
{
int x,y,nx,ny;
// 游戏区域大小
grid.left = Mid_x-num*G_length/2;
grid.right = Mid_x num*G_length/2;
grid.top = Mid_y-num*G_length/2;
grid.bottom = Mid_y num*G_length/2;
// 绘制格子
setlinecolor(color);
for(x=grid.left; x<=grid.right; x =G_length)
{
line(x, grid.top, x, grid.bottom);
Sleep(10);
}
for(y=grid.top; y<=grid.bottom; y =G_length)
{
line(grid.left, y, grid.right, y);
Sleep(10);
}
// 外边框
for(x=20;x>10;x--)
{
line(grid.left-x, grid.top-x, grid.right x, grid.top-x);
line(grid.left-x, grid.bottom x, grid.right x, grid.bottom x);
line(grid.left-x, grid.top-x, grid.left-x, grid.bottom x);
line(grid.right x, grid.top-x, grid.right x, grid.bottom x);
Sleep(5);
}
// 清空单元格
for(x=0; x<num; x )
for(y=0; y<num; y )
grid.array[x][y] = -1;
for(nx=0; nx<num; nx )
for(ny=0; ny<num; ny )
{
setfillcolor(BLACK);
x = nx * G_length grid.left;
y = ny * G_length grid.top;
solidrectangle(x 1, y 1, x G_length-1, y G_length-1);
}
}
///////////////////////////////////////////////
// 显示游戏主界面
void welcome()
{
// 初始化窗口
initgraph(640, 480);
// 输出屏幕提示
cleardevice();
settextcolor(RGB(0,255,0));
settextstyle(64, 0, "黑体");
outtextxy(70, 50, "涂格子游戏(点灯)");
settextcolor(WHITE);
settextstyle(16, 0, "宋体");
outtextxy(100, 200, "每点一个格子,上下左右的格子也会做出于现状相反的动作");
outtextxy(100, 240, "总共11关,左键填色,右键重来,中键退出");
outtextxy(100, 280, "只是一个功能演示版本,以后再改进");
outtextxy(400, 320, "by:doufuguolyl");
settextstyle(16, 0, "黑体");
outtextxy(400, 340, "Ver 0.1");
// 实现闪烁的"按任意键继续"
int c=255;
while(!kbhit())
{
settextcolor(RGB(0, c, 0));
outtextxy(280, 400, "按任意键继续");
c -= 8;
if (c < 0) c = 255;
Sleep(20);
}
getch();
cleardevice();
}
///////////////////////////////////////////////
// 显示结束画面
void goodbye(int num)
{
int c=255;
// 清屏
BeginBatchDraw();
for(int y=0; y<=480; y =5)
{
setlinecolor(RGB(0, 255, 0));
line(0, y, 640, y);
line(0, 480-y, 640, 480-y);
FlushBatchDraw();
Sleep(16);
setfillcolor(BLACK);
solidrectangle(0, y 4, 640, y-5);
solidrectangle(0, 480-y, 640, 480-y 5);
}
EndBatchDraw();
//判断显示文字
if(num == MaxNum 1)
{
settextcolor(RGB(0, c, 0));
settextstyle(48, 0, "黑体");
outtextxy(280, 200, "通关");
settextstyle(20, 0, "黑体");
}
else
{
settextcolor(RGB(0, c, 0));
settextstyle(48, 0, "黑体");
outtextxy(200, 200, "再接再厉");
settextstyle(20, 0, "黑体");
}
while(!kbhit())
{
settextcolor(RGB(0, c, 0));
outtextxy(400, 400, "QQ: 372480348");
c -= 8;
if (c < 0) c = 255;
Sleep(20);
}
getch();
}
代码版本二:
#include<stdio.h>
#include<conio.h>
//easyx图形库
#include<graphics.h>
#include<mmsystem.h>//包含躲媒体1设备接口头文件
#pragma comment(lib,"winmm.lib")
#define WIN_WIDTH 640
#define WIN_HEIGHT 480
#define GRID_WIDTH 30//格子宽度
#define GRID_NUM 4//每一行格子的数量
struct Grid //格子结构,结构体,类首字母大写
{
int top;//上面一条线的y
int down;
int left;
int right;
int foot;//玩家走了多少步
int map[GRID_NUM][GRID_NUM];
int x;//保存鼠标点击的数组下标
int y;
}grid;
MOUSEMSG msg;
//int a=0;
IMAGE img;//保存背景图片
//欢迎界面
void Welcome()
{
/*
错误 1 error C2665: “loadimage”: 2 个重载中没有一个可以转换所有参数类型
什么问题?字符集问题1,在字符串前面加上L
2,在字符串前面加上_T(str) 推荐
3,修改项目字符集属性
*/
mciSendString("open ./森林幻想曲.mp3 alias BGM",0,0,0);//向多媒体设备接口发送一个字符串
mciSendString("play BGM repeat", 0, 0, 0);//重复播放音乐
//Sleep(10000);
//mciSendString("close BGM", 0, 0, 0);//关闭音乐
loadimage(&img, "./bk.jpg", WIN_WIDTH, WIN_HEIGHT);//加载图片
putimage(0, 0, &img);
setbkmode(TRANSPARENT);//设置文字背景颜色透明
settextcolor(GREEN);
settextstyle(50, 0, "楷体");//设置字体大小,类型
char str[] = "涂格子游戏(点灯游戏)";
int twidth = textwidth(str)/2;//让文字居中显示
outtextxy(WIN_WIDTH / 2 - twidth, 20, str);
while (!_kbhit())//如果没有按键就一直循环
{
settextcolor(RGB(rand() % 256, rand() % 256,rand() % 256));
outtextxy(180, 300, "按任意键继续...");
Sleep(300);
}
_getch();//等待按键,没有按键,就一直等待
}
//初始化数据
void GameInit()
{
grid.top = WIN_HEIGHT / 2 - GRID_NUM*GRID_WIDTH / 2;//获取上面的y坐标
grid.down = WIN_HEIGHT / 2 GRID_NUM*GRID_WIDTH / 2;//获取下面的y坐标
//理解不?
grid.left = WIN_WIDTH / 2 - GRID_NUM*GRID_WIDTH / 2;
grid.right = WIN_WIDTH / 2 GRID_NUM*GRID_WIDTH / 2;
grid.foot = 0;
//双重循环初始化二维数组
for (int i = 0; i < GRID_NUM; i )
{
for (int k = 0; k < GRID_NUM; k )
{
grid.map[i][k] = 1;//黑色为1,绿色为-1
}
}
}
//把数据通过图形界面的方式展示出来
void GameDraw()
{
cleardevice();
putimage(0, 0, &img);
//绘制格子
setlinecolor(RGB(0, 200, 0));
//循环绘制格子线条
for (int x = grid.left; x <= grid.right; x =GRID_WIDTH)
{
line(x, grid.top, x, grid.down);//画竖线
}
for (int y = grid.top; y <= grid.down; y = GRID_WIDTH)
{
line(grid.left, y, grid.right,y);
}
//绘制界面边框
for (int x = 20; x > 10; x--)
{
line(grid.left - x, grid.top - x, grid.right x, grid.top - x);
line(grid.left - x, grid.down x, grid.right x, grid.down x);
line(grid.left - x, grid.top - x, grid.left - x, grid.down x);
line(grid.right x, grid.top - x, grid.right x, grid.down x);
}
grid.map[2][2] = -1;
//填充游戏格子为黑色
int x, y;
for (int i = 0; i < GRID_NUM; i )
{
for (int k = 0; k < GRID_NUM; k )
{
y = i*GRID_WIDTH grid.top;//得到的是什么
x = k*GRID_WIDTH grid.left;//得到的是什么
if (grid.map[i][k] == 1)
{
setfillcolor(BLACK);
}
else if (grid.map[i][k] == -1)
{
setfillcolor(GREEN);
}
solidrectangle(x 1, y 1, x GRID_WIDTH - 1, y GRID_WIDTH - 1);
}
}
}
//游戏控制,鼠标点击
void GameControl()
{
if (MouseHit())
{
msg = GetMouseMsg();
//如果是鼠标左键点击,而且点击在游戏区域,格子区域
if (msg.uMsg == WM_LBUTTONDOWN
&& msg.x>grid.left && msg.x<grid.right
&& msg.y>grid.top && msg.y>grid.down)
{
grid.y = (msg.x - grid.left) / GRID_WIDTH;
grid.x = (msg.y - grid.top) / GRID_WIDTH;
grid.map[grid.x][grid.y] = -grid.map[grid.x][grid.y];//改变颜色
if (grid.x >= 0 && grid.x < GRID_NUM - 1)
{
grid.map[grid.x 1][grid.y] = -grid.map[grid.x 1][grid.y];
}
if (grid.x > 0 && grid.x <= GRID_NUM - 1)
{
grid.map[grid.x - 1][grid.y] = -grid.map[grid.x - 1][grid.y];
}
if (grid.y >= 0 && grid.y < GRID_NUM - 1)
{
grid.map[grid.x][grid.y 1] = -grid.map[grid.x ][grid.y 1];
}
if (grid.y >= 0 && grid.y <= GRID_NUM - 1)
{
grid.map[grid.x][grid.y-1] = -grid.map[grid.x][grid.y-1];
}
}
}
}
int main()
{
initgraph(WIN_WIDTH, WIN_HEIGHT);
Welcome();
GameInit();
BeginBatchDraw();
while (1)
{
GameDraw();
FlushBatchDraw();
GameControl();
}
return 0;
}
大家赶紧去动手试试吧!
此外,我也给大家分享我收集的其他资源,从最零基础开始的教程到C语言C 项目案例,帮助大家在学习C语言的道路上披荆斩棘!
编程学习书籍分享:
编程学习视频分享:
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)最重要的是你可以在里面交流提问编程问题哦!
对于C/C 感兴趣可以关注小编在后台私信我:【编程交流】一起来学习哦!可以领取一些C/C 的项目学习视频资料哦!已经设置好了关键词自动回复,自动领取就好了!