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.
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.
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.
#include "Game.hpp"
constdouble 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;
}
#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");
returntrue;
}
//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
elseif (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
}
}
returnfalse;
}
}
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);
}
}
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).
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 usingnamespace 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
enumclass 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.
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
@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.
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.
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.