PDA

View Full Version : Help with my sudoku game



laurynas2003
6th April 2020, 20:46
Hello again...

I am stuck and I don't have any ideas how to solve it.

My main.cpp code:
#########################################
#include "widget.h"

#include <QApplication>

#include <QtCore>
#include <QtWidgets>

int main(int argc, char * argv[])
{
QApplication app(argc,argv);
QWidget mainWidget;
mainWidget.setWindowTitle("Sudoku");

QGridLayout *mainLayout = new QGridLayout(&mainWidget);
mainLayout->setSpacing(0);

for (int mr = 0; mr < 3; mr++) {
for(int mc = 0; mc < 3; mc++) {
QFrame *widget = new QFrame;
widget->setFrameStyle(QFrame::Plain);
widget->setFrameShape(QFrame::Box);

QGridLayout *gridLayout = new QGridLayout(widget);
gridLayout->setSpacing(0);
gridLayout->setMargin(0);

for(int r = 0; r < 3; r++) {
for (int c = 0; c < 3; c++) {
QLineEdit *tile = new QLineEdit("X");
tile->setMaxLength(1);
tile->setFixedSize(30,30);
tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-style: solid; border-color: black black black black; }");
tile->setAlignment(Qt::AlignCenter);
tile->setFrame(QFrame::Box);
gridLayout->addWidget(tile, r, c, 1, 1, Qt::AlignCenter);
}
}

mainLayout->addWidget(widget, mr, mc, 1, 1, Qt::AlignCenter);
}
}
mainWidget.show();
return app.exec();
}
################################################## ###################

So, how can I know when my tile is selected by user?And how to get input from that specific tile(what he typed in the tile) , and how to get edited tile position ?;

Thank you:)

d_stranz
7th April 2020, 03:05
So, how can I know when my tile is selected by user?And how to get input from that specific tile(what he typed in the tile) , and how to get edited tile position ?;

The most convenient way to do this is to create a custom widget to represent your sudoku board, and use that as your main widget instead of just plain QWidget. Call it something like "SudokuWidget". Move all of the widget and layout creation code you now have in main() into the constructor for this new widget.

To monitor the user actions on the line edits, you need to connect the QLineEdit::editingFinished() signals to a slot in your SudokuWidget class. In that slot, you will determine which line edit was responsible (using QObject::sender() or QSignalMapper maybe), convert the line edit's text to an integer, and store that in the data structure you are using to keep track of the player's moves. By the way, you will also have to set some of the line edits to read-only if they contain the predetermined (fixed) numbers. The user can't be allowed to edit those.

You should also consider using a QIntValidator for your line edits to prevent the user from typing anything they want.

To make it easy to determine which line edit was changed, you could send all of the editingFinished() signals through a QSignalMapper. You can use the QSignalMapper::setMapping() "int" version to easily assign the row and column to each QLineEdit. Simply assign the ones digit to the row and the tens digit to the column, so as you go across the first row, the mapping values would be 00, 01, 02, 03, ..., 08, 09. The next row would be 10, 11, ..., 18, 19 and so forth. In your SudokuWidget slot that you connect to the QSignalMapper::mapped() signal, you can decode the row and column as row = i / 10 and column = i % 10, where "i" is the integer passed in the mapping() call.



// SudokuWidget.h

class SudokuWidget : public QWidget
{
Q_OBJECT;

public:
SudokuWidget( QWidget * parent );
~SudokuWidget();

private slots:
void onMapped( int rowColId );

private:
QSignalMapper * mapper;
QVector< QLineEdit * > tiles;
};

// SudokuWidget.cpp

SudokuWidget::Sudokuwidget( QWidget * parent )
: QWidget( parent )
{
mapper = new QSignalMapper( this );

QIntValidator *pValidator = new QIntValidator( this );
pValidator->setRange( 1, 9 );

// Create grid layout, create 9 frames, create 9 cells in each frame

// ... in the innermost loop where you create the tiles

for ( int row = 0; row < 9; row++ )
{
for ( int col = 0; col < 9; col++ )
{
QLineEdit * tile = new QLineEdit( this );
int rowColId = col + row * 10;
mapper.setMapping( tile, rowColId );
connect( tile, &QLineEdit::editingFinished, mapper, &QSignalMapper::map );

tiles.push_back( tile ); // save the line edit so you can get to it later
// ...
}
}

connect( mapper, SIGNAL( mapped( int ) ), this, SLOT( onMapped( int ) ) );
// ...
}

void SudokuWidget::onMapped( int rowColId )
{
int row = rowColId / 10;
int col = rowColId % 10;

QLineEdit * tile = tiles[ row * 9 + col ];

// Retrieve the QString text from the QLineEdit, convert it to an int,
// store it in your game data structure, check to see if it is correct,
// whatever your game decides to do.
}


Google will help you find examples of other Sudoku games written in Qt / C++.

d_stranz
7th April 2020, 15:40
I forgot to set the validator on the line edit. So add this into the loop that creates each tile:



tile->setValidator( pValidator );


Now the line edit will refuse to accept anything the user types except a single digit between 1 - 9. Some sudoku games allow the user to put multiple numbers in the same square (in other words, all the possibilities for that square), then erase them one by one. If you implement that, then the validator will not work for that purpose.

You could derive a different validator in that case, and it could be smarter. For example, if it allows the user to type multiple numbers, then it should not allow typing the same number more than once.