程序名称:拼图盒子
编译环境:Mictosoft Visual Studio 2019, EasyX_2021
作 者:代码骑士<[email protected]>
最后修改:2021-11-18
游戏示例:
目录
====================================================================》》》
第一步:生成九个不相同的随机数存入二维数组。
(1)生成1~9的随机数:
参考了百度上面某位大佬的经典之作:
void nineDiffnum()
{
//先是把数组a赋值1—9,然后产生1--9的随机数,作为数组a的下标,赋值到temp数组。
srand((int)time(0));//使用随机数种子,每次生成不同的随机数
int a[9];
int i, index, x = 0;
for (i = 0; i < 9; i++)
a[i] = i + 1;
for (i = 0; i < 9;)
{
index = rand() % 9;
if (a[index] != 0)
{
temp[i] = a[index];
a[index] = 0;
++i;
}
}
}
上述代码中我的temp数组是全局变量,所以函数中没有定义。
为了方便编程,二维数组也设成了全局变量。
(2)将一维数组中的随机数导入二维数组:
void createPicture(int* a)//将一维数组中的数存入二维数组
{
int it = -1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
Picture[i][j] = a[++it];
}
}
}
第二步:绘制九宫格与颜色填充。
(1)编写绘图函数:
(1)先让除了数字9以外的数字皆涂成红色。
void Show()
{
cleardevice();
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (Picture[i][j] != 9)
{
setfillcolor(RED);
setlinecolor(BLUE);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
}
}
FlushBatchDraw();
}
示例:
第三步:鼠标点击实现方块移动。
(1)首先,引入鼠标操作:
目的:让鼠标在特定的区域内,点击左键或右键发生特定变化。
while (true) {
ExMessage m;//定义一个消息变量
m = getmessage(EM_MOUSE);//获取鼠标消息
switch (m.message)
{
case WM_MOUSEMOVE:
// 鼠标移动的时候画红色的小点
putpixel(m.x, m.y, RED);
break;
case WM_LBUTTONDOWN://鼠标点击左键
// 画一个小方块
if (m.x >= 0 && m.x <= 200 && m.y>=0&&m.y<=200)
{
int i = 0, j = 0;
m.x = i;
m.y = j;
setfillcolor(BLACK);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
break;
case WM_RBUTTONUP:
return; // 按鼠标右键退出程序
}
}
第四步:测试方块移动。
(1)给从1~9的方块不同的颜色。点击有色方块,该方块会移动到无色区域。
void Show()
{
cleardevice();
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (Picture[i][j] == 1)
{
setfillcolor(BLUE);
setlinecolor(BLUE);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
if (Picture[i][j] == 2)
{
setfillcolor(GREEN);
setlinecolor(BLUE);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
if (Picture[i][j] == 3)
{
setfillcolor(YELLOW);
setlinecolor(BLUE);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
if (Picture[i][j] == 4)
{
setfillcolor(RGB(122,122,122));
setlinecolor(BLUE);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
if (Picture[i][j] == 5)
{
setfillcolor(RGB(250, 250, 250));
setlinecolor(BLUE);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
if (Picture[i][j] == 6)
{
setfillcolor(RED);
setlinecolor(BLUE);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
if (Picture[i][j] == 7)
{
setfillcolor(RGB(0, 122, 122));
setlinecolor(BLUE);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
if (Picture[i][j] == 8)
{
setfillcolor(RGB(122, 0, 122));
setlinecolor(BLUE);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
if (Picture[i][j] == 9)
{
setfillcolor(BLACK);
setlinecolor(BLUE);
fillrectangle(j * 200, i * 200, (j + 1) * 200, (i + 1) * 200);
}
}
}
FlushBatchDraw();
}
(2)有色块与无色块互换位置,此程序无色块默认是数字9所在的区域。
示例中,黑色为数字9所在的无色块。
(3)判断方块移动需要判断每个方块是否与无色块相邻,若相邻,点击此块,则与无色块进行交换,算法代码:
在此给出,第一排第一个方块的判断,剩余八个与之同理。
case WM_LBUTTONDOWN:
//第一排:
if (m.x >= 0 && m.x <= 200 && m.y >= 0 && m.y <= 200)//鼠标在第一个格子时:判断2、4格子是否为九
{
if (Picture[0][1] == 9)//1、2换位
{
int temp = Picture[0][1];
Picture[0][1] = Picture[0][0];
Picture[0][0] = temp;
Show();//更新图片
}
else if (Picture[1][0] == 9)//1、4换位
{
int temp = Picture[1][0];
Picture[1][0] = Picture[0][0];
Picture[0][0] = temp;
Show();//更新图片
}
}
第五步:加载图片。
把正方形的照片切割成9块,依次导入和放在相应位置。
(1)加载图片
IMAGE s1, s2, s3, s4, s5, s6, s7, s8, s9;
void Start()
{
initgraph(600, 600);
loadimage(&s1, "s1.jpg", 200, 200);
loadimage(&s2, "s2.jpg", 200, 200);
loadimage(&s3, "s3.jpg", 200, 200);
loadimage(&s4, "s4.jpg", 200, 200);
loadimage(&s5, "s5.jpg", 200, 200);
loadimage(&s6, "s6.jpg", 200, 200);
loadimage(&s7, "s7.jpg", 200, 200);
loadimage(&s8, "s8.jpg", 200, 200);
//loadimage(&s9, "s9.jpg", 200, 200);
}
(2)放置图片
注意:图片坐标位置不要算错!!!
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (Picture[i][j] == 1)
{
putimage(j * 200, i * 200, &s1);
}
else if (Picture[i][j] == 2)
{
putimage(j * 200, i * 200, &s2);
}
else if (Picture[i][j] == 3)
{
putimage(j * 200, i * 200, &s3);
}
else if (Picture[i][j] == 4)
{
putimage(j * 200, i * 200, &s4);
}
else if (Picture[i][j] == 5)
{
putimage(j * 200, i * 200, &s5);
}
else if (Picture[i][j] == 6)
{
putimage(j * 200, i * 200, &s6);
}
else if (Picture[i][j] == 7)
{
putimage(j * 200, i * 200, &s7);
}
else if (Picture[i][j] == 8)
{
putimage(j * 200, i * 200, &s8);
}
else if (Picture[i][j] == 9)
{
putimage(j * 200, i * 200, &s9);
}
}
示例:
第六步:加载音乐。
#pragma comment(lib,"Winmm.lib")
mciSendString(_T("open 121.mp3 alias bkmusic"), NULL, 0, NULL);//播放音乐
mciSendString(_T("play bkmusic repeat"), NULL, 0, NULL);//循环播放
mciSendString(_T("close bkmusic"), NULL, 0, NULL);//停止播放
完整程序代码:
///
// 程序名称:拼图盒子
// 编译环境:Mictosoft Visual Studio 2019, EasyX_2021
// 作 者:代码骑士<[email protected]>
// 最后修改:2021-11-18
//
#include<iostream>
#include<cstdlib>
#include<ctime>
#define random(x)rand()%x
#include<graphics.h>
#include<conio.h>
using namespace std;
//全局变量
int temp[9] = { 0 };
int Picture[4][4];
IMAGE s1, s2, s3, s4, s5, s6, s7, s8, s9;
//Tip:因为在二位数组中判断数据重复的时间复杂度是O(n2)一维数组是O(n),所以先把随机数存入一维数组中好进行判断随机数是否重复
void createPicture(int* a)//将一维数组中的数存入二维数组
{
int it = -1;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
Picture[i][j] = a[++it];
}
}
}
void PrintPic()
{
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
cout << Picture[i][j];
}
cout << endl;
}
}
void nineDiffnum()
{
//先是把数组a赋值1—9,然后产生1--9的随机数,作为数组a的下标,赋值到temp数组。
srand((int)time(0));//使用随机数种子,每次生成不同的随机数
int a[9];
int i, index, x = 0;
for (i = 0; i < 9; i++)
a[i] = i + 1;
for (i = 0; i < 9;)
{
index = rand() % 9;
if (a[index] != 0)
{
temp[i] = a[index];
a[index] = 0;
++i;
}
}
}
void Start()
{
initgraph(600, 600);
loadimage(&s1, "s1.jpg", 200, 200);
loadimage(&s2, "s2.jpg", 200, 200);
loadimage(&s3, "s3.jpg", 200, 200);
loadimage(&s4, "s4.jpg", 200, 200);
loadimage(&s5, "s5.jpg", 200, 200);
loadimage(&s6, "s6.jpg", 200, 200);
loadimage(&s7, "s7.jpg", 200, 200);
loadimage(&s8, "s8.jpg", 200, 200);
//loadimage(&s9, "s9.jpg", 200, 200);
}
void Show()
{
cleardevice();
int i, j;
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
if (Picture[i][j] == 1)
{
putimage(j * 200, i * 200, &s1);
}
else if (Picture[i][j] == 2)
{
putimage(j * 200, i * 200, &s2);
}
else if (Picture[i][j] == 3)
{
putimage(j * 200, i * 200, &s3);
}
else if (Picture[i][j] == 4)
{
putimage(j * 200, i * 200, &s4);
}
else if (Picture[i][j] == 5)
{
putimage(j * 200, i * 200, &s5);
}
else if (Picture[i][j] == 6)
{
putimage(j * 200, i * 200, &s6);
}
else if (Picture[i][j] == 7)
{
putimage(j * 200, i * 200, &s7);
}
else if (Picture[i][j] == 8)
{
putimage(j * 200, i * 200, &s8);
}
else if (Picture[i][j] == 9)
{
putimage(j * 200, i * 200, &s9);
}
}
}
FlushBatchDraw();
}
void Player()
{
while (true) {
ExMessage m;//定义一个消息变量
m = getmessage(EM_MOUSE);//获取鼠标消息
switch (m.message)
{
case WM_MOUSEMOVE:
// 鼠标移动的时候画红色的小点
putpixel(m.x, m.y, RED);
break;
case WM_LBUTTONDOWN:
//第一排:
if (m.x >= 0 && m.x <= 200 && m.y >= 0 && m.y <= 200)//鼠标在第一个格子时:判断2、4格子是否为九
{
if (Picture[0][1] == 9)//1、2换位
{
int temp = Picture[0][1];
Picture[0][1] = Picture[0][0];
Picture[0][0] = temp;
Show();//更新图片
}
else if (Picture[1][0] == 9)//1、4换位
{
int temp = Picture[1][0];
Picture[1][0] = Picture[0][0];
Picture[0][0] = temp;
Show();//更新图片
}
}
else if (m.x >= 200 && m.x <= 400 && m.y >= 0 && m.y <= 200)//鼠标在第二个格子时:判断1、3、5格子是否为九
{
if (Picture[0][0] == 9)//2、1换位
{
int temp = Picture[0][0];
Picture[0][0] = Picture[0][1];
Picture[0][1] = temp;
Show();//更新图片
}
else if (Picture[0][2] == 9)//2、3换位
{
int temp = Picture[0][2];
Picture[0][2] = Picture[0][1];
Picture[0][1] = temp;
Show();//更新图片
}
else if (Picture[1][1] == 9)//2、5换位
{
int temp = Picture[1][1];
Picture[1][1] = Picture[0][1];
Picture[0][1] = temp;
Show();//更新图片
}
}
else if (m.x >= 400 && m.x <= 600 && m.y >= 0 && m.y <= 200)//鼠标在第三个格子时:判断2、6格子是否为九
{
if (Picture[0][1] == 9)//3、2换位
{
int temp = Picture[0][1];
Picture[0][1] = Picture[0][2];
Picture[0][2] = temp;
Show();//更新图片
}
else if (Picture[1][2] == 9)//3、6换位
{
int temp = Picture[1][2];
Picture[1][2] = Picture[0][2];
Picture[0][2] = temp;
Show();//更新图片
}
}
//第二排:
else if (m.x >= 0 && m.x <= 200 && m.y >= 200 && m.y <= 400)//鼠标在第四个格子时:判断1、5、7格子是否为九
{
if (Picture[0][0] == 9)//4、1换位
{
int temp = Picture[0][0];
Picture[0][0] = Picture[1][0];
Picture[1][0] = temp;
Show();//更新图片
}
else if (Picture[1][1] == 9)//4、5换位
{
int temp = Picture[1][1];
Picture[1][1] = Picture[1][0];
Picture[1][0] = temp;
Show();//更新图片
}
else if (Picture[2][0] == 9)//4、7换位
{
int temp = Picture[2][0];
Picture[2][0] = Picture[1][0];
Picture[1][0] = temp;
Show();//更新图片
}
}
else if (m.x >= 200 && m.x <= 400 && m.y >= 200 && m.y <= 400)//鼠标在第五个格子时:判断2、4、6、8格子是否为九
{
if (Picture[0][1] == 9)//5、2换位
{
int temp = Picture[0][1];
Picture[0][1] = Picture[1][1];
Picture[1][1] = temp;
Show();//更新图片
}
else if (Picture[1][0] == 9)//5、4换位
{
int temp = Picture[1][0];
Picture[1][0] = Picture[1][1];
Picture[1][1] = temp;
Show();//更新图片
}
else if (Picture[1][2] == 9)//5、6换位
{
int temp = Picture[1][2];
Picture[1][2] = Picture[1][1];
Picture[1][1] = temp;
Show();//更新图片
}
else if (Picture[2][1] == 9)//5、8换位
{
int temp = Picture[2][1];
Picture[2][1] = Picture[1][1];
Picture[1][1] = temp;
Show();//更新图片
}
}
else if (m.x >= 400 && m.x <= 600 && m.y >= 200 && m.y <= 400)//鼠标在第六个格子时:判断3、5、9格子是否为九
{
if (Picture[0][2] == 9)//6、3换位
{
int temp = Picture[0][2];
Picture[0][2] = Picture[1][2];
Picture[1][2] = temp;
Show();//更新图片
}
else if (Picture[1][1] == 9)//6、5换位
{
int temp = Picture[1][1];
Picture[1][1] = Picture[1][2];
Picture[1][2] = temp;
Show();//更新图片
}
else if (Picture[2][2] == 9)//6、9换位
{
int temp = Picture[2][2];
Picture[2][2] = Picture[1][2];
Picture[1][2] = temp;
Show();//更新图片
}
}
//第三排:
else if (m.x >= 0 && m.x <= 200 && m.y >= 400 && m.y <= 600)//第七个格子:判断4、8是否为九
{
if (Picture[1][0] == 9)//7、4换位
{
int temp = Picture[1][0];
Picture[1][0] = Picture[2][0];
Picture[2][0] = temp;
Show();//更新图片
}
else if (Picture[2][1] == 9)//7、8换位
{
int temp = Picture[2][1];
Picture[2][1] = Picture[2][0];
Picture[2][0] = temp;
Show();//更新图片
}
}
else if (m.x >= 200 && m.x <= 400 && m.y >= 400 && m.y <= 600)//第八个格子:判断7、5、9是否为九
{
if (Picture[2][0] == 9)//8、7换位
{
int temp = Picture[2][0];
Picture[2][0] = Picture[2][1];
Picture[2][1] = temp;
Show();//更新图片
}
else if (Picture[1][1] == 9)//8、5换位
{
int temp = Picture[1][1];
Picture[1][1] = Picture[2][1];
Picture[2][1] = temp;
Show();//更新图片
}
else if (Picture[2][2] == 9)//8、9换位
{
int temp = Picture[2][2];
Picture[2][2] = Picture[2][1];
Picture[2][1] = temp;
Show();//更新图片
}
}
else if (m.x >= 400 && m.x <= 600 && m.y >= 400 && m.y <= 600)//第九个格子:判断8、6是否为九
{
if (Picture[2][1] == 9)//9、8换位
{
int temp = Picture[2][1];
Picture[2][1] = Picture[2][2];
Picture[2][2] = temp;
Show();//更新图片
}
else if (Picture[1][2] == 9)//9、6换位
{
int temp = Picture[1][2];
Picture[1][2] = Picture[2][2];
Picture[2][2] = temp;
Show();//更新图片
}
}
break;
case WM_RBUTTONUP:
return; // 按鼠标右键退出程序
}
}
}
int main()
{
nineDiffnum();//生成九个不同随机数存入一维数组
createPicture(temp);//将一维数组导入二维数组
Start();
while (1)
{
Show();
Player();
}
_getch();
return 0;
}
示例:
第七步:程序的改进。
增加开始界面和多选择性
附加代码:
void Seclet()
{
setbkcolor(WHITE);
cleardevice();
setlinecolor(RED);
line(0, 200, 600, 200);
line(0, 300, 600, 300);
line(0, 400, 600, 400);
line(0, 500, 600, 500);
setbkmode(TRANSPARENT);//显示透明文字
settextcolor(RED);//设置字体颜色
settextstyle(50, 0, _T("宋体"));//设置字体大小,字体
outtextxy(200, 100, _T("拼图盒子"));//输出字体
settextcolor(BLUE);//设置字体颜色
settextstyle(30, 0, _T("宋体"));//设置字体大小,字体
outtextxy(230, 250, _T("图一"));//输出字体
settextcolor(RGB(220, 0, 0));//设置字体颜色
settextstyle(30, 0, _T("宋体"));//设置字体大小,字体
outtextxy(230, 330, _T("图二"));//输出字体
settextcolor(GREEN);//设置字体颜色
settextstyle(30, 0, _T("宋体"));//设置字体大小,字体
outtextxy(230, 430, _T("图三"));//输出字体
while (1)
{
ExMessage m;//定义一个消息变量
m = getmessage(EM_MOUSE);//获取鼠标消息
switch (m.message)
{
case WM_MOUSEMOVE:
// 鼠标移动的时候画红色的小点
putpixel(m.x, m.y, RED);
break;
case WM_LBUTTONDOWN:
// 画一个小方块
rectangle(m.x - 5, m.y - 5, m.x + 5, m.y + 5);
if (m.x >= 0 && m.x <= 600 && m.y >= 200 && m.y <= 300)
{
key = 1; return;
}
else if (m.x >= 0 && m.x <= 600 && m.y >= 300 && m.y <= 400)
{
key = 2; return;
}
else if (m.x >= 0 && m.x <= 600 && m.y >= 400 && m.y <= 500)
{
key = 3; return;
}
break;
}
}
}
改进方法还有很多很多,代码骑士在这里只起到抛砖引玉的作用,更多创意和想法期待读者自己去实现!