$29
Objectives & Intended Learning Outcomes
The objective of this assignment is to familiarise you with Qt programming.0After this assignment you should be able to:
1. Use Qt Designer to build the GUI of a program.
2. Use signals and slots to let Qt objects communicate with each other.
3. Implement a fully functional game in Qt.
End of Objectives & Intended Learning Outcomes
Menu
Honor Code
Objectives & ILOs
Introduction
Description
Tasks
Task 1
Task 2
Task 3
Task 4
Task 5
Bonus Task 1
Bonus Task 2
Bonus Task 3
Bonus Task 4
Bonus Task 5
Testing & Grading
Resources & Sample
Program
Submission
FAQ
Change Log
Homepage
Course Homepage
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 1/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
The popular game Wordle on The New York Times0
Introduction
To get yourself familiar with creating a Qt program, let's build the popular game Wordle!0Wordle is a word guessing game where you must try to guess a 5-letter word within 6 guesses.0Hints are given after each guess about whether each letters are correct, appear in a different position, or do not appear at all. You can play the game on the0New York Times website,0if you are not already familiar with how the game works.0The game only allows you to play once per day, which is why we will implement a Qt version0of the game so that you can play any time you'd like, and with several other modes you0can add in the bonus tasks!
In this assignment, you are required to:
Implement the Wordle coloring scheme and hard mode
Implement the user input keyboard (both physical and on-screen)
Implement GUI widgets for game mode options using Qt Designer
In addition, you may also attempt these tasks for bonus points:0
Implement additional modes: Simultaneous games, Timed mode, Absurd mode
Write a solver to give the player an "optimal" next guess
Use word frequency to generate more common answers
Please read the Qt Programming tutorial notes and lab example before starting this assignment0to understand the basics of programming with Qt. We will use Qt 6.3.2 for this assignment,0so please install the same version to ensure your program can be tested correctly (Note that versions as low as 5.12 may still be able to run the skeleton code, but we have not tested with older versions yet).
End of Introduction
Description
Please read the FAQ section regularly, and do check it0one day before the deadline to make sure you don't miss any clarification,0even if you have already submitted your work by then. You can also raise questions0on Piazza and remember to use the "pa7" tag.
Code structure
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 2/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
Hierarchy of the given skeleton files.
At first glance, the skeleton code can look overwhelming with the number of files.0Don't worry though! This is because the project is built with testing in mind, so it is split into 20sub-projects: app and tests. You can open the app.pro file in Qt Creator0to edit and build only the application - it is recommended that you do this when you first start,0so that you don't waste time building the test programs. The files in tests sub-project is only relevant0in the Testing and Grading section.
There are multiple .cpp and .h files for the app. They are organized so that whenever you work on a task, you only need0to handle a few source files at a time.0Here is a quick breakdown of all the files.
Note: You may find a few topics in this assignment not yet covered in lectures.0Don't worry, you don't need to know them to complete the assignment. Any tasks that may0require you to use these topics will be explicitly stated and will have thorough instructions.
Inheritance and polymorphism: These are extremely useful when0it comes to UI related classes, especially Qt. For this assignment, you don't0have to know a lot about them, they are simply a way to implement similar objects0(such as different game modes) where similar data members/functions can be reused0or reimplemented accordingly. You will learn more about this topic in PA8, so feel0free to come back to this assignment to understand the classes' relationships better.
Friend classes: These are only relevant for test classes, you don't0need to worry about them. Defining the test classes as "friends" of the main classes0allow them to access said classes' private data members, which helps with testing.
Exception handling: Used in dictionary.cpp and mainwindow.cpp as an easy way to exit sub-window's initialization should unexpected errors occur. You don't have to use this in the basic tasks;0for some of the bonus tasks, you can refer to existing code for reference.
Macros: A handy way to shorten repeating codes - any instances of macros0will be replaced with the macro definition during compilation (you can think of this0as similar to Makefile variables). If you are familiar with this,0feel free to use them if necessary; otherwise, just write your code normally.
Containers/Templates: Qt provides helpful containers such as QSet or0QList. These are very similar to standard containers in the STL library,0which will be taught in the lectures soon. These may be relevant when you try to do0the bonus tasks. You can think of containers like QSet<QString> as0"an object capable of storing strings that allows for easy insertion (insert()),0deletion (remove()), and look-up (find())".
main.cpp
This is simply the default main.cpp of Qt, where an application and a MainWindow is created.
This file does not need to be changed.
mainwindow.cpp/.h
These files handle the MainWindow view, which is what the user sees when the program first opens.0The UI for this window is designed in mainwindow.ui.0Here, the user can select the game mode and options. Upon clicking "Play", this window will be hidden,0and the corresponding RoundWindow will be shown.
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 3/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
roundwindow.cpp/.h
These files handle the RoundWindow view, which is what the user sees when starting a game.
The UI for this window is designed in roundwindow.ui.
Note that this is a base class, and for the most part should not be initialized as an object directly.0When user starts a game mode, MainWindow will initialize an object of one of the derived classes,0defined in the [mode]roundwindow.cpp/.h files.0You can consider this class as the "shared" properties of the different windows for each mode,0and implement the tasks normally.
wordleround.cpp/.h
The WordleRound class handles the game logic for a game of Wordle.0Receives key input and update the guess boxes accordingly.0When a complete guess is entered, guess should be validated0before being colored according to Wordle coloring convention.0Handles game over conditions as well.
Note that this is a base class, and for the most part should not be initialized as an object directly.0The derived RoundWindow class should initialize a corresponding WordleRound object of one of the derived classes,0defined in the [mode]wordleround.cpp/.h files.0You can consider this class as the "shared" properties of the different game modes,0and implement the tasks normally.
regularroundwindow.cpp/.h, regularwordleround.cpp/.h
These are the derived classes of RoundWindow and WordleRound for the Regular mode. Since the base classes are essentially sufficient for building a regular game,0not much is added within these files. There's no need to change these files.
absurdroundwindow.cpp/.h, absurdwordleround.cpp/.h
These are the derived classes of RoundWindow and WordleRound for the Absurd mode.0You only need to modify these files for Bonus Task 1.
multiroundwindow.cpp/.h, multiwordleround.cpp/.h
These are the derived classes of RoundWindow and WordleRound for the Multiple mode.0You only need to modify these files for Bonus Task 2.
timedroundwindow.cpp/.h, timedwordleround.cpp/.h
These are the derived classes of RoundWindow and WordleRound for the Timed mode.0You only need to modify these files for Bonus Task 3.
letterbox.cpp/.h
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 4/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
The LetterBox class extends QLineEdit, the widget used for the guess boxes.0Initialized by WordleRound, then added to the UI.0Handles the backend of changing text and color, so that other classes0can simply call setLetter() and setColor().
keyboard.cpp/.h
The Keyboard class holds the 26 Keys and the 2 QPushButtons for Del and Enter.0Initialized by RoundWindow. The keys are defined in the .ui file,0so they need to be added to the Keyboard after initialization.0Communicates with the current WordleRound when a key is pressed,0and receives key color updates from WordleRound.
key.cpp/.h
The Key class extends QToolButton, the widget used for the 26 letter keys.0Handles the backend of changing color, so that other classes0can simply call setColor().
dictionary.cpp/.h
The Dictionary class maintains a set of all English words of given length, by extracting from words_{}.txt.0For Bonus Task 5, also maintain a list of common words with frequencies, used to generate answers.0Initialized by WordleRound.
There is also a DictionaryException class defined for exception throwing.0As mentioned in the note, you don't have to worry about this class.
solver.cpp/.h
The Solver class maintains a set of remaining possible answers as the WordleRound progressed,0and calculates the "optimal" next guess to be hinted to the player.0You only need to modify these files in Bonus Task 4.
mainwindow.ui, roundwindow.ui
These are the UI files that can be edited in Qt Creator's Designer mode.
dictionary/, images/
Additional files used by the program. They are specified in resources.qrc so that0the program can locate them during runtime.
Wordle color convention
In Wordle, 3 colors are used to hint the "correctness" of a letter:
Green letters are in the correct positions.
Yellow letters are in the word, but are not in the correct positions.
Grey letters do not appear in the word at all.
The coloring scheme can also get a bit tricky when a letter appears multiple times in the guess or the answer.0To illustrate this clearly, let's look at an example.
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 5/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
Suppose the answer to the Wordle game is "SLEEP". Here are the coloring schemes for some possible guesses:
L is in the correct position, so it is green.0P is in the word but not in the correct position, so it is yellow.0U, C, K don't appear in the word, so they are grey.
There are 2 Ss in the guess, but only 1 S in the answer. The first S is yellow,0telling you that the correct S is not in this position. The second S is grey,0telling you that there is no extra S, and the correct S is also not in this position.
Same as above, except the second P is green because there is a P there.0The first P is grey because there is no extra P.
The second E is green because there is an E there.0The first E is yellow because there is a 2nd E, which is not at this position.0The third E is grey because there is no 3rd E, and there is no E at this position.
In addition to coloring the guesses, we also need to color the keyboard. The letters on the keyboard are colored0similar to the guesses to tell the player the current "correctness" status for each key.
This keyboard is saying that the letter I has been found at the right position, and letters S, R, K are in the answer but at unknown positions. Grey letters are0known to not be in the answer, while light grey letters have not been used in any guesses.
Whenever a guess is made, the keyboard is updated with new key colors. Only the "highest" color is kept: e.g. in the GEESE example, the key E would be colored green; in the ASSET example, the key S would be colored yellow.
We will describe in detail how to implement this coloring scheme in the Tasks section.
Demo program overview
This section is a brief overview of the demo program, which is essentially how0your program is expected to behave if all tasks (including bonus tasks) are implemented0correctly. Feel free to try out and play the game yourself.
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 6/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
When starting the program, you will be taken to the main window. You can select the game mode0and additional options for each mode, as well as word length. After clicking Play, the game0window will be shown.
This is the window for Regular mode. This can be played exactly like the official Wordle version:0you can either press the buttons to input letters or use the keyboard to type. Popups appear0if the player types a non-English word or finishes the game.
In the Options menu, there are 4 options. "Give Up" ends the game and treat it as a loss. "Reset Round" ends the current game and starts a new game with a new word.0"Cheat" reveals the answer. This is helpful if you would like to test game logic with the0demo program or your program. Finally, "Hint" will try to give the player an "optimal"0word to guess. This is implemented in Bonus Task 4.
For other game modes, there are a few UI changes. These are described in more detail0in the bonus task section, and you don't need to worry about them if you just plan0to do the basic tasks.
Additional remarks
All of the needed header files have been included in the source files, so you don't need to add any new includes. If you do add new includes,0you are only allowed to add the given header files and Qt-provided header files,0such as <QPushButton>.
You are strictly forbidden from modifying the provided files not for submission;0in other words, all of the .h header files and a few .cpp files. During grading, we will use0the version given in the skeleton code of these files, so any changes you made there will be lost during actual grading.
End of Description
Tasks
The tasks are divided into 2 sections: Basic tasks and bonus tasks.0There are 5 tasks for each section, with weighting detailed below.0The bonus tasks are quite challenging so don't spend too much time on them; you will get a total of 15% bonus points for completing all05 bonus tasks.
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 7/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
Tip: All tasks have comment blocks near them detailing what needs to be done in the code. You can use the Search option in Qt Creator and look for the string TODO0to find which part of the code you need to edit.
Basic Tasks
Task 1: Implement letter coloring scheme [20%]
You will need to implement the function
QColor* analyzeGuess(const QString& guess, const QString& answer)
in wordleround.cpp. This function compares the 2 strings guess0and answer, and outputs an array of QColor corresponding to0the color sequence of guess.
To do this, you can use a 2-pass strategy:0Create 2 arrays, one to store the color sequence and the other to be0the "assigned" status of answer's letters.
For the first pass, compare each of guess and answer's letters.0If the letters are the same, color it green and set "assigned" to true.0Otherwise, color it grey and set "assigned" to false.
For the second pass, compare each of guess's remaining letters with all of answer's "unassigned" letters.0If a similar letter is found "unassigned", color it yellow and set "assigned" to true.
The rightmost E is grey because no "unassigned" E remains.0
Now the color array can be returned. Since the array length is not constant,0remember to manage any dynamically allocated variables and delete when unused.
If you think you can come up with a faster algorithm to complete this task0(the above algorithm is O(n^2)), feel free to give it a go, but0make sure it is correct by double checking color sequence output for special cases.
Hint: You can use the colors defined in letterbox.h.
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 8/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
Task 2: Implement on-screen keyboard [25%]
For this task, you need to modify some functions in roundwindow.cpp and keyboard.cpp.
You will also need to work with the roundwindow.ui to add the buttons to the UI.
First, open roundwindow.ui. Qt Creator should take you to the Design tab.0Find the QGridLayout named gridLayoutKey on the UI (you may also look at the widget list on the side bar).0Add 26 QToolButtons to the grid to resemble a keyboard. Set their text as uppercase letters.
Example grid layout of 26 keys and 2 buttons. Hint: widgets can span multiple grid cells.
Rename the widgets to toolButton_{LETTER} so that you can access them in roundwindow.cpp later.0Select all keys, right click and choose Promote to.... Select Key as the class0to promote to, or type in the class name "Key" and header file "key.h". This will convert0the 26 QToolButtons to Key objects.
Also add 2 QPushButtons and set their text as "Del" and "Enter".0Rename the widgets to pushButton_Del and pushButton_Enter.
Important: While widget names can be anything as long as they0can be accessed in the code, please name the widgets as above so that they can be tested.0As an example, the key A should be named toolButton_A.
Then, go to the RoundWindow constructor
RoundWindow::RoundWindow(QWidget *parent)
in roundwindow.cpp. As described in the Description section, the 26 keys and Del/Enter keys defined in roundwindow.ui need to be added to the Keyboard after it is initialized.
Tip: The most straightforward way is to write 26 lines to add the letter keys.0However, this can be drastically shortened if you know how to use macro in C++.
Next, go to keyboard.cpp and implement the following functions:
void Keyboard::addKey(Key *key, const char keyChar)
void Keyboard::addDelKey(QPushButton *key)
void Keyboard::addEnterKey(QPushButton *key)
These functions should set the data members to the right buttons and connect the buttons' clicked() signals to the corresponding handling slots of Keyboard.
Finally, go to
void Keyboard::updateKeyColor(const QChar& key, const QColor& color)
and implement the keyboard coloring scheme described above.0Simply put, the color of each key can only go up from grey to yellow and to green.
Task 3: Implement physical keyboard [15%]
The on-screen keyboard can be cumbersome to use. Therefore, we'd like to implement our existing keyboard0as an alternative input method. To do this, we need to override RoundWindow's keyPressEvent()0method, which gets called whenever the window receives physical keyboard input.
Simply put, you just need to complete the implementation of
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 9/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
void RoundWindow::keyPressEvent(QKeyEvent *event)
in roundwindow.cpp. You can get the key being pressed with event->key(),0which will correspond to one of Qt's defined key enums. Depending on the key being pressed,0call the corresponding Keyboard function.
Hint: Slots can be called as a function normally.
Task 4: Implement round options [25%]
This task will involve editing the mainwindow.ui form, as well as mainwindow.cpp.0You will need to add the widgets that allow players to configure settings before playing.0While some of these are related to the extra modes implemented in bonus tasks, here we just0need to implement the widgets so that they appear correctly (pressing Play when an extra mode0is selected will not do anything yet).
First, open mainwindow.ui. Qt Creator should take you to the Design tab.0Find the
QGridLayout. You will need to add the following items to the Grid:
QLabel labelMode, with text "Mode"
QComboBox comboBoxMode. Double click on the widget to add the following options:
Regular
Absurd
Multiple
Timed
QLabel labelNumWords, with text "Number of Words"
QSpinBox spinBoxNumWords.0Set its minimum and maximum values to 2 and 8. Set its default value to 2.
QLabel labelTime, with text "Time"
QComboBox comboBoxTime. Double click on the widget to add the following options:
1 minute
3 minutes
5 minutes
10 minutes
QLabel labelWordLength, with text "Word Length"
QSpinBox spinBoxWordLength.0Set its minimum and maximum values to 1 and 31.
Set its default value to 5.
QCheckBox checkBoxHardMode, with text "Hard Mode"
Example grid layout of mode selection widgets.
Important: While widget names can be anything as long as they0can be accessed in the code, please name the widgets as above so that they can be tested.
Next, go to mainwindow.cpp and complete the missing implementations. In particular:
MainWindow::MainWindow(QWidget *parent)
Connect the Mode comboBox's signals to the corresponding MainWindow slots and hide the non-default options.
void MainWindow::resetExtraOptions()
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 10/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
This function hides the widgets for Number of Words, Time and Hard Mode, since they are not used by all modes.
void MainWindow::start()
Change wordLength, mode and hardMode to read from the widgets instead of using default values.
void MainWindow::modeChanged(const QString &mode)
Implement this function to show widgets that correspond to selected mode. It should call resetExtraOptions() at the beginning, then show widgets based on mode.
Task 5: Implement hard mode [15%]
Wordle has a Hard Mode option where subsequent guesses must use all letters known to be in the word0(in other words, yellow and green letters).0For example, if your guess was "SUPER" and the letter S is green, letters0E and R are yellow, you must use S, E, R in your next guesses. The game0rejects invalid guesses just like non-English words.
For this task, you will add some extra functions and cases to the implementations0you made in Task 2, so that if Hard Mode is enabled, extra validation is made when guessing.
Implement the
bool validHardModeGuess(const QString& guess, const bool correctLetters[])
function in wordleround.cpp, which checks if guess contains all letters deemed0"correct" by the array correctLetters.
Hint: correctLetters is a boolean array of length 26. If correctLetters[3]0is true, this means the (3+1)-th letter ("D") is "correct".
Next, modify the
void WordleRound::registerEnterKey()
function to add Hard Mode validation, if hard mode is enabled. It should also maintain0the correctLetters array after each guess.
Bonus Tasks
Bonus Task 1: Implement Absurd mode [2%]
This task is inspired by Absurdle,0an adversarial variant of the game where the answer changes so that it takes the player as many guesses as possible to find the right word. Essentially, the answer is only determined when0the set of player's guesses with colors could only have come from one possible answer.0However, this means the answer fully depends on user inputs and will be the same for a given0set of guesses (we can call this game "deterministic"), and has no replayability value.0Therefore, we will implement a slightly different version of the game, where the answer changes by at most one letter after each guess.
You will only have to modify absurdwordleround.cpp, absurdroundwindow.cpp and mainwindow.cpp. For MainWindow, you just need to initialize the AbsurdRoundWindow when the Absurd mode is selected.
In absurdroundwindow.cpp:
Complete the constructor (you may look at RegularRoundWindow's constructor as example).
For this mode, we don't color the keyboard since the answer changes, so no need to connect the signals.
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 11/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
In absurdwordleround.cpp: Implement
QString alterAnswer(const QString& answer, const QSet<QString>& allAnswers)
which finds a word from the set that differs from answer by exactly 1 letter. If no such word exists, the function returns answer.
Bonus Task 2: Implement Multiple mode (Simultaneous games) [4%]
This task is inspired by Dordle, Quordle, and many other variants where0players need to guess more than one word at a time. The guess is used across all answers,0so there is a coloring sequence for each remaining unguessed word.
You will only have to modify multiwordleround.cpp, multiroundwindow.cpp and mainwindow.cpp. For MainWindow, you just need to initialize the MultiRoundWindow when the Multiple mode is selected.0The player can select how many words to guess at the same time (between 2 and 8).
In multiroundwindow.cpp:
Complete the constructor (you may look at RegularRoundWindow's constructor as example).
We need to add another 2D grid of LetterBox* for each extra words that need to be guessed.0The description in the skeleton code provides more detail on how to initialize them0and add them to the UI.
Important: You need to add the QGridLayouts to the0horizontal layout so that the answers appear in order from left to right; that is,0ansMulti[0] corresponds to the leftmost column of LetterBox grid.0You can look at the demo program's behaviour for reference (use Cheat option to0see the answers). This is important for some test cases in grading.
In multiwordleround.cpp: Implement the following functions:
void MultiWordleRound::registerKey(const QChar& key)
void MultiWordleRound::registerDelKey()
void MultiWordleRound::revertGuess()
void MultiWordleRound::registerEnterKey()
You can refer to the implementations in wordleround.cpp; these should mostly be the same except0that you need to handle a 3D array of LetterBox*. Since Hard Mode and Solver are0not applicable in this mode, you don't need to implement them.
Note: Some answers may end up the same, especially if there are not many available words. This does not happen in Dordle, Quordle or other online variations, but for our game we allow it to happen.0We also just update the keyboard color based on values from all "sub-games", so it's possible to see0more than 5 green or yellow keys (in actual variations, the keys are colored in a grid).
Bonus Task 3: Implement Timed mode [4%]
In this mode, the player will try to guess as many words as possible within a given duration.
For this task, you will need to make a few adjustments to the UI:
Add widgets to display time, number of guessed words, button to skip word
Add a widget to display invalid word, correct guess, etc. instead of popups,0since we don't want to be interrupted while playing under time constraints.
While adding widgets can be done with Qt Designer, it would require creating another0.ui form specifically for the Timed mode. Here we use inheritance so that we can0reuse roundwindow.ui, so the extra widgets need to be added via code.
You will only have to modify timedwordleround.cpp, timedroundwindow.cpp and mainwindow.cpp. For MainWindow, you just need to initialize the TimedRoundWindow when the Timed mode is selected.
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 12/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
In timedroundwindow.cpp:
Complete the constructor (you may look at RegularRoundWindow's constructor as example).
We need to initialize several other widgets exclusive to this mode, look at the0description in the skeleton code for more detailed instructions.
Implement the void TimedRoundWindow::updateTimer() function.0This is called every second in order to update the timer shown on the UI.
In timedwordleround.cpp: The invalidWord, invalidHardWord, roundWin, roundLose signals are connected to RoundWindow's popup slots.0We don't want to have popups during the game, so use disconnect to remove them.0Then connect the signals, along with scoreUpdated, to the corresponding slots0in TimedRoundWindow.
Also implement the following functions:
void TimedWordleRound::endRound(const bool win)
void TimedWordleRound::resetTimedRound()
void TimedWordleRound::skipCurrentWord()
Bonus Task 4: Implement Solver [3%]
This task is inspired by this video from0YouTuber 3Blue1Brown, who tried to find0the optimal Wordle starting guess using information theory.0For each word, we calculate the average amount of "information" we expect to learn if0we used this word as a guess (also called entropy).0The formula for entropy:
where X is a random variable representing the color sequence that could appear from guessing this word.0x is one possible outcome of X (for example, GREY-YELLOW-GREEN-GREY-GREY),0and p(x) is the probability that x happens, given that the chosen word is used as0a guess and any of the remaining possible answers could be the actual answer. Therefore, you need to0calculate the color sequence for each possible answer with the given guess, and find the probability of0each color sequence happening (assume uniform probability for possible answers). We use log base 2 for reasons0described in the video, but any logarithm base would still work.
Finally, to get the "optimal" next guess, we select the word from the set of all possible guesses with the highest entropy - we expect to gain the most amount of information, and hence reduce the0size of remaining answers, with this word.
Note: If there is only one possible answer left, all words will have entropy of 00because the size of possible answers cannot be reduced further. In this case, solver should0hint the only remaining possible answer.
Note: We ignore Hard Mode in this bonus task because the solver can hint words not using correct letters. If we were to implement Hard Mode, we just need to check if Hard Mode is enabled, and use the set of remaining possible answers as the possible guesses in entropy calculation.0But you don't need to implement that for this assignment.
For this task, you only need to modify solver.cpp and wordleround.cpp.0In WordleRound, you just need to update void WordleRound::registerEnterKey()0to call the function to update solver's set of remaining possible answers after each guess.
In solver.cpp, implement the following functions:
double computeEntropy(const QString& word, const QSet<QString>& possibleAnswers)
This function calculates the entropy of a given word with the remaining possible answers using the formula calculated above.0Follow the detailed description in the skeleton to implement this function.
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 13/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
QString Solver::hint()
This function returns the "optimal" next guess - the word with the highest entropy. If there is only one0possible answer left, the function returns that answer.
void Solver::updateAnswers(const QString& guess, QColor* const colors)
This function updates the set of possible answers based on the result of newest guess.
Answers that do not0result in the given color sequence is discarded from the set.
Hint: Header file <cmath> has been included in solver.cpp.
Note: Near the bottom of wordleround.cpp, you will see the QString
WordleRound::getHint() function.0This determines the condition for giving hint, since the computation time and space0can become enormous if there are too many letters or too many answers to loop from0(remember that we need a bin length of 3^word_length).0The current settings is to only give hint for words at most 10 letters, and the0number of remaining answers times word length does not exceed 5000. You may modify0these numbers to do your own testing (my computer was able to handle 18 letters),0but don't forget to change back for submission.
Bonus Task 5: Implement Word Frequency [2%]
If you tried playing the game for a while, you'll notice that a lot of games have0very obscure words as answers. This is because the word list (words_{}.txt)0contains all English words, many of which are very rarely used. In this task, we will0incorporate a separate list of most common English words (answers_{}.csv)0so that the answer word can be picked and will more likely be a common word that's guessable.
For this task, you only need to modify dictionary.cpp:
Dictionary::Dictionary(int word_length)
In the constructor, add a section to read from answers_{}.csv and add them into the answer list.0You can make use of the WordFrequency struct.
QString Dictionary::getRandomAnswer() const
Modify this function to instead return a random word from the answer list.0Word counts should determine how likely the word would be picked as the answer.0If answer somehow cannot be picked, you can fall back to the default behaviour of picking from the word set instead.
QSet<QString> Dictionary::getAllAnswers()
Modify this function to instead return the words from answer list instead of word set.
Note: The words in answers_{}.csv are guaranteed to appear in words_{}.txt.
End of Tasks
Testing and Grading
Due to ZINC system not being equipped to grade Qt projects, this assignment0will be graded manually. This is why we have provided you with a set of0test cases in tests sub-project, so that you can do testing on your own0after you have finished the tasks.
Open the PA7.pro project. Click on "Projects" on the top left corner0and navigate to the "Tests" section. You should see something like this:
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 14/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
First, build the project. This will compile both the application and the test programs0(one for each test class).
Then, open the Test Result panel. You can select either "Run All Tests" to run all 10 test classes,0or "Run Selected Tests" to run only the tests checked on the "Tests" section.
Example of test report.0
After the tests complete, you can see the results of which test cases passed or failed. You can click on them to see in detail which specific test failed.
Important: Many of the test cases require the unimplemented UI widgets in tasks 2 and 4,0or the physical keyboard in task 3. You need to make sure the widgets are named according to specification,0otherwise the tests cannot find those widgets. The tests have been designed to compile even if you0have not implemented the widgets or named them incorrectly, but would result in failed tests.
Note: During testing, some windows may pop up and close rapidly. This is normal as the test cases are running GUI tests. If a pop up window appears and do not close, close it manually (this will most likely correlate to a failed test case where pop up window is not expected).
After submission deadline, your project will be graded using a different test sub-project,0with many more test cases. Your assignment will be graded based on how many test cases passed, scaled according to task scoring scheme described above.
End of Testing and Grading
Resources & Sample Program
Last updated: 03:20 22/10/2022
Skeleton code:
Windows/Linux: PA7.zip
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 15/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
Mac: PA7-mac.zip
Demo program:
Windows executable: app.exe
Windows executable with dependencies: PA7-bundle.zip
Linux: app-linux
Mac (Intel): app-mac-intel
Mac (M1): app-mac-m1.zip
The Windows Qt executable cannot run by itself; it requires several Qt dynamic-link libraries.
To run the provided executable, copy the folder bin inside the Qt distribution MinGW folder
(example: Qt/6.3.2/mingw_64/bin) to a different place, then put the app.exe inside.0Also
copy the platform folder from plugins (example:
Qt/6.3.2/mingw_64/plugins/platform)0inside the new folder. Now you can execute the
app.exe program. Alternatively, download the .zip0with dependencies and run the app.exe
inside.
End of Download
Submission
Deadline: 23:59:00 on 29 October, 2022.
ZINC Submission
Submit the following files in .zip format to ZINC:
absurdroundwindow.cpp
absurdwordleround.cpp
dictionary.cpp
keyboard.cpp0
mainwindow.cpp
multiroundwindow.cpp0
multiwordleround.cpp0
roundwindow.cpp0
solver.cpp0
timedroundwindow.cpp0
timedwordleround.cpp0
wordleround.cpp0
mainwindow.ui0
roundwindow.ui
In other words, submit all .ui files and .cpp files, except key.cpp,0letterbox.cpp, main.cpp, regularroundwindow.cpp, regularwordleround.cpp.0ZINC will only be used to check if you have submitted the correct files,0and whether you accidentally submitted the skeleton files. Even if you have0not completed a task related to some files, please still submit them0(you can use the skeleton files, which will only trigger ZINC warnings).0Grading will be done manually using a different test set after the deadline.
End of Submission
Frequently Asked Questions
Please see the Qt FAQ page0for common questions related to Qt.
Q: My code doesn't work, there is an error/bug, here is the code, can you help me fix it?0
A: As the assignment is a major course assessment, to be fair, you are supposed to work on it on your own and we should not finish the tasks for you. We are happy to help with explanations and0advice, but we shall not directly debug the code for you.
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 16/17
, 9:52 PM COMP 2012H Assignment 7: PortaWordle
Q: Am I allowed to use local function declarations (function declaration inside an existing function) for my helper functions?
A: You are strongly discouraged from doing so, as that "feature" is a leftover merely for backwards compatibility with C. In C++, it is superseded with class functions and lambda functions,0which will be taught later in this course. However, you are free to define your own helper functions0in the .cpp files that you submit.
Q: For tasks 2 and 4, do I need to position the widgets exactly according to the demo program/given0illustrations? 0
A: No need, the test cases are designed so that as long as the widgets have the correct name, they0can be accessed by the test programs. You can position the widgets and give them some expansion policy0however you want. But it is important that the widgets are named according to the specifications.
Q: How can I access the widgets added via the .ui forms in the Window's code?0
A: Widgets added via the .ui form will become members of the data member ui of the Window class.0You can access the widget by using ui->[widget_name].
Q: How do I print messages to the terminal? I would like to use it for debugging.0
A: You can use qDebug() the same way you would use cout. Note that endl is not needed.
You will be able to see the debug messages in the Application Output terminal.
End of Frequently Asked Questions
Change Log
17:20 - 14/10/22: Added source code and demo program for MacOS, containing a few differences:
dictionary.h: Changed the signature of DictionaryException what() so that the0code can compile.
resource.qrc: Changed encoding to UTF-8.
If the Mac executable does not work, please try0using the Windows executable/dependencies bundle on the virtual barn machines.
14:45 - 19/10/22: Added a FAQ question about widget accessing in code.
03:15 - 22/10/22: Updated the following source files:
multiwordleround.h
multiroundwindow.h
timedroundwindow.h
roundwindow.h
wordleround.h
The only changes are making the destructors of the classes virtual.0It should not affect the tasks or test cases - you should still be able to complete the assignment with the old files, but it is recommended that you use the new files in case of rare bugs.0
Additionally, added a FAQ question about console debugging.
End of Change Log
Maintained by COMP 2012H Teaching Team © 2021 HKUST Computer Science and Engineering
https://course.cse.ust.hk/comp2012h/assignments/PA7/Description/ 17/17