ASCII Strength Game will not calculate "Bot" word value - c++

I'm making a game that tests the ASCII strength of a user versus a bot. (There is also a 2 player mode but that's working fine.) The full description is given at the top of my .cpp file. As a basic breakdown, the bot opens a txt file with 500 common four letter words and inserts them into a size 500 array. It then randomly generates a number to pick a random one, and then goes through the process of tovalue() to recieve its ASCII value, where in tovalue() runs through chartoint() four times, one for each character of the word. My issue is that the program calculates the ASCII value perfectly fine of the user generated word, but always returns 0 (0000) for the botword, no matter what the word.
I've tried a few iterations of the generateword() function including using a vector but always get the same resutls. I've done a lot of digging about this and haven't quite found any solutions, although I suspect that the chartoint() function could be better optimized, just not sure how to impliment any better solutions for this specific case. Also, don't think the problem is with chartoint() since it works fine for user input, but I'm pretty sure the problem is with generateword(). Suggestions for making chartoint() would be helpful, but its not my main priority right now since I just need the program to 100% work first. Also, I've confirmed that all of the words in my .txt file are all caps and only four characters per line.
// Write the code for a game called “ASCII Strength” of a four-letter word selected by Player 1
// followed by a four-letter word selected by Player 2. The result would be the sum
//of the ASCII value of each of the letters of the selected words and whoever has higher sum (called ASCII strength) wins.
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;;
int chartoint(char a) {
switch (a) {
case 'A':
return 1;
break;
case 'B':
return 2;
break;
case 'C':
return 3;
break;
case 'D':
return 4;
break;
case 'E':
return 5;
break;
case 'F':
return 6;
break;
case 'G':
return 7;
break;
case 'H':
return 8;
break;
case 'I':
return 9;
break;
case 'J':
return 10;
break;
case 'K':
return 11;
break;
case 'L':
return 12;
break;
case 'M':
return 13;
break;
case 'N':
return 14;
break;
case 'O':
return 15;
break;
case 'P':
return 16;
break;
case 'Q':
return 17;
break;
case 'R':
return 18;
break;
case 'S':
return 19;
break;
case 'T':
return 20;
break;
case 'U':
return 21;
break;
case 'V':
return 22;
break;
case 'W':
return 23;
break;
case 'X':
return 24;
break;
case 'Y':
return 25;
break;
case 'Z':
return 26;
break;
}
return 0;
}
int tovalue(string input) {
int first = chartoint(input[0]);
int second = chartoint(input[1]);
int third = chartoint(input[2]);
int fourth = chartoint(input[3]);
cout << first << second << third << fourth; // EXISTS TO TEST CALCULATION
int value = first + second + third + fourth;
return value;
}
string generateword() {
string arr[500];
ifstream file("words.txt");
if (file.is_open())
{
for (int i = 0; i < 500; i++) {
string temp;
getline(file, temp);
arr[i] = temp;
}
file.close();
}
else
{
cout << "Error: Unable to open file.";
exit(0);
}
srand(time(0));
int random_index = rand() % 500;
string random_word = arr[random_index];
return random_word;
}
int main()
{
cout << "Welcome to ASCII strength, a game where the strongest word wins!";
cout << "\nTo play, you must enter a four letter word. The program will calculate the 'ASCII strength' of your word and compare it to your opponent.";
cout << "\nWhoever has the higher sum will win!";
char another;
another = 'y';
while (another == 'y' || another == 'Y') {
cout << "\nWould you like to play against a friend, or against a bot? (F/B)";
char mode;
cin >> mode;
if (mode == 'F' || mode == 'f') {
cout << "\nPlayer 1, please input your four letter word in all caps: ";
string answer1;
cin >> answer1;
int value1;
value1 = tovalue(answer1);
cout << "\nPlayer 2, please input your four letter word in all caps: ";
string answer2;
cin >> answer2;
int value2;
value2 = tovalue(answer2);
if (value1 > value2) {
cout << "\nPlayer 1 wins!";
}
else if (value2 > value1) {
cout << "\nPlayer 2 wins!";
}
else if (value1 == value2) {
cout << "\nTie!";
}
}
else if (mode == 'B' || mode == 'b') {
cout << "\nPlease input your four letter word in all caps: ";
string answer;
cin >> answer;
int valueanswer;
valueanswer = tovalue(answer);
string botword;
botword = generateword();
cout << "\nThe bot generates a random word based on a list of popular four letter words.";
cout << "\nThe bot has generated this word: " << botword;
int valuebot;
valuebot = tovalue("botword");
cout << valueanswer << " " << valuebot; // THIS EXISTS PURELY TO TEST WHETHER THE VALUES ARE PROPERLY CALCULATING
if (valueanswer > valuebot) {
cout << "\nYou win!";
}
else if (valuebot > valueanswer) {
cout << "\nThe bot wins!";
}
else if (valueanswer == valuebot) {
cout << "\nTie!";
}
}
cout << "\nWould you like to start a new game? (y/n)";
cin >> another;
}
}

Your problem is this line:
valuebot = tovalue("botword");
Since all characters in "botword" are lowercase, you get all 0 score. You probably meant to write
valuebot = tovalue(botword);

Related

C++ Newbie: Why don't these nested loops work for this program?

I'm in the middle of taking an online C++ course, and I've been having issues with this homework problem. I tried reaching out to my professor twice, but he hasn't responded. I've sought out many solutions, but since I'm new in the course, many of the solutions involve using techniques I haven't learned yet (like character arrays.) I can get the conversion program to work, but I want the program to allow to process as many user inputs as the user wants.
When I run the program, the program accepts my first input that is 'y' or 'Y' to run the program. It then will ask for a string to convert to the telephone number. This works. However, I need the program to ask the user if they want to run the program again to convert another string to a telephone number or to terminate the program.
I put in another cin at the end of the first while loop to prompt for another input, but it gets skipped over everytime and keeps doing the while loop.
Question: Why is the last prompt to repeat the program get skipped every time I've run it? What am I missing?
Here's the problem and what I've done so far:
Problem:
To make telephone numbers easier to remember, some companies use
letters to show their telephone number. For example, using letters,
the telephone number 438-5626 can be shown as GET LOAN.
In some cases, to make a telephone number meaningful, companies might
use more than seven letters. For example, 225-5466 can be displayed as
CALL HOME, which uses eight letters. Instructions
Write a program that prompts the user to enter a telephone number
expressed in letters and outputs the corresponding telephone number in
digits.
If the user enters more than seven letters, then process only the
first seven letters.
Also output the - (hyphen) after the third digit.
Allow the user to use both uppercase and lowercase letters as well as
spaces between words.
Moreover, your program should process as many telephone numbers as the
user wants.
My code so far:
#include <iostream>
using namespace std;
int main()
{
char letter, runLetter;
int counter = 0;
cout << "Enter Y/y to convert a telephone number from letters to digits"
<< endl;
cout << "Enter any other key to terminate the program." << endl;
cin >> runLetter;
while (runLetter == 'y' || runLetter == 'Y')
{
cout << "Enter in a telephone number as letters: " << endl;
while (cin.get(letter) && counter < 7 )
{
if (letter != ' ' && letter >= 'A' && letter <= 'z')
{
counter++;
if (letter > 'Z')
{
letter = (int)letter-32;
}
if (counter == 4)
cout << "-";
switch (letter)
{
case 'A':
case 'B':
case 'C':
{
cout << "2";
break;
}
case 'D':
case 'E':
case 'F':
{
cout << "3";
break;
}
case 'G':
case 'H':
case 'I':
{
cout << "4";
break;
}
case 'J':
case 'K':
case 'L':
{
cout << "5";
break;
}
case 'M':
case 'N':
case 'O':
{
cout << "6";
break;
}
case 'P':
case 'Q':
case 'R':
case 'S':
{
cout << "7";
break;
}
case 'T':
case 'U':
case 'V':
{
cout << "8";
break;
}
case 'W':
case 'X':
case 'Y':
case 'Z':
{
cout << "9";
break;
}
default:
break;
}
}
}
cout << endl;
cout << "To process another telephone number, enter Y/y" << endl;
cout << "Enter any other key to terminate the program." << endl;
cin >> runLetter;
}
cout << "Goodbye. " << endl;
return 0;
}
Thanks in advance for any help. I know this might be an easy solution, but I've been tinkering with this program for a couple of days now.
Tried moving the last user prompt in and out of each if/else structure and different while loops. Not sure what I can do to make the program take a new input after the first iteration.
A very good hint to your problem is the comment from #AlanBirtles. Also I know you are a beginner and you may not know about std::string but you should use it because you are learning C++ not C. in a nutshell, it is a C++ way of dealing with char arrays, also better than just that.
Here is your code with minimum changes to do what you are looking for. The main changes is the use of std::string, the use of std::getline and the definition of the counter inside the while loop.
#include <iostream>
#include <string>
using namespace std;
int main()
{
char letter;
std::string runLetter;
std::string number;
cout << "Enter Y/y to convert a telephone number from letters to digits"
<< endl;
cout << "Enter any other key to terminate the program." << endl;
std::getline( std::cin, runLetter);
while (runLetter == "y" || runLetter == "Y")
{
int counter = 0;
cout << "Enter in a telephone number as letters: " << endl;
std::getline(std::cin, number);
for (int i = 0; i < number.size(); i++)
{
letter = number[i];
if (counter < 7)
if (letter != ' ' && letter >= 'A' && letter <= 'z')
{
counter++;
if (letter > 'Z')
{
letter = (int)letter - 32;
}
if (counter == 4)
cout << "-";
switch (letter)
{
case 'A':
case 'B':
case 'C':
{
cout << "2";
break;
}
case 'D':
case 'E':
case 'F':
{
cout << "3";
break;
}
case 'G':
case 'H':
case 'I':
{
cout << "4";
break;
}
case 'J':
case 'K':
case 'L':
{
cout << "5";
break;
}
case 'M':
case 'N':
case 'O':
{
cout << "6";
break;
}
case 'P':
case 'Q':
case 'R':
case 'S':
{
cout << "7";
break;
}
case 'T':
case 'U':
case 'V':
{
cout << "8";
break;
}
case 'W':
case 'X':
case 'Y':
case 'Z':
{
cout << "9";
break;
}
default:
break;
}
}
}
cout << endl;
cout << "To process another telephone number, enter Y/y" << endl;
cout << "Enter any other key to terminate the program." << endl;
std::getline(std::cin, runLetter);
}
cout << "Goodbye. " << endl;
return 0;
}
I found the following errors in your code:
You do not reset the variable counter to 0 in the second loop iteration, so that counter has the value 7 in the entire second loop iteration, which causes the inner while loop not to be entered. This bug should be clearly visible when running your program line by line in a debugger while monitoring the values of all variables.
You always read exactly 7 characters from the user per loop iteration, which is wrong. You should always read exactly one line per loop iteration. In other words, you should read until you find the newline character. You can ignore every character after the 7th letter, but you must still consume them from the input stream, otherwise they will be read in the next loop iteration(s), which you do not want. However, this does not mean that you can simply ignore everything after the 7th character, because the number of characters is not necessarily identical to the number of letters. For example, if a 7 character string has one space character, then it only has 6 letters. As stated in the task description, the user should be allowed to enter spaces in the string.

C++ pull a card from deck

I'm trying to create a program that will pull a card from a deck of 52 regular playing cards.
Suits: Heart, Spad, Diamond, Club.
Rank: A,2,3,4,5,6,7,8,9,10,J,Q,K.
This should be the output:
Let's pull a card!
This time we got AH
Wanna pull a card again?
y
This time we got 3J
Wanna pull a card again?
n
My output is:
Let's pull a card!
DKThis time we got 00
Wanna pull a card again?
n
This is my code:
#include <iostream>
#include <ctime>
using namespace std;
// Function Declaration
int rankCard(), suitCard();
int main()
{
srand(time(0));
char answer;
cout << "Let's pull a card!" << endl;
do {
cout << "This time we got " << rankCard() << suitCard() << endl;
cout << "Wanna pull a card again?" << endl;
cin >> answer;
} while ((answer == 'y') || (answer == 'Y'));
return 0;
}
int rankCard() {
int rank = (rand() % 13) + 1;
switch (rank) {
case 1: cout << "A";
break;
case 10: cout << "T";
break;
case 11: cout << "J";
break;
case 12: cout << "Q";
break;
case 13: cout << "K";
break;
default: cout << rank;
break;
}
return 0;
}
int suitCard() {
int suit = (rand() % 4) + 1;
switch (suit) {
case 1: cout << "H";
break;
case 2: cout << "D";
break;
case 3: cout << "C";
break;
case 4: cout << "S";
break;
}
return 0;
}
I can't figure out why the cards pulled (DK) are in that position and why I also get the 00. What am I doing wrong? Thanks
Your calls to rankCard() and suitCard() always return 0.
That 0 value is what's passed to cout in your main function.
The weird 'DK' is caused by the calls to cout inside rankCard and suitCard.
You could modify your functions to avoid the confusion:
#include <string>
std::string rankCard() {
int rank = (rand() % 13) + 1;
switch (rank) {
case 1: return "A";
case 10: return "T";
case 11: return "J";
case 12: return "Q";
case 13: return "K";
default: return std::to_string( rank );
}
return "";
}
std::string suitCard() {
int suit = (rand() % 4) + 1;
switch (suit) {
case 1: return "H";
case 2: return "D";
case 3: return "C";
case 4: return "S";
}
return "";
}
This line:
cout << "This time we got " << rankCard() << suitCard() << endl;
So those functions print the card, and then they return 0, so if you call them in cout, they will do their thing witch is printing the card and then print the return value witch is 0.
What you can do is to call them outside the cout, just do:
//...
cout << "This time we got ";
rankCard();
suitCard();
cout << endl;
cout << "Wanna pull a card again?" << endl;
//...
Personally I would refactor the functions to return the respective card char:
Live sample
const char rankCard() {
int rank = (rand() % 13) + 1;
switch (rank) {
case 1: return 'A';
case 10: return 'T';
case 11: return 'J';
case 12: return 'Q';
case 13: return 'K';
default: return rank + 48; // convert to decimal digit
}
}
const char suitCard() {
int suit = (rand() % 4) + 1;
switch (suit) {
case 1: return 'H';
case 2: return 'D';
case 3: return 'C';
case 4: return 'S';
default: return 0; //ASCII code for null character
}
}

Counting vowels and consonants [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
My program keeps crashing every time I enter an input even though I use a system pause method and displays the same number of vowels and consonants that is incorrect. What's going on?
int main() {
// declare vars
char ch;
int vowels = 0;
int consonants = 0;
string word = "temp";
// prompt user
cout << "Please enter a word: ";
cin >> ch;
// loop vowels and consonants
for (int i = 0; i < word.size(); i++) {
ch = toupper(word[i]);
switch (ch) {
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
vowels++;
break;
default:
consonants++;
}
}
// show num of vowels and consanants
cout << "Number of Vowels: " << vowels << endl;
cout << "Number of Consanants: " << consonants << endl;
// pause and exit
getchar();
getchar();
return 0;
}
Normally it's better to input a full string and then parse... but if for some reason you need to stream characters as they are entered you can use cin.get(). make sure to #include <cctype> if you want to use toupper().
char nextChar;
nextChar = cin.get();
nextChar = toupper(nextChar);
int consonants = 0;
int vowels = 0;
int words = 0;
while (nextChar != '\n')
{
switch (nextChar)
{
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
vowels++:
break;
case ' ':
words++;
break;
default:
consonants++;
break;
}
}
cout << "There were " << consonants << " consonants and " << vowels << " vowels in " << words << " words.";
instead of ending on a newline, if you want to limit to one word simply replace (nextChar != '\n') with (nextChar != ' ').
The only change that needs to occur is the change from:
cin >> ch;
to
cin >> word;
And you code will be fine. Live example
Some chages in your code :
#include <iostream>
#include <string>
using namespace std;
int main() {
// declare vars
char ch;
int vowels = 0;
int consonants = 0;
string word = "temp";
// prompt user
cout << "Please enter a word: ";
cin >> word;
// loop vowels and consonants
for (int i = 0; i < word.size(); i++) {
ch = toupper(word[i]);
switch (ch) {
case 'A':
vowels++;
break;
case 'E':
vowels++;
break;
case 'I':
vowels++;
break;
case 'O':
vowels++;
break;
case 'U':
vowels++;
break;
default:
consonants++;
}
}
// show num of vowels and consanants
cout << "Number of Vowels: " << vowels << endl;
cout << "Number of Consanants: " << consonants << endl;
// pause and exit
getchar();
getchar();
return 0;
}
Okay, so this isn't quite an answer, but it's a bit too detailed to put into a comment...
I just ran your code and it worked fine. I added the following three libraries
#include<string>
#include<iostream>
#include<stdio.h>
And then:
using namespace std;
and then compiled with g++ filename.
Check to make sure you're libraries are up to date and that you're compiling the code correctly.
Hope this helps.

Pig Latin converter using toupper

I'm having trouble converting using toupper on the first character in my string.
I used tolower(first[0]) to turn the first letter into lower case.
Why doesn't toupper(first[0]) make the first character upper case?
Also, is there a way to move the first character in a string to the last spot?
Thanks a lot in advance.
#include <iostream>
#include <string>
using namespace std;
int main ()
{
char ans;
do{
string first, last;
char first_letter, first_letter2;
cout << "This program will convert your name "
<< "into pig latin.\n";
cout << "Enter your first name: \n";
cin >> first;
cout << "Enter your last name: \n";
cin >> last;
cout << "Your full name in pig latin is ";
for(int x = 0; x < first.length(); x++){
first[x] = tolower(first[x]);
}
for(int x = 0; x < last.length(); x++){
last[x] = tolower(last[x]);
}
first_letter = first[0];
bool identify;
switch (first_letter)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
identify = true;
break;
default:
identify = false;
}
if(identify == true){
toupper(first[0]);
cout << first << "way" << " ";
}
first_letter2 = last[0];
bool identify2;
switch (first_letter2)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
identify2 = true;
break;
default:
identify2 = false;
}
if(identify2 == true){
toupper(first[0]);
cout << last << "way" << endl;
}
cout << "You you like to try again? (Y/N)\n";
cin >> ans;
} while(ans == 'y' || ans == 'Y');
return 0;
}
Just a simple blunder, compare
first[x] = tolower(first[x]);
with
toupper(first[0]);
usual case of the 'can't see the obvious thing missing' syndrome... I hate those mistakes.
As for moving the first character to the end I'd usually just use substr() for a simple case:
str = str.substr(1) + str[0];

How do I do this with switch instead of if esle?

I am taking my first programming course and the assignment was to redo a previous program (this one) using a switch statement. I thought that switch was just used to compare single characters.
The program essentially just receives a string and counts numbers, letters, other characters, and total characters.....
#include <iostream>
using namespace std;
int main()
{
char s[50];
int i;
int total = 0;
int letters = 0;
int numbers = 0;
int others = 0;
cout << "Enter a continuous string of characters with no blank spaces" << endl;
cout << "(example: aBc1234!##$%)" << endl << endl;
cout << "Enter your string: ";
cin >> s;
cout << endl;
i = 0;
while (s[i] != 0)
{
if ((s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z'))
letters++;
else if ((s[i] >= '0' && s[i] <= '9'))
numbers++;
else
others++;
i++;
total++;
}
cout << letters << " letters" << endl;
cout << numbers << " numbers" << endl;
cout << others << " other characters" << endl;
return 0;
}
With this particular situation if/else is the best way (as said by #zenith) but if you wished do to it with switch statements you would do
switch(s[i])
{
case `0`:
case '1':
case '2':
//repeat for '3'-'8'
case '9':
//do whatever you want when it is a digit here
break;
case 'A':
case 'a':
case 'B':
case 'b':
//repeat for 'C'-'y'
case 'Z':
case 'z':
//do whatever you want when it is a letter
break;
default:
//do whatever you want when it was not a letter or a digit
break;
}
When a case matches in a switch statement, everything up to the corresponding break is executed - that's how you can group cases like this
You shouldn't. switch statements work based on ==, not <= / >= / < / >.
The cases in a switch statement must be constant expressions. You'd have to make a separate case for each character.
There are situations where switch is a better solution. But this is not one of those situations. Here if and else is the way to go.
You need a mapping from all the characters of interest onto the behaviors.
enum char_category { OTHER, LETTER, NUMBER };
unsigned char mapping[256];
memset(mapping, OTHER, sizeof mapping);
for( char ch = '0'; ch <= '9'; ++ch ) mapping[ch] = NUMBER;
for( char ch = 'A'; ch <= 'Z'; ++ch ) mapping[ch] = mapping[tolower(ch)] = LETTER;
Then you can use a jump table:
switch ( mapping[s[i]] )
{
case NUMBER:
break;
case LETTER:
break;
case OTHER:
break;
}
Or you could completely skip the conditionals:
int count[3] = { 0, 0, 0 };
count[mapping[s[i]]]++;
letters = count[LETTER];
numbers = count[NUMBER];
other = count[OTHER];
Note that the work of setting up the mapping is only justified if you have more than a few dozen input characters.
switch(s[i]) {
case '0':
...
case '9': numbers++; break;
default: {
switch(toupper(s[i])) {
case 'A':
case 'B':
...
case 'Z': letters++; break;
default: others++;
}
}
}