New solver

This commit is contained in:
Stefan Bühler 2012-04-11 15:01:54 +02:00
parent c696f62534
commit fe3b10e35a
4 changed files with 679 additions and 551 deletions

View File

@ -21,6 +21,127 @@
#include <QImage>
namespace libqnono {
static void boolsFromImage(bool ** & data, const QImage &image) {
int cols = image.width(), rows = image.height();
data = new bool*[cols];
for (int col = 0; col < cols; ++col) data[col] = new bool[rows];
for (int row = 0; row < rows; ++row) {
for (int col = 0; col < cols; ++col) {
data[col][row] = 0 == (image.pixel(col, row) & 0x00FFFFFF);
}
}
}
static void freeBools(const QSize & size, bool ** data) {
int cols = size.width();
for (int col = 0; col < cols; ++col) delete [] data[col];
delete[] data;
}
static const quint64 CNonogramNumbers_MAGIC = Q_UINT64_C(0xd33efcacc0050164);
CNonogramNumbers::CNonogramNumbers(const vv_num & rows, const vv_num & columns)
: m_rows(rows), m_columns(columns) {
}
CNonogramNumbers::CNonogramNumbers(const CNonogram & source)
: m_rows(source.height()), m_columns(source.width()) {
// remove the "0" blocks (they are used for otherwise empty lines)
for (int i = 0; i < source.height(); ++i) {
m_rows[i] = source.rowNumbers(i);
if (1 == m_rows[i].count() && 0 == m_rows[i][0]) m_rows[i].clear();
}
for (int i = 0; i < source.width(); ++i) {
m_columns[i] = source.columnNumbers(i);
if (1 == m_columns[i].count() && 0 == m_columns[i][0]) m_columns[i].clear();
}
}
CNonogramNumbers::CNonogramNumbers(QSize size, bool **data) {
calcFromImage(size, data);
}
CNonogramNumbers::CNonogramNumbers(const QImage & image) {
bool ** data = 0;
boolsFromImage(data, image);
calcFromImage(image.size(), data);
freeBools(image.size(), data);
}
void CNonogramNumbers::calcFromImage(QSize size, bool **data) {
int rows = size.height(), cols = size.width();
m_rows.clear(); m_rows.resize(rows);
m_columns.clear(); m_columns.resize(cols);
for (int row = 0; row < rows; ++row) {
quint16 *val = 0;
for (int col = 0; col < cols; ++col) {
bool b = data[col][row];
if (!val && b) {
m_rows[row].append(1);
val = &m_rows[row].last();
} else if (b) {
++(*val);
} else {
val = 0;
}
}
}
for (int col = 0; col < cols; ++col) {
quint16 *val = 0;
for (int row = 0; row < rows; ++row) {
bool b = data[col][row];
if (!val && b) {
m_columns[col].append(1);
val = &m_columns[col].last();
} else if (b) {
++(*val);
} else {
val = 0;
}
}
}
}
bool CNonogramNumbers::readFromStream(QDataStream & stream) {
quint64 magic;
stream >> magic;
if (CNonogramNumbers_MAGIC != magic || QDataStream::Ok != stream.status()) {
if (QDataStream::ReadPastEnd != stream.status()) stream.setStatus(QDataStream::ReadCorruptData);
return false;
}
stream >> m_rows >> m_columns;
return QDataStream::Ok == stream.status();
}
void CNonogramNumbers::writeToStream(QDataStream & stream) {
stream << CNonogramNumbers_MAGIC << m_rows << m_columns;
}
bool CNonogramNumbers::operator==(const CNonogramNumbers &other) const {
return m_rows == other.m_rows && m_columns == other.m_columns;
}
bool CNonogramNumbers::check(bool **data) const {
CNonogramNumbers tmp(size(), data);
return *this == tmp;
}
bool CNonogramNumbers::check(const QImage & image) const {
if (size() != image.size()) return FALSE;
CNonogramNumbers tmp(image);
return *this == tmp;
}
QDataStream & operator<<(QDataStream & stream, CNonogramNumbers & numbers) {
numbers.writeToStream(stream);
return stream;
}
QDataStream & operator>>(QDataStream & stream, CNonogramNumbers & numbers) {
numbers.readFromStream(stream);
return stream;
}
CNonogram::CNonogram()
: m_Size(0, 0),
m_Data(NULL),

View File

@ -27,6 +27,41 @@
class QImage;
namespace libqnono {
class CNonogram;
class CNonogramNumbers;
class CNonogramNumbers {
public:
typedef QVector<quint16> v_num;
typedef QVector<v_num> vv_num;
CNonogramNumbers(const vv_num & rows, const vv_num & columns);
CNonogramNumbers(const CNonogram & source);
CNonogramNumbers(QSize size, bool **data);
CNonogramNumbers(const QImage & image);
void calcFromImage(QSize size, bool **data);
bool readFromStream(QDataStream & stream);
void writeToStream(QDataStream & stream);
bool operator==(const CNonogramNumbers &other) const;
inline const vv_num & rows() const { return m_rows; }
inline const vv_num & columns() const { return m_columns; }
inline QSize size() const { return QSize(m_columns.count(), m_rows.count()); }
inline int width() const { return m_columns.count(); }
inline int height() const { return m_rows.count(); }
bool check(bool **data) const;
bool check(const QImage & image) const;
private:
vv_num m_rows, m_columns;
};
class CNonogram {
public:
typedef QVector<quint16> NumbersVector;

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,36 @@
#define LIBQCROSS_CNONOGRAMSOLVER_H
#include <QObject>
#include <QSize>
#include <QList>
namespace libqnono {
class CNonogramNumbers;
class CNonogramSolution {
public:
CNonogramSolution(QSize size, bool ** data)
: m_size(size), m_data(data) {
}
~CNonogramSolution() {
int cols = m_size.width();
for (int col = 0; col < cols; ++col) delete [] m_data[col];
delete[] m_data;
}
QSize size() const { return m_size; }
bool** data() { return m_data; }
private:
Q_DISABLE_COPY(CNonogramSolution)
QSize m_size;
bool ** m_data;
};
QList<CNonogramSolution*> solve(const CNonogramNumbers & numbers);
class CNonogram;
class CNonogramSolver : public QObject {
@ -20,59 +48,7 @@ namespace libqnono {
protected:
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();
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;
}
};
}