New solver
This commit is contained in:
parent
c696f62534
commit
fe3b10e35a
@ -21,6 +21,127 @@
|
|||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
|
||||||
namespace libqnono {
|
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()
|
CNonogram::CNonogram()
|
||||||
: m_Size(0, 0),
|
: m_Size(0, 0),
|
||||||
m_Data(NULL),
|
m_Data(NULL),
|
||||||
|
@ -27,6 +27,41 @@
|
|||||||
class QImage;
|
class QImage;
|
||||||
|
|
||||||
namespace libqnono {
|
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 {
|
class CNonogram {
|
||||||
public:
|
public:
|
||||||
typedef QVector<quint16> NumbersVector;
|
typedef QVector<quint16> NumbersVector;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -2,8 +2,36 @@
|
|||||||
#define LIBQCROSS_CNONOGRAMSOLVER_H
|
#define LIBQCROSS_CNONOGRAMSOLVER_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QSize>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
namespace libqnono {
|
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 CNonogram;
|
||||||
|
|
||||||
class CNonogramSolver : public QObject {
|
class CNonogramSolver : public QObject {
|
||||||
@ -20,59 +48,7 @@ namespace libqnono {
|
|||||||
protected:
|
protected:
|
||||||
enum MarkerType {CMT_UNMARKED = 0, CMT_MARKED = 1, CMT_CROSSED = 2, CMT_NONE = 3};
|
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;
|
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;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user