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:
Oliver Groß 2011-12-21 12:49:33 +01:00
parent 6aa6b59c88
commit 8ebd6975d7
21 changed files with 1049 additions and 253 deletions

View File

@ -22,7 +22,7 @@
#include <QDataStream>
#include <QFile>
namespace libqcross {
namespace libqnono {
//public:
CCrossPackage::CCrossPackage() {}
CCrossPackage::CCrossPackage(QString fileName) : m_FileName(fileName) {}

View File

@ -23,7 +23,7 @@
#include <QString>
#include <QList>
namespace libqcross {
namespace libqnono {
class CNonogram;
typedef QList<CNonogram *> QMonoPictureList;

View File

@ -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())

View File

@ -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;
};
}

View File

@ -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();

View File

@ -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;
};
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;
}
};
}

View File

@ -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);
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);
QColor markerColor = palette().color(QPalette::Highlight);
QColor errorColor = markerColor;
errorColor.setAlpha(128);
for (int j = 0; j < m_Picture->height(); j++) {
originY = m_OffsetY + m_HeaderHeight + j * m_BoxSize;
markerRect.moveTop(originY + m_MarkerOffset);
painter.setBrush(markerColor);
for (int i = 0; i < m_Picture->width(); i++) {
originX = m_OffsetX + m_HeaderWidth + i * m_BoxSize;
markerRect.moveLeft(originX + m_MarkerOffset);
switch (m_OverlayData[i][j]) {
case CMT_MARKED:
painter.fillRect(markerRect, painter.brush());
break;
case CMT_CROSSED:
if (m_Solved)
break;
for (int j = 0; j < m_Picture->height(); j++) {
originY = m_OffsetY + m_HeaderHeight + j * m_BoxSize;
markerRect.moveTop(originY + m_MarkerOffset);
if (m_ErrorAware && m_ErrorCount && i == m_LastErrorMark.x() && j == m_LastErrorMark.y()) {
switch (m_OverlayData[i][j]) {
case CMT_MARKED:
painter.fillRect(markerRect, painter.brush());
}
break;
case CMT_CROSSED:
if (m_Solved)
break;
painter.drawLine(markerRect.topLeft(), markerRect.bottomRight());
painter.drawLine(markerRect.bottomLeft(), markerRect.topRight());
break;
default:
break;
if (m_ErrorAware && m_ErrorCount && i == m_LastErrorMark.x() && j == m_LastErrorMark.y()) {
painter.setBrush(errorColor);
painter.fillRect(markerRect, painter.brush());
painter.setBrush(markerColor);
}
painter.drawLine(markerRect.topLeft(), markerRect.bottomRight());
painter.drawLine(markerRect.bottomLeft(), markerRect.topRight());
break;
default:
break;
}
}
}
}
// draw grid lines
painter.setPen(palette().color(QPalette::Dark));
for (int i = m_OffsetX + m_HeaderWidth; i < m_OffsetX + m_RasterWidth; i += m_BoxSize) {
@ -475,9 +577,13 @@ namespace qcross {
painter.drawLine(m_OffsetX + m_HeaderWidth, i, m_OffsetX + m_RasterWidth-1, i);
}
// draw numbers area
if (m_Paused)
painter.setPen(palette().color(QPalette::Shadow));
QFont font = painter.font();
font.setPixelSize(m_MarkerSize * 0.9);
painter.setFont(font);
for (int i = 0; i < m_Picture->width(); i++) {
@ -514,10 +620,19 @@ namespace qcross {
painter.drawLine(m_OffsetX, originY, m_OffsetX + m_RasterWidth-1, originY);
}
// draw message if needed
if (m_Message.type != Invalid) {
painter.drawText(m_HeaderWidth + m_OffsetX, m_HeaderHeight + m_OffsetY, m_Message.text);
QRect boxrect(m_HeaderWidth + m_OffsetX, m_HeaderHeight + m_OffsetY, m_RasterWidth - m_HeaderWidth, m_RasterHeight - m_HeaderHeight);
QColor fillColor = palette().color(QPalette::Base);
fillColor.setAlpha(220);
painter.fillRect(boxrect, fillColor);
font.setPixelSize(font.pixelSize() * 2);
painter.setFont(font);
painter.drawText(boxrect, Qt::AlignVCenter | Qt::AlignCenter | Qt::TextWordWrap, m_Message.text);
}
// painter.drawLine(m_OffsetX, m_OffsetY + m_RasterHeight, m_OffsetX + m_RasterWidth, m_OffsetY + m_RasterHeight);
}
/* void CCrossFieldWidget::updateCell(int x, int y) {
@ -570,12 +685,12 @@ namespace qcross {
m_OffsetX = (width() - m_RasterWidth) / 2;
m_OffsetY = (height() - m_RasterHeight) / 2;
int clockHeight = m_Notifier->isVisible() ? m_HeaderHeight - m_Notifier->sizeHint().height() /* * 3.0 / 4.0 */ : m_HeaderHeight;
int clockHeight = /*m_Notifier->isVisible() ? m_HeaderHeight - m_Notifier->sizeHint().height()*/ /* * 3.0 / 4.0 */ /*:*/ m_HeaderHeight;
if (m_Clock)
m_Clock->setGeometry(m_OffsetX, m_OffsetY, m_HeaderWidth, clockHeight);
if (m_Notifier && m_Notifier->isVisible())
m_Notifier->setGeometry(m_OffsetX, m_OffsetY + clockHeight, m_HeaderWidth, m_Notifier->sizeHint().height());
// if (m_Notifier && m_Notifier->isVisible())
// m_Notifier->setGeometry(m_OffsetX, m_OffsetY + clockHeight, m_HeaderWidth, m_Notifier->sizeHint().height());
}
void CCrossFieldWidget::mousePressEvent(QMouseEvent * event) {
@ -600,7 +715,7 @@ namespace qcross {
if (m_OverlayData[pressedX][pressedY] == m_MouseMark)
m_MouseMark = CMT_UNMARKED;
execMark(pressedX, pressedY);
execMark(pressedX, pressedY, m_MouseMark);
update();
}
@ -621,7 +736,7 @@ namespace qcross {
pressedY = (pressedY - m_HeaderHeight) / m_BoxSize;
if (m_OverlayData[pressedX][pressedY] != m_MouseMark) {
execMark(pressedX, pressedY);
execMark(pressedX, pressedY, m_MouseMark);
update();
}
}

View File

@ -27,8 +27,9 @@ class QLCDNumber;
class QFrame;
class QLabel;
namespace libqcross {
namespace libqnono {
class CNonogram;
class CNonogramSolver;
}
namespace qcross {
@ -37,7 +38,7 @@ namespace qcross {
class CCrossFieldWidget : public QWidget {
Q_OBJECT
public:
enum MessageType {Information, Warning, Critical, Invalid};
enum MessageType {Information = 1, Warning = 2, Critical = 3, Invalid = 0};
bool isPaused() const { return m_Paused; }
bool isSolved() const { return m_Solved; }
@ -46,17 +47,20 @@ namespace qcross {
int time() const { return m_Time; }
qint32 errorCount() const { return m_ErrorCount; }
CCrossFieldWidget(libqcross::CNonogram * picture, QWidget * parent = 0);
CCrossFieldWidget(libqnono::CNonogram * picture, QWidget * parent = 0);
~CCrossFieldWidget();
QPoint lastErrorMark() const { return m_LastErrorMark; }
void setPicture(libqcross::CNonogram * picture);
void setPicture(libqnono::CNonogram * picture);
void showMessage(const QString message = QString(), int timeout = 0, MessageType type = Information);
void applyState(QDataStream & stream);
void dumpState(QDataStream & stream);
public slots:
void mark(int x, int y, qcross::MarkerType type);
void mark(int x, int y, int type);
void setTime(int value);
void setErrorAware(bool value);
void setNumbersMarkable(bool value);
@ -81,7 +85,7 @@ namespace qcross {
QQueue<Message> m_Messages;
libqcross::CNonogram * m_Picture;
libqnono::CNonogram * m_Picture;
MarkerType ** m_OverlayData;
quint32 m_RemainingPixels;
@ -107,9 +111,9 @@ namespace qcross {
QLCDNumber * m_Clock;
QFrame * m_Notifier;
QLabel * m_NotifierIcon;
QLabel * m_NotifierText;
// QFrame * m_Notifier;
// QLabel * m_NotifierIcon;
// QLabel * m_NotifierText;
qint32 m_ErrorCount;
QPoint m_LastErrorMark;
@ -126,7 +130,7 @@ namespace qcross {
void timerEvent(QTimerEvent * event);
inline void updateTimeDisplay();
inline void execMark(int x, int y);
inline void execMark(int x, int y, MarkerType & marker);
void paintEvent(QPaintEvent * event);

View File

@ -28,16 +28,18 @@
#include <QDir>
#include <QInputDialog>
#include <libqcross/cnonogram.h>
#include <libqcross/ccrosspackage.h>
#include <libqnono/cnonogram.h>
#include <libqnono/cnonogramsolver.h>
#include <libqnono/ccrosspackage.h>
#include "constants.h"
#include "cgamewindow.h"
#include "ccrossfieldwidget.h"
#include "cnewgamedialog.h"
#include "chighscore.h"
namespace qcross {
using namespace libqcross;
using namespace libqnono;
//public
CGameWindow::CGameWindow(QWidget * parent) : QMainWindow(parent) {
m_Highscore = NULL;
@ -49,11 +51,13 @@ namespace qcross {
m_Field->setTime(42 * 60 + 23);
setCentralWidget(m_Field);
// m_Field->showMessage(tr("Welcome to QCross!"));
m_Field->showMessage(tr("Welcome to QCross!"));
createActions();
// statusBar()->show();
m_Solver = new CNonogramSolver(this);
connect(m_Solver, SIGNAL(markRequested(int, int, int)), m_Field, SLOT(mark(int, int, int)));
connect(m_Field, SIGNAL(solved()), this, SLOT(wonGame()));
connect(m_Field, SIGNAL(timeUp()), this, SLOT(lostGame()));
connect(m_Field, SIGNAL(markError()), this, SLOT(handleErrorMark()));
@ -73,6 +77,9 @@ namespace qcross {
currentMenu = menuBar()->addMenu(tr("&Game"));
currentMenu->addAction(tr("&New..."), this, SLOT(newGame()), Qt::CTRL + Qt::Key_N);
currentMenu->addSeparator();
currentMenu->addAction(tr("&Save..."), this, SLOT(saveGame()), Qt::CTRL + Qt::Key_N);
currentMenu->addAction(tr("&Load..."), this, SLOT(loadGame()), Qt::CTRL + Qt::Key_N);
currentMenu->addSeparator();
m_RestartGameAction = currentMenu->addAction(tr("&Restart"), this, SLOT(restartGame()), Qt::CTRL + Qt::Key_R);
m_RestartGameAction->setEnabled(false);
m_PauseGameAction = currentMenu->addAction(tr("&Pause"));
@ -82,8 +89,8 @@ namespace qcross {
m_PauseGameAction->setEnabled(false);
currentMenu->addSeparator();
currentMenu->addAction(tr("&Quit"), this, SLOT(close()), Qt::CTRL + Qt::Key_Q);
// currentMenu->addSeparator();
// currentMenu->addAction(tr("debug: win"), this, SLOT(wonGame()));
currentMenu->addSeparator();
currentMenu->addAction(tr("debug: solve"), this, SLOT(startSolver()));
currentToolBar = addToolBar(currentMenu->title());
currentToolBar->addActions(currentMenu->actions());
@ -97,33 +104,119 @@ namespace qcross {
void CGameWindow::newGame() {
bool notPaused = !m_Field->isPaused();
if (notPaused)
m_Field->pause();
pauseGame(true);
CNewGameDialog dialog;
if (dialog.exec() == QDialog::Accepted) {
if (m_Highscore)
delete m_Highscore;
m_Field->setPicture(NULL);
if (m_Picture)
delete m_Picture;
m_Highscore = dialog.takeHighscore();
m_PictureIndex = m_Highscore ? dialog.nonogramIndex() : -1;
m_Picture = dialog.takeNonogram();
m_Picture->updateNumbers();
CNonogram * newPicture = dialog.takeNonogram();
newPicture->updateNumbers();
m_PauseGameAction->setEnabled(true);
m_RestartGameAction->setEnabled(true);
m_Field->setPicture(m_Picture);
m_Field->setPicture(newPicture);
if (m_Picture)
delete m_Picture;
m_Picture = newPicture;
m_Field->resume();
m_Field->showMessage(tr("Game started!"), 1000);
}
else if (notPaused)
m_Field->resume();
else
pauseGame(false);
}
const char magicSaveGameHeader[] = {'C', 'R', 'S', 'V'};
void CGameWindow::saveGame() {
if (!m_Field->isPaused())
m_PauseGameAction->setChecked(true);
QString fileName = QFileDialog::getSaveFileName(this, tr("Save current game"),
QDir::homePath(), tr("QCross Saved games (*.csg)"));
qDebug("saving game state file: %s", fileName.toAscii().data());
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly))
return;
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_0);
out.writeRawData(magicSaveGameHeader, 4);
out << int(-1); // debug: m_PicutreIndex
out << *m_Picture;
m_Field->dumpState(out);
m_PauseGameAction->setChecked(false);
}
void CGameWindow::loadGame() {
if (!m_Field->isPaused())
m_PauseGameAction->setChecked(true);
QString fileName = QFileDialog::getOpenFileName(this, tr("Open saved game"),
QDir::homePath(), tr("QCross Saved games (*.csg)"));
qDebug("opening game state file: %s", fileName.toAscii().data());
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly))
return;
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_0);
char magicHeader[4];
in.readRawData(magicHeader, 4);
qDebug("checking magic header");
for (int i = 0; i < 4; i++) {
if (magicHeader[i] != magicSaveGameHeader[i])
return;
}
// picture index
in >> m_PictureIndex; qDebug("m_PictureIndex = %i", m_PictureIndex);
// delete current highscore
if (m_Highscore)
delete m_Highscore;
// package name
if (m_PictureIndex > -1) {
QString highscoreFileName, packageName;
in >> packageName; qDebug("packageName = %s", qPrintable(packageName));
in >> highscoreFileName; qDebug("highscoreFileName = %s", qPrintable(highscoreFileName));
// TODO handle save game porting correctly
m_Highscore = new CHighscore(0);
m_Highscore->setFileName(QCROSS_STRING_DATAPATH + QDir::separator() + highscoreFileName);
m_Highscore->open();
}
// picture
CNonogram * newPicture = new CNonogram(in);
m_Field->setPicture(newPicture);
if (m_Picture)
delete m_Picture;
m_Picture = newPicture;
m_Field->applyState(in);
m_PauseGameAction->setEnabled(true);
m_PauseGameAction->setChecked(false);
}
void CGameWindow::restartGame() {
@ -137,8 +230,8 @@ namespace qcross {
void CGameWindow::pauseGame(bool value) {
if (value) {
m_Field->showMessage(tr("Game paused."));
m_Field->pause();
m_Field->showMessage(tr("Game paused."));
}
else {
m_Field->showMessage(tr("Game resumed."), 1000);
@ -172,4 +265,12 @@ namespace qcross {
void CGameWindow::about() {
QMessageBox::about(this, tr("About"), tr("This is a still unfancy gui for solving nonograms."));
}
void CGameWindow::startSolver() {
m_Solver->setNonogram(m_Picture);
restartGame();
m_Solver->solve();
}
}

View File

@ -22,8 +22,9 @@
#include <QMainWindow>
namespace libqcross {
namespace libqnono {
class CNonogram;
class CNonogramSolver;
}
namespace qcross {
@ -40,8 +41,10 @@ namespace qcross {
~CGameWindow();
protected:
libqnono::CNonogramSolver * m_Solver;
CCrossFieldWidget * m_Field;
libqcross::CNonogram * m_Picture;
libqnono::CNonogram * m_Picture;
CHighscore * m_Highscore;
int m_PictureIndex;
@ -53,8 +56,10 @@ namespace qcross {
protected slots:
void newGame();
// void createPackage();
// void openPackageImage();
void saveGame();
void loadGame();
void restartGame();
void pauseGame(bool value);
@ -64,6 +69,8 @@ namespace qcross {
void handleErrorMark();
void about();
void startSolver();
};
}

View File

@ -17,8 +17,8 @@
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <libqcross/ccrosspackage.h>
#include <libqcross/cnonogram.h>
#include <libqnono/ccrosspackage.h>
#include <libqnono/cnonogram.h>
#include "cmaskedcrosspackagemodel.h"
#include "chighscore.h"
@ -28,7 +28,7 @@
#define COL_TIME 1
namespace qcross {
using namespace libqcross;
using namespace libqnono;
//public:
CMaskedCrossPackageModel::CMaskedCrossPackageModel(QObject * parent) :
CCrossPackageModel(parent), m_Highscore(NULL) {}

View File

@ -20,7 +20,7 @@
#ifndef QCROSS_CMASKEDCROSSPACKAGEMODEL_H
#define QCROSS_CMASKEDCROSSPACKAGEMODEL_H
#include <libqcross/ccrosspackagemodel.h>
#include <libqnono/ccrosspackagemodel.h>
#include <QSortFilterProxyModel>
namespace qcross {
@ -29,7 +29,7 @@ namespace qcross {
/**
@author Oliver Groß <z.o.gross@gmx.de>
*/
class CMaskedCrossPackageModel : public libqcross::CCrossPackageModel {
class CMaskedCrossPackageModel : public libqnono::CCrossPackageModel {
Q_OBJECT
public:
CMaskedCrossPackageModel(QObject * parent = 0);

View File

@ -25,10 +25,9 @@
#include <QFileDialog>
#include <QInputDialog>
#include <libqcross/ccrosspackagelistmodel.h>
// #include <libqcross/ccrosspackagemodel.h>
#include <libqcross/ccrosspackage.h>
#include <libqcross/cnonogram.h>
#include <libqnono/ccrosspackagelistmodel.h>
#include <libqnono/ccrosspackage.h>
#include <libqnono/cnonogram.h>
#include "cmaskedcrosspackagemodel.h"
#include "chighscore.h"
#include "cnewgamedialog.h"
@ -36,12 +35,12 @@
#include "common.h"
namespace qcross {
using namespace libqcross;
using namespace libqnono;
//public:
CNewGameDialog::CNewGameDialog(QWidget * parent, Qt::WindowFlags f) :
QDialog(parent, f),
m_Highscore(new CHighscore(0)),
m_Highscore(NULL),
m_Nonogram(NULL)
{
ui.setupUi(this);
@ -56,7 +55,7 @@ namespace qcross {
ui.buttonBox->addButton(importButton, QDialogButtonBox::ActionRole);
ui.buttonBox->addButton(openPicFileButton, QDialogButtonBox::ActionRole);
ui.packageList->setModel(new CCrossPackageListModel(QCROSS_STRING_DATAPATH));
ui.packageList->setModel(new CCrossPackageListModel(QCROSS_STRING_DATAPATH, "*" QCROSS_STRING_PACKAGE_EXT));
m_PicModel = new CMaskedCrossPackageModel();
m_PicProxyModel = new CMaskedCrossPackageProxyModel();
m_PicProxyModel->setSourceModel(m_PicModel);
@ -84,7 +83,7 @@ namespace qcross {
delete m_Nonogram;
}
/* libqcross::CNonogram * CNewGameDialog::selectedNonogramData() const {
/* libqnono::CNonogram * CNewGameDialog::selectedNonogramData() const {
QModelIndex selected = ui.picList->selectionModel()->selectedIndexes()[0];
return static_cast<CNonogram *>(selected.internalPointer());
}*/
@ -94,13 +93,13 @@ namespace qcross {
return selected.row();
}
libqcross::CCrossPackage * CNewGameDialog::selectedPackage() const {
libqnono::CCrossPackage * CNewGameDialog::selectedPackage() const {
QModelIndex selected = ui.packageList->selectionModel()->selectedIndexes()[0];
return static_cast<CCrossPackage *>(selected.internalPointer());
}
libqcross::CNonogram * CNewGameDialog::takeNonogram() {
libqcross::CNonogram * result;
libqnono::CNonogram * CNewGameDialog::takeNonogram() {
libqnono::CNonogram * result;
if (m_Nonogram) {
result = m_Nonogram;
@ -134,6 +133,9 @@ namespace qcross {
QString fileName = QFileDialog::getOpenFileName(this, tr("Select a package to import"),
QDir::homePath(), tr("QCross Package (*.cpk)"));
if (!fileName.isEmpty()) {
/* if (!File::exists(QCROSS_STRING_DATAPATH))
QDir::mkpath(QCROSS_STRING_DATAPATH);*/
QString newFileName = QCROSS_STRING_DATAPATH + QDir::separator() + fileName.section(QDir::separator(), -1);
if (QFile::copy(fileName, newFileName))
dynamic_cast<CCrossPackageListModel *>(ui.packageList->model())->update();
@ -169,6 +171,9 @@ namespace qcross {
m_PicModel->setHighscore(NULL);
m_PicModel->setPackage(package);
if (!m_Highscore)
m_Highscore = new CHighscore(0);
m_Highscore->setFileName(getHighscoreFileName(package->fileName()));
if (!m_Highscore->open()) {
qDebug("opening highscore file failed. will create a new one when nonogram is solved");

View File

@ -23,7 +23,7 @@
#include <QDialog>
#include "ui_picselect.h"
namespace libqcross {
namespace libqnono {
class CNonogram;
class CCrossPackage;
}
@ -43,9 +43,9 @@ namespace qcross {
~CNewGameDialog();
int nonogramIndex() const;
libqcross::CCrossPackage * selectedPackage() const;
libqnono::CCrossPackage * selectedPackage() const;
libqcross::CNonogram * takeNonogram();
libqnono::CNonogram * takeNonogram();
CHighscore * takeHighscore();
protected slots:
void importPackage();
@ -53,7 +53,7 @@ namespace qcross {
private:
Ui::picselect ui;
CHighscore * m_Highscore;
libqcross::CNonogram * m_Nonogram;
libqnono::CNonogram * m_Nonogram;
CMaskedCrossPackageModel * m_PicModel;
CMaskedCrossPackageProxyModel * m_PicProxyModel;
private slots:

View File

@ -21,8 +21,9 @@
#ifndef QCROSS_CONSTANTS_H
#define QCROSS_CONSTANTS_H
#include <libqcross/constants.h>
#include <libqnono/constants.h>
#define QCROSS_STRING_DATAPATH ((QDir::homePath() + QDir::separator()) + ".qcross")
#define QCROSS_STRING_PACKAGE_EXT ".cpk"
#endif

View File

@ -16,13 +16,13 @@
#include <QFileDialog>
#include <QInputDialog>
#include <libqcross/ccrosspackagemodel.h>
#include <libqcross/ccrosspackage.h>
#include <libqnono/ccrosspackagemodel.h>
#include <libqnono/ccrosspackage.h>
#include "cmainwindow.h"
namespace qcrossedit {
using namespace libqcross;
using namespace libqnono;
//public:
CMainWindow::CMainWindow(QWidget *parent) :
QMainWindow(parent),
@ -60,9 +60,11 @@ namespace qcrossedit {
//edit menu
menu = menuBar()->addMenu("&Edit");
menu->addAction("&Create empty nonogram...", this, SLOT(editCreateEmpty()));
menu->addAction("&Create nonogram from picture...", this, SLOT(editCreateFromPicture()));
menu->addAction("Create nonogram from &picture...", this, SLOT(editCreateFromPicture()));
menu->addSeparator();
menu->addAction("&Delete nongram", this, SLOT(editDelete()));
menu->addAction("&Rename nonogram", this, SLOT(editRename()));
menu->addAction("Set nonogram &time-out", this, SLOT(editSetTimeout()));
menu->addAction("&Delete nonogram", this, SLOT(editDelete()));
menu->addSeparator();
menu->addAction("Set Package&name...", this, SLOT(editSetPackageName()));
@ -180,6 +182,13 @@ namespace qcrossedit {
}
}
void CMainWindow::editRename() {
}
void CMainWindow::editSetTimeout() {
QInputDialog::getInt(this, tr("Set time-out for selected nonogram (in minutes)"));
}
void CMainWindow::editDelete() {
QModelIndexList selectedIndexes = m_PicListView->selectionModel()->selectedIndexes();
foreach (QModelIndex i, selectedIndexes)

View File

@ -14,7 +14,7 @@ class QTreeView;
// class QBitmap;
//class QMenu;
namespace libqcross {
namespace libqnono {
class CCrossPackage;
}
@ -33,7 +33,7 @@ namespace qcrossedit {
// QString m_File;
bool m_Unsaved;
libqcross::CCrossPackage * m_Package;
libqnono::CCrossPackage * m_Package;
/* QBitmap * m_Pics;
QString * m_PackName;*/
@ -51,6 +51,8 @@ namespace qcrossedit {
void editCreateEmpty();
void editCreateFromPicture();
void editRename();
void editSetTimeout();
void editDelete();
void editSetPackageName();