wm: mastermind-qt

Download patch

ref: b5d27c8190334c3a5f05314973df9bee0ba91a57
parent: ac44a33d7047518ca5cc00c7b0bb07b2efe6ad02
author: Mahdi-Hsh <mahdi.hoseini1381@yahoo.com>
date: Fri Apr 28 08:11:50 EDT 2023

lots of fixes and changes

added action_objstate function for controling some objects instead of
repeating setEnabled.
removed functions gengoal, digit, length. Sorry but, i prefer strings
here.
gengoal function from console version added.
replaced spinbox with lineEdit.
added if to check guess.length == user length.
added else for above if to control invalid inputs.
regex validator for lineEdit added to function action_newgame.
lineEdit and textEdit font changed to lucida console size 28.
goal and guess type changed to string.
len type changed to unsigned int, because it caused warning when
compared to string.length (type unsigned long long).
lcd lives aligned at center, we do not allow more than 9 chances(lives)
now. (except hesoyam).
adding guess to tree deprecated in function addguess.
checking guess deprecated in function chkguess.
added windowsflags to disable maximize button.
main form resized to 440x420. max len is 10.
show goal cheat deprecated in function cheatgoal.
added cheat code, 's' then 'g' for show goal.
Show goal option in menu only show goal after entering cheat code
(mcheat bool).
added returnPressed signal to lineGuess. now user can hit enter to guess
when focus is on lineGuess.
added QPalette to change color of lives to red when it reaches 1.
tree font resized.
some comments removed.
changed text of a few mboxes. not really sure about new texts.
added chance integer to mange guess no. in tree.
limited length of characters in lineGuess to user len.
limited another chance button to show only one time.
controlled cancel and X on YOU LOST mbox.
added setAutoDefault for button guess to simulate its click when user
hit enter on button focus.

--- a/mainwindow.cpp
+++ b/mainwindow.cpp
@@ -1,86 +1,79 @@
 #include "mainwindow.h"
 #include "ui_mainwindow.h"
 
-#include <cmath> /* pow() */
+#include <QKeyEvent>
 #include <QMessageBox> /* errors, infos */
 #include <QInputDialog> /* getting len */
 #include <QApplication> /* seems to be needed in all qt programs */
 #include <QTreeWidgetItem> /* guessTree */
 #include <QClipboard>
+#include <QPalette>
 
-uint64_t guess = 0, goal = 0;
-int len = 0, lives = 0;
+using namespace std;
+
+string guess, goal;
+unsigned int len = 0;
+int lives = 0;
+int chance = 1;
 bool win;
+bool anotherchance = true;
+bool cheat = false;
+bool mcheat = false;
+QPalette lcolor;
 
+string gengoal(int len) {
+    srand(time(0));
+    string digits;
+    for (int i = 0; i < len; i++) {
+        string rnd = to_string(rand() % 10);
+        digits += rnd;
+    }
+    return digits;
+}
 
-/* generates a goal, n digits long */
-ulong gengoal(ulong n)
-{
-    ulong num = 0;
-    /* it's technically legal, but
-    we get a int that's shorter than n */
-    do
-        num = rand() % 10;
-    while (num == 0);
-
-    /* we have already generated one digit */
-    while(n > 1)
+void MainWindow::cheatgoal()    {
+    QMessageBox m;
+    QAbstractButton *copy;
+    m.setWindowTitle("Cheat");
+    m.setText(QString::fromStdString("It's " + goal + " you cheater!"));
+    m.setIcon(QMessageBox::Information);
+    copy = m.addButton("Copy to clipboard (that lazy?!)", QMessageBox::YesRole);
+    m.addButton("Fine", QMessageBox::AcceptRole);
+    m.exec();
+    if(m.clickedButton() == copy)
     {
-        num *= 10;
-        num += rand() % 10;
-        n--;
+        QClipboard *cb = QGuiApplication::clipboard();
+        cb->setText(QString::fromStdString(goal));
     }
-    return num;
 }
 
-/* counts from 1 */
-int length(ulong n)
+void MainWindow::keyPressEvent(QKeyEvent *event)
 {
-    ulong t = 0;
-    while(n > 0)
+    if(event->key() == Qt::Key_S)
     {
-        n /= 10;
-        t++;
+        cheat = true;
     }
-    return t;
 }
-
-/* we could also use arrays for this,
-    alas, that would a can of worms
-    digit(number, index) = number[index]
-    counts from 0 btw */
-int digit(long number, int index)
+void MainWindow::keyReleaseEvent(QKeyEvent *event)
 {
-    if((index > length(number)) || (index < 0))
-        return -1;
-
-    int i = 0, j;
-    while(i <= index)
+    if(event->key() == Qt::Key_G && cheat)
     {
-        j = number % 10;
-        number /= 10;
-        i++;
+        cheatgoal();
+        cheat  = false;
+        mcheat = true;
     }
-    return j;
 }
 
-
 MainWindow::MainWindow(QWidget *parent)
     : QMainWindow(parent)
     , ui(new Ui::MainWindow)
 {
-    /* dear Qt, with all due respect, why you on earth
-     * you try to make my life so misearable? */
     if(!action_newgame())
     {
-        /* one might wonder, why we didn't used QApplication::exit(),
-         * or MainWindow's close(), destory() etc.
-         * because, we don't have acess to original QApplicaiton
-         * nor MainWindow has fully created to be able to exit it.
-         * and since it's not an error (valid choice it is)
-         *  we consider it a great SUCCESS, hence the following: */
         std::exit(EXIT_SUCCESS);
     }
+    setWindowFlags( Qt::Window | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint );
+    ui->buttonGuess->setAutoDefault(true);
 }
 
 MainWindow::~MainWindow()
@@ -88,6 +81,38 @@
     delete ui;
 }
 
+
+void MainWindow::action_objstate(bool state) {
+    ui->buttonGuess->setEnabled(state);
+    ui->lineGuess->setEnabled(state);
+    ui->textChecked->setEnabled(state);
+    ui->treeHistory->setEnabled(state);
+}
+
+void MainWindow::addguess(string guess) {
+    QTreeWidgetItem *item = new QTreeWidgetItem();
+    item->setText(0, QString::fromStdString(to_string(chance)));
+    item->setText(1, QString::fromStdString(guess));
+    item->setText(2, ui->textChecked->toPlainText());
+    ui->treeHistory->addTopLevelItem(item);
+}
+
+bool MainWindow::chkguess(string guess, string goal, int len) {
+    string result;
+    for (int i = 0; i < len; i++) {
+        if (guess[i] == goal[i]) {
+            result += "<font color=darkgreen>#</font>";
+        }
+        else { result += "<font color=darkred>X</font>"; }
+    }
+    ui->textChecked->setHtml(QString::fromStdString(result));
+    if (guess == goal)  return true;
+    else {
+
+        return false;
+    }
+}
+
 // help menu
 void MainWindow::action_aboutqt()
 {
@@ -96,7 +121,7 @@
 
 void MainWindow::action_about()
 {
-    QMessageBox::about(this, "about", "MasterMind-qt r2");
+    QMessageBox::about(this, "about", "MasterMind-qt V2.2");
 }
 
 // XXX
@@ -103,7 +128,7 @@
 void MainWindow::action_guide()
 {
     QMessageBox m;
-    m.setWindowTitle("Help? there is no help");
+    m.setWindowTitle("Help");
     m.setText("you fell for this this trap? lol. "
               "seriously, remind me to write one");
     m.setIcon(QMessageBox::Information);
@@ -114,19 +139,17 @@
 // cheats menu
 void MainWindow::action_showgoal()
 {
-    QMessageBox m;
-    QAbstractButton *copy;
-    m.setWindowTitle("Cheat");
-    m.setText(QString::fromStdString("It's " + std::to_string(goal) + " you cheater"));
-    m.setIcon(QMessageBox::Information);
-    copy = m.addButton("i'm too lazy to remember that, please copy that to clipboard", QMessageBox::YesRole);
-    m.addButton("k", QMessageBox::AcceptRole);
-    m.exec();
-    if(m.clickedButton() == copy)
-    {
-        QClipboard *cb = QGuiApplication::clipboard();
-        cb->setText(QString::fromStdString(std::to_string(goal)));
+    if (mcheat) {
+        cheatgoal();
     }
+    else {
+        QMessageBox m;
+        m.setWindowTitle("Cheat");
+        m.setText("Developer only! (Maybe you can find the cheat code?)");
+        m.setIcon(QMessageBox::Information);
+        m.addButton("oh huh", QMessageBox::AcceptRole);
+        m.exec();
+    }
 }
 
 void MainWindow::action_inflives(){
@@ -143,15 +166,15 @@
     else if(win)
         return;
     lives = 999;
-    ui->lcdLives->display(99);
+    lcolor.setColor(QPalette::WindowText, Qt::black);
+    ui->lcdLives->setPalette(lcolor);
+    ui->lcdLives->display(9);
     /* if the game was over */
-    ui->buttonGuess->setEnabled(true);
-    ui->spinGuess->setEnabled(true);
-    ui->textChecked->setEnabled(true);
+    chance++;
+    action_objstate(true);
 }
 
 // file menu
-
 bool MainWindow::action_newgame()
 {
     bool res;
@@ -158,15 +181,18 @@
     len = QInputDialog::getInt(this, "MasterMind", "Enter Length of number:", 2, 2, 10, 1, &res);
     if(res)
     {
-        lives = len;
+        if (len < 10) lives = len;
+        else lives = 9;
         goal = gengoal(len);
         win = false;
         ui->setupUi(this);
         ui->lcdLives->display(lives);
-        ui->spinGuess->setMaximum(pow(10, len) - 1);
-        ui->spinGuess->setMinimum(pow(10, len - 1));
+        ui->lineGuess->setMaxLength(len);
+        ui->lineGuess->setFocus();
+        anotherchance = true;
     }
-    /* you pressed cancel "by mistake" ? too bad! your fault. */
+    ui->lineGuess->setValidator(new QRegularExpressionValidator(QRegularExpression("^[0-9]*$"),this));
+
     return res;
 }
 
@@ -173,81 +199,66 @@
 // main window
 void MainWindow::action_guess()
 {
-    QString s;
-    guess = ui->spinGuess->text().toInt();
-    if(guess == goal)
-    {
-       win = true;
-       s = '#';
-       ui->textChecked->setText(s.repeated(len));
-       ui->buttonGuess->setEnabled(false);
-       ui->spinGuess->setEnabled(false);
-       ui->textChecked->setEnabled(false);
-       ui->treeHistory->setEnabled(false);
-
-       QMessageBox m;
-       m.setWindowTitle("YOU WIN!");
-       m.setText("I am pleased to assure you, that; you have managed to win.");
-       m.setIcon(QMessageBox::Information);
-       m.addButton("indeed", QMessageBox::AcceptRole);
-       m.exec();
-    }
-    else if(lives == 1)
-    {
-        /* :( */
+    guess = ui->lineGuess->text().toStdString();
+    if (guess.length() == len) {
+        bool res = chkguess(guess, goal, len);
         ui->lcdLives->display(--lives);
-        ui->buttonGuess->setEnabled(false);
-        ui->spinGuess->setEnabled(false);
-        ui->textChecked->setEnabled(false);
-        ui->treeHistory->setEnabled(false);
+        if(res)
+        {
+           win = true;
+           addguess(guess);
+           action_objstate(false);
+           QMessageBox m;
+           m.setWindowTitle("YOU WIN!");
+           m.setText("I am pleased to assure you, that; you have managed to win!");
+           m.setIcon(QMessageBox::Information);
+           m.addButton("Indeed!", QMessageBox::AcceptRole);
+           m.exec();
+        }
+        else if (!res && lives == 0)
+        {
 
-        QMessageBox m;
-        QAbstractButton *retry, *newgame, *leave;
-        m.setWindowTitle("INSERT COIN");
-        m.setText("I'm afraid you have failed to acheive what"
-                  " you had to do, and now we are all in"
-                  " brink of impading doom...");
-        m.setIcon(QMessageBox::Critical);
-        retry = m.addButton("another chance?", QMessageBox::AcceptRole);
-        newgame = m.addButton("dices were packed! new game and i shall win!", QMessageBox::RejectRole);
-        leave = m.addButton("God has forsaken me, *leaving in shame*", QMessageBox::DestructiveRole);
-        m.exec();
+            addguess(guess);
+            action_objstate(false);
 
-        /* fun(?) fact: switch doesn't work with non numerical types! */
-        if(m.clickedButton() == retry)
-        {
-                /* maybe we should move these into a funcation?
-                 * or maybe we should not... carry on */
-                ui->lcdLives->display(++lives);
-                ui->buttonGuess->setEnabled(true);
-                ui->spinGuess->setEnabled(true);
-                ui->textChecked->setEnabled(true);
-                ui->treeHistory->setEnabled(true);
+            QMessageBox m;
+            QAbstractButton *retry, *newgame, *leave;
+            m.setWindowTitle("YOU LOST!");
+            m.setText("I am ashamed to tell you, that; you lost.");
+            m.setIcon(QMessageBox::Critical);
+            if (anotherchance) retry = m.addButton("Another chance?", QMessageBox::AcceptRole);
+            newgame = m.addButton("New game and i shall win!", QMessageBox::DestructiveRole);
+            leave = m.addButton("Cancel", QMessageBox::RejectRole);
+            m.exec();
+
+            if(anotherchance && m.clickedButton() == retry)
+            {       anotherchance = false;
+                    ui->lcdLives->display(++lives);
+                    action_objstate(true);
+                    ui->lineGuess->setFocus();
+            }
+            else if(m.clickedButton() == newgame)
+                    action_newgame();
+            else if(m.clickedButton() == leave)
+                    m.close();
         }
-        else if(m.clickedButton() == newgame)
-                action_newgame();
-        else if(m.clickedButton() == leave)
-                close();
-    }
-    else
-    {
-        /* len counts from 1, digit counts from 0 */
-        int i = len - 1;
-        while(i >= 0)
+        else
         {
-            if(digit(goal, i) == digit(guess, i))
-                s += "<font color=darkgreen>#</font>";
-            else
-                s += "<font color=darkred>X</font>";
-           // s += digit(goal, i);
-            i--;
+            addguess(guess);
+            chance++;
         }
-        ui->textChecked->setHtml(s);
-        ui->lcdLives->display(--lives);
-        QTreeWidgetItem *n = new QTreeWidgetItem();
-        n->setText(0, QString::fromStdString(std::to_string(len - lives)));
-        n->setText(1, QString::fromStdString(std::to_string(guess)));
-        n->setText(2, ui->textChecked->toPlainText());
-        ui->treeHistory->addTopLevelItem(n);
+
+        if (lives == 1) {
+            lcolor.setColor(QPalette::WindowText, Qt::red);
+            ui->lcdLives->setPalette(lcolor);
+        }
+    }
+    else {
+        QMessageBox m;
+        m.setWindowTitle("Invalid!");
+        m.setText("Invalid number!");
+        m.setIcon(QMessageBox::Information);
+        m.addButton("Indeed!", QMessageBox::AcceptRole);
+        m.exec();
     }
 }
--- a/mainwindow.h
+++ b/mainwindow.h
@@ -33,6 +33,14 @@
 
     // main window
     void action_guess();
+    void action_objstate(bool);
+    void addguess(std::string);
+    bool chkguess(std::string, std::string, int);
+    void cheatgoal();
+
+protected:
+    void keyPressEvent(QKeyEvent *event);
+    void keyReleaseEvent(QKeyEvent *event);
 };
 
 #endif // MAINWINDOW_H
--- a/mainwindow.ui
+++ b/mainwindow.ui
@@ -6,8 +6,8 @@
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>500</width>
-    <height>440</height>
+    <width>440</width>
+    <height>420</height>
    </rect>
   </property>
   <property name="sizePolicy">
@@ -18,22 +18,25 @@
   </property>
   <property name="minimumSize">
    <size>
-    <width>500</width>
-    <height>364</height>
+    <width>440</width>
+    <height>420</height>
    </size>
   </property>
   <property name="maximumSize">
    <size>
-    <width>500</width>
-    <height>440</height>
+    <width>440</width>
+    <height>420</height>
    </size>
   </property>
   <property name="baseSize">
    <size>
-    <width>500</width>
-    <height>440</height>
+    <width>440</width>
+    <height>420</height>
    </size>
   </property>
+  <property name="focusPolicy">
+   <enum>Qt::StrongFocus</enum>
+  </property>
   <property name="windowTitle">
    <string>MasterMind</string>
   </property>
@@ -45,11 +48,17 @@
     <property name="geometry">
      <rect>
       <x>10</x>
-      <y>130</y>
-      <width>471</width>
+      <y>120</y>
+      <width>421</width>
       <height>261</height>
      </rect>
     </property>
+    <property name="font">
+     <font>
+      <family>Calibri</family>
+      <pointsize>12</pointsize>
+     </font>
+    </property>
     <column>
      <property name="text">
       <string>No.</string>
@@ -70,16 +79,19 @@
     <property name="geometry">
      <rect>
       <x>10</x>
-      <y>20</y>
+      <y>10</y>
       <width>111</width>
       <height>101</height>
      </rect>
     </property>
+    <property name="layoutDirection">
+     <enum>Qt::LeftToRight</enum>
+    </property>
     <property name="smallDecimalPoint">
      <bool>false</bool>
     </property>
     <property name="digitCount">
-     <number>2</number>
+     <number>1</number>
     </property>
     <property name="segmentStyle">
      <enum>QLCDNumber::Flat</enum>
@@ -92,8 +104,8 @@
     <property name="geometry">
      <rect>
       <x>190</x>
-      <y>80</y>
-      <width>291</width>
+      <y>70</y>
+      <width>241</width>
       <height>41</height>
      </rect>
     </property>
@@ -105,13 +117,16 @@
     </property>
     <property name="font">
      <font>
-      <family>Monospace</family>
-      <pointsize>26</pointsize>
+      <family>Lucida Console</family>
+      <pointsize>28</pointsize>
      </font>
     </property>
     <property name="cursor" stdset="0">
      <cursorShape>IBeamCursor</cursorShape>
     </property>
+    <property name="focusPolicy">
+     <enum>Qt::NoFocus</enum>
+    </property>
     <property name="layoutDirection">
      <enum>Qt::LeftToRight</enum>
     </property>
@@ -135,7 +150,7 @@
     <property name="geometry">
      <rect>
       <x>140</x>
-      <y>40</y>
+      <y>30</y>
       <width>31</width>
       <height>21</height>
      </rect>
@@ -151,7 +166,7 @@
     <property name="geometry">
      <rect>
       <x>130</x>
-      <y>80</y>
+      <y>70</y>
       <width>51</width>
       <height>41</height>
      </rect>
@@ -160,33 +175,35 @@
      <string>Guess!</string>
     </property>
    </widget>
-   <widget class="QSpinBox" name="spinGuess">
+   <widget class="QLineEdit" name="lineGuess">
     <property name="geometry">
      <rect>
       <x>190</x>
-      <y>33</y>
-      <width>291</width>
+      <y>10</y>
+      <width>241</width>
       <height>41</height>
      </rect>
     </property>
     <property name="font">
      <font>
-      <family>Monospace</family>
-      <pointsize>26</pointsize>
+      <family>Lucida Console</family>
+      <pointsize>28</pointsize>
      </font>
     </property>
-    <property name="cursor">
-     <cursorShape>IBeamCursor</cursorShape>
+    <property name="text">
+     <string>0</string>
     </property>
-    <property name="inputMethodHints">
-     <set>Qt::ImhNone</set>
+   </widget>
+   <widget class="QWidget" name="verticalLayoutWidget">
+    <property name="geometry">
+     <rect>
+      <x>100</x>
+      <y>210</y>
+      <width>258</width>
+      <height>31</height>
+     </rect>
     </property>
-    <property name="maximum">
-     <number>1000000000</number>
-    </property>
-    <property name="stepType">
-     <enum>QAbstractSpinBox::AdaptiveDecimalStepType</enum>
-    </property>
+    <layout class="QVBoxLayout" name="verticalLayout"/>
    </widget>
   </widget>
   <widget class="QMenuBar" name="menubar">
@@ -194,7 +211,7 @@
     <rect>
      <x>0</x>
      <y>0</y>
-     <width>500</width>
+     <width>440</width>
      <height>20</height>
     </rect>
    </property>
@@ -400,6 +417,22 @@
     <hint type="destinationlabel">
      <x>219</x>
      <y>181</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>lineGuess</sender>
+   <signal>returnPressed()</signal>
+   <receiver>MainWindow</receiver>
+   <slot>action_guess()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>335</x>
+     <y>60</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>249</x>
+     <y>219</y>
     </hint>
    </hints>
   </connection>