I have two separate sets of code. One of a menu and the other of a rock paper scissors game. Im not sure how to link the two. Im pretty new to C and have been scrawling the internet looking for answers but I keep coming up with nothing. Im not sure what to look for either.
#define _CRT_SECURE_NO_WARNINGS
// C program for the above approach
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <windows.h>
#include <conio.h>
//UDF declaration
int inapp(); //UDF inapp
int exitapp(); //UDF exit app
int exitapp(); //UDF mainmenu
int menu = 0;
int mainmenu(int x) {
system("cls");
printf("Welcome to Rock Paper Scissors! \n---------------------\n\nc To continue \nb To exit\n");
int menumain = _getch();
while (1) {
if (menumain == 'c') { //checks if the user is in the app, then makes it so they go to the inapp
inapp();
}
else if (menumain == 'b') { // checks
exitapp();
}
else {
printf("\nNah. I don't get it.");
Sleep(1000);
mainmenu(1);
}
}
}
//In app function
int inapp() {
system("cls");
printf("Welcome to the menu.\n\n0 to exit \n1 to continue\n2 to return\n");
//scanf_s("%d", &menuin);
printf("\nPlease enter your choice\n");
char menuin = _getch();
if (menuin == '0') {
exitapp();
}
else if (menuin == '1') {
;
}
else if (menuin == '2') {
mainmenu(1);
}
else {
printf("\nNah. I don't get it.");
Sleep(1000);
inapp();
}
}
//Exit app function
int exitapp() {
system("cls");
printf("Goodbye, and thank you for your time.\n\n");
exit(0);
}
// Function to implement the game
int game(char you, char computer)
{
// If both the user and computer
// has chose the same thing
if (you == computer)
return -1;
// If user's choice is stone and
// computer's choice is paper
if (you == 's' && computer == 'p')
return 0;
// If user's choice is paper and
// computer's choice is stone
else if (you == 'p' && computer == 's') return 1;
// If user's choice is stone and
// computer's choice is scissor
if (you == 's' && computer == 'z')
return 1;
// If user's choice is scissor and
// computer's choice is stone
else if (you == 'z' && computer == 's')
return 0;
// If user's choice is paper and
// computer's choice is scissor
if (you == 'p' && computer == 'z')
return 0;
// If user's choice is scissor and
// computer's choice is paper
else if (you == 'z' && computer == 'p')
return 1;
}
// Driver Code
int main()
{
// Stores the random number
int n;
char you, computer, result;
// Chooses the random number
// every time
srand((unsigned int)time(NULL));
// Make the random number less
// than 100, divided it by 100
n = rand() % 100;
// Using simple probability 100 is
// roughly divided among stone,
// paper, and scissor
if (n < 33)
// s is notating Stone
computer = 's';
else if (n > 33 && n < 66)
// p is notating Paper
computer = 'p';
// z is notating Scissors
else
computer = 'z';
printf("\n\n\n\n\t\t\t\tEnter s for STONE, p for PAPER and z for SCISSOR\n\t\t\t\t\t\t\t");
// this is the input from the user
scanf("%c", &you);
// Function Call to play the game
result = game(you, computer);
if (result == -1) {
printf("\n\n\t\t\t\tGame Draw!\n");
}
else if (result == 1) {
printf("\n\n\t\t\t\tWow! You have won the game!\n");
}
else {
printf("\n\n\t\t\t\tOh! You have lost the game!\n");
}
printf("\t\t\t\tYOu choose : %c and Computer choose : %c\n", you, computer);
return 0;
}
I have all the errors gone and the rock paper scissors game works but the menu isnt showing up. I don't know what else to search for or what the issue is.
CodePudding user response:
The entry for your program is main()
and it doesn't call either mainmenu()
or inapp()
. mainmenu()
and inapp()
seems to be doing the same thing so let's eliminate inapp()
.
Looking at mainmenu()
it seems c
is what should invoke our game. To do that we rename main()
to rock_paper_scissors()
and rename mainmenu(int x)
to int main()
. We can use a switch instead of the if-else if-else to make it a little cleaner. Also, you don't want to call mainmenu()
recursively as stack space is finite. Just loop around instead. In terms of user experience, it's better to just start the game and then ask if user wants to continue.
I don't use windows but getchar()
gets a byte from the stdin, but it's line buffered so we have to ignore everything that comes after till we read a newline. I will call that function getchar_and_flush()
. You wan to use this instead of scanf()
to read the choice from user.
There are other issues with your program. For instance, if n == 33
the computer will elect z
which is surprising. Those single letter symbols makes your code hard to read. I suggest you introduce enum symbol { ROCK, PAPER, SCISSORS }
and use that instead of s
, p
, and z
. You sometimes call it rock, other times stone (internally inconsistent). The game()
function looks weird to me as you sometimes you if
and sometimes else if
. There a much better trick, namely, a table. Let's first rename the result, using an enum:
enum result {
LOSS = -1,
TIE,
WIN
};
you \ computer | rock | paper | scissors |
---|---|---|---|
rock | TIE | LOSS | WIN |
paper | WIN | TIE | LOSS |
scissor | LOSS | WIN | TIE |
which can directly expressed as a 2d array (see game()
).
After cleaning up the prompts, and removing windows specific features the code now looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
enum result {
LOSS = -1,
TIE,
WIN
};
enum symbol {
ROCK,
PAPER,
SCISSORS,
INVALID
};
struct {
enum symbol s;
char c;
const char *name;
} map[] = {
{ ROCK, 'r', "rock" },
{ PAPER, 'p', "paper" },
{ SCISSORS, 's', "scissors" },
{ INVALID, '?' }
};
int getchar_and_flush() {
int c = getchar();
while(getchar() != '\n');
return c;
}
const char *name_from_symbol(enum symbol s) {
for(size_t i = 0; i < sizeof map / sizeof *map; i )
if(s == map[i].s)
return map[i].name;
return map[INVALID].name;
}
enum symbol symbol_from_char(char c) {
for(size_t i = 0; i < sizeof map / sizeof *map; i )
if(c == map[i].c)
return map[i].s;
return INVALID;
}
int game(enum symbol you, enum symbol computer) {
return (enum result [3][3]) {
{ TIE, LOSS, WIN },
{ WIN, TIE, LOSS },
{ LOSS, WIN, TIE }
}[you][computer];
}
void rock_paper_scissor() {
enum symbol computer;
srand((unsigned int)time(NULL));
int n = rand() % 100;
if (n < 33)
computer = ROCK;
else if (n < 66)
computer = PAPER;
else
computer = SCISSORS;
enum symbol you;
do {
printf("Enter r for ROCK, p for PAPER and s for SCISSORS: ");
you = symbol_from_char(getchar_and_flush());
if(you == INVALID)
printf("Invalid input\n");
} while(you == INVALID);
switch(game(you, computer)) {
case LOSS:
printf("Oh! You have lost the game!\n");
break;
case TIE:
printf("Game Draw!\n");
break;
case WIN:
printf("Wow! You have won the game!\n");
break;
}
printf(
"You choose : %s and Computer choose : %s\n"
"\n",
name_from_symbol(you), name_from_symbol(computer)
);
}
int main() {
printf(
"Welcome to Rock Paper Scissors!\n"
"-------------------------------\n"
"\n"
);
for(;;) {
rock_paper_scissor();
printf("Again (y/n)? ");
switch(getchar_and_flush()) {
case 'y':
printf("\n");
continue;
break;
case 'n':
printf("Goodbye, and thank you for your time.\n");
return 0;
default:
printf("Nah. I don't get it.\n");
break;
}
}
}
and example session:
Welcome to Rock Paper Scissors!
-------------------------------
Enter r for ROCK, p for PAPER and s for SCISSORS: r
Oh! You have lost the game!
You choose : rock and Computer choose : paper
Again (y/n)? y
Enter r for ROCK, p for PAPER and s for SCISSORS: r
Game Draw!
You choose : rock and Computer choose : rock
Again (y/n)? y
Enter r for ROCK, p for PAPER and s for SCISSORS: s
Wow! You have won the game!
You choose : scissors and Computer choose : paper
Again (y/n)? n
Goodbye, and thank you for your time.
CodePudding user response:
NOT INTENDED AS AN ANSWER (please do not DV)
If your ambition is to become a coder, you have to learn to break apart a problem and produce a good solution. Your version of game()
is long and convoluted.
Study the following and see how it serves to compare the two players' selections with only a few lines of code. (This could be further reduced when you learn about modulo arithmetic.)
int game( char you, char computer ) {
if( you == computer ) return -1;
if( you == 's' ) return computer == 'z'; // stone/scissors wins
if( you == 'p' ) return computer == 's'; // paper/stone wins
/* if( you == 'z' ) */ return computer == 'p'; // scissors/paper wins
}
Notice that else
is not necessary. When the if()
evaluates true, the execution is already diverted by return;
With less code to read, the answer to your question will not be hidden in too many lines of code and you may be able to solve it for yourself.
EDIT
Following the (customary) excellent answer from @AllanWind and in support of his demonstration of using a look up table to determine the results of a combination, the following shows how one might implement the slightly more complicated decisions of Sheldon Cooper's Variation:
"Rock/Paper/Scissors/Lizard/Spock".
In brief, the user makes a selection from the terse menu and a similar random(!) selection is made for the PC. Then evaluate
performs a table lookup to determine the winner and the appropriate string to explain the basis of the winning relationship.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *dr = "DRAW\n\n";
char *sp = "scissors cuts paper";
char *pr = "paper covers rock";
char *rl = "rock crushes lizard";
char *ln = "lizard poisons Spock";
char *ns = "Spock smashes scissors";
char *sl = "scissors decapitates lizard";
char *lp = "lizard eats paper";
char *pn = "paper disproves Spock";
char *nr = "Spock vaporizes rock";
char *rs = "rock crushes scissors";
char *tbl[][6] = {
{ dr, pr, rs, rl, nr, " lwwl", },
{ pr, dr, sp, lp, pn, "w llw", },
{ rs, sp, dr, sl, ns, "lw wl", },
{ rl, lp, sl, dr, ln, "lwl w", },
{ nr, pn, ns, ln, dr, "wlwl ", },
};
void evaluate( int usr, int cpu ) {
char *elems[] = { "rock", "paper", "scissors", "lizard", "nimoy(spock)" };
printf ( "\nYou: %-14s - PC: %-14s - %s", elems[ usr ], elems[ cpu ], tbl[usr][cpu] );
if( usr != cpu )
printf( " - %s\n\n", tbl[usr][5][cpu] == 'w' ? "WIN!!" : "lose..." );
}
void oneRound() {
char *choices = "rpslnRPSLN";
char buf[32];
printf( "choose [r]ock [p]aper [s]cissors [l]izard [n]imoy(Spock): " );
fgets( buf, sizeof buf, stdin );
char *cp = strchr( choices, buf[0] );
if( cp == NULL )
puts( "bad entry" );
else
evaluate( ( cp - choices ) % 5, rand() % 5 );
}
int main() {
srand( time(NULL) );
for( ;; )
oneRound();
return 0;
}
choose [r]ock [p]aper [s]cissors [l]izard [n]imoy(Spock): n
You: nimoy(spock) - PC: paper - paper disproves Spock - lose...
choose [r]ock [p]aper [s]cissors [l]izard [n]imoy(Spock): r
You: rock - PC: paper - paper covers rock - lose...
choose [r]ock [p]aper [s]cissors [l]izard [n]imoy(Spock): r
You: rock - PC: nimoy(spock) - Spock vaporizes rock - lose...
choose [r]ock [p]aper [s]cissors [l]izard [n]imoy(Spock): l
You: lizard - PC: rock - rock crushes lizard - lose...
choose [r]ock [p]aper [s]cissors [l]izard [n]imoy(Spock):
Of note may be the very few lines of code at the heart of this program. "Window dressing" of user interaction can be added to taste.