Results 1 to 19 of 19

Thread: Random Sudoku board generator

  1. #1
    Join Date
    Apr 2020
    Location
    Lithuania
    Posts
    24
    Thanks
    17
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Random Sudoku board generator

    Hello ,

    So i am trying to generate a sudoku board that would be solvable, with 20 random digits in random positions , but when I run the code numbers appear in different places then they should be , for example
    my function generates y = 8 x = 8 value = 5 , but on my board that tile is empty and 5 appears in other position. Could someone tell me how to fix this?

    Thank you

    Qt Code:
    1. // widget.h
    2. #ifndef WIDGET_H
    3. #define WIDGET_H
    4.  
    5. #include <QWidget>
    6.  
    7. QT_BEGIN_NAMESPACE
    8. class QLineEdit;
    9. QT_END_NAMESPACE
    10.  
    11.  
    12.  
    13. class SudokuWidget : public QWidget
    14. {
    15. Q_OBJECT;
    16.  
    17. public:
    18. SudokuWidget( QWidget *parent );
    19.  
    20.  
    21. private slots:
    22. // void onMapped( int rowColId );
    23. // void on_pushButton_clicked();
    24.  
    25. private:
    26. // QSignalMapper *mapper;
    27. QVector < QLineEdit *> tiles;
    28.  
    29. QVector <QPair <int, int>> random_pos_value;
    30. void random_position(int digits, QVector < QPair <int, int> > &pos_value);
    31.  
    32. bool is_legal_row(int value, int y, int x, QVector< QVector < QLineEdit* >> &tiles1);
    33. bool is_legal_colum(int value, int y, int x, QVector< QVector < QLineEdit* >> &tiles1);
    34.  
    35. int box_position(int y, int x);
    36. bool is_legal_box(int value, int y,int x, QVector< QVector < QLineEdit* >> &tiles1);
    37. };
    38.  
    39.  
    40. #endif // WIDGET_H
    41.  
    42. // widget.cpp
    43.  
    44. #include "widget.h"
    45. #include "ui_widget.h"
    46.  
    47. #include <QGridLayout>
    48. #include <QFrame>
    49. #include <QLineEdit>
    50. #include <QIntValidator>
    51. #include <QMessageBox>
    52. #include <QPushButton>
    53. #include <QRandomGenerator>
    54. #include <QDateTime>
    55. #include <QSet>
    56. #include <iostream>
    57.  
    58.  
    59. SudokuWidget::SudokuWidget(QWidget * parent)
    60. : QWidget(parent) {
    61.  
    62. QIntValidator *pValidator = new QIntValidator( this );
    63. pValidator->setRange( 1, 9 );
    64.  
    65. int square_counter = 0;
    66. random_position(20, random_pos_value);
    67.  
    68.  
    69. QGridLayout *mainLayout = new QGridLayout(this);
    70. mainLayout->setSpacing(0);
    71.  
    72. for (int mr = 0; mr < 3; mr++) {
    73. for(int mc = 0; mc < 3; mc++) {
    74.  
    75. QFrame *widget = new QFrame;
    76. widget->setFrameStyle(QFrame::Plain);
    77. widget->setFrameShape(QFrame::Box);
    78.  
    79. QGridLayout *gridLayout = new QGridLayout(widget);
    80. gridLayout->setSpacing(0);
    81. gridLayout->setMargin(0);
    82.  
    83. for(int r = 0; r < 3; r++) {
    84. for (int c = 0; c < 3; c++) {
    85.  
    86. QLineEdit *tile = new QLineEdit("");
    87. square_counter++;
    88.  
    89. tile->setMaxLength(1);
    90. tile->setFixedSize(30,30);
    91. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-style: solid; border-color: black black black black; }");
    92. tile->setAlignment(Qt::AlignCenter);
    93. tile->setFrame(QFrame::Box);
    94. tile->setValidator(pValidator);
    95.  
    96. tiles.push_back( tile );
    97.  
    98. gridLayout->addWidget(tile, r, c, 1, 1, Qt::AlignCenter);
    99. }
    100. }
    101. mainLayout->addWidget(widget, mr, mc, 1, 1, Qt::AlignCenter);
    102. }
    103. }
    104. for (int i = 0;i < 80; i++){
    105. for (int j = 0;j < 20; j++){
    106. if (random_pos_value[j].first == i){
    107. tiles[i]->setText(QString::number(random_pos_value[j].second));
    108. tiles[i]->setReadOnly(true);
    109. }
    110. }
    111. }
    112.  
    113. setLayout(mainLayout);
    114. }
    115.  
    116.  
    117. bool SudokuWidget::is_legal_row(int value,int y, int x, QVector< QVector < QLineEdit* >> &tiles1)
    118. {
    119. int count = 0;
    120. for (int i = 0;i < 9; i++){
    121. if (QString::number(value) == tiles1[y][i]->text()){
    122. count++;
    123. }
    124. }
    125. if (count == 1){
    126. return true;
    127. }
    128. return false;
    129. }
    130.  
    131. bool SudokuWidget::is_legal_colum(int value,int y, int x, QVector<QVector<QLineEdit *> > &tiles1)
    132. {
    133. int count = 0;
    134. for (int i = 0;i < 9; i++){
    135. if (QString::number(value) == tiles1[i][x]->text()){
    136. count++;
    137. }
    138. }
    139. if (count == 1){
    140. return true;
    141. }
    142. return false;
    143. }
    144.  
    145. void SudokuWidget::random_position(int digits, QVector <QPair <int, int> > &random_pos_value)
    146. {
    147.  
    148. QVector < QVector < QLineEdit* > > random_boards(81);
    149. for (int y1 = 0;y1 < 9; y1++){
    150. for (int x1 = 0;x1 < 9; x1++){
    151. QLineEdit *line_edit = new QLineEdit("0");
    152. random_boards[y1].push_back(line_edit);
    153. }
    154. }
    155. qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
    156. int count = 0;
    157. int value;
    158. while (true){
    159. int position = (qrand() % 80) + 0;
    160. int y = position / 9;
    161. int x = position % 9;
    162. if (random_boards[y][x]->text() == "0"){
    163. while (true){
    164. value = (qrand() % 9) + 1;
    165. random_boards[y][x]->setText(QString::number(value));
    166. if (is_legal_box(value, y, x, random_boards) && is_legal_colum(value, y, x, random_boards) ){
    167. break;
    168. }
    169. random_boards[y][x]->setText("0");
    170. }
    171. QPair <int, int> values = {position,value};
    172. random_pos_value.push_back(values);
    173. count++;
    174. if (count == digits){
    175. break;
    176. }
    177. }
    178. }
    179. }
    180.  
    181.  
    182. int SudokuWidget::box_position(int y, int x)
    183. {
    184. return 3*(y/3) + (x/3);
    185. }
    186.  
    187. bool SudokuWidget::is_legal_box(int value, int y1, int x1, QVector<QVector<QLineEdit *> > &tiles1)
    188. {
    189. //box
    190. int count = 0;
    191. int square_position = box_position(y1, x1);
    192. QVector <QString> values;
    193. for (int y = (square_position / 3) * 3; y < ((square_position / 3) * 3) + 3;y++){
    194. for (int x = (square_position % 3) * 3; x < ((square_position % 3) * 3) + 3;x++){
    195. if (tiles1[y][x]->text() == QString::number(value)){
    196. count++;
    197. }
    198. }
    199.  
    200. }
    201. if (count == 1){
    202. return true;
    203. }
    204. return false;
    205. }
    To copy to clipboard, switch view to plain text mode 
    Last edited by laurynas2003; 10th April 2020 at 11:02.

  2. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,481
    Thanks
    252
    Thanked 711 Times in 701 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Random Sudoku board generator

    Qt Code:
    1. for (int i = 0;i < 80; i++){
    2. for (int j = 0;j < 20; j++){
    3. if (random_pos_value[j].first == i){
    4. tiles[i]->setText(QString::number(random_pos_value[j].second));
    5. tiles[i]->setReadOnly(true);
    6. }
    7. }
    8. }
    To copy to clipboard, switch view to plain text mode 

    Think about this loop. The innermost part of it runs 3200 times. Is that what you want to do?
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. #3
    Join Date
    Apr 2020
    Location
    Lithuania
    Posts
    24
    Thanks
    17
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Random Sudoku board generator

    Qt Code:
    1. for (int i = 0;i < 20; i++){
    2. tiles[random_pos_value[i].first]->setText(QString::number(random_pos_value[i].second));
    3. QMessageBox::about(this,"????????", "(" + QString::number(random_pos_value[i].first / 9) + ", " + QString::number(random_pos_value[i].first % 9) + ")" + " = " +
    4. QString::number(random_pos_value[i].second));
    5. tiles[i]->setReadOnly(true);
    6. }
    To copy to clipboard, switch view to plain text mode 

    I change it to this code , but still doesnt work properly. With MessageBox i check where the tile value should be.


    Added after 59 minutes:


    Qt Code:
    1. if (is_legal_box(value, y, x, random_boards) && is_legal_colum(value, y, x, random_boards ) && is_legal_row(value, y, x, random_boards) ){ // i forgot to add is_legal_row
    2. break;
    3. }
    To copy to clipboard, switch view to plain text mode 


    Ohh I forgot to add is_legal function to random_position function, but still doesn't work . I think my random_position function is fine, because I checked with QMessageBox every coordinate that it gave and wrote it on paper Sudoku board, and that board was fine.
    Last edited by laurynas2003; 10th April 2020 at 19:46.

  4. #4
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,481
    Thanks
    252
    Thanked 711 Times in 701 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Random Sudoku board generator

    tiles[i]->setReadOnly(true);
    So if you have 81 tiles on your board, and you are setting 20 of them to fixed numbers, and you are using the variable "i" to count from 0 to 19, which tiles do you think this code is setting to read-only?

    Hint: Why don't you write a little function:

    Qt Code:
    1. int SudokuWidget::mapRowAndColumnToTileIndex( int row, int column ) const
    2. {
    3. int tileIndex = -1; // ALWAYS initialize; -1 means an invalid row or column was passed
    4.  
    5. if ( row >= 0 && row < 9 && column >= 0 && column < 9 )
    6. {
    7. // it's a valid row / column location
    8. // add code here to compute index into the tiles array from row and column
    9. }
    10. return tileIndex;
    11. }
    To copy to clipboard, switch view to plain text mode 

    and use that function every time you need to get a tile from a row and column. You could even write the reverse mapping function

    Qt Code:
    1. bool SudokuWidget::mapTileIndexToRowAndColumn( int tileIndex, int & row, int & column ) const
    2. {
    3. bool bValid = false; // set to true if the index is within range
    4. if ( tileIndex >= 0 && tileIndex < tiles.size() )
    5. {
    6. bValid = true;
    7.  
    8. // add code here to compute row and column from index
    9. }
    10. return bValid;
    11. }
    To copy to clipboard, switch view to plain text mode 

    and use it every time you need to go the other way. The code you need to add is in an answer I gave to one of your other posts, if I remember correctly...
    Last edited by d_stranz; 10th April 2020 at 23:19.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  5. #5
    Join Date
    Apr 2020
    Location
    Lithuania
    Posts
    24
    Thanks
    17
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Random Sudoku board generator

    Qt Code:
    1. #include "widget.h"
    2. #include "ui_widget.h"
    3.  
    4. #include <QGridLayout>
    5. #include <QFrame>
    6. #include <QLineEdit>
    7. #include <QIntValidator>
    8. #include <QMessageBox>
    9. #include <QPushButton>
    10. #include <QRandomGenerator>
    11. #include <QDateTime>
    12. #include <QSet>
    13. #include <iostream>
    14. #include <QSignalMapper>
    15.  
    16.  
    17.  
    18. SudokuWidget::SudokuWidget(QWidget * parent)
    19. : QWidget(parent) {
    20.  
    21. mapper = new QSignalMapper( this );
    22.  
    23. for (int y = 0;y < 9; y++){
    24. for (int x =0; x < 9; x++){
    25. game_data[y].push_back(0);
    26. }
    27. }
    28.  
    29. QIntValidator *pValidator = new QIntValidator( this );
    30. pValidator->setRange( 1, 9 );
    31.  
    32. int square_counter = 0;
    33.  
    34. // random_position(20, random_pos_value); // QVector <QPair <int, int>
    35.  
    36.  
    37. QGridLayout *mainLayout = new QGridLayout(this);
    38. mainLayout->setSpacing(0);
    39. mainLayout->setAlignment(Qt::AlignCenter);
    40.  
    41.  
    42. for (int mr = 0; mr < 3; mr++) {
    43. for(int mc = 0; mc < 3; mc++) {
    44.  
    45. QFrame *widget = new QFrame;
    46. widget->setFrameStyle(QFrame::Plain);
    47. widget->setFrameShape(QFrame::Box); /
    48.  
    49. QGridLayout *gridLayout = new QGridLayout(widget);
    50. gridLayout->setSpacing(0);
    51. gridLayout->setMargin(0);
    52.  
    53. for(int r = 0; r < 3; r++) {
    54. for (int c = 0; c < 3; c++) {
    55.  
    56. QLineEdit *tile = new QLineEdit(this);
    57.  
    58. int rowColId = (square_counter / 9) + (square_counter % 9) * 10;
    59. mapper->setMapping( tile, rowColId );
    60. connect(tile, &QLineEdit::editingFinished, mapper, &QSignalMapper::map ); // error - no matching member function for call to connect
    61.  
    62. tile->setMaxLength(1);
    63. tile->setFixedSize(30,30);
    64. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-style: solid; border-color: black black black black; }");
    65. tile->setAlignment(Qt::AlignCenter);
    66. tile->setFrame(QFrame::Box);
    67. tile->setValidator(pValidator);
    68.  
    69. tiles.push_back( tile );
    70. square_counter++;
    71. gridLayout->addWidget(tile, r, c, 1, 1, Qt::AlignCenter);
    72. }
    73. }
    74. mainLayout->addWidget(widget, mr, mc, 1, 1, Qt::AlignCenter);
    75. }
    76. }
    77. connect( mapper, SIGNAL( mapped( int ) ), this, SLOT( onMapped( int ) ) );
    78. // for (int i = 0;i < 20; i++){
    79.  
    80. // tiles[random_pos_value[i].first]->setText(QString::number(random_pos_value[i].second));
    81. // QMessageBox::about(this,"????????", "(" + QString::number(random_pos_value[i].first / 9) + ", " + QString::number(random_pos_value[i].first % 9) + ")" + " = " + QString::number(random_pos_value[i].second));
    82.  
    83. // tiles[random_pos_value[i].first]->setReadOnly(true);
    84. // }
    85.  
    86. //setLayout(mainLayout);
    87. }
    88.  
    89. void SudokuWidget::onMapped( int rowColId )
    90. {
    91. int row = rowColId / 10;
    92. int col = rowColId % 10;
    93.  
    94. QLineEdit * tile = tiles[ row * 9 + col ];
    95.  
    96. int square_value = tile->text().split(" ")[0].toInt(); // Retrieve the QString text from the QLineEdit, convert it to an int,
    97.  
    98. // store it in your game data structure, check to see if it is correct,
    99. game_data[col][row] = square_value;
    100. if (is_legal_box(square_value, col, row, game_data) && is_legal_row(square_value, col, game_data) && is_legal_colum(square_value, row, game_data) ){
    101. QMessageBox::about(this, "?", "Its working"); // whatever your game decides to do.
    102. }
    103.  
    104.  
    105.  
    106.  
    107.  
    108.  
    109. }
    110.  
    111. bool SudokuWidget::is_legal_row(int value, int y, QVector< QVector < int >> &tiles1)
    112. {
    113. int count = 0;
    114. for (int i = 0;i < 9; i++){
    115. if (value == tiles1[y][i]){
    116. count++;
    117. }
    118. }
    119. if (count == 1){
    120. return true;
    121. }
    122. return false;
    123. }
    124.  
    125. bool SudokuWidget::is_legal_colum(int value, int x, QVector<QVector< int > > &tiles1)
    126. {
    127. int count = 0;
    128. for (int i = 0;i < 9; i++){
    129. if (value == tiles1[i][x]){
    130. count++;
    131. }
    132. }
    133. if (count == 1){
    134. return true;
    135. }
    136. return false;
    137. }
    138.  
    139. //void SudokuWidget::random_position(int digits, QVector <QPair <int, int> > &random_pos_value)
    140. //{
    141.  
    142. // QVector < QVector < QLineEdit* > > random_boards(81);
    143. // for (int y1 = 0;y1 < 9; y1++){
    144. // for (int x1 = 0;x1 < 9; x1++){
    145. // QLineEdit *line_edit = new QLineEdit("0");
    146. // random_boards[y1].push_back(line_edit);
    147. // }
    148. // }
    149. // qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
    150. // int count = 0;
    151. // int value;
    152. // while (true){
    153. // int position = (qrand() % 80) + 0;
    154. // int y = position / 9;
    155. // int x = position % 9;
    156. // if (random_boards[y][x]->text() == "0"){
    157. // while (true){
    158. // value = (qrand() % 9) + 1;
    159. // random_boards[y][x]->setText(QString::number(value));
    160. // if (is_legal_box(value, y, x, random_boards) && is_legal_colum(value, x, random_boards) && is_legal_row(value, y, random_boards)){
    161. // break;
    162. // }
    163. // random_boards[y][x]->setText("0");
    164. // }
    165. // QPair <int, int> values = {position,value};
    166. // random_pos_value.push_back(values);
    167. // count++;
    168. // if (count == digits){
    169. // break;
    170. // }
    171. // }
    172. // }
    173. //}
    174.  
    175.  
    176. int SudokuWidget::box_position(int y, int x)
    177. {
    178. return 3*(y/3) + (x/3);
    179. }
    180.  
    181. bool SudokuWidget::is_legal_box(int value, int y1, int x1, QVector<QVector< int > > &tiles1)
    182. {
    183. //box
    184. int count = 0;
    185. int square_position = box_position(y1, x1);
    186. QVector <QString> values;
    187. for (int y = (square_position / 3) * 3; y < ((square_position / 3) * 3) + 3;y++){
    188. for (int x = (square_position % 3) * 3; x < ((square_position % 3) * 3) + 3;x++){
    189. if (tiles1[y][x] == value){
    190. count++;
    191. }
    192. }
    193.  
    194. }
    195. if (count == 1){
    196. return true;
    197. }
    198. return false;
    199. }
    To copy to clipboard, switch view to plain text mode 


    So i changed it to this code, but now i am getting an error "no matching member function for call to connect"

  6. #6
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,481
    Thanks
    252
    Thanked 711 Times in 701 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Random Sudoku board generator

    So i changed it to this code, but now i am getting an error "no matching member function for call to connect"
    It is an obscure error, and I have been burned by it more than once. It is because QSignalMapper::map() is an overloaded function, and the compiler cannot determine which one of the two overloads to use.

    There are two solutions:

    1 - Use the "old style" form of connect:

    Qt Code:
    1. connect( tile, SIGNAL( editingFinished() ), mapper, SLOT( map() ) );
    To copy to clipboard, switch view to plain text mode 

    2 - Use the new style, with a special template which resolves the overload so it can compile:

    Qt Code:
    1. connect( tile, &QLineEdit::editingFinished, mapper, QOverload<>::of( &QSignalMapper::map ) ); // C++11
    2.  
    3. // or
    4.  
    5. connect( tile, &QLineEdit::editingFinished, mapper, qOverload<>( &QSignalMapper::map ) ); // C++14
    To copy to clipboard, switch view to plain text mode 

    Even though the new style is more complex, you should use it instead of the old style if you can, because it allows the connect() arguments to be evaluated at -compile- time.

    The old style will always compile, even if the signal or slot are not defined at all and it will not be caught until run time. Even then, all that happens is a warning, and the program will run (incorrectly because the connection won't be made between signal and slot). This makes it really hard to debug a program unless you happen to pay attention to all of the startup warnings and messages that are displayed in the Qt Creator or Visual Studio Output window.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  7. The following user says thank you to d_stranz for this useful post:

    laurynas2003 (11th April 2020)

  8. #7
    Join Date
    Apr 2020
    Location
    Lithuania
    Posts
    24
    Thanks
    17
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Random Sudoku board generator

    By the way i just figured out why my first code didn't work.

    I thought that my square positions were like that:

    0 1 2 3 4 5 6 7 8
    9 10 11...

    but actually it looks like that:

    0 1 2 9 10 11 18 19 20....
    3 4 5 12 13 14
    6 7 8 15 16 17

  9. #8
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,481
    Thanks
    252
    Thanked 711 Times in 701 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Random Sudoku board generator

    but actually it looks like that:
    Yes, my mistake, too. It is because your code to create the 3 x 3 grid of tiles is inside another two loops to create the 3 x 3 grid of big squares. It would probably be a good idea to change your grid creating code so the the cell indexes are like the first case (0 1 2 3 4 5 6 7 8...). It will make it much easier to design your game logic.

    I would create the outer grid of big squares first, in a 3 x 3 loop. Then outside of that, in a 9 x 9 loop, create the tiles and put them in the right position in the big grids.

    You actually don't need the big grid at all, I don't think. Just a 9 x 9 grid is all you really need. Grids within grids just makes everything harder.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  10. The following user says thank you to d_stranz for this useful post:

    laurynas2003 (11th April 2020)

  11. #9
    Join Date
    Apr 2020
    Location
    Lithuania
    Posts
    24
    Thanks
    17
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Random Sudoku board generator

    Quote Originally Posted by d_stranz View Post
    I would create the outer grid of big squares first, in a 3 x 3 loop. Then outside of that, in a 9 x 9 loop, create the tiles and put them in the right position in the big grids.
    Maybe you could show me how to make it because I can't figure out how to make that without using another gridlayout ?
    Last edited by laurynas2003; 11th April 2020 at 21:05.

  12. #10
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,481
    Thanks
    252
    Thanked 711 Times in 701 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Random Sudoku board generator

    Qt Code:
    1. // SudokuWidget constructor
    2.  
    3. QGridLayout * pMainLayout( this );
    4.  
    5. // Make the 3 x 3 array of grid layouts
    6. QVector< QGridLayout * > bigGrids;
    7. for ( int row = 0; row < 3; row++ )
    8. {
    9. for ( int col = 0; col < 3; col++ )
    10. {
    11. QGridLayout * pInnerGrid = new QGridLayout( this );
    12. pMainLayout->addLayout( pInnerGrid, row, col );
    13. bigGrids.push_back( pInnerGrid );
    14. }
    15. }
    16.  
    17. // Big grid array corresponds to these positions
    18. // 0 1 2
    19. // 3 4 5
    20. // 6 7 8
    21.  
    22. // Now make the 9 x 9 arrays of tiles
    23. // These will have indexes
    24. // 0 1 2 3 4 5 6 7 8
    25. // 9 10 11 12 13 14 15 16 17
    26. // 18 19 20 21 22 23 24 25 25
    27. // ...
    28. // 72 73 74 75 76 77 78 79 80
    29.  
    30. // QVector< QLineEdit * > tiles is a member variable
    31. // Resize the tiles array, set all pointers to null
    32. tiles.resize( 81, nullptr );
    33.  
    34. for ( int row = 0; row < 9; row++ )
    35. {
    36. for ( int col = 0; col < 9; col++ )
    37. {
    38. // index of grid in bigGrids array
    39. int bigGridIndex = 3 * (row / 3 ) + col / 3; // ex: if row = 5 and col = 4, index = 3 + 1 = 4
    40. QGridLayout * pInnerGrid = bigGrids[ bigGridIndex ];
    41.  
    42. // row, col coordinates of line edit inside of inner grid
    43. int gridRow = row % 3;
    44. int gridCol = col %3;
    45.  
    46. QLineEdit * tile = new QLineEdit( this );
    47. pInnerGrid->addWidget( tile, gridRow, gridCol );
    48.  
    49. // index of tile in tiles array
    50. int tileIndex = row * 9 + col;
    51. tiles[ tileIndex ] = tile;
    52. }
    53. }
    54.  
    55. setLayout( pMainLayout );
    To copy to clipboard, switch view to plain text mode 

    Now you have a SudokuWidget with a grid layout inside it. This grid layout has 9 smaller grid layouts inside it.
    In each of these 9 smaller grids, there are 9 QLineEdit tiles.

    The tiles are stored in a QVector of QLineEdit pointers. The tiles are numbered as a 9 x 9 grid like above (row = 0 .. 8, col = 0 .. 8).

    Helpful functions:

    Qt Code:
    1. QVector< QLineEdit * > SudokuWidget::tilesForColumn( int col )
    2. {
    3. QVector< QLineEdit * > colTiles;
    4. for ( int row = 0; row < 9; row++ )
    5. {
    6. int tileIndex = col + row * 9;
    7. colTiles.push_back( tiles[ tileIndex ] );
    8. }
    9. return colTiles;
    10. }
    11.  
    12. QVector< QLineEdit * > SudokuWidget::tilesForRow( int row )
    13. {
    14. QVector< QLineEdit * > rowTiles;
    15. for ( int col = 0; col < 9; col++ )
    16. {
    17. int tileIndex = col + row * 9;
    18. rowTiles.push_back( tiles[ tileIndex ] );
    19. }
    20. return rowTiles;
    21. }
    To copy to clipboard, switch view to plain text mode 

    Another function you will probably want is tilesForSquare( int row, int col ), which gives you the 9 tiles in the inner grid that contains row and col.
    Last edited by d_stranz; 11th April 2020 at 23:54.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  13. The following user says thank you to d_stranz for this useful post:

    laurynas2003 (11th April 2020)

  14. #11
    Join Date
    Apr 2020
    Location
    Lithuania
    Posts
    24
    Thanks
    17
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Random Sudoku board generator

    Could you tell me how to change outer grid of big squares size?

  15. #12
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,481
    Thanks
    252
    Thanked 711 Times in 701 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Random Sudoku board generator

    What do you mean, "change the size"? Make the widget bigger or smaller? Change the number of squares inside it?

    Show some of your code for how you are creating your SudokuWidget instance and a screenshot of the result.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  16. #13
    Join Date
    Apr 2020
    Location
    Lithuania
    Posts
    24
    Thanks
    17
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Random Sudoku board generator

    Qt Code:
    1. // widget.cpp
    2.  
    3.  
    4. #include "widget.h"
    5. #include "ui_widget.h"
    6.  
    7. #include <QGridLayout>
    8. #include <QFrame>
    9. #include <QLineEdit>
    10. #include <QIntValidator>
    11. #include <QMessageBox>
    12. #include <QPushButton>
    13. #include <QRandomGenerator>
    14. #include <QDateTime>
    15. #include <QSet>
    16. #include <iostream>
    17. #include <QSignalMapper>
    18.  
    19.  
    20.  
    21. SudokuWidget::SudokuWidget(QWidget * parent)
    22. : QWidget(parent) {
    23.  
    24. QIntValidator *pValidator = new QIntValidator( this ); // user can input only 1 - 9
    25. pValidator->setRange( 1, 9 ); // 1 - 9
    26.  
    27. QGridLayout *pMainLayout = new QGridLayout( this );
    28. pMainLayout->setSpacing(0);
    29. pMainLayout->setAlignment(Qt::AlignCenter);
    30. QRect size = QRect(0,0,5000,1000);
    31. this->setGeometry(size);
    32.  
    33.  
    34.  
    35.  
    36.  
    37. // 3 x 3 array of grid layouts
    38. QVector< QGridLayout * > bigGrids;
    39. for ( int y = 0; y < 3; y++ ){
    40. for ( int x = 0; x < 3; x++ ){
    41. QGridLayout *pInnerGrid = new QGridLayout( this );
    42.  
    43. pInnerGrid->setAlignment(Qt::AlignHCenter);
    44. pInnerGrid->setSpacing(0);
    45. pInnerGrid->setMargin(0);
    46.  
    47. pMainLayout->addLayout( pInnerGrid, y, x );
    48. bigGrids.push_back( pInnerGrid );
    49. }
    50. }
    51.  
    52. tiles.resize(81);
    53. solve_data.resize(81);
    54.  
    55. for (int y = 0; y < 9; y++){
    56. for (int x = 0; x < 9; x++){
    57. int bigGridIndex = box_position( y, x);
    58. QGridLayout *pInnerGrid = bigGrids[bigGridIndex];
    59.  
    60. // square coordinates in the box
    61. int grid_y = y % 3;
    62. int grid_x = x % 3;
    63.  
    64. QLineEdit *tile = new QLineEdit( this );
    65.  
    66. // tile customization
    67. tile->setValidator(pValidator); // input 1 - 9
    68. tile->setMaxLength(1);
    69. tile->setFixedSize(30,30);
    70. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-style: solid; border-color: gray gray gray gray; }");
    71. tile->setAlignment(Qt::AlignCenter);
    72. tile->setFrame(QFrame::Box);
    73.  
    74. if (y == 0){
    75. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-top: 5px; border-style: solid; border-color: black gray gray gray; }");
    76. }
    77.  
    78. if (x == 8){
    79. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-right: 5px; border-style: solid; border-color: gray black gray gray; }");
    80. }
    81. if (y == 8){
    82. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-bottom: 5px; border-style: solid; border-color: gray gray black gray; }");
    83. }
    84. if (x == 0){
    85. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-left: 5px; border-style: solid; border-color: gray gray gray black; }");
    86. }
    87. if (x == 0 && y == 0){
    88. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-top: 5px; border-left: 5px; border-style: solid; border-color: black gray gray black; }");
    89. }
    90. if (x == 8 && y == 0){
    91. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-top: 5px; border-right: 5px; border-style: solid; border-color: black black gray gray; }");
    92. }
    93. if (x == 8 && y == 8){
    94. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-bottom: 5px; border-right: 5px; border-style: solid; border-color: gray black black black; }");
    95. }
    96. if (x == 0 && y == 8){
    97. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-bottom: 5px; border-left: 5px; border-style: solid; border-color: gray gray black black; }");
    98. }
    99. if (x == 5 || x == 2){
    100. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-right: 5px; border-style: solid; border-color: gray black gray gray; }");
    101. }
    102. if (y == 2 || y == 5){
    103. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-bottom: 5px; border-style: solid; border-color: gray gray black gray; }");
    104. }
    105. if (x == 2 && y == 8){
    106. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-bottom: 5px; border-right: 5px; border-style: solid; border-color: gray black black gray; }");
    107. }
    108. if (x == 5 && y == 8){
    109. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-bottom: 5px; border-right: 5px; border-style: solid; border-color: gray black black gray; }");
    110. }
    111. if ( ( x == 2 || x == 5 || x == 8 ) && y == 5){
    112. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-bottom: 5px; border-right: 5px; border-style: solid; border-color: gray black black gray; }");
    113. }
    114. if ( ( x == 2 || x == 5 || x == 8 ) && y == 2){
    115. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-bottom: 5px; border-right: 5px; border-style: solid; border-color: gray black black gray; }");
    116. }
    117. if (x == 0 && (y == 2 || y == 5)){
    118. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-bottom: 5px; border-left: 5px; border-style: solid; border-color: gray gray black black; }");
    119. }
    120. if ( y == 0 && ( x == 2 || x == 5 ) ){
    121. tile->setStyleSheet("QLineEdit{ border-width: 1.5px; border-top: 5px; border-right: 5px; border-style: solid; border-color: black black gray gray; }");
    122. }
    123.  
    124.  
    125.  
    126. pInnerGrid->addWidget( tile, grid_y, grid_x);
    127.  
    128. // inedex of tile in tiles array
    129. int tileIndex = y * 9 + x;
    130. tiles [tileIndex] = tile;
    131. }
    132. }
    133.  
    134. // Generate random digits with solvable solution ( 20 digs )
    135. random_position(20, random_pos_value);
    136. for (int i = 0;i < 20; i++){
    137. tiles[random_pos_value[i].first]->setText(QString::number(random_pos_value[i].second));
    138. tiles[random_pos_value[i].first]->setReadOnly(true);
    139. }
    140. // solve button
    141. Solve = new QPushButton( "Solve", this);
    142. connect( Solve, SIGNAL(released()), this, SLOT(on_Solve_clicked()) );
    143. pMainLayout->addWidget(Solve, 5, 0);
    144.  
    145. setLayout( pMainLayout );
    146. }
    147. // .......
    To copy to clipboard, switch view to plain text mode 

    I want to make my whole widget bigger, it is very small if you compare it to the window, and i attached Screenshot to see how it looks
    Attached Images Attached Images
    Last edited by laurynas2003; 12th April 2020 at 17:21.

  17. #14
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,481
    Thanks
    252
    Thanked 711 Times in 701 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Random Sudoku board generator

    It looks like you are putting this SudokuWidget inside of a QMainWindow class. Are you doing something like this?

    Qt Code:
    1. MainWindow::MainWindow( QWidget * parent )
    2. : QMainWindow( parent )
    3. {
    4.  
    5. // setup ui and all that
    6.  
    7. SudokuWidget * pSudokuWidget = new SudokuWidget( this );
    8.  
    9. setCentralWidget( pSudokuWidget );
    10. }
    To copy to clipboard, switch view to plain text mode 

    Making your widget the central widget of the main window means that the main window will take control of the size and will grow or shrink the central widget to match the size of the main window's central area.

    What might happen is that your QLineEdit tiles might not grow as big as the grid cells they are in. The fonts won't grow either, and you probably want both to happen.

    So now you will need to implement resizeEvent() for your SudokuWidget class. the sizeEvent() will give you the new size that the main window will set. You can take that size, divide by 9, and that will give you a rough estimate for the largest size font height in pixels that will fit in a square. You can then use QFont and maybe QFontMetrics to create a new QFont that is as close as possible to the desired height. Set that font on the SudokuWidget instance and the line edits should inherit it (and hopefully resize themselves to fit)

    Another complication is that if you make these changes constantly while the user is resizing the main window, it could lead to ugly flashing as the widget constantly adjusts the fonts. In this case, what I usually do is use a QTimer and a resize() slot to control how often the UI gets updated.

    Make the QTimer and slot members of your SudokuWidget class. Connect its timeout() signal to your resize() slot. When you first receive a resizeEvent(), start (or restart) it with a timeout of maybe 250 ms. Then, 250 ms after the last resizeEvent(), the timer will fire, and you will enter the resize() slot. Here is where you do the font adjustment to make a larger or smaller font. If 250 ms seems too sluggish, make it smaller until you get a good balance between excessive flashiness and slow response to resizing.

    Qt Code:
    1. void SudokuWidget::resizeEvent( QResizeEvent * pEvent )
    2. {
    3. // Start (or restart) the timer for another mResizeTimeout waiting period
    4. mpTimer->start( mResizeTimeout ); // Another member variable to make it easy the adjust the response time
    5. }
    6.  
    7. void SudokuWidget::resize() // slot
    8. {
    9. QSize newSize = size();
    10.  
    11. // Divide by 9, subtract some for padding, create a new QFont (on the stack) with this new size and face, then use setFont() to install it
    12. }
    To copy to clipboard, switch view to plain text mode 
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  18. The following user says thank you to d_stranz for this useful post:

    laurynas2003 (12th April 2020)

  19. #15
    Join Date
    Apr 2020
    Location
    Lithuania
    Posts
    24
    Thanks
    17
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Random Sudoku board generator

    Quote Originally Posted by d_stranz View Post
    It looks like you are putting this SudokuWidget inside of a QMainWindow class. Are you doing something like this?
    No, I don't have QMainWindow class, I just have one header file, main.cpp file and widget.cpp

    My widget.h and main.cpp code:

    Qt Code:
    1. // widget.h
    2. #ifndef WIDGET_H
    3. #define WIDGET_H
    4.  
    5. #include <QWidget>
    6.  
    7. QT_BEGIN_NAMESPACE
    8. class QLineEdit;
    9. QT_END_NAMESPACE
    10.  
    11.  
    12.  
    13.  
    14. class SudokuWidget : public QWidget
    15. {
    16. Q_OBJECT;
    17.  
    18. public:
    19. SudokuWidget( QWidget * parent = nullptr );
    20. // ~SudokuWidget();
    21.  
    22. private slots:
    23. // void onMapped( int rowColId );
    24. void on_Solve_clicked();
    25.  
    26. private:
    27.  
    28. // QSignalMapper *mapper;
    29. QVector < QLineEdit *> tiles;
    30. // QVector <QVector < int > > game_data;
    31.  
    32. QPushButton *Solve;
    33. QVector <QVector < QLineEdit* > > solve_data;
    34. bool Solve_Board( QVector< QVector < QLineEdit* > > &board );
    35. bool empty_cell( QVector< QVector < QLineEdit* > >, int &y, int &x );
    36.  
    37.  
    38. QVector <QPair <int, int>> random_pos_value;
    39. void random_position(int digits, QVector < QPair <int, int> > &pos_value);
    40.  
    41. // int mapRowAndColumnToTileIndex( int row, int column ) const;
    42. //bool mapTileIndexToRowAndColumn( int tileIndex, int & row, int & column ) const;
    43.  
    44.  
    45. bool is_legal_row(int value, int y, QVector< QVector < QLineEdit* > > &tiles1);
    46. bool is_legal_colum(int value, int x, QVector< QVector < QLineEdit* > > &tiles1);
    47.  
    48. int box_position(int y, int x);
    49. bool is_legal_box(int value, int y,int x, QVector <QVector < QLineEdit* > > &tiles1);
    50. };
    51.  
    52.  
    53. #endif // WIDGET_H
    To copy to clipboard, switch view to plain text mode 

    Qt Code:
    1. // main.cpp
    2.  
    3. #include "widget.h"
    4. #include <QApplication>
    5.  
    6.  
    7. int main(int argc, char * argv[])
    8. {
    9. QApplication a(argc,argv);
    10. SudokuWidget *sudokuwidged = new SudokuWidget(nullptr);
    11. sudokuwidged->show();
    12. return a.exec();
    13. }
    To copy to clipboard, switch view to plain text mode 

  20. #16
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,481
    Thanks
    252
    Thanked 711 Times in 701 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Random Sudoku board generator

    Then I would suggest you add a MainWindow class as your main top-level widget. It isn't hard - just look at the Qt Application example but ignore almost everything in it for now. All you need is the header file that derives MainWindow from QMainWindow and the code in the constructor that creates your SudokuWidget and makes it the central widget (like I showed above). When you are ready to start using menus, toolbars, and statusbars, then you can take a look at some of the other parts of the examples.

    In you main() function, you just substitute MainWindow for SudokuWidget and you are good to go, resizing and all.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  21. The following user says thank you to d_stranz for this useful post:

    laurynas2003 (12th April 2020)

  22. #17
    Join Date
    Apr 2020
    Location
    Lithuania
    Posts
    24
    Thanks
    17
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Random Sudoku board generator

    Quote Originally Posted by d_stranz View Post
    So now you will need to implement resizeEvent() for your SudokuWidget class. the sizeEvent() will give you the new size that the main window will set. You can take that size, divide by 9, and that will give you a rough estimate for the largest size font height in pixels that will fit in a square. You can then use QFont and maybe QFontMetrics to create a new QFont that is as close as possible to the desired height. Set that font on the SudokuWidget instance and the line edits should inherit it (and hopefully resize themselves to fit)

    Another complication is that if you make these changes constantly while the user is resizing the main window, it could lead to ugly flashing as the widget constantly adjusts the fonts. In this case, what I usually do is use a QTimer and a resize() slot to control how often the UI gets updated.

    Make the QTimer and slot members of your SudokuWidget class. Connect its timeout() signal to your resize() slot. When you first receive a resizeEvent(), start (or restart) it with a timeout of maybe 250 ms. Then, 250 ms after the last resizeEvent(), the timer will fire, and you will enter the resize() slot. Here is where you do the font adjustment to make a larger or smaller font. If 250 ms seems too sluggish, make it smaller until you get a good balance between excessive flashiness and slow response to resizing.
    Isn't there a simpler way to make it bigger? It looks very complicated to do this way

  23. #18
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    4,481
    Thanks
    252
    Thanked 711 Times in 701 Posts
    Qt products
    Qt5
    Platforms
    Windows Android

    Default Re: Random Sudoku board generator

    You do not need to do any of this. All you need to do is make the SudokuWidget the central widget of a MainWindow and the MainWindow class will automatically resize its SudokuWidget child window when the MainWindow is resized.

    But like I said, resizing will not change anything except the size of the grid. The font will not get bigger, and the QLineEdits might enlarge to their maximum preferred height and stop growing. So you probably won't be happy with the result.

    The simplest thing is just to implement resizeEvent() for the SudokuWidget, and all you need to do there is to calculate a new font size and set that. The QLineEdits should inherit it and grow to accommodate.

    The suggestion of the QTimer is only if you don't like the way the resizing looks while you are doing it. If the UI flashing with a repaint ever time your mouse poves doesn't bother you, then leave the resize event simple and just change the font.
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  24. #19
    Join Date
    Apr 2020
    Location
    Lithuania
    Posts
    24
    Thanks
    17
    Qt products
    Qt5
    Platforms
    MacOS X

    Default Re: Random Sudoku board generator

    But maybe I can make that you couldn't change mainwindow size , and set it that it would showfullscreen, and make widget bigger and make that user couldn't change mainwindow size, so there wouldn't be resizing problems.
    Attached Images Attached Images
    Last edited by laurynas2003; 13th April 2020 at 08:32.

Similar Threads

  1. Replies: 6
    Last Post: 21st April 2019, 00:28
  2. Random Generator for Androidx86 in Qt5
    By alexo in forum Newbie
    Replies: 1
    Last Post: 8th September 2014, 06:30
  3. Replies: 1
    Last Post: 7th April 2010, 16:26
  4. Random No Generator in C/C++
    By ankurjain in forum General Programming
    Replies: 1
    Last Post: 6th July 2006, 11:33

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.