Review / Advice

Pages: 12
Hello everyone. Im a freshman in college taking my first programming class. It teaches c++. One of our final projects (I'm 5 weeks early to make sure I get it right) is to recreate wordle but instead of having a list of words the use inputs the word and number of attempts. Any advice would be extremely helpful.

Https://GitHub.com/ciullaanthonyj/CPPWordle
Didn't get too far yet, but first thing right off: name your constants
enum colors {green = 10, whatever,...}
so that the reader can follow switch cases and assignments and so on.
First off, you're going to have to decide what kind of a game you're going to create. Since this is your first programming class, you've probably not gone past cout. So that means, you're going to be creating a console game. Since Wordle uses colored squares to represent whether guesses are in the answer, are in the correct position, on not in the answer at all, you're going to need a way to represent this in a console game.

Whether you're choosing from a list, or letting the user specify the word should be irrelevant to your game logic. i.e. You want to separate the the input phase from the solution phase.

Edit: If your system supports VT100 emulation (Windows console does) you may be able to produce colored squares. If you're interested, I'll post a VT100 class for Windows.

Last edited on
Jonin I couldn't figure out how to implement an enum, so I settled for changing it from reviewing an int to a string like "blue". I still haven't gotten that all the way functional whenever you compile from source with cmake outside of visual studio. I've done other programming over the last 10 years but cpp definitely has it's challenges and quirks I'm trying to learn. Ive got the coloring down per the project guidelines where each color is color depending on if it's correct, in word but wrong place or flat out wrong. I just want to see how I can make the project better / continue to learn via doing.
I just want to see how I can make the project better / continue to learn via doing.

Post your code you've written so far and we can give pointers on making the code more C++ efficient, plus offer differing ways to do things to help you broaden your understanding.

If you do post code
Please learn to use code tags, they make reading and commenting on source code MUCH easier.

How to use code tags: http://www.cplusplus.com/articles/jEywvCM9/

There are other tags available.

How to use tags: http://www.cplusplus.com/articles/z13hAqkS/

HINT: you can edit your post and add code tags.

Some formatting & indentation would not hurt either

A complete compileable example is really useful.
http://www.sscce.org/
George I posted the GitHub link
Most people don't have the time, desire nor inclination to muck around with code posted elsewhere.

I'm one of them.

One of the best reasons why code should be posted here, with code tags, is everyone is seeing the same thing.
Not sure anyone would want to read this if it had 500 lines of code pasted in the body.
Not sure anyone would want to read this if it had 500 lines of code pasted in the body.

You would be surprised. We've had much longer programs than that posted here.
edit: Just make sure what you post can be compiled.
Last edited on
If the 500 lines of code are less than 8,000 characters including code tags that would require a single post. Split between two posts if over 8,000.

Why 8K? That's the size allowed by the edit box.
CPPWordle.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include "Game.hpp"

const double VERSION = 2.0;

int main()
{
	std::cout << "\033[18h";

	//Class Declaration
	Game mygame;

	//set output
	std::cout << std::fixed << std::setprecision(1) << std::showpoint << std::endl;

	//Header
	mygame.changeColor("blue");
	std::cout
		<< "################################################################################\n"
		<< "#        CPPWordle                Version " << VERSION << "              Anthony Ciulla      #\n"
		<< "################################################################################\n"
		<<
		std::endl;
	mygame.changeColor("white");
	//Program Description
	std::cout << std::endl;
	std::cout
		<< "Description:\n"
		<< "To play Wordle, you first will be asked to enter a number reflecting\n"
		<< "the number of attempts the player will have to guess the obejctive word\n"
		<< "then, you will then be asked to submit a five character word to try to guess.\n"
		<< "\nLegend:\n"
		<< "After you guess a word, you will have it redisplayed to you with the colors\n"
		<< "indicating if it was correct or wrong.\n"
		<<
		std::endl;
	mygame.changeColor("green");
	std::cout
		<< "This color indicates the letter is in the correct place and spot in the word"
		<<
		std::endl;
	mygame.changeColor("yellow");
	std::cout
		<< "This color indicates the letter appears in the word but not in the current spot"
		<<
		std::endl;
	mygame.changeColor("gray");
	std::cout
		<< "This color indicates the letter does not appear in the word\n"
		<<
		std::endl;
	mygame.changeColor("white");

	bool continuePlaying = true;

	while (continuePlaying) {

		bool continuePlaying = false;
		bool gameControl = false;
		bool playerInput = true;

		//Ask if player wants to play
		//This is also where the loop will run to if they 
		//want to play again

		char userInputChar;

		std::cout << std::endl << "would you like to play? (y/n): ";
		std::cin >> userInputChar;
		std::cout << std::endl;

		//Do they want to play again? 
		//Force input char to upper and check it with switch

		char playAgain = toupper(userInputChar);

		//switch control
		switch (playAgain) {
		case 'Y':
			gameControl = true;
			continuePlaying = false;
			break;
		case 'N':
			std::cout << "Play again later!" << std::endl;
			return 0;
			break;
		default:
			return 1;
			break;
		}

		//reset and initialize variables
		std::vector<char> gameWord;
		std::vector<char> playerWord;
		int maxRounds;
		int roundNumber;


		//They want to play
		while (gameControl == true) {

			//Reset Variables
			mygame.ResetVariables();

			//get max attempts allowed and verify it's a number
			std::cout << "\nHow many attempts allowed: ";
			std::cin >> maxRounds;

			//set the max rounds
			mygame.verifyNum(maxRounds);
			mygame.SetMaxRounds(maxRounds);
			std::cout << "\n" << std::endl;

			std::string tempGameWord;

			//get word to be guessed from player
			std::cout << "What word would you like the player to guess: ";
			std::cin >> tempGameWord;
			std::cout << "\n" << std::endl;

			//verify / set word
			std::vector<char> gameWordVec;
			mygame.verifyLength(tempGameWord);
			mygame.ConvertToVec(tempGameWord, gameWordVec);
			mygame.SetGameWord(gameWordVec);
			//clear the game word
			tempGameWord = "";
			gameWordVec.clear();

			// clear screen
			mygame.clearScreen();


			//get players word
			std::cout << "Enter a five character word: \n";

			//guess
			while (playerInput == true) {
				
				//Begin attempt
				mygame.SetRoundNumber();

				roundNumber = mygame.GetRoundNumber();
				maxRounds = mygame.GetMaxRounds();

				std::string tempPlayerWord;

				std::cout << "\nGUESS (" << roundNumber << "/" << maxRounds << "): ";

				//get and verify guess
				std::vector<char> playerWordVec;
				std::cin >> tempPlayerWord;
				mygame.verifyLength(tempPlayerWord);
				mygame.ConvertToVec(tempPlayerWord, playerWordVec);
				mygame.SetPlayerWord(playerWordVec);
				playerWordVec.clear();

				tempPlayerWord = "";

				//compare
				bool ansCheck = mygame.CompareWords();


				//works
				if (ansCheck == true) {
					//correct answer
					std::cout << "\nSuccess! It took you " << roundNumber << " tries!\n";
					//reset the while loops
					gameControl = false;
					continuePlaying = true;
					playerInput = false;
				}
				if (ansCheck != true) {
					//wrong answer, keep the loop going for the Nth try
					playerInput = true;
				}

				if (roundNumber == maxRounds && ansCheck != true) {
					//reset loops, player lost via max attempts
					playerInput = false;
					continuePlaying = true;
					gameControl = false;
					std::string tempGameWord = mygame.GetGameWord();

					std::cout << "\nFailure. The correct word was: " << tempGameWord << "\n";

					tempGameWord.clear();
				}
			}
		}
	}
	return 0;
}
Game.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

#pragma once

#ifndef GAME_H

#define GAME_H

//library headers
#include <algorithm>
#include <cstdio>
#include <iomanip>
#include <iostream>
#include <map>
#include <string>
#include <vector>

//Class
class Game {
	private:

		std::vector<char> SafeGameWord;

		std::vector<char> SafePlayerWord;

		int SafeMaxRounds;

		int SafeRoundNumber = 0;

	public:

		void ConvertToVec(std::string OldWord, std::vector<char>& NewVector);

		void SetGameWord(std::vector<char> GameWord);

		void SetPlayerWord(std::vector<char> PlayerWord);

		void SetMaxRounds(int MaxRounds);

		void SetRoundNumber();

		bool CompareWords();

		void ResetVariables();

		int GetMaxRounds();

		int GetRoundNumber();

		std::string GetGameWord();

		void changeColor(std::string newColor);

		void clearScreen();

		void verifyLength(std::string& word);

		void verifyNum(int& num);
};


#endif 
Last edited on
Game.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187

#include "Game.hpp"

//Converts string to vector
void Game::ConvertToVec(std::string OldWord, std::vector<char>& NewVector) {
	for (int i = 0; i < 5; i++) {
		NewVector.push_back(toupper(OldWord[i]));
	}
}

//set private class properties:
void Game::SetGameWord(std::vector<char> GameWord)
{
	SafeGameWord = GameWord;
}

void Game::SetPlayerWord(std::vector<char> PlayerWord)
{
	SafePlayerWord = PlayerWord;
}

void Game::SetMaxRounds(int MaxRounds)
{
	SafeMaxRounds = MaxRounds;
}

void Game::SetRoundNumber()
{
	SafeRoundNumber++;
}

//BIG BOY ALGORITHM lol
bool Game::CompareWords()
{
	//initialize a temp vector to hold the correct characters,
	//so that we can test against them. This is for the common
	//case of the word being 'hyper' and the guess being
	//'reset'
	std::vector<char> correct;

	//Exact Match
	if (SafePlayerWord == SafeGameWord) {
		changeColor("green"); //green

		for (auto& num : SafePlayerWord) {
			std::cout << num;
		}
		changeColor("white");
		return true;
	}

	//Lets test for maybes and nos
	else {
		//First we will check if any are correct and push them into the correct vector for later
		for (int i = 0; i < 5; i++) {
			if (SafePlayerWord[i] == SafeGameWord[i]) {
				correct.push_back(SafePlayerWord[i]);
			}
		}
		//Check for correct char
		for (int i = 0; i < 5; i++) {
			if (SafePlayerWord[i] == SafeGameWord[i]) {
				changeColor("green"); //green
				std::cout << SafePlayerWord[i];
				changeColor("white"); //white
			}
			//Check for correct char wrong place
			else if (find(SafeGameWord.begin(), SafeGameWord.end(), SafePlayerWord[i]) != SafeGameWord.end()) {
				//Make sure that the char isn't correct somewhere in the word
				if (find(correct.begin(), correct.end(), SafePlayerWord[i]) == correct.end()) {
					changeColor("yellow"); //yellow
					std::cout << SafePlayerWord[i];
					changeColor("white"); //white
				}
				//if it is print it gray
				else {
					changeColor("gray"); //gray
					std::cout << SafePlayerWord[i];
					changeColor("white"); //white
				}
			}
			//lastly wrong char doesn't belong in word.
			else {
				changeColor("gray"); //gray
				std::cout << SafePlayerWord[i];
				changeColor("white"); //white
			}
		}
		return false;
	}
}

void Game::ResetVariables()
{
	SafeRoundNumber = 0;
	SafeMaxRounds = 0;
	SafePlayerWord.clear();
	SafeGameWord.clear();
}

int Game::GetMaxRounds()
{
	return SafeMaxRounds;
}

int Game::GetRoundNumber()
{
	return SafeRoundNumber;
}

//Returns game word
std::string Game::GetGameWord()
{
	std::string TempGameWordString;
	for (auto num : SafeGameWord) {
		TempGameWordString.push_back(toupper(SafeGameWord[num]));
	}
	return TempGameWordString;
}

//Change the color of the console text via ansi. Haven't gotten functional 100% on CMake build from github copy outside of vs
void Game::changeColor(std::string newColor)
{
	//Couldn't figure out the enum type or how to properly match it so this will have to do for now
	if (newColor == "gray") {
		std::cout << "\033[38;2;192;192;192m";
	}
	if (newColor == "green") {
		std::cout << "\033[38;2;0;255;0m";
	}
	if (newColor == "blue") {
		std::cout << "\033[38;2;0;204;204m";
	}
	if (newColor == "red") {
		std::cout << "\033[38;2;255;0;0m";
	}
	if (newColor == "yellow") {
		std::cout << "\033[38;2;255;255;0m";
	}
	if (newColor == "white") {
		std::cout << "\033[38;2;255;255;255m";
	}
}

//Clears screen for gameplay
void Game::clearScreen()
{
	for (int i = 0; i < 50; i++) {
		std::cout << "\n" << std::endl;
	}
}

//Checks to verify the length of the string and ensure it's 5, if not it can ask for the variable and change it via the reference
void Game::verifyLength(std::string& word)
{
	//reset input
	std::cin.clear();
	std::cin.ignore();

	if (word.size() != 5) {
		changeColor("red");
		std::cout << "Invalid input. Try again:";
		changeColor("white");
		std::cout << " ";
		std::cin >> word;
		verifyLength(word);
	}
}

//Checks to verify the length of the number or that it's a real num. Can ask for a new number and change it via reference variable
void Game::verifyNum(int& num)
{
	//clear input to surpress that whole loop screaming invalid input lol
	std::cin.clear();
	std::cin.ignore();

	if (num <= 0) {
		//number is negative invalid
		changeColor("red");
		std::cout << "Invalid input. Try again:";
		changeColor("white");
		std::cout << " ";
		std::cin >> num;
		verifyNum(num);
	}
}
Last edited on
Make your colours an enum rather than strings. enum are easier to use, easier to read (if good names used) and easier to spot mistakes - I would spell 'gray' as grey! See https://cplusplus.com/doc/tutorial/other_data_types/

Also you might want to set the VT100 escape codes as const string literals in a header.

If you're using VT100, then there's also an escape code sequence for clear screen, move cursor etc etc.

Why a std::vector<char> instead of std::string? Just use std::string. You don't then need a specific conversion function.

Why have a .resetvariables() member function? Why not define mygame there? Also, why define and initialise variables that are only used within the gamecontrol loop outside of the loop (playerWord, gameWord etc).
Last edited on
I couldn't figure out how to implement an enum


https://www.learncpp.com/cpp-tutorial/unscoped-enumerations/
In addition to what seeeplus has pointed out:
- #pragma once and #ifndef include guards are redundant. Yes, #pragma once is not standard, but according to cppreference.com it is "accepted by the vast majority of modern compilers".

- SetRoundNumber could be better named to IncrRoundNumber.

- Kudos for not using using namespace std

- As others have said, use an enum for colors.
This is from the standard VGA colors.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
enum class COLORS : int
{
	BLACK = 0,
	DARKBLUE = 1,
	DARKGREEN = 2,
	DARKCYAN = 3,
	DARKRED = 4,
	DARKMAGENTA = 5,
	DARKYELLOW = 6,
	WHITE = 7,
	GREY = 8,
	BLUE = 9,
	GREEN = 10,
	CYAN = 11,
	RED = 12,
	MAGENTA = 13,
	YELLOW = 14,
	LIGHTGREY = 15,
};


- In changeColor, a switch works well with an enum.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void Game::changeColor(COLORS newColor)
{
	switch (newColor) 
	{
	case COLORS::GREY: 
		std::cout << ESC << "[38;2;192;192;192m";
		break;	
	case COLORS::GREEN:
		std::cout << ESC << "[38;2;0;255;0m";
		break;
	case COLORS::BLUE:
		std::cout << ESC << "[38; 2; 0; 204; 204m";
		break;
	case COLORS::RED:
		std::cout << ESC << "[38; 2; 255; 0; 0m";
		break;
	case COLORS::YELLOW: 
		std::cout << ESC << "[38;2;255;255;0m";
		break;
	case COLORS::WHITE:
		std::cout << ESC << "[38;2;255;255;255m";
		break;
	}
}


edit 1: for spelling.
edit 2: - Your VT100 formatting really doesn't belong as part of your game class. You should have a separate output class.
- Your getters should be const
Last edited on
@AbstractionAnon, I made the correct changes. What do you mean my getters should be const? Getters in the game class? I haven't made an output class yet, but will tomorrow or maybe later tonight after some calc homework.
Making a getter const: int GetMaxRounds() const;.

You are required to match the member function's definition with const:
101
102
103
104
int Game::GetMaxRounds() const
{
	return SafeMaxRounds;
}


Why make them const? A getter is not supposed to alter the data member it is retrieving. Making the member function, AKA class method, const ensures the compiler flags as errors any changes to the data member within the body of the function.

https://stackoverflow.com/questions/21478342/c-const-in-getter
That makes alot of sense! Okay then, all changes have been made including the creating of an output class.
Something else to consider, combining your member function's declaration in the class declaration with the function definition since the function is so trivial:

int GetMaxRounds() const { return SafeMaxRounds; }

That would appear in your Game.hpp file, remove the function definition in Game.cpp.
Pages: 12