接下来是Qt部分,基本的内容已经实现,目前欠缺的是可视化等一些用于用户操作的内容。

该文件中我会逐个写入代码,后续可能增加修改或演示等

widget

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QLabel>
#include <QWidget>
#include <QPushButton>
#include <QStackedWidget>
#include<QVBoxLayout>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
Q_OBJECT

public:
Widget(QWidget *parent = nullptr);
~Widget();
static std::vector<QString> nowUser;
protected:
void resizeEvent(QResizeEvent *event) override;
private:
Ui::Widget *ui;
QLabel *backgroundLabel;

};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "./ui_widget.h"
#include<QPushButton>
#include <QStackedWidget>
#include<QHBoxLayout>
#include<QLabel>
#include <QVBoxLayout>
// #include "base.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
// , base(nullptr)
// , stack(new QStackedWidget)
{
backgroundLabel=(new QLabel(this));
// 设置布局
setMaximumSize(1800,1200);
setMinimumSize(1200,900);
// 加载并设置背景图片
QPixmap backgroundPixmap(":/image/tree.png");
backgroundLabel->setPixmap(backgroundPixmap);
backgroundLabel->setScaledContents(true);

ui->setupUi(this);

// 加载背景图片
// QPixmap image();
// // resize(1800,1200);

// // 设置背景图片
// QPalette palette;
// palette.setBrush(this->backgroundRole(), QBrush(image));
// this->setPalette(palette);
// this->setAutoFillBackground(true);
}

Widget::~Widget()
{
// if(stack!=nullptr)
// delete stack;
// stack=nullptr;
if(ui!=nullptr)
delete ui;
ui=nullptr;
}

void Widget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
backgroundLabel->resize(size());
}

std::vector<QString> Widget::nowUser=std::vector<QString>(6)={"Null","XXX","0","NNNNNN","0"};
//名称,密码,通过挑战地图情况,六关通过情况,用时多少,积分


介绍

在这个类中,主要搭载了所有界面的背景板,后续如果你有需求,也可以在里面加入音乐播放器。
image-20240525162605473
目前效果如上(背景板)

initial

initial.h

#ifndef INITIAL_H
#define INITIAL_H

#include "widget.h"
#include <QApplication>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QWidget>
#include <QGridLayout>
#include <QPushButton>
#include <QStackedWidget>
#include <QFile>
#include <QTextStream>
#include <QMessageBox>
#include "start.h"

class initial:public Widget
{
Q_OBJECT
public:
initial(Widget *parent = nullptr);
~initial();
void turnOut();
//退出
void goIn();
//进入登录
void store();
//存储的开始
private:
start* Start;
QStackedWidget *stack;
QVBoxLayout* menu;
};

#endif // INITIAL_H

initial.cpp

#include "initial.h"

initial::initial(Widget *parent)
:Widget(parent)
,stack(new QStackedWidget)
{


QLabel *tital=new QLabel(this);
QPixmap _map1(":/image/title.png");
tital->setPixmap(_map1);
tital->setFixedSize(800,400);

// QLabel *pixs=new QLabel(this);
// QPixmap _map2(":/image/meishuzi.png");
// tital->setPixmap(_map2);
// tital->setFixedSize(50,70);

QWidget* startIn=new QWidget(this);

QGridLayout* allIn =new QGridLayout(startIn);
allIn->setHorizontalSpacing(300);
allIn->setVerticalSpacing(100);
allIn->setSizeConstraint(QLayout::SetFixedSize);

QPushButton* startL=new QPushButton("开始游戏",startIn);
QPushButton* out=new QPushButton("退出",startIn);
out->setStyleSheet(
"QPushButton { background-color: lightgray; }"
"QPushButton:hover { background-color: yellow; }"
);

startL->setFixedSize(480,120);
out->setFixedSize(480,120);

// allIn->addWidget(pixs,0,0);
allIn->addWidget(tital,1,3);

allIn->addWidget(startL,5,13);
allIn->addWidget(out,12,13);

// QHBoxLayout* _menu=new QHBoxLayout(this);
// menu=new QVBoxLayout();
// menu->addStretch();
// menu->addWidget(startIn);
// _menu->addLayout(menu);

stack->addWidget(this);
Start=new start(stack,this);
stack->addWidget(Start);
stack->addWidget(this);
stack->setCurrentWidget(this);
stack->show();

connect(out,&QPushButton::clicked,this,&initial::turnOut);
connect(startL,&QPushButton::clicked,this,&initial::goIn);
}

initial::~initial()
{
delete menu;
}

void initial::turnOut()
{
QCoreApplication::quit();
}

void initial::goIn()
{
stack->setCurrentWidget(Start);
}

void initial::store()
{
Start->preStore();
}

介绍

这里搭建的是开始页面,包含一个主题图标和两个按钮,分别为开始和退出。作为未优化的版本,看起来或许会不顺眼。

image-20240525162605473

点击退出就退出,点击开始进入下一个界面

start

start.h

#ifndef START_H
#define START_H

#include <QFile>
#include <QWidget>
#include <QLineEdit>
#include <QGridLayout>
#include <QVBoxLayout>
#include <QTextStream>
#include <QPushButton>
#include <QApplication>
#include <QStackedWidget>

#include "game.h"
#include "widget.h"
#include "dialog.h"

class start:public Widget
{
Q_OBJECT
public:
start(QStackedWidget *,Widget *parent = nullptr);
~start();
void signIn();
//登录
void subscribe();
//注册
void reIn();
//返回
void readIn();
//写入账号
void creaIn();
//创建账号
void hideShow();
//密码是否可见
void nullIn();
//虚空登入
void readLog();
//读取文件
void writeLog();
//写入文件
void preStore();
//接收写入信号

private:
QStackedWidget *stack;
game *Game;
QLineEdit *account;
QLineEdit *password;
QPushButton *logIn;
QPushButton *registe;
QPushButton *finishRead;
QPushButton *finishCrea;
QPushButton *look;
QPushButton *toReturn;
QPushButton *nullLog;
bool state;
int max;
//从1开始
int now;
//从0开始
bool out;
std::vector<std::vector<QString>> users;
};
#endif // START_H

start.cpp

#include "start.h"

start::start(QStackedWidget* s,Widget *parent)
:Widget(parent)
,stack(s)
,state(true)
{
out=true;
stack=s;
QWidget *useWidget=new QWidget(this);
//窗口小部件
account = new QLineEdit(useWidget);
account->hide();
password = new QLineEdit(useWidget);
password->hide();
account->setPlaceholderText("点击登录以登入");
password->setPlaceholderText("点击注册以注册账户...");
account->setReadOnly(true);
password->setReadOnly(true);
password->setEchoMode(QLineEdit::Password);
// account->setsi
// 创建文本框

logIn=new QPushButton("登录",useWidget);
registe=new QPushButton("注册",useWidget);
finishRead=new QPushButton("完成",useWidget);
finishRead->hide();
finishCrea=new QPushButton("完成",useWidget);
finishCrea->hide();
look=new QPushButton("显示",useWidget);
look->hide();
toReturn=new QPushButton("返回",useWidget);
toReturn->hide();
nullLog=new QPushButton("游客模式",this);
//构建按钮

logIn->setFixedSize(240,80);
registe->setFixedSize(240,80);
finishRead->setFixedSize(240,80);
finishCrea->setFixedSize(240,80);
look->setFixedSize(240,80);
toReturn->setFixedSize(240,80);
account->setFixedSize(480,40);
password->setFixedSize(480,40);
nullLog->setFixedSize(240,80);
//

QGridLayout *menu=new QGridLayout(useWidget);
menu->setHorizontalSpacing(100);
menu->setVerticalSpacing(100);
menu->setSizeConstraint(QLayout::SetFixedSize);
QHBoxLayout *total=new QHBoxLayout(this);
total->addWidget(useWidget);
// useWidget->setAlignment(Qt::AlignCenter | Qt::AlignBottom);


// 创建布局并将文本框添加到布局中

menu->addWidget(account,0,0);
menu->addWidget(logIn,0,1);
menu->addWidget(password,1,0);
menu->addWidget(registe,1,1);
menu->addWidget(finishRead,0,2);
menu->addWidget(finishCrea,0,2);
menu->addWidget(look,1,2);
menu->addWidget(toReturn,2,0);
menu->addWidget(nullLog,2,1);
//

Game=new game(stack,this);
stack->addWidget(Game);
stack->show();

connect(logIn,&QPushButton::clicked,this,&start::signIn);
connect(registe,&QPushButton::clicked,this,&start::subscribe);
connect(toReturn,&QPushButton::clicked,this,&start::reIn);
connect(finishRead,&QPushButton::clicked,this,&start::readIn);
connect(finishCrea,&QPushButton::clicked,this,&start::creaIn);
connect(look,&QPushButton::clicked,this,&start::hideShow);
connect(nullLog,&QPushButton::clicked,this,&start::nullIn);

readLog();

}

start::~start(){}

void start::signIn()
{
account->setReadOnly(false);
account->show();
password->setReadOnly(false);
password->show();
nullLog->hide();
account->setPlaceholderText("输入账号...");
password->setPlaceholderText("输入密码...");
logIn->hide();
registe->hide();
finishRead->show();
look->show();
toReturn->show();
}

void start::subscribe()
{
account->setReadOnly(false);
account->show();
password->setReadOnly(false);
password->show();
nullLog->hide();
account->setPlaceholderText("输入账号...");
password->setPlaceholderText("输入密码...");
logIn->hide();
registe->hide();
finishCrea->show();
look->show();
toReturn->show();
}

void start::reIn()
{
state=true;
account->clear();
password->clear();
password->setEchoMode(QLineEdit::Password);
account->setReadOnly(true);
account->hide();
password->setReadOnly(true);
password->hide();
nullLog->show();
account->setPlaceholderText("点击登录以登入...");
password->setPlaceholderText("点击注册以注册账户...");
logIn->show();
registe->show();
finishRead->hide();
look->hide();
toReturn->hide();
finishCrea->hide();
}

void start::readIn()
{
int end=0;

nowUser[0]=account->text();
nowUser[1]=password->text();

nowUser[0]=account->text();
if(nowUser[0]=="")
{
return;
}
//拒绝空名

for(int i=0;i<max-1;i++)
{
if(users[i][0]==nowUser[0])
{
if(users[i][1]!=nowUser[1])
{
end=1;
//结局1
}

else
{
now=i;
end=2;
//结局2
}
}
}

dialog *log=new dialog(this);

switch(end)
{
case 0:
log->setMessage("没有这个账号");
log->exec();
reIn();
break;
case 1:
log->setMessage("密码错误");
log->exec();
reIn();
break;
case 2:
log->setMessage("登录成功");
log->exec();
stack->setCurrentWidget(Game);

max--;
break;
}
log->deleteLater();
}

void start::creaIn()
{
int end=0;

nowUser[0]=account->text();
if(nowUser[0]=="")
{
return;
}
nowUser[1]=password->text();

int post=0;

for(int i=0;i<max-1;i++)
{
if(users[i][0]==nowUser[0])
{
end=1;
//结局1
}
}

dialog* regist=new dialog(this);

switch(end)
{
case 0:
regist->setMessage("注册成功,进入游戏");
regist->exec();
regist->deleteLater();
//清空

now=max-1;
stack->setCurrentWidget(Game);
break;
case 1:
regist->setMessage("已有账号");
regist->exec();
regist->deleteLater();

reIn();
break;
}
}

void start::hideShow()
{
if(state==true)
{
password->setEchoMode(QLineEdit::Normal);
state=false;
}
else
{
password->setEchoMode(QLineEdit::Password);
state=true;
}

}

void start::nullIn()
{

out=false;
dialog *regist=new dialog();
regist->setMessage("游客登录将无法计入数据");
regist->exec();

stack->setCurrentWidget(Game);

}

void start::readLog()
{
QFile file("log.bin");

if (!file.open(QIODevice::ReadOnly))
{
qDebug() << "无法打开文件";
return ;
}

QDataStream in(&file);

in>>max;
users=std::vector<std::vector<QString>>(max,std::vector<QString>(5));
for(int i=0;i<max;i++)
{
for(int j=0;j<5;j++)
{
in>>users[i][j];
}
qDebug()<<users[i][0];
}

max++;

file.close();
}

void start::writeLog()
{

if(nowUser[0]=="Null"&&out==false)
{
dialog* ddd=new dialog(this);
ddd->readUser(users,nowUser);
ddd->exec();
}

if(nowUser[0]=="Null"||nowUser[0]=="")
{
now=max;
}
else{
now=max-1;
}
//考虑是否加入

QFile file("log.bin");

if (!file.open(QIODevice::WriteOnly))
{
qDebug() << "无法打开文件";
return ;
}

QDataStream out(&file);

out<<max;
for(int i=0;i<max;i++)
{
if(i==now)
{
for(int j=0;j<5;j++)
{
out<<nowUser[j];
}
}
else
{
for(int j=0;j<5;j++)
{
out<<users[i][j];
}
}
}

file.close();
}

void start::preStore()
{
writeLog();
}

介绍

image-20240525165027815

进入登录注册界面
分三个按钮,前两个会在输入账号密码时检测,第三个则直接进入游戏。

image-20240525165708790

这里没有切换界面,只是隐藏了部分按钮,点击返回时EDIT隐藏。
正确输入账号或者注册账号后进入下一个界面。

game

game.h

#ifndef GAME_H
#define GAME_H
#include<QLabel>
#include <QWidget>
#include<QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QStackedWidget>

#include "map.h"
#include "hard.h"
#include "base.h"
#include "dialog.h"
#include "widget.h"
#include "ranking.h"
#include "storage.h"

class game : public Widget
{
Q_OBJECT
public:
game(QStackedWidget *,Widget *parent = nullptr);
void relemap();
//回到上级页面
~game();
public slots:
void Clickbase();
//基础模式的跳转
void ClickHard();
//苦难的跳转
void ClickStorage();
//回顾的跳转
void repage();
//转置页面
void setBasePage(int);
//设置基础模式地图
void setSysPage();
//设置系统地图
void setHumPage();
//设置用户地图
void setPastPage(int);
//设置回顾地图
void setlevel();
//初始填入排行榜
void checkLevel();
//每次检视排行榜
void writeLevel();
//写入排行榜
void midMap(int *);
//中间地图过度
private:
std::vector<QPushButton*> models;
QPushButton *score;
base *Base;
map *Map;
hard *Hard;
QStackedWidget *stack;
int previousPage;
ranking *Level;
dialog* Dialog;
QStringList horHeaders;
storage *Storage;
};

#endif // GAME_H

game.cpp

#include "game.h"
game::game(QStackedWidget* s,Widget *parent)
: Widget(parent)
, stack(s)
, previousPage(0)
,Dialog(new dialog(this))
{

horHeaders=QStringList()<< "玩家" << "困难通关数" << "通过关卡数" << "总积分";
Level=new ranking(4);

QVBoxLayout *vlayout = new QVBoxLayout(this); // 垂直布局

QWidget *buttonWidget = new QWidget(this); // 包含按钮的小部件

QWidget *scores=new QWidget(this);//包含分数的小部件

models.push_back(new QPushButton("关卡模式", buttonWidget));
models.push_back(new QPushButton("挑战模式", buttonWidget));
models.push_back(new QPushButton("存储回顾", buttonWidget)); // 创建三个按钮

score = new QPushButton("积分榜",scores);//积分榜按钮

QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
//大小策略

score->setSizePolicy(sizePolicy);
score->setMinimumSize(QSize(60, 20));
score->setMaximumSize(QSize(240, 80));
for(QPushButton *button : models)
{
button->setSizePolicy(sizePolicy);
button->setMinimumSize(QSize(30, 20));
button->setMaximumSize(QSize(240, 160));
}

//为四个按钮设置大小

QHBoxLayout *blayout = new QHBoxLayout(buttonWidget);
blayout->setSpacing(100);
// 设置组件之间的间距为100像素

QHBoxLayout *slayout = new QHBoxLayout(scores);
//两个水平布局(小部件)

for(QPushButton *button : models)
{
blayout->addWidget(button);
}
//为按钮设置

slayout->addStretch();
slayout->addWidget(score);
slayout->addStretch();
//为积分榜设置

//vlayout->addStretch(); // 垂直布局在顶部放置一个伸缩空间,将水平布局推到底部
vlayout->addWidget(scores);
//vlayout->addStretch(); // 在水平布局和窗口底部之间添加一个伸缩空间
vlayout->addWidget(buttonWidget);
//为垂直布局设置

connect(models[0], &QPushButton::clicked, this, &game::Clickbase);
// 关卡模式槽函数
connect(models[1], &QPushButton::clicked, this, &game::ClickHard);
// 挑战模式槽函数
connect(models[2],&QPushButton::clicked, this, &game::ClickStorage);

stack->addWidget(this);
Base = new base(this);
stack->addWidget(Base);
Hard=new hard(this);
stack->addWidget(Hard);
Map=new map(this);
Storage=new storage(this);
stack->addWidget(Storage);
stack->addWidget(Map);
stack->setCurrentWidget(this);
stack->show();

connect(Base,&base::repage,this,&game::repage);
//返回到关卡模式
connect(Hard,&hard::repage,this,&game::repage);
//返回
connect(Base, &base::tomap, this,&game::setBasePage);
//关卡模式的地图返回
connect(Hard,&hard::Cretomap,this,&game::setSysPage);
connect(Hard,&hard::HumtoMap,this,&game::setHumPage);

connect(Map, &map::back,this,&game::relemap);
//检测map的返回操作,若有,则将记录的页面给上去

connect(score,&QPushButton::clicked, this, &game::checkLevel);
//更新排行榜
connect(Storage,&storage::over, this,&game::setPastPage);
//设置回顾
connect(Storage,&storage::repage, this,&game::repage);
//回顾的返回

setlevel();
//填入数组


}
void game::setBasePage(int i)
{
previousPage = stack->currentIndex();
//初始化
Base->readMap(i);
//读取地图

//读取排行榜
Map->readmap(Base->reBaseMap(),Base->reBaseSolution());
//填充地图

Map->setModule(0);
//设置模式

Map->putmap();
//初始化等操作

Map->setIn(i);
//调用对应数组

stack->setCurrentWidget(Map);
//添加到页面
}

void game::setSysPage()
{
previousPage = stack->currentIndex();

Hard->createMap();

Map->readmap(Hard->reMap(),Hard->reSolution());

Map->setModule(1);
//设置模式

Map->putmap();
//初始

Map->setIn(6);
//调用对应数组

stack->setCurrentWidget(Map);
//添加到页面
}

void game::setHumPage()
{
previousPage = stack->currentIndex();
//初始化
dialog* humMap=new dialog(this);

connect(humMap,&dialog::outData,this,&game::midMap);
//调用对应

humMap->getMap();
humMap->exec();

Map->setModule(2);
Map->putmap();
stack->setCurrentWidget(Map);
//添加到页面
}

void game::setPastPage(int i)
{
previousPage = stack->currentIndex();
//初始化
Storage->reSet();
Storage->readMap(i);
//读取地图

Map->readmap(Storage->reMap(),Storage->reSolution());

Map->putmap();
//初始

Map->setModule(3);
//设置模式

stack->setCurrentWidget(Map);
//添加到页面

}
void game::Clickbase()
{
stack->setCurrentWidget(Base);
}

void game::ClickHard()
{
stack->setCurrentWidget(Hard);
}

void game::ClickStorage()
{
Storage->reSet();
stack->setCurrentWidget(Storage);
}
void game::repage()
{
stack->setCurrentWidget(this);
}

game::~game()
{
if(Level!=nullptr)
{
delete Level;
}
Level=nullptr;
}

void game::relemap()
{
stack->setCurrentIndex(previousPage);
//设置当前页面
// Map->dele();
// //释放关卡
}

void game::setlevel()
{
QFile file("totalLevel.bin");
if (!file.open(QIODevice::ReadOnly))
{
qDebug() << "无法打开文件";
}

QDataStream in(&file);

in>>*Level;

file.close();
}

void game::checkLevel()
{
if(nowUser[0]=="Null")
{
Dialog->setMessage("游客不能访问排行榜");
Dialog->exec();
return;
}

Level->toCheckLevel(nowUser);
//对比

Dialog->setLevel(*Level,horHeaders);
Dialog->exec();
//调出排行榜
}

void game::writeLevel()
{
QFile file("totalLevel.bin");
if (!file.open(QIODevice::WriteOnly))
{
qDebug() << "无法打开文件";
}

QDataStream out(&file);

out<<*Level;

file.close();
}

void game::midMap(int* a)
{
int solution[7]={-1};
Map->readmap(a,solution);
}


介绍

image-20240525170412988

这里使用了游客登录,进入了游戏界面,有三个大模块,分别为基础,困难和回顾,分别通往三个界面。
还有排行榜,由dialog窗口唤出
image-20240525172147781
game将自己的排行数组传给dialog,然后在dialog中比较并修改,在展示。

现在点击基础模式

base

base.h

#ifndef BASE_H
#define BASE_H

#include <QFile>
#include<QHBoxLayout>
#include <QPushButton>

#include "widget.h"


class base : public Widget
{
Q_OBJECT
public:
base(QWidget *parent=nullptr);
~base();
void readMap(int);
//读取全部
int* reBaseMap();
//返回地图
int* reBaseSolution();
//返回答案
signals:
void repage();
void tomap(int);
public slots:
void clickback();
//返回信号
void clicklevel(int);
//进入的关卡
private:
QPushButton* back;
std::vector<QPushButton*> bases;
int baseMap[36];
int baseSolution[7];
};

#endif // BASE_H

base.cpp

#include "base.h"
base::base(QWidget *parent)
: Widget(parent)
{

QWidget *basewid=new QWidget(this);
QWidget *backwid=new QWidget(this);

QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
//大小策略

for(int i = 0; i < 6; ++i)
{
QString name = "第" + QString::number(i + 1) + "关"; // 构造按钮名称,例如 "第1关", "第2关", 等等
bases.push_back(new QPushButton(name, this)); // 将按钮添加到 bases 数组中
bases[i]->setSizePolicy(sizePolicy);
bases[i]->setMinimumSize(QSize(30, 20));
bases[i]->setMaximumSize(QSize(240, 160));
}

QHBoxLayout *base_layout = new QHBoxLayout(basewid);
//添加水平布局

QHBoxLayout *back_layout=new QHBoxLayout(backwid);

QVBoxLayout *vlayout = new QVBoxLayout(this);
// 垂直布局

base_layout->setSpacing(100);
// 设置组件之间的间距为100像素

for(QPushButton *button : bases)
{
base_layout->addWidget(button);
}

back=new QPushButton("返回",backwid);
back->setSizePolicy(sizePolicy);
back->setMinimumSize(QSize(40, 30));
back_layout->addWidget(back);

vlayout->addWidget(backwid);
vlayout->addStretch();
vlayout->addWidget(basewid);
// 初始化按钮任务

connect(back,&QPushButton::clicked,this,&base::clickback);
// 关卡模式返回

for(int i=0;i<6;i++)
{
connect(bases[i],&QPushButton::clicked,[this, i]() { clicklevel(i); });
}
//6个按钮的地图进入
}
base::~base()
{
for (QPushButton* button : bases)
{
delete button;
}
if(back!=nullptr)
delete back;
back=nullptr;
}

void base::clickback()
{
emit repage();
}

void base::clicklevel(int i)
{
emit tomap(i);

}

void base::readMap(int a)
{
QFile file("basemap.bin");
if (!file.open(QIODevice::ReadOnly))
{
qDebug() << "basemap not open";
return;
}

QDataStream ifs(&file);
int temp=0;

for(int i=0;i<43*a;i++)
{
ifs>>temp;
}
for (int j = 0; j < 36; j++) {
ifs >>baseMap[j];
}
for(int i=0;i<7;i++)
{
ifs>>baseSolution[i];
}
file.close();
}

int* base::reBaseMap()
{

return baseMap;
}
int* base::reBaseSolution()
{

return baseSolution;
}

介绍

image-20240525170625090

现在进入了基础模式界面,内含六个关卡,点击对应的按钮后读取地图,然后将地图传递给最核心的页面————地图。

hard

hard.h

#ifndef HARD_H
#define HARD_H

#include <QFile>
#include<QLabel>
#include<QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>

#include "widget.h"

class hard :public Widget//系统和自主
{
Q_OBJECT
public:
hard(QWidget *parent=nullptr);
~hard();
void sysCreate();
//系统创建地图
void humCreate();
//用户创建
void createMap();
//系统创建地图
bool checkFour(int*,int);
//判断随机的四个初始拼图是否合法
void choiceSys(int*,int);
//根据number存入的合法位置,得到随机地址的合法性
int findFour(int*,int,int);
//找到基于位置4的合法最大位置
bool endMap();
//根据solution得到地图,检查地图后就可以开工了
void readLevel();
//读入地图
void writeLevel();
//写入地图
int* reMap();
//返回地图
int* reSolution();
//返回答案
signals:
void repage();
void Cretomap();
void HumtoMap();
public slots:
void clickback();
//返回信号
private:
int workmap[36];
int solution[7];
std::vector<std::vector<int>> number;//记录随机地点
};
#endif // HARD_H

hard.cpp

#include "hard.h"
hard::hard(QWidget *parent)
: Widget(parent)
{

QPushButton *autoMap=new QPushButton("系统生成",this);
QPushButton *customMap=new QPushButton("用户输入",this);
QPushButton *_return=new QPushButton("返回",this);
//设置两个子模式

QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);//大小策略
autoMap->setSizePolicy(sizePolicy);
autoMap->setMinimumSize(QSize(60, 20));
autoMap->setMaximumSize(QSize(240, 80));
customMap->setSizePolicy(sizePolicy);
customMap->setMinimumSize(QSize(60, 20));
customMap->setMaximumSize(QSize(240, 80));
_return->setSizePolicy(sizePolicy);
_return->setMinimumSize(QSize(120, 50));
_return->setMaximumSize(QSize(440, 130));
//设置按钮尺寸

QHBoxLayout *mode=new QHBoxLayout(this);
QVBoxLayout *frame=new QVBoxLayout(this);
//两个布局

mode->addWidget(autoMap);
mode->addWidget(customMap);
mode->addWidget(_return);

frame->addLayout(mode);
//框架

connect(autoMap,&QPushButton::clicked,this,&hard::sysCreate);
// connect(autoMap,&QPushButton::clicked,this);
connect(_return,&QPushButton::clicked,this,&hard::clickback);
connect(customMap,&QPushButton::clicked,this,&hard::humCreate);

};
hard::~hard()
{
}

void hard::clickback()
{
emit repage();
}

void hard::sysCreate()
{
emit Cretomap();
}

void hard::humCreate()
{
emit HumtoMap();
}

void hard::createMap()
{

number = {
{0, 1, 2, 6, 7, 8, 12, 13, 14},
{0, 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, 15, 18, 19, 20, 21},
{0, 1, 2, 3, 6, 7, 8, 9, 12, 13, 14, 15, 18, 19, 20, 21},
{0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28},
{0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35},
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35} };
//number 的初始化

int pos4 = 0;//位置4
int autopost[5] = {}; // 随机到了哪副拼图
int autoposi[8] = {}; // 记录哪副没有被随机,方便check
int onerand = 0;
for (;;)
{
pos4 = rand() % 36 + 1;

for (int i = 1; i <= 4; i++)
{
for (;;)
{
onerand = rand() % 7 + 1;
if (checkFour(autopost, onerand))
break;
}
autopost[i] = onerand; // 1~7
autoposi[autopost[i]]++;
}
// 得到一个不重复的数组
choiceSys(autopost, pos4);
// 对以上四个解得到结果
for (int i = 1; i <= 7; i++)
{
if (autoposi[i] != 1)
{
int erand = rand() % (number[i - 1].size());
solution[i-1]=number[i-1][erand];
// 得到随机数

}
}
//现在得到了7副拼图的位置信息

if(endMap())
break;

}
}
// 先得到随机的要合成“4”的拼图和位置,然后随机剩余的,
//最后根据随机的记录生成work。

void hard::choiceSys(int* autopost, int pos4)
{
// 以pos4作为能覆盖区域的最大值,最小值选择

for (int i = 1; i <= 4; i++)
// 判断choice是否覆盖

{
int findmax = findFour(number[autopost[i] - 1].data(), number[autopost[i] - 1].size() - 1, pos4);
// 拿到最大位置
int findmin = 0; // 得到最小位置
int erand = 0; // 最后的随机
switch (autopost[i])
{
case 7:
case 6:
erand = pos4;
solution[autopost[i]-1]=erand; // 7,6在number中的上下限为1
break;
case 5:
case 4: // 重构得到最小位置
findmin = findmax - 6;
if (findmin < 0)
findmin = 0; // 移动到指定位置(左上角
erand = rand() % (findmax - findmin) + findmin;
solution[autopost[i]-1]=number[autopost[i] - 1][erand];
break;
case 3:
case 2:
findmin = findmax - 4; // 移动到指定位置(左上角
if (findmin < 0)
findmin = 0;
erand = rand() % (findmax - findmin) + findmin;
solution[autopost[i]-1]=number[autopost[i] - 1][erand];
break;
case 1: // 重构得到最小位置
findmin = findmax - 4;
if (findmin < 0)
findmin = 0; // 移动到指定位置(左上角
erand = rand() % (findmax - findmin) + findmin;
solution[autopost[i]-1]=number[autopost[i] - 1][erand];
break;
}
}
}

int hard::findFour(int* a, int end, int c)
// 得到位置“4”的地点
{
// 二分查找
int str = 0;
int empt = 0;
for (; str <= end;)
{
int min = (str + end) / 2;
if (a[min] <= c)
{
str = min + 1;
empt = min;
}
else
end = min - 1;
}
return empt;
}

bool hard::checkFour(int* post,int n)
{
for (int i = 1; i <= 4; i++)
{
if (post[i]==n)
{
return false;
}
}
return true;
}

bool hard::endMap()
{
int work_map[36]={};
for (int i = 0; i < 7; i++)
{
int empt = solution[i];
// 拿到随机到的结果
switch (i+1)
{
case 7:
case 6:
work_map[empt]++;
break;
case 5:
case 4:
work_map[empt]++;
work_map[empt + 1]++;
work_map[empt + 6]++;
work_map[empt + 7]++;
break;
case 3:
case 2:
for (int i = 0; i < 3; i++) // 9格有点多,循环吧
{
work_map[empt + i]++;
work_map[empt + 6 + i]++;
work_map[empt + 12 + i]++;
}
break;
case 1:
for (int i = 0; i < 4; i++) // 16格有点多,循环吧
{
work_map[empt + i]++;
work_map[empt + 6 + i]++;
work_map[empt + 12 + i]++;
work_map[empt + 18 + i]++;
}
break;
}
}
int count = 0;
for (int i = 0; i < 36; i++)
{
if (work_map[i] > 4)
{
return false;
}
else if (work_map[i] == 4)
count++;
}
if (count != 1)
{
return false;
}
else
{

for(int i=0;i<36;i++)
{
int empt = work_map[i]; // 拿到随机到的结果
switch (empt)
{
case 4:
workmap[i]=4;
break;

case 3:
workmap[i]=3;
break;

case 1:
workmap[i]=3;
break;

case 2:
workmap[i]=2;
break;

case 0:
workmap[i]=2;
break;
}
}
//文本替换

QFile file("hardMap.bin");
if (!file.open(QIODevice::Append))
{
qDebug() << "无法打开文件";
return 0;
}
QDataStream in(&file);

for(int i=0;i<36;i++)
{
in<<workmap[i];
}
for(int i=0;i<7;i++)
{
in<<solution[i];
}
file.close();
//写入地图

return true;
}
}

int* hard::reMap()
{
return workmap;
}

int* hard::reSolution()
{
return solution;
}

介绍

image-20240525171548571

这个页面包含三个按钮,分别为系统生成,用户创建,返回。
点击系统生成,系统会自动将生成的地图写入文件,然后将副本传入map。
点击用户创建,弹出弹窗,输入地图判断后,将地图信息传入map。
image-20240525172359407
该图为用户子输入的弹窗。

storage

storage.h

#ifndef STORAGE_H
#define STORAGE_H

#include <QLabel>
#include <QFile>
#include <QLineEdit>
#include <QPushButton>
#include <QPushButton>
#include<QHBoxLayout>

#include "widget.h"
#include "dialog.h"
class storage : public Widget
{
Q_OBJECT
public:
storage(QWidget *parent=nullptr);
~storage();
void readTotal();
//读取地图个数
void readMap(int);
//读取地图文件
void startIn();
//进入作答
void reSet();
//重置
int* reMap();
//返回地图
int* reSolution();
//返回解决方案
void clickBack();
//返回
signals:
void over(int);
void repage();
private:
int total;
int workMap[36];
int solution[7];
QLineEdit *choice;
QPushButton *start;
QPushButton *re;
QLabel *tips;
};

#endif // STORAGE_H

storage.cpp

#include "storage.h"

storage::storage(QWidget *parent)
: Widget(parent)
{
total=100;
readTotal();

start=new QPushButton("开始",this);
start->setFixedSize(80,80);
re=new QPushButton("返回",this);
re->setFixedSize(80,80);
tips=new QLabel(this);
tips->setFixedSize(80,80);
tips->setStyleSheet("color: green;");
tips->setAlignment(Qt::AlignCenter);
choice=new QLineEdit(this);
choice->setPlaceholderText("输入数字以进入关卡,请勿输入非法字符及0");
tips->setText("目前存在"+QString::number(total)+"关");
//基本组件

QHBoxLayout *hlayout=new QHBoxLayout();
QVBoxLayout *vlayout=new QVBoxLayout(this);
//布局

hlayout->addWidget(start);
hlayout->addWidget(re);
vlayout->addWidget(tips);
vlayout->addWidget(choice);
vlayout->addLayout(hlayout);
//添加


connect(start,&QPushButton::clicked,this,&storage::startIn);
connect(re,&QPushButton::clicked,this,&storage::clickBack);
}

storage::~storage(){}

void storage::clickBack()
{
emit repage();
}
void storage::reSet()
{
readTotal();
tips->setText("目前存在"+QString::number(total)+"关");
}

void storage::readTotal()
{
QFile file("hardMap.bin");

QDataStream in(&file);
if (!file.open(QIODevice::ReadOnly))
{
qDebug() << "无法打开文件";
return;
}
int empt=0;
int count=0;
while(!file.atEnd())
{
in>>empt;
count++;
}
total=count/43;
file.close();
}

void storage::readMap(int a)
{
QFile file("hardMap.bin");

QDataStream in(&file);
if (!file.open(QIODevice::ReadOnly))
{
qDebug() << "无法打开文件";
return;
}
int empt=0;
for(int i=0;i<a-1;i++)
{
for(int j=0;j<43;j++)
{
in>>empt;
}
}

for(int i=0;i<36;i++)
{
in>>workMap[i];
qDebug()<<workMap[i];
}
for(int i=0;i<7;i++)
{
in>>solution[i];
qDebug()<<solution[i];
}
file.close();
}

void storage::startIn()
{
int set=choice->text().toInt();
if(set==0||set>total||total<0)
{
dialog *empt=new dialog(this);
empt->setMessage("输入错误或地图不足");
empt->exec();
}
else
{
emit over(set);
}
}

int* storage::reMap()
{
return workMap;
}

int* storage::reSolution()
{
return solution;
}

介绍

在这个界面中
image-20240525172641630
有如上的界面,读取存储了所有地图的文件后拿到地图数,用户输入后跳转

map

这里是最核心的类

map.h

#ifndef MAP_H
#define MAP_H
#include<QFile>
#include<QLabel>
#include <QTimer>
#include <QWidget>
#include <vector>
#include <QDateTime>
#include <QMessageBox>
#include<QHBoxLayout>
#include<QVBoxLayout>
#include <QTextStream>
#include <QGridLayout>

#include "widget.h"
#include "draglabel.h"
#include "droplabel.h"
#include "ranking.h"

class map:public Widget
{
Q_OBJECT
public:
map(QWidget *parent = nullptr);
~map();
void readmap(int*,int*);
//读取地图
void putmap();
//设置地图
void pause_on();
//暂停或继续
void update();
//更新时间
void check();
//检查是否做对
void nullMap();
//创建空地图
void humanMap();
//输入地图
void forState(int,int);
//记录回溯信息
void cleanBack();
//清空回溯数组
void toBack();
//回溯
void helpMe();
//帮帮我
void setIn(int);
//传入排行榜
void writeOut();
//写入排行榜
void compare();
//对比排行榜
void callLevel();
//唤出排行榜
void popLevel();
//隐藏排行榜
void setModule(int);
//切换模式
void calculate();
//计算积分
void callTools();
//呼唤工具
signals:
void back();
private:
int nowIndex;
int now_back;
int now_help;
QGridLayout *gridLayout;
QGridLayout *menu;
int workmap[36];
int solution[7];
std::vector<QLabel*> piclabel;
std::vector<DragLabel*> uselabel;
std::vector<DropLabel*> droplabels;
bool state;
QPushButton* start;
QPushButton* pullBack;
QPushButton* help;
QPushButton* inLevel;
QPushButton* tools;
QLabel* time;
QTimer *timer;
QDateTime nowtime;
QDateTime lasttime;
QLabel *helpCounter;
QLabel *backCounter;
std::vector<std::vector<QString>> dropBack;
std::vector<int> dragBack;
std::vector<int> helpInt;
ranking *level;
QStringList horHeaders;
int module;
int fault;
//0为关卡,1为挑战,2为自定义,3为回顾
QString now_time;

};
#endif // MAP_H

map.cpp

#include "map.h"
#include "dialog.h"

map::map(QWidget *parent)
: Widget(parent),
nowIndex(110)
,now_back(0)
,now_help(0)
,state(false)
{

level=new ranking(2);
fault=0;
horHeaders=QStringList()<< "玩家" << "本关用时";

helpInt=std::vector<int> (7,-1);
for (int i = 0; i < 36; ++i) {
piclabel.push_back(new QLabel);
}//初始化36副图片

for (int i = 0; i < 7; ++i) {
uselabel.push_back(new DragLabel);
}//初始化7副拼图

for(int i=0;i<36;i++)
{
droplabels.push_back(new DropLabel);
droplabels[i]->setFixedSize(80,80);
droplabels[i]->setText("0");
droplabels[i]->setStyleSheet("color: green;");
droplabels[i]->setAlignment(Qt::AlignCenter);
}//初始化拖拽标签

QPixmap map1(":/image/4.png");
QPixmap map2(":/image/3.png");
QPixmap map3(":/image/2.png");
QPixmap map4(":/image/1.png");

uselabel[0]->setPixmap(map1);
uselabel[0]->put_text("1");
uselabel[0]->setScaledContents(true);

uselabel[1]->setPixmap(map2);
uselabel[1]->put_text("2");
uselabel[1]->setScaledContents(true);

uselabel[2]->setPixmap(map2);
uselabel[2]->put_text("3");
uselabel[2]->setScaledContents(true);

uselabel[3]->setPixmap(map3);
uselabel[3]->put_text("4");
uselabel[3]->setScaledContents(true);

uselabel[4]->setPixmap(map3);
uselabel[4]->put_text("5");
uselabel[4]->setScaledContents(true);

uselabel[5]->setPixmap(map4);
uselabel[5]->put_text("6");
uselabel[5]->setScaledContents(true);

uselabel[6]->setPixmap(map4);
uselabel[6]->put_text("7");
uselabel[6]->setScaledContents(true);
//初始化7副拼图

uselabel[0]->setFixedSize(280,280);
uselabel[1]->setFixedSize(120,120);
uselabel[2]->setFixedSize(120,120);
uselabel[3]->setFixedSize(80,80);
uselabel[4]->setFixedSize(80,80);
uselabel[5]->setFixedSize(80,80);
uselabel[6]->setFixedSize(80,80);
// 创建一个网格布局
gridLayout = new QGridLayout();
gridLayout->setSpacing(0);
gridLayout->setHorizontalSpacing(0); // 设置水平间距
gridLayout->setVerticalSpacing(0); // 设置垂直间距

// 设置网格布局的大小策略为 Fixed,确保不会在大小不匹配时拉伸
gridLayout->setSizeConstraint(QLayout::SetFixedSize);

//添加图片和拼图到网格布局
for(int i = 0; i < 6; i++)
{
for(int j = 0; j < 6; j++)
{
int index = i * 6 + j;
DropLabel *dropLabel = droplabels[index];
//二者对应的指针

dropLabel->putpost(i*6+j,droplabels);
//设置坐标信息
gridLayout->addWidget(dropLabel, i, j);
//加入
}
}
// 设置拼图布局

QHBoxLayout *double0=new QHBoxLayout();
double0->addWidget(uselabel[0]);
QHBoxLayout *double1=new QHBoxLayout();
double1->addWidget(uselabel[1]);
double1->addWidget(uselabel[2]);
QHBoxLayout *double2=new QHBoxLayout();
double2->addWidget(uselabel[3]);
double2->addWidget(uselabel[4]);
QHBoxLayout *double3=new QHBoxLayout();
double3->addWidget(uselabel[5]);
double3->addWidget(uselabel[6]);
//分层次

QVBoxLayout *rivlayout = new QVBoxLayout();
rivlayout->setSpacing(20);
rivlayout->addLayout(double0);
rivlayout->addLayout(double1);
rivlayout->addLayout(double2);
rivlayout->addLayout(double3);
//右侧垂直布局

QPushButton *back = new QPushButton("返回", this);
back->setFixedSize(80,80);
start = new QPushButton("开始", this);
start->setFixedSize(80,80);
QPushButton *over = new QPushButton("检查", this);
over->setFixedSize(80,80);
inLevel = new QPushButton("排行", this);
inLevel->setFixedSize(80,80);
pullBack=new QPushButton("后撤",this);
pullBack->setFixedSize(160,80);
help=new QPushButton("提示",this);
help->setFixedSize(160,80);
tools=new QPushButton("道具",this);
tools->setFixedSize(80,80);
tools->hide();
//按钮

time=new QLabel(this);
time->setFixedSize(320,160);
time->setText("00:00:00");
time->setStyleSheet("color: green;");
time->setAlignment(Qt::AlignCenter);
timer=new QTimer(this);
nowtime = QDateTime::currentDateTime();
//计时器

backCounter=new QLabel(this);
backCounter->setText("0");
backCounter->setFixedSize(80,80);
backCounter->setStyleSheet("color: green;");
helpCounter=new QLabel(this);
helpCounter->setText("0");
helpCounter->setFixedSize(80,80);
helpCounter->setStyleSheet("color: green;");

menu=new QGridLayout();
menu->addWidget(back,0,0);
menu->addWidget(start,0,1);
menu->addWidget(over,0,2);
menu->addWidget(inLevel,0,3);
menu->addWidget(pullBack,1,0);
menu->addWidget(help,1,2);
menu->addWidget(backCounter,1,1);
menu->addWidget(helpCounter,1,3);
menu->addWidget(tools,2,1);
//创建操作菜单

QHBoxLayout *interect=new QHBoxLayout();
interect->addStretch();
interect->addLayout(gridLayout);
//防止gridlabel出现空格

QVBoxLayout *lelayout=new QVBoxLayout();
lelayout->addLayout(interect);
lelayout->addLayout(menu);
lelayout->addWidget(time);

// 创建总的水平布局
QHBoxLayout *tohlayout = new QHBoxLayout(this);

// 将左侧网格布局和右侧拼图布局加入总的水平布局
tohlayout->addLayout(lelayout);
tohlayout->addStretch();
tohlayout->addLayout(rivlayout);
tohlayout->addStretch();

connect(back, &QPushButton::clicked, this,[=]()
{
writeOut();
emit map::back();
});

connect(start,&QPushButton::clicked,this,&map::pause_on);
//返回按钮
connect(timer, &QTimer::timeout, this, &map::update);

connect(over,&QPushButton::clicked,this,&map::check);

for (int i = 0; i < 36; ++i)
{
connect(droplabels[i], &DropLabel::back, this,[=](int a,int b) {
forState(a,b);
});
}
connect(pullBack,&QPushButton::clicked,this,&map::toBack);
connect(help,&QPushButton::clicked,this,&map::helpMe);
connect(inLevel,&QPushButton::clicked,this,&map::callLevel);
connect(tools,&QPushButton::clicked,this,&map::callTools);

};

map::~map()
{
if(level!=nullptr)
{
delete level;
}
level=nullptr;
};

void map::readmap(int* _map,int*_solution)
{
for(int i=0;i<36;i++)
{
workmap[i]=_map[i];
}
for(int i=0;i<7;i++)
{
solution[i]=_solution[i];
}
}

void map::putmap()
{
cleanBack();
//清空提示,回溯
start->setText("开始");

nowtime = QDateTime::currentDateTime(); // 确保nowtime是最新的当前时间
QTime t_time(0, 0);
time->setText(t_time.toString("mm:ss.zzz"));
//设置时间标签为初始时间

state=false;
//当前开关状态

backCounter->setText("0");
helpCounter->setText("0");
//计数器设置

//设置图片
QPixmap map1(":/image/0t.png");
QPixmap map2(":/image/02t.png");
QPixmap map3(":/image/13t.png");
QPixmap map4(":/image/4t.png");

//添加图片和拼图到网格布局
for(int i = 0; i < 6; i++)
{
for(int j = 0; j < 6; j++)
{
int index = i * 6 + j;
DropLabel *dropLabel = droplabels[index];
QLabel *picLabel = piclabel[index];
//二者对应的指针

dropLabel->setText("0");
int temp=workmap[index];

switch(temp)
{
case 1:
picLabel->setPixmap(map1);
break;
case 2:
picLabel->setPixmap(map2);
break;
case 3:
picLabel->setPixmap(map3);
break;
case 4:
picLabel->setPixmap(map4);
break;
}
//给36个图片

picLabel->setFixedSize(80,80);
picLabel->setScaledContents(true);
gridLayout->addWidget(picLabel, i, j);
dropLabel->raise();
}
}
if (timer->isActive()) {
timer->stop();
}
//判断计时器是否在工作

lasttime = QDateTime::currentDateTime();
// 重置暂停相关的时间记录

if(module==2)
{
pullBack->hide();
//回撤
help->hide();
//提示
helpCounter->hide();
//提示计数板
backCounter->hide();
//回撤计数板
inLevel->hide();
tools->show();
}
else if(module==3)
{
inLevel->hide();
tools->hide();
help->show();
helpCounter->show();
backCounter->show();
pullBack->show();
}
else
{
pullBack->show();
inLevel->show();
help->show();
helpCounter->show();
backCounter->show();
tools->hide();
}
//模式设置
}

void map::pause_on()
{
if(state==true)
{

lasttime = QDateTime::currentDateTime(); // 记录暂停时的时间
timer->stop();
for(int i=0;i<36;i++)
{
droplabels[i]->setAcceptDrops(false);
}
state=false;
start->setText("开始");
}
else
{
timer->start(10);
for(int i=0;i<36;i++)
{
droplabels[i]->setAcceptDrops(true);
}
state=true;
start->setText("暂停");
qint64 elapsedPausedTime = lasttime.msecsTo(QDateTime::currentDateTime());
nowtime = nowtime.addMSecs(elapsedPausedTime);
}
}
//根据当前状态修改是否能继续游戏

void map::update()
{
qint64 elapsedTime = nowtime.msecsTo(QDateTime::currentDateTime());

// 将时间转换成字符串并设置给QLabel
QTime t_time(0, 0);
t_time = t_time.addMSecs(elapsedTime);
time->setText(t_time.toString("mm:ss.zzz"));
}

void map::check()
{
lasttime = QDateTime::currentDateTime();
// 记录暂停时的时间

timer->stop();
//暂停计时器

bool end=true;
int empt=0;
for(int i=0;i<36;i++)
{
empt=droplabels[i]->text().toInt();
switch(workmap[i])
{
case 4:
if(empt!=4)
{
end=false;
}
break;
case 3:
if(empt!=3&&empt!=1)
{
end=false;
}
break;
case 2:
if(empt!=2&&empt!=0)
{
end=false;
}
break;
case 1:
if(empt!=0)
{
end=false;
}
break;
}
droplabels[i]->setText("0");
}
if(end==true)
{
dialog *mess1=new dialog();
mess1->setMessage("没想到让你赢了");
mess1->exec();
qint64 elapsedTime = nowtime.msecsTo(QDateTime::currentDateTime());

// 将时间转换成字符串并设置给QLabel
QTime t_time(0, 0);
t_time = t_time.addMSecs(elapsedTime);

now_time=t_time.toString("mm:ss.zzz");
//准备工作完成

calculate();
//计算积分

switch(module)
{
case 0:
nowUser[3][nowIndex]='Y';
break;
case 1:
int empt=nowUser[2].toInt();
empt++;
nowUser[2]=QString::number(empt);
//通关信息
}
//统计过关数和信息

//统计分数和用户数据修改
if(nowUser[0]!="Null")
{
switch(module)
{
case 0:
compare();
//修改关卡信息,积分榜
break;
case 1:
empt++;
nowUser[2]=QString::number(empt);
compare();
//计入排行榜
}
}
//三个模式下的各自策略
}

else
{
dialog *mess2=new dialog();
mess2->setMessage("呕吼失败辣");
mess2->exec();
}
state=false;
start->setText("开始");
//开始重置
//回溯
cleanBack();
// 重置当前时间显示
nowtime = QDateTime::currentDateTime(); // 确保nowtime是最新的当前时间
QTime t_time(0, 0);
time->setText(t_time.toString("mm:ss.zzz"));
// 设置时间标签为初始时间
}

void map::forState(int i,int post)
{
if(module==2)
{
return;
}
i--;
uselabel[i]->hide();
dropBack.push_back(std::vector<QString>(36));
dragBack.push_back(i);
helpInt[i]=post;
for(int j=0;j<36;j++)
{
dropBack[dropBack.size()-1][j]=droplabels[j]->text();
}
int empt=dropBack.size();
QString _empt=QString::number(empt);
backCounter->setText(_empt);

int a=0;
for(int i=0;i<7;i++)
{
if(helpInt[i]==solution[i])
a++;
}
QString _empt1=QString::number(a);
helpCounter->setText(_empt1);
}

void map::cleanBack()
{
dropBack.clear();
dragBack.clear();
now_back=0;
now_help=0;
for(int i=0;i<7;i++)
{
helpInt[i]=-1;
}
for(int i=0;i<7;i++)
{
uselabel[i]->show();
}
helpCounter->setText("0");
backCounter->setText("0");

fault=0;
}

void map::toBack()
{
QString temp=backCounter->text();

int _temp=temp.toInt();
_temp--;

if(_temp>=0)
{
fault++;
now_back++;
for(int i=0;i<36;i++)
{
droplabels[i]->setText(dropBack[_temp][i]);
}
uselabel[dragBack[_temp]]->show();
temp=QString::number(_temp);
backCounter->setText(temp);
dropBack.pop_back();
dragBack.pop_back();
helpInt[_temp]=-1;
}

}

void map::helpMe()
{
for(int i=0;i<7;i++)
{
if(solution[i]!=helpInt[i]&&solution[i]!=-1)
{
dialog* temp=new dialog(this);

int x=solution[i]/6+1;
int y=solution[i]%6+1;
temp->setMessage("第"+QString::number(i+1)+"图片的坐标为:第"+QString::number(x)+"列,第"+QString::number(y)+"排");

temp->exec();
temp->deleteLater();
now_help++;
fault++;
return;
}
}

dialog* temp=new dialog(this);
temp->setMessage("快去交卷");
temp->exec();
// temp->gameMode();
// temp->show();
}

void map::setIn(int i)
{
nowIndex=i;
QString a="level"+QString::number(i)+".bin";

QFile file(a);

QDataStream in(&file);
if (!file.open(QIODevice::ReadOnly))
{
qDebug() << "无法打开文件";
return;
}
in>>*level;
}

void map::compare()
{
level->liCheckLevel(nowUser,now_time);
}

void map::callLevel()
{
if(nowUser[0]=="Null")
{
dialog* tip=new dialog(this);
tip->setMessage("游客不能访问排行榜");
tip->exec();
return;
}
dialog *Dialog=new dialog();
Dialog->setLevel(*level,horHeaders);
Dialog->exec();
}

void map::humanMap()
{
QFile file("basemap.bin");
if (!file.open(QIODevice::Append))
{
qDebug() << "Failed to open file.";
return;
}

QDataStream ifs(&file);

for(int i=0;i<36;i++)
{
ifs<<droplabels[i]->text().toInt();
}

for(int i=0;i<7;i++)
{
ifs<<helpInt[i];
}

file.close();

qDebug()<<"完成";
}

void map::nullMap()
{
for(int i=0;i<36;i++)
{
workmap[i]=0;
}
for(int i=0;i<7;i++)
{
helpInt[i]=-1;
}
}

void map::popLevel()
{
inLevel->hide();
}

void map::setModule(int n)
{
module=n;
}

void map::calculate()
{
int a = now_time.mid(0, 2).toInt(); // 提取前两个字符
int b= now_time.mid(3, 2).toInt(); // 提取中间两个字符,从索引3开始
int c= now_time.mid(6, 3).toInt();
double total=a+b*0.01+c*0.001;
int score=nowUser[4].toInt();;

switch(module)
{
case 0:
if(nowUser[3][nowIndex]!='Y')
{
score-=fault*20;
score+=100;
if(total<3)
score+=300;
else
{
score+=900/total;
}
}
break;

case 1:
score-=fault*30;
if(total<1)
score+=400;
else
{
score+=1000/total;
}
break;
case 2:
score+=100;
case 3:
score+=20;
}
nowUser[4]=QString::number(score);
}

void map::callTools()
{
dialog* gametool=new dialog(this);
gametool->gameMode();
gametool->show();
tools->hide();
}

void map::writeOut()
{
if(module==1||module==0)
{
QString a="level"+QString::number(nowIndex)+".bin";

QFile file(a);

if (!file.open(QIODevice::WriteOnly))
{
qDebug() << "无法打开文件";
return;
}

QDataStream out(&file);

out<<*level;

file.close();
}
}

介绍

image-20240525173019553
在这个页面中,用户对图片进行拖拽,左侧的控件检测拖拽,给出反应。此外,还有回溯,提示,返回,排行榜,检查,计时器等功能。

ranking

ranking.h

#ifndef RANKING_H
#define RANKING_H
\
#include <vector>
#include <QString>
#include <QDataStream>
class ranking
{
friend QDataStream& operator>>(QDataStream& in, ranking& p);
friend QDataStream& operator<<(QDataStream& out, ranking& p);
public:
ranking( int);
~ranking();
void toCheckLevel(std::vector<QString>&);
//总榜对比
void liCheckLevel(std::vector<QString>&,QString&);
//子榜对比
int reData();
//返回规模
std::vector<std::vector<QString>> reVector();
//返回数组
void clear();
//清空
private:
int datas;
std::vector<std::vector<QString>> levelOnes;
};

#endif // RANKING_H

ranking.cpp

#include "ranking.h"
#include "qdebug.h"

ranking::ranking(const int a)
{
datas=a;
for(int i=0;i<10;i++)
{
levelOnes.push_back(std::vector<QString>(a,""));
}
}

QDataStream& operator>>(QDataStream& in, ranking& p)
{
for(int i=0;i<10;i++)
{
for(int j=0;j<p.datas;j++)
{
in>>p.levelOnes[i][j];
}
}
return in;
}

QDataStream& operator<<(QDataStream& out,ranking& p)
{

for(int i=0;i<10;i++)
{
for(int j=0;j<p.datas;j++)
{
out<<p.levelOnes[i][j];
}
}
return out;
}

void ranking::toCheckLevel(std::vector<QString>&nowUser)
{
ranking empt(4);
int index=10;

for(int i=9;i>=0;i--)
{
empt.levelOnes[i][0]=this->levelOnes[i][0];
//名称
empt.levelOnes[i][1]=this->levelOnes[i][1];
//关卡数目
empt.levelOnes[i][2]=this->levelOnes[i][2];
//六关情况
empt.levelOnes[i][3]=this->levelOnes[i][3];
//积分榜

index=i;
if(nowUser[4]<empt.levelOnes[i][3])
{
index=i+1;
break;
}
}
//获得排行

for(int i=0,j=0;i<10&&j<10;i++,j++)
{
if(i==index)
{
this->levelOnes[i][0]=nowUser[0];
this->levelOnes[i][1]=nowUser[2];
this->levelOnes[i][2]=nowUser[3];
this->levelOnes[i][3]=nowUser[4];
i++;
j--;
}
else
{
this->levelOnes[i][0]=empt.levelOnes[j][0];
this->levelOnes[i][1]=empt.levelOnes[j][1];
this->levelOnes[i][2]=empt.levelOnes[j][2];
this->levelOnes[i][3]=empt.levelOnes[j][3];
}
}
}

void ranking::liCheckLevel(std::vector<QString>&nowUser,QString &now_time)
{
ranking empt(3);

int index=-1;
for(int i=0;i<10;i++)
{
if(this->levelOnes[i][0]=="")
{

index=i;
break;
}
}

int j=0;
for(int i=0,k=0;i<index&&k<index;i++,k++)
{
if(j==1||this->levelOnes[i][1]<now_time)
{
empt.levelOnes[i][0]=this->levelOnes[k][0];

empt.levelOnes[i][1]=this->levelOnes[k][1];
}
else
{
j=1;

empt.levelOnes[i][0]=nowUser[0];

empt.levelOnes[i][1]=now_time;
k--;

}
}
if(index!=-1&&j==0)
{
this->levelOnes[index][0]=nowUser[0];
this->levelOnes[index][1]=now_time;
return;
}
for(int i=0;i<10;i++)
{
if(this->levelOnes[i][0]=="")
{
this->levelOnes[i][0]=empt.levelOnes[i][0];
this->levelOnes[i][1]=empt.levelOnes[i][1];
}
this->levelOnes[i][0]=empt.levelOnes[i][0];
this->levelOnes[i][1]=empt.levelOnes[i][1];
}
}

int ranking::reData()
{
return datas;
}

std::vector<std::vector<QString>> ranking::reVector()
{
return levelOnes;
}

ranking::~ranking()
{
}

void ranking::clear()
{
for(int i=0;i<10;i++)
{
for(int j=0;j<datas;j++)
{
levelOnes[i][j]="";
}
}
}

介绍

这个类用于传递排行榜,根据传入的QStringlist和数字自动开排行榜。示例之前已给出

dialog

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QLabel>
#include <QPixmap>
#include <QWidget>
#include <QMessageBox>
#include <QPushButton>
#include <QVBoxLayout>
#include <QTableWidget>
#include <QTableWidgetItem>
#include <QLineEdit>

#include "ranking.h"
#include "draglabel.h"

class dialog : public QDialog
{
Q_OBJECT
public:
explicit dialog(QWidget *parent = nullptr);
//初始构造
void setLevel(const ranking,QStringList);
//排行榜
void setMessage(QString);
//显示消息
void returnout();
//返回
void gameMode();
//游戏模式
void getMap();
//获得玩家地图
void check();
//检查地图
void readUser(std::vector<std::vector<QString>>&,std::vector<QString>&);
//读取游客模式的账号和密码
void checkLog();
//检查末尾密码
signals:
void outData(int*);
private:
QLineEdit* workMap;
QLineEdit* account;
QLineEdit* password;
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

dialog::dialog(QWidget *parent)
: QDialog(parent)
{
}

void dialog::setLevel( ranking level,QStringList horHeaders)
{
QStringList verHeaders;
verHeaders << "玩家序列 1" << "玩家序列 2" << "玩家序列 3" << "玩家序列 4" << "玩家序列 5"
<< "玩家序列 6" << "玩家序列 7" << "玩家序列 8" << "玩家序列 9" << "玩家序列 10";

setFixedSize(700,600);

// 创建 QTableWidget
QTableWidget *levelTable = new QTableWidget(this);
levelTable->setFixedSize(700,400);
levelTable->setRowCount(10); // 设置行数
levelTable->setColumnCount(level.reData()); // 设置列数
levelTable->setVerticalHeaderLabels(verHeaders);
levelTable->setHorizontalHeaderLabels(horHeaders);

// 设置每个单元格的大小
for (int i = 0; i < 10; i++) {
levelTable->setRowHeight(i, 70); // 设置第 i 行的高度为 40 像素
}
for (int j = 0; j < level.reData(); j++) {
levelTable->setColumnWidth(j, 130); // 设置第 j 列的宽度为 100 像素
}

std::vector<std::vector<QString>> temp=level.reVector();
// 填充表格数据
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < level.reData(); j++)
{
QTableWidgetItem *item = new QTableWidgetItem(temp[i][j]);
item->setTextAlignment(Qt::AlignCenter);
levelTable->setItem(i, j, item);
}
}

//创建按钮
QPushButton *_return=new QPushButton("返回",this);

QVBoxLayout *layout=new QVBoxLayout();
layout->addWidget(levelTable);
layout->addWidget(_return);


connect(_return,&QPushButton::clicked, this, &dialog::returnout);
// 将表格添加到主窗口布局中
setLayout(layout);
}

void dialog::returnout()
{
close();
}

void dialog::setMessage(QString a)
{
setFixedSize(200,300);

QLabel *tital=new QLabel(a,this);
tital->setFixedSize(200,200);
tital->setAlignment(Qt::AlignCenter);

QPushButton *set=new QPushButton("确认",this);

QVBoxLayout *layout=new QVBoxLayout();
layout->addWidget(tital);
layout->addWidget(set);

connect(set,&QPushButton::clicked, this, &dialog::returnout);

setLayout(layout);
}

void dialog::gameMode()
{
setFixedSize(200,300);

DragLabel *pic=new DragLabel(this);

QPixmap map4(":/image/1.png");

pic->setFixedSize(200,200);
pic->setAlignment(Qt::AlignCenter);
pic->setPixmap(map4);
pic->put_text("4");
pic->setScaledContents(true);

QPushButton *set=new QPushButton("确认",this);

QVBoxLayout *layout=new QVBoxLayout();
// layout->addWidget(pic);
layout->addWidget(set);

connect(set,&QPushButton::clicked, this, &dialog::returnout);

setLayout(layout);

}

void dialog::getMap()
{
setFixedSize(600,500);

workMap=new QLineEdit(this);
workMap->setPlaceholderText("在此输入地图");
QLabel *number=new QLabel(this);
number->setText("0");

QPushButton *start=new QPushButton("完成",this);
start->hide();
QPushButton *_return=new QPushButton("返回",this);

QHBoxLayout *layout1=new QHBoxLayout();
layout1->addWidget(start);
layout1->addWidget(_return);

QVBoxLayout *layout2=new QVBoxLayout(this);
layout2->addWidget(number);
layout2->addWidget(workMap);
layout2->addLayout(layout1);

connect(_return,&QPushButton::clicked, this, &dialog::returnout);
connect(workMap,&QLineEdit::textEdited,this,[number](const QString &text)
{
number->setText("已输入 " + QString::number(text.length()));
});
connect(workMap,&QLineEdit::textEdited,this,[start](const QString &text)
{
if(text.length()==36)
{
start->show();
}
else
{
start->hide();
}
});
connect(start,&QPushButton::clicked, this,&dialog::check);

setLayout(layout2);
}


void dialog::check()
{
QString number=workMap->text();
for(int i=0;i<36;i++)
{
if(number[i]!='1'&&number[i]!='2'&&number[i]!='3'&&number[i]!='4')
{
workMap->clear();
workMap->setPlaceholderText("输入无效");
return;
}
}
int workmap[36];
for(int i=0;i<36;i++)
{
workmap[i]=number[i].digitValue();
}

emit outData(workmap);
close();

}

void dialog::readUser(std::vector<std::vector<QString>>&users,std::vector<QString>& user)
{

setFixedSize(600,500);

account=new QLineEdit(this);
password=new QLineEdit(this);

account->setPlaceholderText("在此输入账号");
password->setPlaceholderText("在此输入密码");

QPushButton *start=new QPushButton("完成",this);
QPushButton *_return=new QPushButton("结束",this);

QHBoxLayout *layout1=new QHBoxLayout();
layout1->addWidget(start);
layout1->addWidget(_return);

QVBoxLayout *layout2=new QVBoxLayout(this);
layout2->addWidget(account);
layout2->addWidget(password);
layout2->addLayout(layout1);

connect(_return,&QPushButton::clicked, this, &dialog::returnout);
connect(start, &QPushButton::clicked, this, [this, &users, &user]() {
QString enteredAccount = account->text();
QString enteredPassword = password->text();

if(enteredAccount=="")
account->setPlaceholderText("无效账号");
for (int i=0;i<users.size();i++)
{
if (users[i][0]== enteredAccount)
{
account->setPlaceholderText("账号重复");
return;

}
}
user[0]=enteredAccount;
user[1]=enteredPassword;
account->setPlaceholderText("账号创建完毕,点击结束退出");
});
setLayout(layout2);
}

介绍

这个类主要用于弹出提示词,小道具,小提示等不值得被做成单个界面的东西

droplabel

draoplabel.h

#ifndef DROPLABEL_H
#define DROPLABEL_H

#include <QDrag>
#include <QLabel>
#include <QWidget>
#include <QMimeData>
#include <QMouseEvent>
#include <QGridLayout>
#include <QApplication>
#include <QGraphicsDropShadowEffect>

class DropLabel : public QLabel
{
Q_OBJECT
public:
explicit DropLabel(QWidget *parent = nullptr);
void putpost(int,std::vector<DropLabel*>);
//设置坐标,并传入网格的指针
void findlabel(int);
//衍生到其他label
void checkchar();
//1->2->3->4
protected:
void dragEnterEvent(QDragEnterEvent *event) override;
//判断是否要接收这个拖拽
void dropEvent(QDropEvent *event) override;
//接收之后的操作
signals:
void back(int,int);
private:
int post;//位置信息
std::vector<DropLabel*> droplabel;//指针
};
#endif // DROPLABEL_H

droplabel.cpp

#include "DropLabel.h"
DropLabel::DropLabel(QWidget *parent)
: QLabel(parent)
{
setAcceptDrops(false); // 接受拖放事件
}

void DropLabel::dragEnterEvent(QDragEnterEvent *event)
{
QString droppedText = event->mimeData()->text();
int empt=droppedText.toInt();
switch(empt)
{
case 1:
if (post % 6 < 3&&post/6<3)
{
this->setStyleSheet("color: blue;");
event->acceptProposedAction();
}
else
{
this->setStyleSheet("color: red;");
event->ignore();
}
break;
case 2:
case 3:
if (post % 6 < 4&&post/6<4)
{
this->setStyleSheet("color: blue;");
event->acceptProposedAction();
}
else
{
this->setStyleSheet("color: red;");
event->ignore();
}
break;
case 4:
case 5:
if (post % 6 < 5&&post/6<5)
{
this->setStyleSheet("color: blue;");
event->acceptProposedAction();
}
else
{
this->setStyleSheet("color: red;");
event->ignore();
}
break;
case 6:
case 7:
this->setStyleSheet("color: blue;");
event->acceptProposedAction();
break;
}
}
//能写入的一定是合法的

void DropLabel::dropEvent(QDropEvent *event)
{
QString droppedText = event->mimeData()->text();
int empt=droppedText.toInt();

emit DropLabel::back(empt,post);

for(int i=0;i<36;i++)
{
droplabel[i]->setStyleSheet("color: green;");
}

switch(empt)
{
case 1:
for (int i = 0,posi=post; i < 4; i++,posi+=6)
{
findlabel(posi);
findlabel(posi+1);
findlabel(posi+2);
findlabel(posi+3);
}
event->accept();
break;
case 2:
case 3:
for (int i = 0,posi=post; i < 3; i++,posi+=6)
{
findlabel(posi);
findlabel(posi+1);
findlabel(posi+2);
}
event->accept();
break;
case 4:
case 5:
for (int i = 0,posi=post; i < 2; i++,posi+=6) // 16格有点多,循环吧
{
findlabel(posi);
findlabel(posi+1);
}
event->accept();
break;
case 6:
case 7:
findlabel(post);
event->accept();
break;
}
}

void DropLabel::putpost(int i,std::vector<DropLabel*> labels)
{
post=i;
droplabel=labels;
}

void DropLabel::findlabel(int i)
{
DropLabel *dropLabel =droplabel[i];// 转换为DropLabel
dropLabel->checkchar();
}
void DropLabel::checkchar()
{
QString a=text();
int b=a.toInt();
b++;
a=QString::number(b);
setText(a);
}

介绍

map左侧的6*6的区域,接收右侧图片的拖拽,并显示动态数字

draglabel

draglabel.h

#ifndef DRAGLABEL_H
#define DRAGLABEL_H

#include <QWidget>
#include <QLabel>
#include <QMouseEvent>
#include <QDrag>
#include <QMimeData>
#include <QApplication>
#include <QGraphicsDropShadowEffect>
#include <QString>
#include <QGraphicsPixmapItem>
#include <QGraphicsScene>
#include <QPainter>

class DragLabel : public QLabel
{
Q_OBJECT
public:
explicit DragLabel(QWidget *parent = nullptr);
void put_text(QString);
protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
private:
QString text;
QPoint dragStartPos;
};

#endif // DRAGLABEL_H

draglabel.cpp

#include "DragLabel.h"

DragLabel::DragLabel(QWidget *parent)
: QLabel(parent)
{
setMouseTracking(true); // 跟踪鼠标移动
setCursor(Qt::OpenHandCursor); // 设置手型光标
}

void DragLabel::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
dragStartPos = event->pos(); // 记录鼠标按下时的位置
}
QLabel::mousePressEvent(event);
}
void DragLabel::put_text(QString t)
{
text=t;
}
void DragLabel::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) { // 检查鼠标左键是否被按下
QPoint diff = event->pos() - dragStartPos; // 计算鼠标移动的距离
if (diff.manhattanLength() < QApplication::startDragDistance()) {
return; // 如果移动距离小于启动拖动的距离,则不执行拖动
}
//第一部分结束

// 创建拖动图像并应用虚化效果
QPixmap originalPixmap = pixmap(Qt::ReturnByValue);
QGraphicsScene scene;
QGraphicsPixmapItem *pixmapItem = scene.addPixmap(originalPixmap);
QGraphicsBlurEffect *blurEffect = new QGraphicsBlurEffect;
blurEffect->setBlurRadius(0); // 调整此值以改变虚化程度

pixmapItem->setGraphicsEffect(blurEffect);
//将模糊效果(blurEffect)应用于 pixmapItem,从而将其模糊化。

QImage blurredImage(scene.width(), scene.height(), QImage::Format_ARGB32);
QPainter painter(&blurredImage);
scene.render(&painter);
//将模糊场景捕获为图像

QPixmap blurredPixmap = QPixmap::fromImage(blurredImage);

// 实现拖动逻辑
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
mimeData->setText(text); // 将标签的文本作为MIME数据
drag->setMimeData(mimeData);
drag->setPixmap(blurredPixmap); // 使用虚化后的图像
drag->setHotSpot(QPoint(0, 0)); // 热区设置在图像的左上角,让图像跟随鼠标箭头
drag->exec();
}
QLabel::mouseMoveEvent(event);
}

介绍

map中右侧的可拖拽的图片。

main

main.cpp

#include "initial.h"
#include <QApplication>
#include <QDebug>
#include<QFile>
#include <QTextStream>
#include <QVBoxLayout>
#include <QStackedWidget>
int main(int argc, char *argv[])
{
srand(time(0));
QApplication app(argc, argv);
initial Start;
QDialogButtonBox::connect(&app, &QApplication::aboutToQuit, &Start,&initial::store);
Start.show();
return app.exec();

//获取应用数据目录
// QFile file("log.bin");

// QDataStream in(&file);
// if (!file.open(QIODevice::WriteOnly))
// {
// qDebug() << "无法打开文件";
// }
// int i=0;
// in<<i;
// file.close();

}

介绍

存在一个槽函数,用于在程序退出后存储所有的信息和询问游客是否注册