Consider:
int main() {
int x;
const int Maxword = 5;
char Guess[Maxword] {};
std::string words[Maxword] = {
"Hello",
"World",
"Shift",
"Green",
"Seven"
};
srand(time(NULL));
int iSecret = rand() % Maxword;
std::string Word(words[iSecret]);
for (int i = 0; i < 5; i++) {
std::cout << Word[i] << std::endl;
}
for (int i = 0; i < 5; i++) {
std::cout << ("Please enter the letters you would like to guess") << std::endl;
std::cin >> Guess[i];
std::cout << Guess[i] << std::endl;
}
for (int i = 0; i < 5; i++) {
if (Guess[i] == Word[i]) {
std::cout << Guess[i] << "\t" << "Is in the right place" << std::endl;
} else if (Guess[i] != Word[i]) {
std::cout << Guess[i] << "\t" << "Isnt in the right place" << std::endl;
} else {
}
}
}
Here I have my code and I would like to compare the two character arrays Guess and Word to check for a common character. How would I do this?
According to your clarification in the comments, you want to have three kinds of output:
the letter is in the word and guessed in the correct position
the letter is in the word but guessed in the wrong position
the letter is not in the word
Your current loop is handling only case #1.
To handle #2 (and by extension #3) you can use std::string::find. That function will return the position of the character in the string, or if not found it returns std::string::npos.
So, the logic could be:
if (Guess[i] == Word[i]) {
std::cout << Guess[i] << "\tis in the right place\n";
} else if (Word.find(Guess[i]) != std::string::npos) {
std::cout << Guess[i] << "\tisn't in the right place\n";
} else {
std::cout << Guess[i] << "\tisn't in the word\n";
}
See the documentation for std::string::find
In C++23, there is a nicer way to test if the string contains a character: std::string::contains
As a closing comment, it's important that you understand the distinction between a string object and an array:
In your question and followup discussion, you keep referring to Word an array, but it is not -- it is a std::string. It overloads the operator[](size_t) so that you can use array syntax to access characters, but that does not make it an array.
The only arrays in your program are Guess (an array of char values) and words (an array of std::string values).
I know this is strictly speaking not directly an answer to your question but I believe it might help you and others nevertheless.
Correct me if I am wrong but I believe what you are trying to do is to implement the game of Wordle.
Wordle with Map
While your approach with arrays would work I have implemented a different approach to implement the game using maps. Maps are well suited for quick lookups in constant time i. e. O(1) so they are generally faster than searching in arrays and this is why I am using this approach here now. However, for this little example with just 5 character searching in an array might probably be even faster than in a map.
Pre-processing
As soon as you know the word you can pre-process a map which maps each character in the word to its position in the word. As there might be many positions for the same character I store the positions in a list.
Checking guesses
Now when you have to check a guess you iterate over all characters of the guess and you can now use the pre-processed map to check whether a character is in the word (i.e in the map) or not. This will happen in constant time O(1) independent of the size of the word.
If the character is in the map, retrieve the associated list of positions for this character and iterate over this list in order to check if any of the positions match the position in the guess.
If so, the letter is at the correct position, if not, it is in the word but at a wrong position.
Java program
Unfortunately I am not a C++ programmer but I believe the following Java code should easily be portable to C++. Instead of Java's HashMap you may use std::unordered_map and the rest should just be some small differences in syntax.
This is just a simple implementation of Wordle in Java without getting into too much detail but it should be sufficient as a reference for your implementation.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Simple implemantation of Wordle.
*/
public class Wordle {
// word to guess
private String word;
// map: Character in word -> list of positions of that character in the word
private HashMap<Character, List<Integer>> wordLookup;
public Wordle(String word){
this.word = word;
// allocate memory for lookup table containing characters of word and their positions within the word
this.wordLookup = new HashMap<>(word.length());
var wordCharArr = word.toCharArray();
// for each character in the word save it's position
for (int i = 0; i < wordCharArr.length; i++) {
if(this.wordLookup.containsKey(wordCharArr[i])){
// a character appears more than once -> add the other position to the list of positions
var positionsList = this.wordLookup.get(wordCharArr[i]);
positionsList.add(i);
} else {
var positionsList = new ArrayList<Integer>();
positionsList.add(i);
this.wordLookup.put(wordCharArr[i], positionsList);
}
}
}
public void checkGuess(String guess){
checkGuess(guess.toCharArray());
}
public void checkGuess(char[] guess){
System.out.println("Checking you guess...");
for (int i = 0; i < guess.length; i++) {
var guessedChar = guess[i];
// lookup if guessed character is in word
if(wordLookup.containsKey(guessedChar)){
// guessed character is in word
// is it in (one of) the right position(s)?
var posInWord = wordLookup.get(guessedChar);
int finalI = i;
if(posInWord.stream().anyMatch(pos -> finalI == pos)){
// character also is at the right position (this implementation does not signal that there may be multiple positions this character might go)
System.out.printf("> %c is correct at position %s!\n", guessedChar, i);
}
else {
// character is not at the right position
System.out.printf("> %c is in word but not at the right position!\n", guessedChar);
}
} else {
// guessed character is not in word
System.out.printf("> %c is not in word!\n", guessedChar);
}
}
System.out.println("Done.");
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public HashMap<Character, List<Integer>> getWordLookup() {
return wordLookup;
}
public void setWordLookup(HashMap<Character, List<Integer>> wordLookup) {
this.wordLookup = wordLookup;
}
public static void main(String[] args) {
// create a game of Wordle for the word "hello"
var aGameOfWordle = new Wordle("hello");
// get user input for a guess here
//...
// check guesses..
aGameOfWordle.checkGuess("hello");
aGameOfWordle.checkGuess("holas");
}
}
Expected output:
Checking you guess...
> h is correct at position 0!
> e is correct at position 1!
> l is correct at position 2!
> l is correct at position 3!
> o is correct at position 4!
Done.
Checking you guess...
> h is correct at position 0!
> o is in word but not at the right position!
> l is correct at position 2!
> a is not in word!
> s is not in word!
Done.
Related
I'm currently trying to figure out how I can replace a certain character in a char array using a for loop to check each index position in the array. However, when I assign the correct character to the char variable "letterGuessed" and it is checked it instantly goes to the else statement. This leaves the character as an asterisks. This is the code below:
#include <iostream>
#include <cstring>
void hide_Word(char hide[], int size);
int main()
{
char hiddenWord[] = "Hello";
char displayWord[30] = { 0 };
int length = strlen(hiddenWord);
hide_Word(displayWord, length);
std::cout << hiddenWord << std::endl;
std::cout << displayWord << std::endl;
char letterGuessed;
std::cout << "Enter a character: ";
std::cin >> letterGuessed;
for (int i = 0; i < length; i++)
{
if (displayWord[i] == letterGuessed)
{
letterGuessed == displayWord[i];
}
else
{
std::cout << "*";
}
}
std::cout << std::endl;
std::cout << displayWord << std::endl;
std::cin.get();
return 0;
}
void hide_Word(char hide[], int size)
{
for (int i = 0; i < size; i++)
{
hide[i] = '*';
}
}
When I compile your code I get the warning
main.cpp|27|warning: statement has no effect [-Wunused-value]
for the line
letterGuessed == displayWord[i];
This, for one, means that what you do to make correctly guessed letters visible is achieving nothing. Reading and considering warning messages is really helpful, you know.
I guess that your goal here is to turn the "*", which you filled displayWord with, should be replaced by the correctly guessed character.
That would better be achieved by an assignment using =.
letterGuessed = displayWord[i]; /* still unhelpful */
But that line would still not achieve anything visible.
To change something in the displayWord, it should be what gets the guessed character as a new value, not the other way around.
displayWord[i] = letterGuessed;
This is however still not satisfying, because you don't do this in the right situation.
Let's have a look at the condition which determines when you do it.
if (displayWord[i] == letterGuessed) /* unhelpful */
This will trigger, when the guessed character is an asterisk "*", because displayWord is filled with asterisks early on.
Which means that the condition only triggers if the user guesses an asterisk, which is unlikely. Even if it happens, the result is to overwrite an asterisk with an asterisk.
The condition you need should not check the asterisk-filled displayWord, it should instead check the "Hello"-filled hiddenWord.
if (hiddenWord[i] == letterGuessed)
In total, the code should hence be
for (int i = 0; i < length; i++)
{
if (hiddenWord[i] == letterGuessed)
{
displayWord[i]=letterGuessed;
std::cout << letterGuessed;
}
else
{
std::cout << "*";
}
}
This turns an asterisk in the displayed word into the correctly guessed character at each found position.
Note that I added an output of the guessed letter, to complete the letter-by-letter output. I guess you want to delete that output, or the word-output after the loop, so that the filled in word is only seen once.
Output:
Hello
*****
Enter a character: l
**ll*
**ll*
I am passing a string to my function, and the function is supposed to use that string to put individual chars in a stack. Then the stack is supposed to spit it back out (Since it's a stack it should be reversed). For example if my string is hello, it should print "olleh". But instead I'm getting ooooo. I think it has something to do with the fact that I'm setting ch equal to a different character every time but I'm not sure how to input those character in a different way.
void Stack::function2reverse(string myString) {
int countItIt = 0;
int sizeOfString = myString.size();
char Ch ;
for (int i= 0; i< sizeOfString; x++)
{
Ch = myString[x];
stack.push(Ch);
countIt ++;
}
while (countIt != 0)
{
cout << Ch;
stack.pop();
countIt --;
}
}
cout << Ch; - you print the same character every time (the last one entered, so 'o').
Instead, print the top character in the stack: std::cout << stack.top().
std::stack keeps track of its own size, so you don't need to worry about that either. Then you can replace your print loop with:
while (!stack.empty()) {
std::cout << stack.top();
stack.pop();
}
And of course, the Standard Library provides a std::reverse function anyway, so if this was not just an exercise in learning about std::stack, you could use that (and I can think of several other things to do as well, depending on exactly what you are trying to achieve):
std::string s = "hello";
std::reverse(std::begin(s), std::end(s));
// s now contains "olleh"
You may also want to read up on why using namespace std; is a bad practice.
Let's say I have the following string:
aabccd
I'd like to find and remove all patterns that are repeated. In this example, one a is followed by another one, which is a repetition. Same thing about cc.
The final string would be:
bd
Another example: banana => ba (because two an or two na).
Here's the algorithm I've come up with:
Splitting the string in two halves and taking the biggest one
Let's say it has a length of 4; I look in the other half if it's there
Next turn of loop, I shift my string from one character (but still of
length 4) until I loop all the possible patterns
Then I reduce the half by one character (so length 3) and start again
// etc.
It would do something like this:
helloguys -> hell -> ello -> llog
And some code, not working as it should:
std::string processWord(std::string word)
{
// Split word in the two halves
std::string firstHalf = word.substr(0, word.size() / 2);
std::string secondHalf = word.substr(firstHalf.size());
// Check if the tiniest half is present in the biggest one (firstHalf will be eitheir lower or equal to secondHalf)
if (secondHalf.find(firstHalf) != std::string::npos)
{
std::cout << firstHalf << " is found in " << secondHalf << std::endl;
// Remove firstHalf from secondHalf
word.replace(word.find(firstHalf), firstHalf.size(), "");
std::cout << word << std::endl;
return word;
}
for (size_t i = 1; i < secondHalf.size(); ++i)
{
// Get secondHalf minus one character at each loop turn to check occurences
std::string occurence = secondHalf.substr(0, secondHalf.size() - i);
// Mark the first occurence
size_t startIndex = indexOf(word, occurence);
// Mark the last occurence
size_t lastIndex = startIndex;
int totalOccurences = 1;
// As long as there are occurences following each other, we continue
// Example: "anandgdfgd". We see "an" twice. But it would not work with "anshfsduihsuan" since they are not following each other
while (word.find(occurence, lastIndex + occurence.size()) != std::string::npos)
{
lastIndex += occurence.size();
totalOccurences++;
}
std::ostringstream oss;
oss << "[" << totalOccurences << "*" << occurence << "]";
word.replace(startIndex, lastIndex, oss.str());
}
// Some code is missing here
return word;
}
I'm sure this problem has already been solved but I can't find anything. Any tips?
Clear rules have not been defined yet, but I think that building Suffix Array is good starting point. You can compare neighbour suffixes, find length of common starting parts and make decision - what substrings are the best candidates for removing.
I'm writing a program to help solve crossword puzzles. So I'm getting a word from a text list of all words in the english language, making each one a vector of chars, and comparing that vector to a vector of whatever starting letters I have. It runs fine and gives me good output, but every time I'm getting an error "libc++abi.dylib: terminating with uncaught exception of type std::length_error: vector".
Here's my code:
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <string>
#include <iterator>
using namespace std;
string getLetters() {
string word; // Get user letter, put in variable word
cout << "Enter a set of letters" << endl;
cin >> word;
return word;
}
int getLengthOfWord() {
int length; // Get length of word
cout << "Enter the number of letters in the word" << endl;
cin >> length;
return length;
}
// Change strings to vectors of chars
vector<char> stringToVector(string word) {
std::vector<char> v(word.begin(), word.end());
return v;
}
bool compareVectors(vector<char> userWord, vector<char> listWord, int length) {
if (listWord.size() != length) // Make sure the word from the list is the right length
{
return false;
}
int counter = 0; // Counter
for (int i = 0; i < userWord.size(); i++) { // Iterating through the two words
for (int j = 0; j < listWord.size(); j++) {
if (listWord[j] == userWord[i]) { // If the letters match
listWord.erase(listWord.begin() - 1 + j); // Erase the letter from the word
counter++; // Increase counter
break; // Break out of for loop
}
}
}
if (counter == userWord.size()) { // If there were as many matches as letters in user set
return true;
}
else {
return false;
}
}
int main() {
string example; // variable to put words
ifstream wordList; // New ifstream object
wordList.open("/Users/alexray/Dropbox/C++ Practice/WordJumbleSolver/wordsEn.txt"); //open word list
int length = getLengthOfWord(); // Get user input
string word = getLetters();
vector<char> vector1(stringToVector(word));
while (wordList.is_open()) {
getline(wordList, example); // Get word, put it in example variable
vector<char> vector2(stringToVector(example)); // Make word from list a vector
vector2.erase(vector2.end() - 1); // Erase escape character from end of word
if(compareVectors(vector1, vector2, length)) { // compare the vectors
cout << example << endl;
}
}
wordList.close(); // Close stream
return 0;
}
From googling around, I thought that it was a matter of my vector wasn't initially large enough to handle some of the words, but doing vector.reserve(some_number) before assigning a value to the vector didn't help anything. Also, I couldn't imagine that a vector would have any problems with <20 elements.
Thanks for the help! (I'm new to C++ so if there's something I should obviously be doing differently, let me know).
Edit: The file I'm working with is the wordsEn.txt file from this website: http://www-01.sil.org/linguistics/wordlists/english/
In my case it was a mismatch between C++ standard on two vcxproj projects.
I've simply aligned both projects to the same C++ standard (17) and it worked.
project ➤ Properties ➤ C/C++ ➤ Language ➤ C++ Language Standard
One issue I see is that you are not erasing the character you claim you want to erase:
listWord.erase(listWord.begin() - 1 + j);
This does not erase the jth character in the sequence.
The easiest example of this failing is if j == 0 at the start of the loop, and the first character matches.
Just simply do this instead:
listWord.erase(listWord.begin() + j);
I was looking in the wrong place the whole time. I looked at the number of words/lines in the file (109582) and changed the
while (wordList.is_open()) {
getline(wordList, example); // Get word, put it in example variable
vector<char> vector2(stringToVector(example)); // Make word from list a vector
vector2.erase(vector2.end() - 1); // Erase escape character from end of word
if(compareVectors(vector1, vector2, length)) { // compare the vectors
cout << example << endl;
}
counter++;
}
to
while (counter < 109582) {
getline(wordList, example); // Get word, put it in example variable
vector<char> vector2(stringToVector(example)); // Make word from list a vector
vector2.erase(vector2.end() - 1); // Erase escape character from end of word
if(compareVectors(vector1, vector2, length)) { // compare the vectors
cout << example << endl;
}
counter++;
}
It seems I was getting some sort of overflow error by trying to read in more lines than were available in the file.
I am looking for some quick tips on a homework assignment. We are given a few problems and have to write two quick programs on how to solve the problems with one each of iteration and recursion. I'm sure this is easier than I think, but I am getting easily confused over the two. By no means do I want anyone to fully solve the problems for me, I won't learn anything! But if you could look at what I have so far and let me know if I am heading in the right direction. Also, the code does not need to compile, our professor wants us to have a general idea of the differences of iteration vs. recursion.
Problem: check a string to see if it is a palindrome.
My solution- I think it is the iterative solution:
bool iterative_palindrome (const string& str) {
string line, result;
stack <char> stack_input;
//user enters string, program takes it
cout << "Enter string: " << endl;
while (getline (cin, line) && (line != "")) {
//push string into stack
for (size_t i = 0; i < line.size(); i++) {
stack_input.push(line[i]);
//create reverse of original string
while (!stack_input.empty()) {
result += stack_input.top();
stack_input.pop();
return result;
}
//check for palindrome, empty string
if (line == result || line = "0" || line.empty()) {
return true;
cout << line << " is a palindrome!" << endl;
} else {
return false;
cout << line << " is NOT a palindrome." << endl;
cout << "Enter new string: " << endl;
}
}
}
}
I remind everyone, I am pretty new to this stuff. I've read a few things already, but am still having a hard time wrapping my head around this.
Here's the general idea:
Iterative:
Initialize two pointers one pointer to the start and end of the string.
Compare the characters pointed, if different -> not palindrome.
Increase the start pointer and decrease the end pointer.
Repeat until start pointer >= end pointer.
Recursive (more difficult than iterative in this case):
End condition: A string of length zero or one is a palindrome.
A string is a palindrome if the first and last characters are the same and if the string without the first and last characters is a palindrome.
You can implement this recursive algorithm more efficiently by passing pointers to the first and last character in the string instead of copying the string between recursions.
Hope this helps :-)
I figure writing code is the best way to explain the two approaches. Is this code understandable?
bool iterative_palindrome(const string& str) {
int size = str.size();
for (int i=0; i<str.size()/2; i++) {
if (str[i] != str[size-i-1])
return false;
}
return true;
}
You call this like recursive_palindrome(str, 0).
bool recursive_palindrome(const string& str, int index) {
int size = str.size();
if (index >= size/2)
return true;
if (str[index] == str[size-index-1])
recursive_palindrome(str, index+1);
else
return false;
}