Commit a8083240 authored by Ian Wadham's avatar Ian Wadham

Add experimental code to display Mathdoku and Killer Sudoku puzzles.

parent fc5beae7
......@@ -93,7 +93,10 @@ void Renderer::fillNameHashes() {
m_borderTypes << "column";
m_borderTypes << "block";
m_borderTypes << "special";
m_borderTypes << "special";
// IDW test. m_borderTypes << "special";
// m_borderTypes << "special_h"; // IDW test.
m_borderTypes << "block"; // IDW test.
// m_borderTypes << "cage"; // IDW test.
m_borderTypes << "special";
m_borderTypes << "special";
m_borderTypes << QString();
......@@ -101,7 +104,8 @@ void Renderer::fillNameHashes() {
m_borderTypes << "column_h";
m_borderTypes << "block_h";
m_borderTypes << "special_h";
m_borderTypes << "special_h";
// IDW test. m_borderTypes << "special_h";
m_borderTypes << "block_h";
m_borderTypes << "special_h";
m_borderTypes << "special_h";
m_specialNames << "cell";
......@@ -301,7 +305,8 @@ QPixmap Renderer::renderMarker(int symbol, int range, int size) const {
QPixmap Renderer::renderMarkerOn(QPixmap pixmap, int symbol, int range, int color) const {
// TODO maybe it would be good to directly integrate the renderMarker implementation and
// make renderMarker be based on this method. (same for renderSymbol and renderSymbolOn)
int size = pixmap.width();
// IDW TODO - Use smaller size in Mathdoku and Killer only.
int size = pixmap.width() * 8 / 10; // IDW test. ;
QPixmap symbolPixmap = renderMarker(symbol, range, size);
if(color) {
QPainter p(&symbolPixmap);
......@@ -314,7 +319,10 @@ QPixmap Renderer::renderMarkerOn(QPixmap pixmap, int symbol, int range, int colo
return symbolPixmap;
} else {
QPainter p(&pixmap);
p.drawPixmap(0, 0, symbolPixmap);
// IDW TODO - Use offset from 0,0 in Mathdoku and Killer only.
// IDW test. p.drawPixmap(0, 0, symbolPixmap);
int offset = (size + 10)/10; // IDW test.
p.drawPixmap(offset, 2*offset, symbolPixmap); // IDW test.
p.end();
return pixmap;
}
......
......@@ -37,6 +37,7 @@ enum GroupType {
GroupColumn = 0x02,
GroupBlock = 0x03,
GroupSpecial = 0x04,
GroupCage = 0x05, // IDW test.
GroupUnhighlightedMask = 0x07,
GroupHighlight = 0x08
};
......@@ -97,12 +98,15 @@ private:
private:
void fillNameHashes();
private:
// TODO - The next 6 data items are unused.
/*
bool m_hasRowAndColumn : 1;
bool m_hasRowAndColumnHighlight : 1;
bool m_hasBlock : 1;
bool m_hasBlockHighlight : 1;
bool m_hasSpecial : 1;
bool m_hasSpecialHighlight : 1;
*/
QVector<QString> m_borderNames;
QVector<QString> m_borderTypes;
QVector<QString> m_specialNames;
......
......@@ -52,6 +52,7 @@ public:
QPoint pos() const { return m_pos; }
void showCursor(QGraphicsItem* cursor);
void setType(SpecialType type);
void setCageLabel (const QString cageLabel);
void setValues(QVector<ColoredValue> values);
protected:
......@@ -64,6 +65,7 @@ private:
QPoint m_pos;
SpecialType m_type;
QVector<ColoredValue> m_values;
QString m_cageLabel;
int m_id;
int m_size;
int m_range;
......@@ -123,6 +125,10 @@ void CellGraphicsItem::setValues(QVector<ColoredValue> values) {
updatePixmap();
}
void CellGraphicsItem::setCageLabel(const QString cageLabel) {
m_cageLabel = cageLabel;
}
void CellGraphicsItem::updatePixmap() {
if(m_size == 0) return;
......@@ -148,6 +154,22 @@ void CellGraphicsItem::updatePixmap() {
} break;
default: break; // TODO maybe assert as this is not allowed to occur
}
if (! m_cageLabel.isEmpty()) {
// TODO - Do this in gui/views/renderer.cpp.
// TODO - More work on layout of targets, markers and symbols.
// TODO - Leave everything unchanged for pure Sudoku puzzles.
// TODO - Do font setup once during resize? Put 0+-x/ in themes?
// TODO - Draw a background rectangle for the target text?
int size = pic.width();
QPainter p(&pic);
p.setPen(QString("white")); // TODO - Scribble needs black?
QFont f = p.font();
f.setBold(true);
f.setPixelSize((size+5)/6);
p.setFont(f);
p.drawText(size/6, (size+4)/5, m_cageLabel);
p.end();
}
setPixmap(pic);
show();
......@@ -163,8 +185,9 @@ struct GroupGraphicItemSegment {
class GroupGraphicsItem : public QGraphicsItemGroup {
public:
GroupGraphicsItem(QVector<QPoint> cells);
GroupGraphicsItem(QVector<QPoint> cells, bool isCage = false);
~GroupGraphicsItem();
void hideBlockBorder (bool visible);
public:
void resize(int gridSize, bool highlight);
void setHighlight(bool highlight);
......@@ -178,16 +201,26 @@ private:
GroupTypes m_type;
QVector<QPoint> m_cells;
QVector<GroupGraphicItemSegment> m_segments;
bool m_isCage; // Is the group a cage, as in Killer Sudoku or Mathdoku?
bool m_borderVisible;
};
GroupGraphicsItem::GroupGraphicsItem(QVector<QPoint> cells) {
GroupGraphicsItem::GroupGraphicsItem(QVector<QPoint> cells, bool isCage) {
m_cells = cells;
m_isCage = isCage;
m_borderVisible = true;
setEnabled(false);
setAcceptedMouseButtons(0);
detectType();
if (isCage) {
// Draw border around cage, even if it is all in one row or column.
// IDW test. m_type = GroupBlock;
m_type = GroupCage; // IDW test.
setZValue(4); // IDW test.
}
createContour();
if(!m_cells.contains(QPoint(1,1))) setHighlight(false);
......@@ -201,6 +234,12 @@ GroupGraphicsItem::~GroupGraphicsItem() {
}
}
void GroupGraphicsItem::hideBlockBorder (bool hide) {
if ((m_type == GroupBlock) && hide) {
m_borderVisible = false;
}
}
void GroupGraphicsItem::detectType() {
int x = m_cells[0].x();
int y = m_cells[0].y();
......@@ -212,10 +251,18 @@ void GroupGraphicsItem::detectType() {
if(x==-1) m_type |= GroupRow;
if(y==-1) m_type |= GroupColumn;
// TODO - Does this code *really* affect highlights? See setHighlight().
// Row and column highlights must go above the GroupBlock boundary-line.
if(m_type == GroupColumn) setZValue(4);
else if(m_type == GroupRow) setZValue(4);
else if(m_type == GroupBlock) setZValue(3);
// IDW test. if(m_type == GroupColumn) setZValue(4);
// IDW test. else if(m_type == GroupRow) setZValue(4);
// IDW test. else if(m_type == GroupBlock) setZValue(3);
//
// TODO - It really looks better to have the block highlight on top of
// the row and column, especially with cages or irregular blocks.
// Might also be a good idea to reduce opacity of row and column.
if(m_type == GroupColumn) setZValue(3);
else if(m_type == GroupRow) setZValue(3);
else if(m_type == GroupBlock) setZValue(4);
}
void GroupGraphicsItem::createContour() {
......@@ -234,7 +281,10 @@ void GroupGraphicsItem::createContour() {
idx[7] = m_cells.indexOf(QPoint(x, y+1)); // South.
idx[8] = m_cells.indexOf(QPoint(x+1, y+1)); // South East.
if(idx[1] == -1 && idx[3] == -1 && idx[5] == -1 && idx[7] == -1)
// IDW test. if(idx[1] == -1 && idx[3] == -1 && idx[5] == -1 && idx[7] == -1)
// IDW test. if(!m_isCage && // A cage can consist of one cell and a border.
if((m_type != GroupCage) && // A cage can consist of one cell and a border.
idx[1] == -1 && idx[3] == -1 && idx[5] == -1 && idx[7] == -1) // IDW test.
{
// No adjoining neighbour to N, S, E or W.
m_type = GroupSpecial; // Used in the "X" of XSudoku.
......@@ -272,6 +322,7 @@ void GroupGraphicsItem::createSegment(const QPoint& pos, int shape) {
segment.standard = 0;
break;
case GroupBlock:
case GroupCage: // IDW test.
segment.standard = (shape == 15) ? 0 // No middle.
: new QGraphicsPixmapItem(this);
break;
......@@ -308,9 +359,11 @@ void GroupGraphicsItem::setHighlight(bool highlight) {
if ((m_type & GroupBlock) == GroupBlock) {
// Block highlight goes on top of row, column and special
// highlights. Block boundary-line goes underneath them.
setZValue(highlight ? 6 : 3);
// IDW test. setZValue(highlight ? 6 : 3);
setZValue(highlight ? 8 : 4);
}
if ((m_type & GroupSpecial) == GroupSpecial) {
// IDW test. if ((m_type & GroupSpecial) == GroupSpecial) {
if (m_type == GroupSpecial) { // IDW test.
// Special highlight goes on top of unhighlighted special cell.
setZValue(highlight ? 5 : 4);
}
......@@ -337,13 +390,13 @@ void GroupGraphicsItem::resize(int gridSize, bool highlight) {
for(segment = m_segments.begin(); segment != m_segments.end(); ++segment) {
QPointF pos = segment->pos*gridSize;
// Has standard pixmap item?
if(segment->standard) {
if(m_borderVisible && segment->standard) {
QPixmap pic = r->renderBorder(segment->shape, standard, size);
segment->standard->setPixmap(pic);
segment->standard->setOffset(pos);
}
// Highlights on and has highlighted pixmap item?
if(highlight && segment->highlighted) {
if(m_borderVisible && highlight && segment->highlighted) {
QPixmap pic = r->renderBorder(segment->shape, highlighted, size);
segment->highlighted->setPixmap(pic);
segment->highlighted->setOffset(pos);
......@@ -410,7 +463,9 @@ void View2DScene::init(const Game& game) {
m_cells[i] = new CellGraphicsItem(QPoint(g->cellPosX(i), g->cellPosY(i)), i, this);
m_cells[i]->setParentItem(m_cellLayer);
if(game.given(i))
// TODO - Implement allCellsLookSame preference.
m_cells[i]->setType(SpecialCellPreset);
// m_cells[i]->setType(SpecialCell); // IDW test.
else
m_cells[i]->setType(SpecialCell);
if(game.value(i))
......@@ -419,16 +474,40 @@ void View2DScene::init(const Game& game) {
m_cells[i]->setValues(QVector<ColoredValue>());
if(m_cursorPos < 0) m_cursorPos = i;
}
m_groups.resize(g->cliqueCount());
m_groups.resize(g->cliqueCount() + g->cageCount());
for(int i = 0; i < g->cliqueCount(); ++i) {
// Set the shape of each group.
QVector<int> idx = g->clique(i);
QVector<QPoint> pts = QVector<QPoint>(idx.size());
for(int j = 0; j < idx.size(); ++j) {
pts[j] = QPoint(g->cellPosX(idx[j]), g->cellPosY(idx[j]));
pts[j] = QPoint(g->cellPosX(idx[j]), g->cellPosY(idx[j]));
}
m_groups[i] = new GroupGraphicsItem(pts);
m_groups[i]->setParentItem(m_groupLayer);
// IDW TODO - Draw Killer Sudoku cages inside cell borders?
// Avoid ugly crossings of cages and blocks in Killer Sudoku.
// Show borders of blocks only if there are no cages present.
m_groups[i]->hideBlockBorder((g->cageCount() > 0));
}
int offset = g->cliqueCount();
for(int i = 0; i < g->cageCount(); ++i) {
// Set the shape of each Mathdoku or KillerSudoku cage.
QVector<int> idx = g->cage(i);
QVector<QPoint> pts = QVector<QPoint>(idx.size());
for(int j = 0; j < idx.size(); ++j) {
pts[j] = QPoint(g->cellPosX(idx[j]), g->cellPosY(idx[j]));
}
m_groups[offset + i] = new GroupGraphicsItem(pts, true);
m_groups[offset + i]->setParentItem(m_groupLayer);
// Set the label of each cage (value and operator), but...
if (g->cage(i).size() > 1) { // Not in single cells.
QString str = QString::number(g->cageValue(i));
if (g->specificType() == Mathdoku) { // Not in KillerSudoku.
str = str + QString(" /-x+").mid(g->cageOperator(i), 1);
}
m_cells[g->cageTopLeft(i)]->setCageLabel(str);
}
}
m_cursor = new QGraphicsPixmapItem();
......@@ -514,7 +593,9 @@ void View2DScene::update(int cell) {
QVector<ColoredValue> values;
switch(cellInfo.state()) {
case GivenValue:
// TODO - Implement allCellsLookSame preference.
m_cells[cell]->setType(SpecialCellPreset);
// m_cells[cell]->setType(SpecialCell); // IDW test.
if(cellInfo.value()) values << ColoredValue(cellInfo.value(),0);
m_cells[cell]->setValues(values);
break;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment