You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
391 lines
13 KiB
C++
391 lines
13 KiB
C++
#include "mainwindow.hpp"
|
|
#include "ui_mainwindow.h"
|
|
|
|
extern std::unique_ptr<QSettings> settings;
|
|
|
|
void MainWindow::clearConnected(std::set<std::vector<int>> *connected) {
|
|
QString text = "\u2605";
|
|
int n = connected->size();
|
|
int new_score = ui->lcdScore->intValue() + (n * (n-1));
|
|
ui->lcdScore->display(new_score);
|
|
for (auto i = connected->begin(); i != connected->end(); i++) {
|
|
buttonGrid[(*i)[0]][(*i)[1]]->setText(text);
|
|
}
|
|
qApp->processEvents();
|
|
usleep(550000);
|
|
for (auto i = connected->begin(); i != connected->end(); i++) {
|
|
game->deleteCell((*i)[0], (*i)[1]);
|
|
}
|
|
usleep(5000); // paranoia
|
|
refreshButtonGrid();
|
|
qApp->processEvents();
|
|
}
|
|
|
|
void MainWindow::refreshButtonGrid() {
|
|
for (int i = 0; i < rows; i++) {
|
|
for (int j = 0; j < columns; j++) {
|
|
buttonGrid[i][j]->setStyleSheet("color: #FFFFFF; Font : 30pt; background-color: " + game->getCell(i,j) + "; border: none;");
|
|
buttonGrid[i][j]->setText("");
|
|
}
|
|
}
|
|
MainWindow::setEnabled(false);
|
|
qApp->processEvents();
|
|
}
|
|
|
|
void MainWindow::checkColumn(int column) {
|
|
bool isEmpty;
|
|
isEmpty = true;
|
|
for (int row = 0; row < rows; row++) {
|
|
if (game->getCell(row, column) != "none")
|
|
isEmpty = false;
|
|
}
|
|
if (isEmpty) {
|
|
bubbleRight(column);
|
|
}
|
|
}
|
|
|
|
bool MainWindow::checkLeftoverMoves() {
|
|
for(int row = 0; row < rows; row++) {
|
|
for(int column = 0; column < columns; column++)
|
|
{
|
|
if (game->getCell(row,column) != "none") {
|
|
std::set<std::vector<int>> tset;
|
|
game->getConnected(&tset, game->getCell(row,column), row, column);
|
|
if (tset.size() > 1) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MainWindow::bubbleRight(int column) {
|
|
if (column < columns-1) {
|
|
for (int row = 0; row < rows; row++) {
|
|
QString tcolor = game->getCell(row, column);
|
|
game->setCell(row, column, game->getCell(row, column+1));
|
|
game->setCell(row, column+1, tcolor);
|
|
}
|
|
bubbleRight(column+1);
|
|
}
|
|
}
|
|
|
|
void MainWindow::bubbleUp(int row, int column) {
|
|
if (row > 0) {
|
|
QString tcolor = game->getCell(row, column);
|
|
game->setCell(row, column, game->getCell(row-1, column));
|
|
game->setCell(row-1, column, tcolor);
|
|
bubbleUp(row-1, column);
|
|
}
|
|
}
|
|
|
|
void MainWindow::bubbleBoxes(std::set<std::vector<int>> *connected) {
|
|
usleep(400000);
|
|
for (auto i = connected->begin(); i != connected->end(); i++) {
|
|
bubbleUp((*i)[0], (*i)[1]);
|
|
}
|
|
refreshButtonGrid();
|
|
qApp->processEvents();
|
|
for (int j = 0; j < columns; j++) {
|
|
for (int x = 0; x < columns; x++)
|
|
checkColumn(j);
|
|
}
|
|
refreshButtonGrid();
|
|
}
|
|
|
|
QMap<QPair<QString, QDateTime>, int> MainWindow::newEntry() {
|
|
QDialog entryDial;
|
|
entryDial.setPalette(MainWindow::palette());
|
|
|
|
QLabel *label1 = new QLabel("New top 10 score!");
|
|
QLabel *label2 = new QLabel("Enter your name:");
|
|
QLabel *label3 = new QLabel("Score:");
|
|
QLineEdit *lineEdit = new QLineEdit;
|
|
QString name = qgetenv("USER");
|
|
if (name.isEmpty())
|
|
name = qgetenv("USERNAME");
|
|
lineEdit->setText(name);
|
|
QString confirmed_name;
|
|
QPushButton *button = new QPushButton("Ok");
|
|
QLCDNumber *lcdNumber = new QLCDNumber();
|
|
lcdNumber->display(ui->lcdScore->intValue());
|
|
|
|
entryDial.connect(button, &QPushButton::clicked, &entryDial, [&]() {
|
|
confirmed_name = lineEdit->text();
|
|
entryDial.done(0);
|
|
});
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout;
|
|
QHBoxLayout *sub_layout1 = new QHBoxLayout;
|
|
QHBoxLayout *sub_layout2 = new QHBoxLayout;
|
|
layout->addWidget(label1);
|
|
layout->addLayout(sub_layout1);
|
|
sub_layout1->addWidget(label2);
|
|
sub_layout1->addWidget(lineEdit);
|
|
layout->addLayout(sub_layout2);
|
|
sub_layout2->addWidget(label3);
|
|
sub_layout2->addWidget(lcdNumber);
|
|
layout->addWidget(button, Qt::AlignRight);
|
|
entryDial.setLayout(layout);
|
|
|
|
entryDial.exec();
|
|
|
|
QMap<QPair<QString, QDateTime>, int> new_entry;
|
|
QPair<QString, QDateTime> new_key(confirmed_name, QDateTime::currentDateTime());
|
|
new_entry.insert(new_key, ui->lcdScore->intValue());
|
|
|
|
entryDial.disconnect();
|
|
return new_entry;
|
|
}
|
|
|
|
void MainWindow::processHighscore() {
|
|
QMap<QPair<QString, QDateTime>, int> entry = newEntry();
|
|
if(!highscore.empty() && highscore.size() == 10) {
|
|
QList<int> scores = highscore.values();
|
|
std::sort(scores.begin(), scores.end());
|
|
if (ui->lcdScore->intValue() <= *(scores.end()))
|
|
return;
|
|
|
|
auto smallest = highscore.keyValueBegin();
|
|
for (auto map_entry = highscore.keyValueBegin(); map_entry != highscore.keyValueEnd(); map_entry++) {
|
|
if (map_entry->second < smallest->second)
|
|
smallest = map_entry;
|
|
}
|
|
highscore.remove(smallest->first);
|
|
}
|
|
highscore.insert(entry);
|
|
|
|
QDir appdata = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
|
QFile highscoreCSV = QFile(appdata.filePath(csv_name));
|
|
if (!appdata.exists()) {
|
|
appdata.mkpath(appdata.absolutePath());
|
|
qDebug() << "Created data folder at " << appdata.absolutePath();
|
|
}
|
|
|
|
if (!highscoreCSV.open(QIODevice::WriteOnly)) {
|
|
qDebug() << "Error: Couldn't write new highscore.";
|
|
return;
|
|
}
|
|
|
|
QTextStream hs(&highscoreCSV);
|
|
for (auto key = highscore.keyValueBegin(); key != highscore.keyValueEnd(); key++){
|
|
hs << key->first.first << ";" << key->first.second.toString(Qt::DateFormat::ISODate) << ";" << key->second << Qt::endl;
|
|
}
|
|
|
|
highscoreCSV.close();
|
|
usleep(500); // paranoia
|
|
}
|
|
|
|
void MainWindow::readHighscore() {
|
|
highscore.clear();
|
|
QDir appdata = QDir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
|
|
QFile highscoreCSV = QFile(appdata.filePath(csv_name));
|
|
if (!appdata.exists()) {
|
|
appdata.mkpath(appdata.absolutePath());
|
|
qDebug() << "Created data folder at " << appdata.absolutePath();
|
|
}
|
|
if (!highscoreCSV.exists())
|
|
return;
|
|
if (!highscoreCSV.open(QIODevice::ReadOnly))
|
|
return;
|
|
|
|
QTextStream hs(&highscoreCSV);
|
|
QString line;
|
|
QStringList fields;
|
|
while (hs.readLineInto(&line)) {
|
|
fields = line.split(";");
|
|
QPair<QString, QDateTime> entry;
|
|
entry.first = fields[0];
|
|
entry.second = QDateTime::fromString(fields[1], Qt::ISODate);
|
|
highscore.insert(entry, fields[2].toInt());
|
|
}
|
|
|
|
highscoreCSV.close();
|
|
}
|
|
|
|
void MainWindow::showHighscore_triggered() {
|
|
readHighscore();
|
|
if (highscore.size() == 0) {
|
|
ui->statusBar->showMessage("There are no highscores yet.", 3000);
|
|
return;
|
|
}
|
|
|
|
QDialog highscoreDial;
|
|
highscoreDial.setPalette(MainWindow::palette());
|
|
|
|
QVBoxLayout *layout = new QVBoxLayout;
|
|
QLabel *title = new QLabel("<h1> Hall of Fame </h1>");
|
|
title->setAlignment(Qt::AlignCenter);
|
|
//title->set
|
|
layout->addWidget(title);
|
|
struct KeyValuePair {
|
|
QPair<QString, QDateTime> key;
|
|
int value;
|
|
};
|
|
std::vector<KeyValuePair> sorted_entries;
|
|
|
|
for (auto entry = highscore.begin(); entry != highscore.end(); entry++) {
|
|
KeyValuePair pair;
|
|
pair.key = entry.key();
|
|
pair.value = entry.value();
|
|
sorted_entries.push_back(pair);
|
|
}
|
|
|
|
std::sort(sorted_entries.begin(), sorted_entries.end(), [](const KeyValuePair& a, const KeyValuePair& b) {
|
|
return a.value > b.value;
|
|
});
|
|
|
|
QGridLayout *entry_layout = new QGridLayout;
|
|
QLabel *placeholder = new QLabel(" ");
|
|
for (unsigned long i = 1; i < sorted_entries.size()+1; i++) {
|
|
QLabel *entry_name = new QLabel(QString::fromStdString(std::to_string(i)) + ") <b>" + sorted_entries[i-1].key.first + "</b>");
|
|
QLCDNumber *entry_score = new QLCDNumber();
|
|
entry_score->display( sorted_entries[i-1].value);
|
|
QLabel *entry_datetime = new QLabel( sorted_entries[i-1].key.second.toString(Qt::DateFormat::TextDate));
|
|
entry_datetime->setAlignment(Qt::AlignRight);
|
|
entry_layout->addWidget(entry_name, i, 0);
|
|
entry_layout->addWidget(entry_score, i, 1);
|
|
entry_layout->addWidget(placeholder, i, 2);
|
|
entry_layout->addWidget(entry_datetime, i, 3);
|
|
}
|
|
layout->addLayout(entry_layout);
|
|
|
|
highscoreDial.setLayout(layout);
|
|
highscoreDial.exec();
|
|
}
|
|
|
|
void MainWindow::button_clicked(int row, int column) {
|
|
MainWindow::setEnabled(false);
|
|
if(game->getCell(row, column) != "none") {
|
|
std::set<std::vector<int>> connected;
|
|
game->getConnected(&connected, game->getCell(row, column), row, column);
|
|
if ( connected.size() > 1) {
|
|
clearConnected(&connected);
|
|
bubbleBoxes(&connected);
|
|
} else
|
|
ui->statusBar->showMessage("Only friends get Stars!", 3000);
|
|
}
|
|
MainWindow::setEnabled(true);
|
|
if (!checkLeftoverMoves()) {
|
|
gameOver();
|
|
}
|
|
}
|
|
|
|
void MainWindow::gameOver() {
|
|
ui->statusBar->showMessage("Game over.");
|
|
usleep(400000);
|
|
readHighscore();
|
|
if (rows == 9 && columns == 9 && game->getNumberOfColors() == 5 )
|
|
processHighscore();
|
|
showHighscore_triggered();
|
|
}
|
|
|
|
void MainWindow::newGame_triggered() {
|
|
gameOver(); // only for testing right now -- remove me!
|
|
ui->statusBar->clearMessage();
|
|
MainWindow::setEnabled(false);
|
|
QMessageBox newGameDialog;
|
|
newGameDialog.setText("Do you really want to start a new game?");
|
|
newGameDialog.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
|
|
if (newGameDialog.exec() == QMessageBox::Yes) {
|
|
game->initialiseGameMatrix(rows, columns);
|
|
refreshButtonGrid();
|
|
ui->lcdScore->display(0);
|
|
}
|
|
MainWindow::setEnabled(true);
|
|
if (!checkLeftoverMoves()) {
|
|
gameOver();
|
|
}
|
|
}
|
|
|
|
void MainWindow::initialiseGame() {
|
|
game->initialiseGameMatrix(rows, columns);
|
|
initialiseGameGrid();
|
|
ui->lcdScore->display(0);
|
|
}
|
|
|
|
void MainWindow::initialiseGameGrid() {
|
|
QSize button_size(max_width/columns, max_height/rows);
|
|
buttonGrid.clear();
|
|
|
|
for(int i = 0; i < rows; i++)
|
|
{
|
|
std::vector<QPushButton *> button_row;
|
|
for(int j = 0; j < columns; j++)
|
|
{
|
|
QPushButton * button = new QPushButton(this);
|
|
button->setFixedSize(button_size);
|
|
button->setStyleSheet("color: #FFFFFF; Font : 30pt; background-color: " + game->getCell(i,j) + "; border: none;");
|
|
ui->gameGridLayout->addWidget(button, i, j);
|
|
button_row.push_back(button);
|
|
|
|
connect(button, &QPushButton::clicked, button, [=, this](){
|
|
button_clicked(i, j);
|
|
});
|
|
}
|
|
buttonGrid.push_back(std::move(button_row));
|
|
}
|
|
}
|
|
|
|
void MainWindow::initialiseWindow() {
|
|
MainWindow::setWindowTitle("ThinkPink | SameGame in PINK by Isifluff");
|
|
MainWindow::setWindowIcon(QIcon(":/icons/ThinkPink.png"));
|
|
}
|
|
|
|
void MainWindow::initialiseMenuBar() {
|
|
QAction *new_game_action = ui->menuPlay->addAction("New Game");
|
|
connect(new_game_action, SIGNAL(triggered()), this, SLOT(newGame_triggered()));
|
|
ui->menuPlay->addSeparator();
|
|
QAction *show_highscore_action = ui->menuPlay->addAction("Highscores");
|
|
connect(show_highscore_action, SIGNAL(triggered()), this, SLOT(showHighscore_triggered()));
|
|
}
|
|
|
|
void MainWindow::refreshSizes() {
|
|
max_width = MainWindow::width();
|
|
max_height = MainWindow::height() - ui->menuBar->height() - ui->lcdScore->height() - ui->statusBar->height();
|
|
}
|
|
|
|
void MainWindow::setPalettes() {
|
|
QPalette palLight = QPalette();
|
|
QPalette palDark = QPalette();
|
|
const QBrush bgLightBrush = QBrush(0xfff0f3);
|
|
const QBrush bgDarkBrush = QBrush(0xffd1d9);
|
|
const QBrush textBrush = QBrush(0xa4133c);
|
|
auto setColorGroups = [](QPalette *pal, QBrush textBrush, QBrush bgBrush) -> void {
|
|
pal->setColorGroup(QPalette::Active, textBrush, bgBrush, textBrush, bgBrush, bgBrush, textBrush, textBrush, bgBrush, bgBrush);
|
|
pal->setColorGroup(QPalette::Inactive, textBrush, bgBrush, textBrush, bgBrush, bgBrush, textBrush, textBrush, bgBrush, bgBrush);
|
|
pal->setColorGroup(QPalette::Disabled, textBrush, bgBrush, textBrush, bgBrush, bgBrush, textBrush, textBrush, bgBrush, bgBrush);
|
|
};
|
|
setColorGroups(&palLight, textBrush, bgLightBrush);
|
|
setColorGroups(&palDark, textBrush, bgDarkBrush);
|
|
this->setPalette(palLight);
|
|
ui->menuPlay->setPalette(palLight);
|
|
ui->menuBar->setPalette(palDark);
|
|
ui->statusBar->setPalette(palLight);
|
|
}
|
|
|
|
MainWindow::MainWindow(QWidget *parent)
|
|
: QMainWindow(parent)
|
|
, ui(new Ui::MainWindow)
|
|
, rows(settings->value("size/rows", 9).toInt())
|
|
, columns(settings->value("size/columns", 9).toInt())
|
|
, max_width(800)
|
|
, max_height(519)
|
|
{
|
|
ui->setupUi(this);
|
|
setPalettes();
|
|
refreshSizes();
|
|
game = new SameGame(rows, columns);
|
|
initialiseGame();
|
|
initialiseWindow();
|
|
initialiseMenuBar();
|
|
}
|
|
|
|
MainWindow::~MainWindow()
|
|
{
|
|
delete game;
|
|
delete ui;
|
|
}
|
|
|