big ugly commit
- renamed library - added support for saving loading current game - added (still crappy) nonogram solver - some code cleanups
This commit is contained in:
parent
6aa6b59c88
commit
8ebd6975d7
@ -22,7 +22,7 @@
|
||||
#include <QDataStream>
|
||||
#include <QFile>
|
||||
|
||||
namespace libqcross {
|
||||
namespace libqnono {
|
||||
//public:
|
||||
CCrossPackage::CCrossPackage() {}
|
||||
CCrossPackage::CCrossPackage(QString fileName) : m_FileName(fileName) {}
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
|
||||
namespace libqcross {
|
||||
namespace libqnono {
|
||||
class CNonogram;
|
||||
|
||||
typedef QList<CNonogram *> QMonoPictureList;
|
||||
|
@ -22,10 +22,10 @@
|
||||
#include "cnonogram.h"
|
||||
#include "ccrosspackagelistmodel.h"
|
||||
|
||||
namespace libqcross {
|
||||
namespace libqnono {
|
||||
//public:
|
||||
CCrossPackageListModel::CCrossPackageListModel(QString dataPath, QObject * parent) : QAbstractItemModel(parent),
|
||||
m_DataPath(dataPath) {
|
||||
CCrossPackageListModel::CCrossPackageListModel(QString dataPath, QString dataFilter, QObject * parent) : QAbstractItemModel(parent),
|
||||
m_DataPath(dataPath), m_DataFilter(dataFilter) {
|
||||
update();
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ namespace libqcross {
|
||||
CCrossPackage * newPackage;
|
||||
|
||||
QDir workDir(m_DataPath);
|
||||
QStringList fileNames = workDir.entryList(QStringList("*.cpk"), QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
|
||||
QStringList fileNames = workDir.entryList(QStringList(m_DataFilter), QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
|
||||
foreach (QString fileName, fileNames) {
|
||||
newPackage = new CCrossPackage(workDir.filePath(fileName));
|
||||
if (newPackage->open())
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include <QAbstractItemModel>
|
||||
#include <QList>
|
||||
|
||||
namespace libqcross {
|
||||
namespace libqnono {
|
||||
class CCrossPackage;
|
||||
|
||||
/**
|
||||
@ -32,7 +32,7 @@ namespace libqcross {
|
||||
class CCrossPackageListModel : public QAbstractItemModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
CCrossPackageListModel(QString dataPath, QObject * parent = 0);
|
||||
CCrossPackageListModel(QString dataPath, QString dataFilter, QObject * parent = 0);
|
||||
~CCrossPackageListModel();
|
||||
|
||||
void update();
|
||||
@ -47,8 +47,9 @@ namespace libqcross {
|
||||
virtual bool hasChildren(const QModelIndex & parent = QModelIndex()) const;
|
||||
private:
|
||||
QString m_DataPath;
|
||||
QString m_DataFilter;
|
||||
|
||||
QList<libqcross::CCrossPackage *> m_PackageList;
|
||||
QList<libqnono::CCrossPackage *> m_PackageList;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
#define COL_NAME 0
|
||||
#define COL_TIME 1
|
||||
|
||||
namespace libqcross {
|
||||
namespace libqnono {
|
||||
QString formatedTime(quint32 seconds, bool showSeconds = false) {
|
||||
quint32 strippedSeconds = seconds % 60;
|
||||
quint8 minutes = seconds / 60;
|
||||
@ -67,7 +67,7 @@ namespace libqcross {
|
||||
setPackage(NULL);
|
||||
}
|
||||
|
||||
void CCrossPackageModel::setPackage(libqcross::CCrossPackage * package) {
|
||||
void CCrossPackageModel::setPackage(libqnono::CCrossPackage * package) {
|
||||
if (m_Package)
|
||||
m_Package->pictures().clear();
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
|
||||
namespace libqcross {
|
||||
namespace libqnono {
|
||||
class CCrossPackage;
|
||||
|
||||
/**
|
||||
@ -34,7 +34,7 @@ namespace libqcross {
|
||||
CCrossPackageModel(QObject * parent = 0);
|
||||
~CCrossPackageModel();
|
||||
|
||||
void setPackage(libqcross::CCrossPackage * package);
|
||||
void setPackage(libqnono::CCrossPackage * package);
|
||||
|
||||
virtual QModelIndex index(int row, int column = 0, const QModelIndex & parent = QModelIndex()) const;
|
||||
virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
|
||||
@ -53,7 +53,7 @@ namespace libqcross {
|
||||
virtual bool insertRows(int row, int count, const QModelIndex & parent = QModelIndex());
|
||||
virtual bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex());
|
||||
protected:
|
||||
libqcross::CCrossPackage * m_Package;
|
||||
libqnono::CCrossPackage * m_Package;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "cnonogram.h"
|
||||
#include <QImage>
|
||||
|
||||
namespace libqcross {
|
||||
namespace libqnono {
|
||||
CNonogram::CNonogram()
|
||||
: m_Size(0, 0),
|
||||
m_Data(NULL),
|
||||
@ -32,6 +32,14 @@ namespace libqcross {
|
||||
init();
|
||||
}
|
||||
|
||||
CNonogram::CNonogram(QImage & image) : m_Data(NULL), m_MaximumNumberCount(0) {
|
||||
loadFromImage(image);
|
||||
}
|
||||
|
||||
CNonogram::CNonogram(QDataStream & stream) : m_Data(NULL), m_MaximumNumberCount(0) {
|
||||
loadFromStream(stream);
|
||||
}
|
||||
|
||||
CNonogram::~CNonogram() {
|
||||
cleanup();
|
||||
}
|
||||
@ -42,9 +50,24 @@ namespace libqcross {
|
||||
|
||||
resize(image.size());
|
||||
|
||||
for (int i = 0; i < m_Size.width(); i++)
|
||||
for (int j = 0; j < m_Size.height(); j++)
|
||||
m_Data[i][j] = !(image.pixel(i, j) & 0x00FFFFFF);
|
||||
for (int iy = 0; iy < m_Size.height(); iy++)
|
||||
for (int ix = 0; ix < m_Size.width(); ix++)
|
||||
m_Data[ix][iy] = !(image.pixel(ix, iy) & 0x00FFFFFF);
|
||||
}
|
||||
|
||||
void CNonogram::loadFromStream(QDataStream & stream) {
|
||||
qDebug("loading picture from stream...");
|
||||
stream >> m_Name; qDebug("m_Name = %s", qPrintable(m_Name));
|
||||
int imageWidth, imageHeight;
|
||||
stream >> imageWidth; qDebug("imageWidth = %i", imageWidth);
|
||||
stream >> imageHeight; qDebug("imageHeight = %i", imageHeight);
|
||||
resize(QSize(imageWidth, imageHeight));
|
||||
|
||||
stream >> m_Timeout;
|
||||
|
||||
for (int iy = 0; iy < m_Size.height(); iy++)
|
||||
for (int ix = 0; ix < m_Size.width(); ix++)
|
||||
stream >> m_Data[ix][iy];
|
||||
}
|
||||
|
||||
void CNonogram::resize(QSize size) {
|
||||
@ -130,4 +153,23 @@ namespace libqcross {
|
||||
m_RowNumbers = new NumbersVector[m_Size.height()];
|
||||
m_ColumnNumbers = new NumbersVector[m_Size.width()];
|
||||
}
|
||||
|
||||
QDataStream & operator<<(QDataStream & stream, CNonogram & nonogram) {
|
||||
stream << nonogram.name();
|
||||
stream << nonogram.width();
|
||||
stream << nonogram.height();
|
||||
stream << nonogram.timeout();
|
||||
|
||||
for (int iy = 0; iy < nonogram.height(); iy++)
|
||||
for (int ix = 0; ix < nonogram.width(); ix++)
|
||||
stream << nonogram.pixel(ix, iy);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
QDataStream & operator>>(QDataStream & stream, CNonogram & nonogram) {
|
||||
nonogram.loadFromStream(stream);
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2008 by Oliver Groß *
|
||||
* z.o.gross@gmx.de *
|
||||
* Copyright (C) 2008 by Oliver Groß *
|
||||
* z.o.gross@gmx.de *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
@ -26,36 +26,40 @@
|
||||
|
||||
class QImage;
|
||||
|
||||
namespace libqcross {
|
||||
namespace libqnono {
|
||||
class CNonogram {
|
||||
public:
|
||||
typedef QVector<quint16> NumbersVector;
|
||||
|
||||
CNonogram();
|
||||
CNonogram(QSize size);
|
||||
CNonogram(QImage & image);
|
||||
CNonogram(QDataStream & stream);
|
||||
~CNonogram();
|
||||
|
||||
void loadFromImage(QImage & image);
|
||||
void loadFromStream(QDataStream & stream);
|
||||
void resize(QSize size);
|
||||
|
||||
QString name() const { return m_Name; }
|
||||
void setName(QString value) { m_Name = value; }
|
||||
inline QString name() const { return m_Name; }
|
||||
inline void setName(QString value) { m_Name = value; }
|
||||
|
||||
quint16 timeout() const { return m_Timeout; }
|
||||
inline quint16 timeout() const { return m_Timeout; }
|
||||
void setTimeout(quint16 value) { m_Timeout = value; }
|
||||
|
||||
int width() const { return m_Size.width(); }
|
||||
int height() const { return m_Size.height(); }
|
||||
inline QSize size() const { return m_Size; }
|
||||
inline int width() const { return m_Size.width(); }
|
||||
inline int height() const { return m_Size.height(); }
|
||||
|
||||
bool pixel(int x, int y) const { return m_Data[x][y]; }
|
||||
inline bool pixel(int x, int y) const { return m_Data[x][y]; }
|
||||
void setPixel(int x, int y, bool value);
|
||||
|
||||
NumbersVector & rowNumbers(int index) const { return m_RowNumbers[index]; }
|
||||
NumbersVector & columnNumbers(int index) const { return m_ColumnNumbers[index]; }
|
||||
|
||||
int maximumNumberCount() const { return m_MaximumNumberCount; }
|
||||
inline int maximumNumberCount() const { return m_MaximumNumberCount; }
|
||||
|
||||
quint32 blackPixels() const { return m_BlackPixels; }
|
||||
inline quint32 blackPixels() const { return m_BlackPixels; }
|
||||
|
||||
void updateNumbers();
|
||||
|
||||
@ -79,6 +83,9 @@ namespace libqcross {
|
||||
void cleanup();
|
||||
void init();
|
||||
};
|
||||
|
||||
QDataStream & operator<<(QDataStream & stream, CNonogram & nonogram);
|
||||
QDataStream & operator>>(QDataStream & stream, CNonogram & nonogram);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,12 +1,65 @@
|
||||
#include "cnonogramsolver.h"
|
||||
#include "cnonogram.h"
|
||||
|
||||
namespace libqcross {
|
||||
CNonogramSolver::CNonogramSolver(QObject * parent) : QObject(parent), m_Nonogram(NULL), m_OverlayData(NULL) {
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
|
||||
namespace libqnono {
|
||||
CNonogramSolver::CNonogramSolver(QObject * parent) : QObject(parent),
|
||||
m_Nonogram(NULL),
|
||||
|
||||
m_RowsOverlay(NULL),
|
||||
m_ColumnsOverlay(NULL),
|
||||
|
||||
m_OverlayData(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CNonogramSolver::~CNonogramSolver() {
|
||||
cleanup();
|
||||
if (m_Nonogram)
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void CNonogramSolver::setNonogram(CNonogram * nonogram) {
|
||||
if (m_Nonogram)
|
||||
cleanup();
|
||||
|
||||
m_Nonogram = nonogram;
|
||||
}
|
||||
|
||||
void CNonogramSolver::printOverlays() {
|
||||
qDebug("row overlays:");
|
||||
QString debugoutput;
|
||||
for (int i = 0; i < m_Nonogram->height(); i++) {
|
||||
if (i) debugoutput += '\n';
|
||||
for (int e = 0; e < m_RowsOverlay[i].numbersSize; e++) {
|
||||
debugoutput += ' ' + QString::number(m_RowsOverlay[i].numbers[e].borderLeft)
|
||||
+ '-' + QString::number(m_RowsOverlay[i].numbers[e].borderRight - 1);
|
||||
|
||||
if (m_RowsOverlay[i].numbers[e].finished)
|
||||
debugoutput += '*';
|
||||
|
||||
debugoutput += ' ';
|
||||
}
|
||||
}
|
||||
qDebug(qPrintable(debugoutput));
|
||||
|
||||
debugoutput.clear();
|
||||
|
||||
qDebug("column overlays:");
|
||||
for (int i = 0; i < m_Nonogram->width(); i++) {
|
||||
if (i) debugoutput += '\n';
|
||||
for (int e = 0; e < m_ColumnsOverlay[i].numbersSize; e++) {
|
||||
debugoutput += ' ' + QString::number(m_ColumnsOverlay[i].numbers[e].borderLeft)
|
||||
+ '-' + QString::number(m_ColumnsOverlay[i].numbers[e].borderRight - 1);
|
||||
|
||||
if (m_ColumnsOverlay[i].numbers[e].finished)
|
||||
debugoutput += '*';
|
||||
|
||||
debugoutput += ' ';
|
||||
}
|
||||
}
|
||||
qDebug(qPrintable(debugoutput));
|
||||
}
|
||||
|
||||
bool CNonogramSolver::solve() {
|
||||
@ -14,52 +67,461 @@ namespace libqcross {
|
||||
return false;
|
||||
|
||||
cleanup();
|
||||
prepare();
|
||||
|
||||
m_OverlayData = new int *[m_Nonogram->width()];
|
||||
for (int i = 0; i < m_Nonogram->width(); i++) {
|
||||
m_OverlayData[i] = new int[m_Nonogram->height()];
|
||||
for (int j = 0; j < m_Nonogram->height(); j++)
|
||||
m_OverlayData[i][j] = 0;
|
||||
qDebug("clearing trivial lines ...");
|
||||
|
||||
// nach trivial lösbaren Reihen suchen und diese füllen bzw. abkreuzen
|
||||
for (int i = 0; i < m_Nonogram->height(); i++) {
|
||||
if (m_RowsOverlay[i].numbersSize == 1) {
|
||||
if (m_RowsOverlay[i].numbers[0].entry == 0) {
|
||||
fillRow(i, CMT_CROSSED);
|
||||
m_RowsOverlay[i].numbers[0].finished = true;
|
||||
}
|
||||
else if (m_RowsOverlay[i].numbers[0].entry == m_Nonogram->height()) {
|
||||
fillRow(i, CMT_MARKED);
|
||||
m_RowsOverlay[i].numbers[0].finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_Nonogram->height(); i++)
|
||||
solveRow(i);
|
||||
for (int i = 0; i < m_Nonogram->width(); i++) {
|
||||
if (m_ColumnsOverlay[i].numbersSize == 1) {
|
||||
if (m_ColumnsOverlay[i].numbers[0].entry == 0) {
|
||||
fillColumn(i, CMT_CROSSED);
|
||||
m_ColumnsOverlay[i].numbers[0].finished = true;
|
||||
}
|
||||
else if (m_ColumnsOverlay[i].numbers[0].entry == m_Nonogram->width()) {
|
||||
fillColumn(i, CMT_MARKED);
|
||||
m_ColumnsOverlay[i].numbers[0].finished = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printOverlays();
|
||||
|
||||
qDebug("processing non-trivial lines...");
|
||||
|
||||
bool changed;
|
||||
int iter = 0;
|
||||
const int iter_max = 10;
|
||||
do {
|
||||
changed = false;
|
||||
|
||||
for (int l = 0; l < m_Nonogram->height(); l++)
|
||||
if (solveLine_ng(l, true))
|
||||
changed = true;
|
||||
|
||||
for (int i = 0; i < m_Nonogram->width(); i++)
|
||||
if (solveLine_ng(i, false))
|
||||
changed = true;
|
||||
|
||||
iter++;
|
||||
} while (changed && iter < iter_max);
|
||||
|
||||
// qDebug("needed %i iterations", iter);
|
||||
|
||||
printOverlays();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CNonogramSolver::solveLine_ng(int index, bool isRow) {
|
||||
LineOverlay * overlay = isRow ? &(m_RowsOverlay[index]) : &(m_ColumnsOverlay[index]);
|
||||
int rightMax = isRow ? m_Nonogram->width() : m_Nonogram->height();
|
||||
|
||||
NumberOverlay * number;
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (int i = 0; i < overlay->numbersSize; i++) {
|
||||
number = &(overlay->numbers[i]);
|
||||
|
||||
if (number->finished)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* |-start- null
|
||||
*
|
||||
* null -marked-> markierung
|
||||
* null -crossed-> kreuze
|
||||
* null -unmarked-> keine
|
||||
*
|
||||
* kreuze -marked-> markierung
|
||||
* kreuze -crossed-> kreuze
|
||||
* kreuze -unmarked-> keine
|
||||
*
|
||||
* keine -marked-> markierung
|
||||
* keine -crossed-> kreuzstop
|
||||
* keine -unmarked-> keine
|
||||
*
|
||||
* markierung -marked-> markierung
|
||||
* markierung -crossed-> kreuzstop
|
||||
* markierung -unmarked-> keine
|
||||
*
|
||||
* kreuzstop -stop-|
|
||||
* fertig -stop-|
|
||||
*
|
||||
* null : keine aktion
|
||||
* fertig : rechten rand stzen, als fertig markieren und stop
|
||||
* kreuze : linken rand anpassen
|
||||
* keine : keine aktion
|
||||
*
|
||||
* markierung : rechten rand anpassen
|
||||
* kreuzstop : rechten rand setzen und stop
|
||||
*
|
||||
*/
|
||||
|
||||
{
|
||||
enum{ST_NULL = 0, ST_NONE = 1, ST_CROSSES = 2, ST_MARK = 3, ST_FINISHED = 4, ST_CROSS_STOP = 5} state = ST_NULL;
|
||||
int f = number->borderLeft;
|
||||
MarkerType marker;
|
||||
while (f < number->borderRight && state < ST_FINISHED) {
|
||||
marker = static_cast<MarkerType>(m_OverlayData[isRow ? f : index][isRow ? index : f]);
|
||||
|
||||
switch (state) {
|
||||
case ST_NULL:
|
||||
case ST_CROSSES:
|
||||
switch (marker) {
|
||||
case CMT_MARKED: state = ST_MARK; break;
|
||||
case CMT_CROSSED: state = ST_CROSSES; break;
|
||||
case CMT_UNMARKED: state = ST_NONE; break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case ST_NONE:
|
||||
case ST_MARK:
|
||||
switch (marker) {
|
||||
case CMT_MARKED: state = ST_MARK; break;
|
||||
case CMT_CROSSED: state = ST_CROSS_STOP; break;
|
||||
case CMT_UNMARKED: state = ST_NONE; break;
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case ST_FINISHED:
|
||||
case ST_CROSS_STOP:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case ST_NONE:
|
||||
case ST_NULL:
|
||||
default:
|
||||
break;
|
||||
case ST_CROSSES:
|
||||
number->borderLeft = f + 1;
|
||||
break;
|
||||
case ST_MARK:
|
||||
if ((f < overlay->borderLeftDef(i + i, rightMax)) &&
|
||||
(overlay->borderRightDef(i - 1, 0) < f) &&
|
||||
(f + number->entry < number->borderRight))
|
||||
number->borderRight = f + number->entry;
|
||||
break;
|
||||
case ST_FINISHED:
|
||||
number->finished = true;
|
||||
number->borderRight = f + number->entry;
|
||||
if (i + 1 < overlay->numbersSize && overlay->numbers[i+1].borderLeft < number->borderRight + 1)
|
||||
overlay->numbers[i+1].borderLeft = number->borderRight + 1;
|
||||
break;
|
||||
case ST_CROSS_STOP:
|
||||
number->borderRight = f;
|
||||
if (i + 1 < overlay->numbersSize && overlay->numbers[i+1].borderLeft < number->borderRight + 1)
|
||||
overlay->numbers[i+1].borderLeft = number->borderRight + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
f++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
sicher markierbare Steine
|
||||
r - l < 2m - 1
|
||||
0 < l + m - r + m - 1
|
||||
0 < (l + m - 1) - (r - m)
|
||||
*/
|
||||
for (int k = number->borderRight - number->entry; k < number->borderLeft + number->entry; k++)
|
||||
mark(isRow ? k : index, isRow ? index : k, CMT_MARKED);
|
||||
|
||||
if (!number->finished && number->borderRight - number->borderLeft == number->entry)
|
||||
number->finished = true;
|
||||
|
||||
for (int g = overlay->borderRightDef(i - 1, 0); g < number->borderLeft; g++)
|
||||
mark(isRow ? g : index, isRow ? index : g, CMT_CROSSED);
|
||||
|
||||
for (int g = number->borderRight; g < overlay->borderLeftDef(i + 1, rightMax); g++)
|
||||
mark(isRow ? g : index, isRow ? index : g, CMT_CROSSED);
|
||||
|
||||
|
||||
result = result || overlay->dirty;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CNonogramSolver::cleanup() {
|
||||
if (m_OverlayData && m_Nonogram) {
|
||||
if (m_OverlayData) {
|
||||
for (int i = 0; i < m_Nonogram->width(); i++)
|
||||
delete[] m_OverlayData[i];
|
||||
delete[] m_OverlayData;
|
||||
}
|
||||
|
||||
if (m_RowsOverlay)
|
||||
delete[] m_RowsOverlay;
|
||||
|
||||
if (m_ColumnsOverlay)
|
||||
delete[] m_ColumnsOverlay;
|
||||
}
|
||||
|
||||
bool CNonogramSolver::solveRow(int /*y*/) {
|
||||
return false;
|
||||
// int left = 0;
|
||||
// int right = m_Nonogram->width()-1;
|
||||
//
|
||||
// foreach (int k, m_Nonogram->rowNumbers(y)) {
|
||||
// if (k == m_Nonogram->width())
|
||||
// for (int i = 0; )
|
||||
// m_OverlayData[i][y] = 1;
|
||||
// }
|
||||
inline void CNonogramSolver::mark(int x, int y, int marker) {
|
||||
if ((x < 0) || (y < 0) || (x > m_Nonogram->width() - 1) || (y > m_Nonogram->height() - 1) || m_OverlayData[x][y] == marker)
|
||||
return;
|
||||
|
||||
//
|
||||
// while (m_OverlayData[right][y] && left < right)
|
||||
// right++;
|
||||
//
|
||||
// if (left == right)
|
||||
// return true;
|
||||
//
|
||||
// if (m_Nonogram->rowNumbers(y)[0] == 0)
|
||||
// for (int i = left; i <= right; i++)
|
||||
// m_OverlayData[i][y] = MT_CROSSED;
|
||||
//
|
||||
// foreach (int k, m_Nonogram->rowNumbers(y)) {
|
||||
//
|
||||
// }
|
||||
emit markRequested(x, y, marker);
|
||||
m_OverlayData[x][y] = marker;
|
||||
|
||||
m_RowsOverlay[y].dirty = true;
|
||||
m_ColumnsOverlay[x].dirty = true;
|
||||
}
|
||||
|
||||
inline void CNonogramSolver::fillRow(int index, int marker) {
|
||||
for (int i = 0; i < m_Nonogram->width(); i++)
|
||||
mark(i, index, marker);
|
||||
}
|
||||
|
||||
inline void CNonogramSolver::fillColumn(int index, int marker) {
|
||||
for (int i = 0; i < m_Nonogram->height(); i++)
|
||||
mark(index, i, marker);
|
||||
}
|
||||
|
||||
void CNonogramSolver::prepare() {
|
||||
m_OverlayData = new int *[m_Nonogram->width()];
|
||||
|
||||
for (int i = 0; i < m_Nonogram->width(); i++) {
|
||||
m_OverlayData[i] = new int[m_Nonogram->height()];
|
||||
for (int j = 0; j < m_Nonogram->height(); j++)
|
||||
m_OverlayData[i][j] = static_cast<int>(CMT_UNMARKED);
|
||||
}
|
||||
|
||||
int leftSum, rightSum, numSize;
|
||||
|
||||
m_RowsOverlay = new LineOverlay [m_Nonogram->height()];
|
||||
|
||||
for (int i = 0; i < m_Nonogram->height(); i++) {
|
||||
m_RowsOverlay[i].numbersSize = m_Nonogram->rowNumbers(i).size();
|
||||
m_RowsOverlay[i].numbers = new NumberOverlay [m_RowsOverlay[i].numbersSize];
|
||||
|
||||
numSize = m_Nonogram->rowNumbers(i).size();
|
||||
|
||||
leftSum = 0;
|
||||
for (int j = 0; j < numSize; j++) {
|
||||
m_RowsOverlay[i].numbers[j].entry = m_Nonogram->rowNumbers(i).at(j);
|
||||
m_RowsOverlay[i].numbers[j].finished = false;
|
||||
m_RowsOverlay[i].numbers[j].borderRight = m_Nonogram->width();
|
||||
|
||||
m_RowsOverlay[i].numbers[j].borderLeft = leftSum + j;
|
||||
leftSum += m_RowsOverlay[i].numbers[j].entry;
|
||||
}
|
||||
|
||||
rightSum = 0;
|
||||
for (int j = numSize - 1; j > -1; j--) {
|
||||
m_RowsOverlay[i].numbers[j].borderRight -= rightSum;
|
||||
rightSum += m_RowsOverlay[i].numbers[j].entry + 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_ColumnsOverlay = new LineOverlay [m_Nonogram->width()];
|
||||
|
||||
for (int i = 0; i < m_Nonogram->width(); i++) {
|
||||
m_ColumnsOverlay[i].numbersSize = m_Nonogram->columnNumbers(i).size();
|
||||
m_ColumnsOverlay[i].numbers = new NumberOverlay [m_ColumnsOverlay[i].numbersSize];
|
||||
|
||||
numSize = m_Nonogram->columnNumbers(i).size();
|
||||
|
||||
leftSum = 0;
|
||||
for (int j = 0; j < numSize; j++) {
|
||||
m_ColumnsOverlay[i].numbers[j].borderRight = m_Nonogram->height();
|
||||
m_ColumnsOverlay[i].numbers[j].finished = false;
|
||||
m_ColumnsOverlay[i].numbers[j].entry = m_Nonogram->columnNumbers(i).at(j);
|
||||
|
||||
m_ColumnsOverlay[i].numbers[j].borderLeft = leftSum + j;
|
||||
leftSum += m_ColumnsOverlay[i].numbers[j].entry;
|
||||
}
|
||||
|
||||
rightSum = 0;
|
||||
for (int j = numSize - 1; j > -1; j--) {
|
||||
m_ColumnsOverlay[i].numbers[j].borderRight -= rightSum;
|
||||
rightSum += m_ColumnsOverlay[i].numbers[j].entry + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool CNonogramSolver::solveLine(int index, bool isRow) {
|
||||
LineOverlay * overlay = isRow ? &(m_RowsOverlay[index]) : &(m_ColumnsOverlay[index]);
|
||||
|
||||
bool result = false;
|
||||
|
||||
QString dbgOut;
|
||||
QTextStream dbg(&dbgOut);
|
||||
|
||||
dbg << "overlay ";
|
||||
if (isRow)
|
||||
dbg << "row ";
|
||||
else
|
||||
dbg << "col ";
|
||||
|
||||
dbg << index << ": ";
|
||||
|
||||
int length = 0;
|
||||
int offset = 0;
|
||||
for (int i = 0; i < overlay->numbersSize; i++) {
|
||||
if (overlay->numbers[i].finished) {
|
||||
dbg << "(fin)";
|
||||
continue;
|
||||
}
|
||||
|
||||
dbg << '(' << overlay->numbers[i].borderLeft << ", " << overlay->numbers[i].borderRight << "; ";
|
||||
|
||||
length = safeLength(&(overlay->numbers[i]));
|
||||
offset = overlay->numbers[i].entry - length + overlay->numbers[i].borderLeft;
|
||||
|
||||
dbg << length << ", " << offset << ") ";
|
||||
|
||||
if (length > 0) {
|
||||
if (isRow) {
|
||||
for (int j = 0; j < length; j++)
|
||||
mark(offset + j, index, CMT_MARKED);
|
||||
}
|
||||
else {
|
||||
for (int j = 0; j < length; j++)
|
||||
mark(index, offset + j, CMT_MARKED);
|
||||
}
|
||||
|
||||
if (length == overlay->numbers[i].entry) {
|
||||
if (isRow) {
|
||||
mark(overlay->numbers[i].borderLeft - 1, index, CMT_CROSSED);
|
||||
mark(overlay->numbers[i].borderRight, index, CMT_CROSSED);
|
||||
}
|
||||
else {
|
||||
mark(index, overlay->numbers[i].borderLeft - 1, CMT_CROSSED);
|
||||
mark(index, overlay->numbers[i].borderRight, CMT_CROSSED);
|
||||
}
|
||||
overlay->numbers[i].finished = true;
|
||||
}
|
||||
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << dbgOut;
|
||||
|
||||
if (fillGaps(index, isRow))
|
||||
return true;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool CNonogramSolver::fillGaps(int index, bool isRow) {
|
||||
LineOverlay * overlay = isRow ? &(m_RowsOverlay[index]) : &(m_ColumnsOverlay[index]);
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (isRow) {
|
||||
for (int i = 0; i < overlay->numbersSize + 1; i++) {
|
||||
for (int j = overlay->borderRightDef(i - 1, 0); j < overlay->borderLeftDef(i, m_Nonogram->width()); j++) {
|
||||
if (m_OverlayData[j][index] == 0) {
|
||||
mark(j, index, CMT_CROSSED);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < overlay->numbersSize + 1; i++) {
|
||||
for (int j = overlay->borderRightDef(i - 1, 0); j < overlay->borderLeftDef(i, m_Nonogram->height()); j++) {
|
||||
if (m_OverlayData[index][j] == 0) {
|
||||
mark(index, j, CMT_CROSSED);
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void gtSet(int & target, int value) {
|
||||
if (target > value)
|
||||
target = value;
|
||||
}
|
||||
|
||||
inline void ltSet(int & target, int value) {
|
||||
if (target < value)
|
||||
target = value;
|
||||
}
|
||||
|
||||
inline void CNonogramSolver::prepareBorders(LineOverlay * overlay) {
|
||||
for (int i = 1; i < overlay->numbersSize; i++)
|
||||
ltSet(overlay->numbers[i].borderLeft, overlay->numbers[i - 1].borderLeft + overlay->numbers[i - 1].entry + 1);
|
||||
|
||||
for (int i = overlay->numbersSize - 1; i > 0; i--)
|
||||
gtSet(overlay->numbers[i - 1].borderRight, overlay->numbers[i].borderRight - overlay->numbers[i].entry - 1);
|
||||
}
|
||||
|
||||
inline void CNonogramSolver::updateBorders(int index, bool isRow) {
|
||||
LineOverlay * overlay = isRow ? &(m_RowsOverlay[index]) : &(m_ColumnsOverlay[index]);
|
||||
|
||||
if (!overlay->dirty)
|
||||
return;
|
||||
|
||||
int marker = 0;
|
||||
|
||||
for (int i = 0; i < overlay->numbersSize; i++) {
|
||||
if (overlay->numbers[i].finished)
|
||||
continue;
|
||||
|
||||
int j = overlay->numbers[i].borderLeft;
|
||||
// int markedCount = 0;
|
||||
while (j < overlay->numbers[i].borderRight) {
|
||||
marker = (isRow ? m_OverlayData[j][index] : m_OverlayData[index][j]);
|
||||
switch (marker) {
|
||||
case CMT_CROSSED:
|
||||
if (overlay->numbers[i].borderLeft == j)
|
||||
overlay->numbers[i].borderLeft = j+1;
|
||||
else {
|
||||
if (j - overlay->numbers[i].borderLeft + 1 < j + overlay->numbers[i].entry)
|
||||
overlay->numbers[i].borderLeft = j+1;
|
||||
else
|
||||
overlay->numbers[i].borderRight = j;
|
||||
if (i < overlay->numbersSize-1)
|
||||
ltSet(overlay->numbers[i + 1].borderLeft, j);
|
||||
}
|
||||
break;
|
||||
case CMT_MARKED:
|
||||
gtSet(overlay->numbers[i].borderRight, j + overlay->numbers[i].entry);
|
||||
/* if (markedCount != -1)
|
||||
markedCount++;*/
|
||||
break;
|
||||
default:
|
||||
/* if (markedCount > 0) {
|
||||
markedCount = -1;
|
||||
ltSet(overlay->numbers[i].borderLeft, j - overlay->numbers[i].entry + 1);
|
||||
}*/
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
overlay->dirty = false;
|
||||
}
|
||||
|
||||
void CNonogramSolver::updateBorders() {
|
||||
for (int i = 0; i < m_Nonogram->height(); i++)
|
||||
updateBorders(i, true);
|
||||
|
||||
for (int i = 0; i < m_Nonogram->width(); i++)
|
||||
updateBorders(i, false);
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace libqcross {
|
||||
namespace libqnono {
|
||||
class CNonogram;
|
||||
|
||||
class CNonogramSolver : public QObject {
|
||||
@ -12,27 +12,67 @@ namespace libqcross {
|
||||
CNonogramSolver(QObject * parent = 0);
|
||||
~CNonogramSolver();
|
||||
|
||||
void setNonogram(CNonogram * nonogram) { m_Nonogram = nonogram; }
|
||||
void setNonogram(CNonogram * nonogram);
|
||||
public slots:
|
||||
bool solve();
|
||||
signals:
|
||||
void markRequested(int x, int y, int type);
|
||||
protected:
|
||||
// struct Range {
|
||||
// int left;
|
||||
// int right;
|
||||
//
|
||||
// Range() : left(-1), right(-1) {}
|
||||
// bool isNULL() { return left == -1; }
|
||||
// };
|
||||
enum MarkerType {CMT_UNMARKED = 0, CMT_MARKED = 1, CMT_CROSSED = 2, CMT_NONE = 3};
|
||||
|
||||
struct NumberOverlay {
|
||||
int borderLeft;
|
||||
int borderRight;
|
||||
|
||||
quint16 entry;
|
||||
bool finished;
|
||||
};
|
||||
|
||||
struct LineOverlay {
|
||||
NumberOverlay * numbers;
|
||||
int numbersSize;
|
||||
|
||||
bool dirty;
|
||||
|
||||
inline int borderLeftDef(int index, int def) {
|
||||
return (index > -1 && index < numbersSize) ? numbers[index].borderLeft : def;
|
||||
}
|
||||
|
||||
inline int borderRightDef(int index, int def) {
|
||||
return (index > -1 && index < numbersSize) ? numbers[index].borderRight : def;
|
||||
}
|
||||
|
||||
LineOverlay() : numbers(NULL), dirty(false) {}
|
||||
~LineOverlay() { if (numbers) delete[] numbers; }
|
||||
};
|
||||
|
||||
CNonogram * m_Nonogram;
|
||||
|
||||
LineOverlay * m_RowsOverlay;
|
||||
LineOverlay * m_ColumnsOverlay;
|
||||
|
||||
int ** m_OverlayData;
|
||||
|
||||
void cleanup();
|
||||
void prepare();
|
||||
|
||||
bool solveRow(int y);
|
||||
bool solveColumn(int x);
|
||||
inline void mark(int x, int y, int marker);
|
||||
inline void fillRow(int index, int marker);
|
||||
inline void fillColumn(int index, int marker);
|
||||
|
||||
void printOverlays();
|
||||
bool solveLine_ng(int index, bool isRow);
|
||||
|
||||
inline bool solveLine(int index, bool isRow);
|
||||
inline bool fillGaps(int index, bool isRow);
|
||||
inline void prepareBorders(LineOverlay * overlay);
|
||||
inline void updateBorders(int index, bool isRow);
|
||||
|
||||
void updateBorders();
|
||||
|
||||
inline int safeLength(NumberOverlay * overlay) {
|
||||
return (overlay->entry * 2) + overlay->borderLeft - overlay->borderRight;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,10 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
||||
***************************************************************************/
|
||||
#include "ccrossfieldwidget.h"
|
||||
#include <libqcross/cnonogram.h>
|
||||
|
||||
#include <libqnono/cnonogram.h>
|
||||
#include <libqnono/cnonogramsolver.h>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QMouseEvent>
|
||||
#include <QLCDNumber>
|
||||
@ -30,7 +33,7 @@
|
||||
#include <QApplication>
|
||||
|
||||
namespace qcross {
|
||||
using namespace libqcross;
|
||||
using namespace libqnono;
|
||||
|
||||
int min(int a, int b) {
|
||||
return (a < b) ? a : b;
|
||||
@ -54,28 +57,28 @@ namespace qcross {
|
||||
m_MessageTimeoutId(-1),
|
||||
m_Clock(NULL),
|
||||
m_ErrorCount(0),
|
||||
m_LastErrorMark(-1,-1)
|
||||
m_LastErrorMark(-1, -1)
|
||||
{
|
||||
m_Notifier = new QFrame(this);
|
||||
m_Notifier->setLineWidth(10);
|
||||
m_Notifier->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
|
||||
// m_Notifier = new QFrame(this);
|
||||
// m_Notifier->setLineWidth(10);
|
||||
// m_Notifier->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
|
||||
QPalette notifierPalette(QApplication::palette().color(QPalette::ToolTipBase));
|
||||
notifierPalette.setColor(QPalette::Text, QApplication::palette().color(QPalette::ToolTipText));
|
||||
|
||||
m_Notifier->setPalette(notifierPalette);
|
||||
m_Notifier->setAutoFillBackground(true);
|
||||
// m_Notifier->setPalette(notifierPalette);
|
||||
// m_Notifier->setAutoFillBackground(true);
|
||||
|
||||
QHBoxLayout * notifierLayout = new QHBoxLayout(m_Notifier);
|
||||
m_NotifierIcon = new QLabel(m_Notifier);
|
||||
m_NotifierText = new QLabel(m_Notifier);
|
||||
// QHBoxLayout * notifierLayout = new QHBoxLayout(m_Notifier);
|
||||
// m_NotifierIcon = new QLabel(m_Notifier);
|
||||
// m_NotifierText = new QLabel(m_Notifier);
|
||||
|
||||
m_NotifierText->setWordWrap(true);
|
||||
notifierLayout->addWidget(m_NotifierIcon);
|
||||
notifierLayout->addWidget(m_NotifierText);
|
||||
notifierLayout->addStretch();
|
||||
m_Notifier->setLayout(notifierLayout);
|
||||
// m_NotifierText->setWordWrap(true);
|
||||
// notifierLayout->addWidget(m_NotifierIcon);
|
||||
// notifierLayout->addWidget(m_NotifierText);
|
||||
// notifierLayout->addStretch();
|
||||
// m_Notifier->setLayout(notifierLayout);
|
||||
|
||||
m_Notifier->hide();
|
||||
// m_Notifier->hide();
|
||||
|
||||
m_Clock = new QLCDNumber(8, this);
|
||||
m_Clock->setVisible(m_Picture);
|
||||
@ -92,12 +95,15 @@ namespace qcross {
|
||||
CCrossFieldWidget::~CCrossFieldWidget() {
|
||||
cleanup();
|
||||
|
||||
delete m_Clock;
|
||||
// delete m_Clock;
|
||||
}
|
||||
|
||||
void CCrossFieldWidget::setPicture(CNonogram * picture) {
|
||||
cleanup();
|
||||
if (m_Picture)
|
||||
cleanup();
|
||||
|
||||
m_Picture = picture;
|
||||
|
||||
if (m_Picture) {
|
||||
m_LastErrorMark.setX(-1);
|
||||
m_LastErrorMark.setY(-1);
|
||||
@ -120,7 +126,7 @@ namespace qcross {
|
||||
}
|
||||
m_Clock->setVisible(m_Picture);
|
||||
}
|
||||
//beim Laden eines neuen Spiels nach einem beendeten wird das neue nicht automatisch gestartet (Restart nötig)
|
||||
|
||||
void CCrossFieldWidget::showMessage(const QString message, int timeout, MessageType type) {
|
||||
if (!message.isEmpty()) {
|
||||
Message newMessage;
|
||||
@ -134,15 +140,85 @@ namespace qcross {
|
||||
nextMessage();
|
||||
}
|
||||
|
||||
void CCrossFieldWidget::applyState(QDataStream & stream) {
|
||||
qDebug("trying to apply state...");
|
||||
qDebug("reading basic stuff:");
|
||||
|
||||
// error state
|
||||
stream >> m_ErrorAware; qDebug("m_ErrorAware = %i", int(m_ErrorAware));
|
||||
stream >> m_ErrorCount; qDebug("m_ErrorCount = %i", m_ErrorCount);
|
||||
|
||||
// time(out)
|
||||
stream >> m_Time; qDebug("m_Time = %i", m_Time);
|
||||
updateTimeDisplay();
|
||||
emit timeChanged(m_Time);
|
||||
|
||||
// messages
|
||||
int messageCount;
|
||||
stream >> messageCount; qDebug("messageCount = %i", messageCount);
|
||||
|
||||
m_Messages.clear();
|
||||
|
||||
unsigned char byteBuffer;
|
||||
for (int i = 0; i < messageCount; i++) {
|
||||
qDebug("message #%i:", i);
|
||||
stream >> byteBuffer; qDebug("type = %i", byteBuffer);
|
||||
m_Message.type = MessageType(byteBuffer);
|
||||
if (m_Message.type != Invalid) {
|
||||
stream >> m_Message.timeout; qDebug("timeout = %i", m_Message.timeout);
|
||||
stream >> m_Message.text; qDebug("text = %s", qPrintable(m_Message.text));
|
||||
|
||||
m_Messages.enqueue(m_Message);
|
||||
}
|
||||
}
|
||||
nextMessage();
|
||||
|
||||
// overlaydata
|
||||
for (int iy = 0; iy < m_Picture->height(); iy++) {
|
||||
for (int ix = 0; ix < m_Picture->width(); ix++) {
|
||||
stream >> byteBuffer;
|
||||
m_OverlayData[ix][iy] = MarkerType(byteBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CCrossFieldWidget::dumpState(QDataStream & stream) {
|
||||
if (!m_OverlayData || !m_Picture)
|
||||
return;
|
||||
|
||||
// error state
|
||||
stream << m_ErrorAware;
|
||||
stream << m_ErrorCount;
|
||||
|
||||
// time(out)
|
||||
stream << m_Time;
|
||||
|
||||
// messages
|
||||
// actually we should dump the message queue
|
||||
// for now only dump last displayed
|
||||
// TODO dump message queue
|
||||
stream << 1; // dummy message count
|
||||
stream << (unsigned char)(m_Message.type);
|
||||
if (m_Message.type != Invalid) {
|
||||
stream << m_Message.timeout;
|
||||
stream << m_Message.text;
|
||||
}
|
||||
|
||||
// overlaydata
|
||||
for (int iy = 0; iy < m_Picture->height(); iy++) {
|
||||
for (int ix = 0; ix < m_Picture->width(); ix++)
|
||||
stream << (unsigned char)(m_OverlayData[ix][iy]);
|
||||
}
|
||||
}
|
||||
|
||||
//public slots
|
||||
void CCrossFieldWidget::mark(int x, int y, qcross::MarkerType type) {
|
||||
void CCrossFieldWidget::mark(int x, int y, int type) {
|
||||
if (type == CMT_NONE || x < 0 || x >= m_Picture->width() || y < 0 || y >= m_Picture->height())
|
||||
return;
|
||||
|
||||
if (type == CMT_MARKED && checkNoError(x, y))
|
||||
m_OverlayData[x][y] = CMT_MARKED;
|
||||
else
|
||||
m_OverlayData[x][y] = type;
|
||||
MarkerType marker = static_cast<qcross::MarkerType>(type);
|
||||
|
||||
execMark(x, y, marker);
|
||||
}
|
||||
|
||||
void CCrossFieldWidget::setTime(int value) {
|
||||
@ -154,6 +230,7 @@ namespace qcross {
|
||||
|
||||
if (m_ErrorAware && !m_Time) {
|
||||
killTimer(m_TimerId);
|
||||
m_TimerId = -1;
|
||||
m_Paused = true;
|
||||
emit timeUp();
|
||||
}
|
||||
@ -182,6 +259,17 @@ namespace qcross {
|
||||
return;
|
||||
|
||||
killTimer(m_TimerId);
|
||||
m_TimerId = -1;
|
||||
|
||||
if (m_Message.type != Invalid) {
|
||||
m_Messages.enqueue(m_Message);
|
||||
|
||||
if (m_MessageTimeoutId != -1) {
|
||||
killTimer(m_MessageTimeoutId);
|
||||
m_MessageTimeoutId = -1;
|
||||
}
|
||||
}
|
||||
|
||||
m_Paused = true;
|
||||
setEnabled(false);
|
||||
}
|
||||
@ -205,31 +293,33 @@ namespace qcross {
|
||||
|
||||
if (m_Messages.isEmpty()) {
|
||||
m_Message.type = Invalid;
|
||||
// m_Notifier->hide();
|
||||
// updateMetrics();
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
Message m_Next = m_Messages.dequeue();
|
||||
m_Message = m_Messages.dequeue();
|
||||
update();
|
||||
|
||||
// switch (next.type) {
|
||||
// case Information:
|
||||
// m_NotifierIcon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxInformation).pixmap(22, 22));
|
||||
// break;
|
||||
// case Warning:
|
||||
// m_NotifierIcon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(22, 22));
|
||||
// break;
|
||||
// case Critical:
|
||||
// m_NotifierIcon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(22, 22));
|
||||
// break;
|
||||
// default:
|
||||
// break;
|
||||
// }
|
||||
/* switch (m_Message.type) {
|
||||
case Information:
|
||||
m_NotifierIcon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxInformation).pixmap(22, 22));
|
||||
break;
|
||||
case Warning:
|
||||
m_NotifierIcon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxWarning).pixmap(22, 22));
|
||||
break;
|
||||
case Critical:
|
||||
m_NotifierIcon->setPixmap(style()->standardIcon(QStyle::SP_MessageBoxCritical).pixmap(22, 22));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// m_NotifierText->setText(next.text);
|
||||
m_NotifierText->setText(m_Message.text);
|
||||
|
||||
// m_Notifier->show();
|
||||
// updateMetrics();
|
||||
m_Notifier->show();
|
||||
updateMetrics();*/
|
||||
|
||||
if (m_Message.timeout)
|
||||
m_MessageTimeoutId = startTimer(m_Message.timeout);
|
||||
@ -259,8 +349,16 @@ namespace qcross {
|
||||
}
|
||||
|
||||
void CCrossFieldWidget::cleanup() {
|
||||
killTimer(m_TimerId);
|
||||
killTimer(m_MessageTimeoutId);
|
||||
qDebug("m_TimerId = %i m_MessageTimeoutId = %i", m_TimerId, m_MessageTimeoutId);
|
||||
if (m_TimerId != -1) {
|
||||
killTimer(m_TimerId);
|
||||
m_TimerId = -1;
|
||||
}
|
||||
|
||||
if (m_MessageTimeoutId != -1) {
|
||||
killTimer(m_MessageTimeoutId);
|
||||
m_MessageTimeoutId = -1;
|
||||
}
|
||||
|
||||
if (m_OverlayData) {
|
||||
for (int i = 0; i < m_Picture->width(); i++)
|
||||
@ -321,27 +419,24 @@ namespace qcross {
|
||||
m_Clock->display(time);
|
||||
}
|
||||
|
||||
void CCrossFieldWidget::execMark(int x, int y) {
|
||||
/* if (m_OverlayData[x][y] == m_MouseMark)
|
||||
return;*/
|
||||
|
||||
switch (m_MouseMark) {
|
||||
void CCrossFieldWidget::execMark(int x, int y, MarkerType & marker) {
|
||||
switch (marker) {
|
||||
case CMT_MARKED:
|
||||
if (m_Picture->pixel(x, y)) {
|
||||
m_RemainingPixels--;
|
||||
m_OverlayData[x][y] = m_MouseMark;
|
||||
}
|
||||
else if (m_ErrorAware) {
|
||||
m_ErrorCount++;
|
||||
m_MouseMark = CMT_NONE;
|
||||
m_OverlayData[x][y] = CMT_CROSSED;
|
||||
m_LastErrorMark.setX(x);
|
||||
m_LastErrorMark.setY(y);
|
||||
emit markError();
|
||||
m_OverlayData[x][y] = marker;
|
||||
}
|
||||
else {
|
||||
m_ErrorCount++;
|
||||
m_OverlayData[x][y] = m_MouseMark;
|
||||
if (m_ErrorAware) {
|
||||
m_OverlayData[x][y] = CMT_CROSSED;
|
||||
marker = CMT_NONE;
|
||||
m_LastErrorMark.setX(x);
|
||||
m_LastErrorMark.setY(y);
|
||||
emit markError();
|
||||
}
|
||||
else
|
||||
m_OverlayData[x][y] = marker;
|
||||
}
|
||||
break;
|
||||
case CMT_CROSSED:
|
||||
@ -354,11 +449,11 @@ namespace qcross {
|
||||
if (m_OverlayData[x][y] == CMT_MARKED) {
|
||||
if (m_Picture->pixel(x, y))
|
||||
m_RemainingPixels++;
|
||||
else
|
||||
else if (!m_ErrorAware)
|
||||
m_ErrorCount--;
|
||||
}
|
||||
|
||||
m_OverlayData[x][y] = m_MouseMark;
|
||||
m_OverlayData[x][y] = marker;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -366,6 +461,7 @@ namespace qcross {
|
||||
|
||||
if (!m_RemainingPixels && (m_ErrorAware || !m_ErrorCount)) {
|
||||
killTimer(m_TimerId);
|
||||
m_TimerId = -1;
|
||||
m_Paused = true;
|
||||
m_Solved = true;
|
||||
emit solved();
|
||||
@ -387,6 +483,7 @@ namespace qcross {
|
||||
int gridWidth = m_RasterWidth - m_HeaderWidth;
|
||||
int gridHeight = m_RasterHeight - m_HeaderHeight;
|
||||
|
||||
// draw background
|
||||
{
|
||||
const int delta = 5 * m_BoxSize;
|
||||
|
||||
@ -395,76 +492,81 @@ namespace qcross {
|
||||
int deltaX = delta;
|
||||
int deltaY;
|
||||
|
||||
bool useBase = false;
|
||||
bool useBaseX;
|
||||
bool useBaseY = true;
|
||||
|
||||
while (offsetX < gridWidth) {
|
||||
offsetY = 0;
|
||||
deltaY = delta;
|
||||
while (offsetY < gridHeight) {
|
||||
painter.fillRect(originX + offsetX, originY + offsetY, deltaX, deltaY,
|
||||
palette().color(useBase ? QPalette::Base : QPalette::AlternateBase));
|
||||
|
||||
useBase = !useBase;
|
||||
|
||||
offsetY += delta;
|
||||
|
||||
if (gridWidth - offsetY < delta)
|
||||
deltaY = gridWidth - offsetY;
|
||||
}
|
||||
|
||||
useBase = !useBase;
|
||||
|
||||
offsetX += delta;
|
||||
|
||||
if (gridWidth - offsetX < delta)
|
||||
deltaX = gridWidth - offsetX;
|
||||
|
||||
offsetY = 0;
|
||||
deltaY = delta;
|
||||
|
||||
useBaseX = useBaseY;
|
||||
while (offsetY < gridHeight) {
|
||||
if (gridHeight - offsetY < delta)
|
||||
deltaY = gridHeight - offsetY;
|
||||
|
||||
painter.fillRect(originX + offsetX, originY + offsetY, deltaX, deltaY,
|
||||
palette().color(useBaseX ? QPalette::Base : QPalette::AlternateBase));
|
||||
|
||||
useBaseX = !useBaseX;
|
||||
|
||||
offsetY += deltaY;
|
||||
}
|
||||
|
||||
useBaseY = !useBaseY;
|
||||
|
||||
offsetX += deltaX;
|
||||
}
|
||||
}
|
||||
|
||||
painter.setBrush(palette().color(QPalette::Highlight));
|
||||
|
||||
QFont font = painter.font();
|
||||
font.setPixelSize(m_MarkerSize * 0.9);
|
||||
|
||||
// draw markers and crosses
|
||||
{
|
||||
QPen pen;
|
||||
|
||||
pen.setWidth(m_MarkerSize / 10);
|
||||
|
||||
pen.setWidth(m_MarkerSize / 8);
|
||||
painter.setPen(pen);
|
||||
}
|
||||
|
||||
QRectF markerRect(m_MarkerOffset, m_MarkerOffset, m_MarkerSize, m_MarkerSize);
|
||||
|
||||
for (int i = 0; i < m_Picture->width(); i++) {
|
||||
originX = m_OffsetX + m_HeaderWidth + i * m_BoxSize;
|
||||
markerRect.moveLeft(originX + m_MarkerOffset);
|
||||
|
||||
for (int j = 0; j < m_Picture->height(); j++) {
|
||||