You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

935 lines
20 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <graphics.h>
#include <mmsystem.h>
#include <string>
#include <ctime>
#include <iostream>
#include <vector>
#pragma comment(lib,"winmm.lib") //静态库资源
#define ROW 12
#define COL 12
using namespace std;
const int WALL = 1;
const int BOX = 4;
const int TARGET = 3;
const int PLAYER = 5;
const int EMPTY = 0;
const int _SIZE = 12;
int DUISHU = 3;
const std::vector<std::pair<int, int>> dir = { {0, 1}, {1, 0}, {0, -1}, {-1, 0} };
class MyMap {
public:
int Map[_SIZE][_SIZE]{ WALL };
private:
int X1{}, X2{}, Y1{}, Y2{};//分别为1、2步之前的坐标
int X{}, Y{}, Direction{};//当前坐标、方向
int PX{}, PY{};//玩家坐标
int StartX{}, StartY{};//记录起点,用于生成箱子
bool test() {//一定程度避免随机数整烂活;
int test{};
for (int i = 0; i < _SIZE; i++) {
for (int j = 0; j < _SIZE; j++) {
if (Map[i][j] == 3)test += 1;
if (Map[i][j] == 4)test += 10;
if (Map[i][j] == 5)test += 100;
}
}
return (test == 100 + 11 * DUISHU);
}
bool _near(int StartX, int StartY, int X, int Y) {
return (StartX == X + 1 && StartY == Y ||
StartX == X - 1 && StartY == Y ||
StartY == Y + 1 && StartX == X ||
StartY == Y - 1 && StartX == X);
}
void update() {
X2 = X1;
Y2 = Y1;
X1 = X;
Y1 = Y;
}
void change(int x, int y) {
if (Map[x][y] == WALL) {
Map[x][y] = EMPTY;
}
}
void through() {//打通箱子周边,使得每个箱子都可推动
int dx = StartX - PX, dy = StartY - PY;
if (dx == 0) {
change(StartX + 2 * (StartX > _SIZE / 2) - 1, StartY);
change(StartX + 2 * (StartX > _SIZE / 2) - 1, StartY + 1);
change(StartX + 2 * (StartX > _SIZE / 2) - 1, StartY - 1);
}
if (dy == 0) {
change(StartX, StartY + 2 * (StartX > _SIZE / 2) - 1);
change(StartX - 1, StartY + 2 * (StartX > _SIZE / 2) - 1);
change(StartX + 1, StartY + 2 * (StartX > _SIZE / 2) - 1);
}
}
public:
MyMap() {
for (int i = 0; i < _SIZE; i++) {
for (int j = 0; j < _SIZE; j++) {
Map[i][j] = WALL;
}
}
}//初始化
bool generatemap(int Complexity) {
int time{};
do {//主体
for (int i = 0; i < _SIZE; i++) {
for (int j = 0; j < _SIZE; j++) {
Map[i][j] = WALL;
}
}//初始化
for (int a = 0; a < DUISHU; a++)//箱子与目标的对数
{
do {
X = rand() % (_SIZE - 4) + 2;
Y = rand() % (_SIZE - 4) + 2;
time++;
if (time > 100) {
std::cout << "error" << std::endl;
return 0;
}//防死循环
} while (Map[X][Y] != WALL);//在墙上生成起点
time = 0;
StartX = X; StartY = Y;//记录起点,用于生成箱子
do {
int _time{};//实际运动次数
for (int i = 0; i < Complexity; i++) {
int temp = rand() % 6;
switch (temp) {
case 0:
Direction++;
break;
case 1:
Direction--;
}//控制直走和转弯的概率,不要频繁转弯且不会掉头
Direction = (4 + Direction) % 4;//防止负数
if (//各种不宜移动的情况
X + dir[Direction].first <= 2 ||
X + dir[Direction].first >= _SIZE - 3 ||
Y + dir[Direction].second <= 2 ||
Y + dir[Direction].second >= _SIZE - 3 ||
Map[X + dir[Direction].first][Y + dir[Direction].second] == BOX
) {
continue;
}
update();
X += dir[Direction].first;
Y += dir[Direction].second;
change(X, Y);
change(X - 2 * dir[Direction].first, Y - 2 * dir[Direction].second);
if (_time > 0) {
change(
dir[Direction].first == 0 ? X2 : X - 2 * dir[Direction].first,
dir[Direction].second == 0 ? Y2 : Y - 2 * dir[Direction].second
);
}
if (_time == 0) {
PX = X - 2 * dir[Direction].first;
PY = Y - 2 * dir[Direction].second;
}//生成玩家
_time++;
}
Map[StartX][StartY] = BOX;
Map[X][Y] = TARGET;
} while (_near(StartX, StartY, X, Y));
through();
}
Map[PX][PY] = PLAYER;
} while (test() == 0);
for (int i = 0; i < _SIZE; i++)//修复墙壁
{
for (int j = 0; j < _SIZE; j++) {
if (i == 0 || j == 0 || i == _SIZE - 1 || j == _SIZE - 1) {
Map[i][j] = WALL;
}
}
}
return 1;
}
void printmap() {
std::cout << std::endl;
for (int i = 0; i < _SIZE; i++) {
for (int j = 0; j < _SIZE; j++) {
std::cout << Map[i][j] << ' ';
}
std::cout << std::endl;
}
}
};
//用三维数组特定的数字描绘出这个地图
int cas = 0;//地图编号
int _count = 0;//已走步数
wchar_t result[10] = { L"0" };//用来显示步数
int temp_map[ROW][COL] = { 0 };//用来暂存地图,以备重置
char c[10] = { 0 };
int map[4][ROW][COL] = { 0 };
IMAGE img[6]; //6张图片6个名字
IMAGE* bacground=new IMAGE;
void loadResource()
{
loadimage(img + 0, L"0.bmp", 50, 50);
loadimage(img + 1, L"1.bmp", 50, 50);
loadimage(img + 2, L"3.bmp", 50, 50);
loadimage(img + 3, L"4.bmp", 50, 50);
loadimage(img + 4, L"5.bmp", 50, 50);
loadimage(img + 5, L"7.bmp", 50, 50);
loadimage(bacground, L"背景.png", 50, 50);
}
//绘制地图
void drawGraph()
{
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
//算贴图的坐标
int x = 50 * j;
int y = 50 * i;
switch (map[cas][i][j])
{
case 0:
//一个汉字符号占用两个位置
//printf(" ");
putimage(x, y, img + 0);
break;
case 1:
putimage(x, y, img + 1);
//printf("■");
break;
case 3:
putimage(x, y, img + 2);
//printf("☆");
break;
case 4:
putimage(x, y, img + 3);
//printf("★");
break;
case 5:
case 8:
putimage(x, y, img + 4);
//printf("人");
break;
case 7:
putimage(x, y, img + 5);
//printf("●");
break;
}
}
//printf("\n");
}
}
void drawGraph1()//绘制背景图
{
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
int x = 50 * j;
int y = 50 * i;
putimage(x, y, bacground);
}
}
}
//玩游戏
void keyDown()
{
int userKey = _getch(); //不可见输入
//定位:找到人的位置
int i = 0;
int j = 0;
for (i = 1; i < ROW; i++)
{
for (j = 1; j < COL; j++)
{
if (map[cas][i][j] == 5 || map[cas][i][j] == 8)
{
goto NEXT;
}
}
}
NEXT:
//我们这个游戏用什么按键去玩
switch (userKey)
{
case 'W':
case 'w':
case 72:
if (map[cas][i - 1][j] == 0 || map[cas][i - 1][j] == 3)
{
map[cas][i][j] -= 5;
map[cas][i - 1][j] += 5;
_count++;
}
if (map[cas][i - 1][j] == 4 || map[cas][i - 1][j] == 7)
{
if (map[cas][i - 2][j] == 0 || map[cas][i - 2][j] == 3)
{
map[cas][i][j] -= 5;
map[cas][i - 1][j] += 1;
map[cas][i - 2][j] += 4;
_count++;
}
}
break;
case 's':
case 'S':
case 80:
if (map[cas][i + 1][j] == 0 || map[cas][i + 1][j] == 3)
{
map[cas][i][j] -= 5;
map[cas][i + 1][j] += 5;
_count++;
}
if (map[cas][i + 1][j] == 4 || map[cas][i + 1][j] == 7)
{
if (map[cas][i + 2][j] == 0 || map[cas][i + 2][j] == 3)
{
map[cas][i][j] -= 5;
map[cas][i + 1][j] += 1;
map[cas][i + 2][j] += 4;
_count++;
}
}
break;
case 'a':
case 'A':
case 75:
if (map[cas][i][j - 1] == 0 || map[cas][i][j - 1] == 3)
{
//a+=1 a=a+1 复合赋值运算符
map[cas][i][j] -= 5;
map[cas][i][j - 1] += 5;
_count++;
}
if (map[cas][i][j - 1] == 4 || map[cas][i][j - 1] == 7)
{
if (map[cas][i][j - 2] == 0 || map[cas][i][j - 2] == 3)
{
map[cas][i][j] -= 5;
map[cas][i][j - 1] += 1;
map[cas][i][j - 2] += 4;
_count++;
}
}
break;
case 'd':
case 'D':
case 77:
if (map[cas][i][j + 1] == 0 || map[cas][i][j + 1] == 3)
{
map[cas][i][j] -= 5;
map[cas][i][j + 1] += 5;
_count++;
}
if (map[cas][i][j + 1] == 4 || map[cas][i][j + 1] == 7)
{
if (map[cas][i][j + 2] == 0 || map[cas][i][j + 2] == 3)
{
map[cas][i][j] -= 5;
map[cas][i][j + 1] += 1;
map[cas][i][j + 2] += 4;
_count++;
}
}
break;
case 'z'://按下z重置
case 'Z':
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
map[cas][i][j] = temp_map[i][j];
}
}
_count = 0;
for (int k = 0; k < 10; k++)
{
result[k] = 0;
}
result[0] = L'0';
drawGraph();
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(20, 0, _T("微软雅黑"));
outtextxy(145, 55, L"已走步数:");
outtextxy(230, 55, result);
break;
case 'x':
case 'X':
cas = 3;
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
map[cas][i][j] = 0;
}
}
break;
}
}
//胜负的判断:
int gameOver()
{
//地图上没有箱子就可以结束
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
if (map[cas][i][j] == 4)
{
return 0;
}
}
}
return 1;
}
class Button
{
private:
int x; // 按钮左上角x坐标
int y; // 按钮左上角y坐标
int width; // 按钮宽度
int height; // 按钮高度
float scale; // 缩放比例,用于实现鼠标悬停效果
bool isMouseOver; // 表示鼠标是否在按钮上方
bool has_been_clicked;//表示此按钮是否被点击过(主要用于难度选择)
wstring text; // 按钮文本
public:
Button(int x, int y, int width, int height, const wstring& text)
: x(x), y(y), width(width), height(height), text(text), scale(1.0f), isMouseOver(false),has_been_clicked(false)
{
}
// 检查鼠标是否在按钮上方
void checkMouseOver(int mouseX, int mouseY)
{
isMouseOver = (mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height);
if (isMouseOver) {
scale = 1.0f; // 鼠标悬停时缩放按钮
}
else {
scale = 1.0f; // 恢复按钮原始大小
}
}
// 检查鼠标点击是否在按钮内,并执行函数
bool checkClick(int mouseX, int mouseY)
{
if (mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height)
{
has_been_clicked_convert();
isMouseOver = false;
scale = 1.0f;
return true;
}
return false;
}
void has_been_clicked_convert()
{
if (has_been_clicked == false)
has_been_clicked = true;
else
has_been_clicked = false;
}
bool get_has_been_clicked()
{
return has_been_clicked;
}
// 绘制按钮
void draw()
{
int scaledWidth = width * scale; // 缩放后的按钮宽度
int scaledHeight = height * scale; // 缩放后的按钮高度
int scaledX = x + (width - scaledWidth) / 2; // 缩放后的按钮x坐标
int scaledY = y + (height - scaledHeight) / 2; // 缩放后的按钮y坐标
if (isMouseOver || has_been_clicked)
{
setlinecolor(RGB(0, 120, 215)); // 鼠标悬停时按钮边框颜色
setfillcolor(RGB(229, 241, 251)); // 鼠标悬停时按钮填充颜色
}
else
{
setlinecolor(RGB(173, 173, 173)); // 按钮边框颜色
setfillcolor(RGB(225, 225, 225)); // 按钮填充颜色
}
fillrectangle(scaledX, scaledY, scaledX + scaledWidth, scaledY + scaledHeight); // 绘制按钮
settextcolor(BLACK); // 设置文本颜色为黑色
setbkmode(TRANSPARENT); // 设置文本背景透明
settextstyle(20 * scale, 0, _T("微软雅黑")); // 设置文本大小和字体
//居中显示按钮文本
int textX = scaledX + (scaledWidth - textwidth(text.c_str())) / 2; // 计算文本在按钮中央的x坐标
int textY = scaledY + (scaledHeight - textheight(_T("微软雅黑"))) / 2; // 计算文本在按钮中央的y坐标
outtextxy(textX, textY, text.c_str()); // 在按钮上绘制文本
}
};
void play_easy()
{
const wchar_t* mapping = L"0123456789";
_count = 0;
std::srand(static_cast<unsigned int>(std::time(0)));
MyMap _map{};
DUISHU = 2;
for (int i = 0; i < 4; i++)
{
while (!_map.generatemap(50))
{
if (_map.generatemap(50))
{
break;
}
}
for (int j = 0; j < ROW; j++)
{
for (int k = 0; k < COL; k++)
{
map[i][j][k] = _map.Map[j][k];
}
}
}
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
temp_map[i][j] = map[cas][i][j];
}
}
/*Button* restart = new Button{ 100, 300, 100, 25, L"重置" };*/
/*ExMessage msg;*/
while (1)
{
drawGraph();
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(20, 0, _T("微软雅黑"));
outtextxy(500, 570, L"已走步数:");
outtextxy(100, 570, L"重置Z");
outtextxy(200, 570, L"主菜单X");
int q = 0;
int temp = _count;
while (temp != 0)
{
c[q] = mapping[temp % 10];
temp /= 10;
q++;
}
if (q != 0)
{
for (int j = 0; j < q; j++)
{
result[j] = c[q - j - 1];
}
}
outtextxy(570, 570, result);
if (gameOver())//如果游戏结束
{
cas++; //变换关卡
_count = 0;
for (int i = 0; i < 10; i++)
result[i] = 0;
result[0] = { L'0' };
for (int i = 0; i < 10; i++)
c[i] = 0;
if (cas != 4)
{
Sleep(500);
drawGraph();
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(20, 0, _T("微软雅黑"));
outtextxy(500, 570, L"已走步数:");
outtextxy(570, 570, result);
outtextxy(100, 570, L"重置Z");
outtextxy(200, 570, L"主菜单X");
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
temp_map[i][j] = map[cas][i][j];
}
}
}
else if (cas == 4)
{
cas = 0;
break;
}
}
FlushBatchDraw(); // 将缓冲区内容显示在屏幕上
Sleep(10);
keyDown();//循环按下按键
//system("cls");
}
/*delete restart;*/
}
void play_normal()
{
const wchar_t* mapping = L"0123456789";
_count = 0;
std::srand(static_cast<unsigned int>(std::time(0)));
MyMap _map{};
DUISHU = 4;
for (int i = 0; i < 4; i++)
{
while (!_map.generatemap(30))
{
if (_map.generatemap(30))
{
break;
}
}
for (int j = 0; j < ROW; j++)
{
for (int k = 0; k < COL; k++)
{
map[i][j][k] = _map.Map[j][k];
}
}
}
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
temp_map[i][j] = map[cas][i][j];
}
}
while (1)
{
drawGraph();
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(20, 0, _T("微软雅黑"));
outtextxy(500, 570, L"已走步数:");
outtextxy(100, 570, L"重置Z");
outtextxy(200, 570, L"主菜单X");
int q = 0;
int temp = _count;
while (temp != 0)
{
c[q] = mapping[temp % 10];
temp /= 10;
q++;
}
if (q != 0)
{
for (int j = 0; j < q; j++)
{
result[j] = c[q - j - 1];
}
}
outtextxy(570, 570, result);
if (gameOver())//如果游戏结束
{
cas++; //变换关卡
_count = 0;
for (int i = 0; i < 10; i++)
result[i] = 0;
result[0] = { L'0' };
for (int i = 0; i < 10; i++)
c[i] = 0;
if (cas != 4)
{
Sleep(500);
drawGraph();
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(20, 0, _T("微软雅黑"));
outtextxy(500, 570, L"已走步数:");
outtextxy(570, 570, result);
outtextxy(100, 570, L"重置Z");
outtextxy(200, 570, L"主菜单X");
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
temp_map[i][j] = map[cas][i][j];
}
}
}
else if (cas == 4)
{
cas = 0;
break;
}
}
FlushBatchDraw(); // 将缓冲区内容显示在屏幕上
Sleep(10);
keyDown();//循环按下按键
//system("cls");
}
}
void play_hard()
{
const wchar_t* mapping = L"0123456789";
_count = 0;
std::srand(static_cast<unsigned int>(std::time(0)));
MyMap _map{};
DUISHU = 6;
for (int i = 0; i < 4; i++)
{
while (!_map.generatemap(8))
{
if (_map.generatemap(8))
{
break;
}
}
for (int j = 0; j < ROW; j++)
{
for (int k = 0; k < COL; k++)
{
map[i][j][k] = _map.Map[j][k];
}
}
}
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
temp_map[i][j] = map[cas][i][j];
}
}
while (1)
{
drawGraph();
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(20, 0, _T("微软雅黑"));
outtextxy(500, 570, L"已走步数:");
outtextxy(100, 570, L"重置Z");
outtextxy(200, 570, L"主菜单X");
int q = 0;
int temp = _count;
while (temp != 0)
{
c[q] = mapping[temp % 10];
temp /= 10;
q++;
}
if (q != 0)
{
for (int j = 0; j < q; j++)
{
result[j] = c[q - j - 1];
}
}
outtextxy(570, 570, result);
if (gameOver())//如果游戏结束
{
cas++; //变换关卡
_count = 0;
for (int i = 0; i < 10; i++)
result[i] = 0;
result[0] = { L'0' };
for (int i = 0; i < 10; i++)
c[i] = 0;
if (cas != 4)
{
Sleep(500);
drawGraph();
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(20, 0, _T("微软雅黑"));
outtextxy(500, 570, L"已走步数:");
outtextxy(570, 570, result);
outtextxy(100, 570, L"重置Z");
outtextxy(200, 570, L"主菜单X");
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
temp_map[i][j] = map[cas][i][j];
}
}
}
else if (cas == 4)
{
cas = 0;
break;
}
}
FlushBatchDraw(); // 将缓冲区内容显示在屏幕上
Sleep(10);
keyDown();//循环按下按键
//system("cls");
}
}
int main()
{
loadResource();//定义加载资源函数
//mciSendString(L"open 1.mp3", 0, 0, 0);//加载音乐
//mciSendString(L"play 1.mp3 repeat", 0, 0, 0);//循环播放音乐资源
initgraph(50 * ROW, 50 * COL);
Button* start = new Button{ 150, 400, 100, 25, L"开始" };
Button* easy = new Button{ 100, 300, 100, 25, L"简单" };
Button* normal = new Button{ 250, 300, 100, 25, L"中等" };
Button* hard = new Button{ 400, 300, 100, 25, L"困难" };
Button* exit = new Button{ 350, 400, 100, 25, L"退出" };
while (1)
{
if (start->get_has_been_clicked())
start->has_been_clicked_convert();
if (easy->get_has_been_clicked())
easy->has_been_clicked_convert();
if (normal->get_has_been_clicked())
normal->has_been_clicked_convert();
if (hard->get_has_been_clicked())
hard->has_been_clicked_convert();
if (exit->get_has_been_clicked())
exit->has_been_clicked_convert();
drawGraph1();
setbkmode(TRANSPARENT);
settextcolor(BLACK);
settextstyle(50, 0, _T("微软雅黑"));
outtextxy(250, 150, L"推箱子");
ExMessage msg;
while (true)
{
if (peekmessage(&msg)) // 检查是否有消息
{
int mouseX = msg.x; // 获取鼠标x坐标
int mouseY = msg.y; // 获取鼠标y坐标
if (msg.message == WM_LBUTTONDOWN)
{
if (start->checkClick(mouseX, mouseY))
{
if (easy->get_has_been_clicked())
{
play_easy();
break;
}
else if (normal->get_has_been_clicked())
{
play_normal();
break;
}
else if(hard->get_has_been_clicked())
{
play_hard();
break;
}
else
{
}
}
else if (easy->checkClick(mouseX, mouseY))
{
if (normal->get_has_been_clicked())
normal->has_been_clicked_convert();
if (hard->get_has_been_clicked())
hard->has_been_clicked_convert();
}
else if (normal->checkClick(mouseX, mouseY))
{
if (easy->get_has_been_clicked())
easy->has_been_clicked_convert();
if (hard->get_has_been_clicked())
hard->has_been_clicked_convert();
}
else if (hard->checkClick(mouseX, mouseY))
{
if (normal->get_has_been_clicked())
normal->has_been_clicked_convert();
if (easy->get_has_been_clicked())
easy->has_been_clicked_convert();
}
else if (exit->checkClick(mouseX, mouseY))
{
return 0;
}
}
else if (msg.message == WM_MOUSEMOVE)
{
start->checkMouseOver(mouseX, mouseY);
easy->checkMouseOver(mouseX, mouseY);
normal->checkMouseOver(mouseX, mouseY);
hard->checkMouseOver(mouseX, mouseY);
exit->checkMouseOver(mouseX, mouseY);
}
}
start->draw(); // 绘制当前页面内容
easy->draw();
normal->draw();
hard->draw();
exit->draw();
FlushBatchDraw(); // 将缓冲区内容显示在屏幕上
Sleep(10);
}
}
delete start;
delete easy;
delete normal;
delete hard;
delete exit;
delete bacground;
closegraph();//关闭窗口
return 0;
}