Michael Brown
Michael Brown

Reputation: 31

Two C Programs to interact with each other and play guessing game

So, for my class here I'm supposed to first create a guessing game that takes input from the user and based and their name, tell them if they're close to the magic number. Here is my program for that.

#include <stdio.h>
#include <string.h>

typedef struct { //user info. stores name and number from file input.
char list_name[20];
int list_num;
}list;

char user_name[20]; // info scanned in from user playing the game.
int user_magic_num; // "

int main(){

FILE *fp;
int i; // for the for loop.
list answers;
int matched = 0;

fp = fopen("answers.txt", "rb");
if(fp == NULL)
{
  perror("Error opening file");
  return -1;
}

inquiry();

for (i=0; i<3; i++)
{
    fscanf (fp, "%s %d", answers.list_name, &answers.list_num);
    if(feof(fp))
    {
       puts("End of file.");
       break;
    }

    if (strcmp(answers.list_name,user_name)==0)//User is recognized.
    {
        matched = 1;
        if(user_magic_num==answers.list_num)
        {
            printf("\n Yes, %s. You guess correctly! %d is the magic 
number!\n",user_name, answers.list_num);
            break;
        }
        else if(user_magic_num>answers.list_num)
        {
            printf("\n No, that's too high.\n");
        }
        else
        {
            printf("\n No, that's too low.\n");
        }
    }
}
if (!matched)
{
    answers.list_num = 12345;
    printf ("\n User not recognized. Default magic number set.\n\n");

     if(user_magic_num==answers.list_num)
        {
            printf("\n You guess correctly! %d is the magic number!\n", 
answers.list_num);
        }
        else if(user_magic_num>answers.list_num)
        {
            printf("\n No, that's too high.\n");
        }
        else
        {
            printf("\n No, that's too low.\n");
        }
}
  return 0;
}

void inquiry()
{
printf("\n Hi, what's your name? \n \n");
scanf("%s",user_name);
printf("\n Hello, %s! \n \n What's the magic number? \n \n",user_name);
scanf("%d", &user_magic_num);
printf("\n You guessed %d.\n\n", user_magic_num);
}

It works, but now I have to write another program that responds to it.

My task is to write a simple C program that ”plays” the guessing game run by my program questioner.c. It must respond to the two prompts described above with appropriate answers, that is, a name and a number. It’s OK if the program provides the same name and number each time.

For example: (Output from my program in bold, its input in italics)

 *What is your name?*
 **Bob**
 *What is the magic number, Bob?*
 **78901**
 *TOO HIGH*

If your program receives an input string other than the prompts described in Problem 2 above, it should reply with three question marks (???) and then exit. For example:

 *What is your name?**
 **Bob**
 *Do you like apples?*
 **???

The instructions also say to turn this in as a single .c file, but I'm not entirely sure how I would do that without using headers? Any help or hints are greatly appreciated.

Upvotes: 2

Views: 985

Answers (2)

IanC
IanC

Reputation: 2058

As Jonathan Leffler commented, you need two pipes: One for reading the program stdout and another to write to its stdin.

Here is a small example:

program.c:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv){
    char name[20];
    int number;

    //Ask
    printf("Hi, what is your name?\n");
    fflush(stdout);
    //Get user input
    scanf("%19s", name);
    //Ask
    printf("What is the magic number?\n");
    fflush(stdout);
    //Get user input
    scanf("%d", &number);

    printf("Thanks!\n");
    fflush(stdout);
    printf("\nYour name is %s and the magic number is %d!\n", name, number);
    fflush(stdout);

    return 0;
}

Note that on the program I'm constantly flushing the stdout, because it's fully buffered when it points to a non-interactive device, which means it would wait for all the output to be accumulated before actually flushing it. If I didn't flush every printf in the program, the interacting program would hang waiting for the question while the program itself would wait for the answer before flushing the question to the stdout pipe.

interacting_program.c:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

int main(int argc, char **argv){

    //A pipe to read the program output
    int output_pipe[2];
    //A pipe to send input to the program
    int input_pipe[2];
    //For the fork/exec
    pid_t pid;

    //To read the program output
    char process_line[4096];

    //Create pipes
    if(pipe(output_pipe) == -1){
        printf("Failed on pipe();\n");
        exit(1);
    } else if(pipe(input_pipe) == -1){
        printf("Failed on pipe();\n");
        exit(1);
    }

    //Fork the process
    pid = fork();

    if(pid == -1){
        printf("Failed on fork();\n");
        exit(1);
    } else if(pid == 0){
        //CHILD PROCESS

        //We duplicate the writing end of the output pipe to have the same file descriptor number as the process stdout, so everything it writes to stdout will be sent to the reading side of the pipe (output_pipe[0])
        dup2(output_pipe[1], STDOUT_FILENO);
        //Now that the output is redirected we can close the pipes
        close(output_pipe[1]);
        close(output_pipe[0]);

        //We duplicate the reading end of the input pipe to have the same file descriptor number as the process stdin, so everything that is written to the other end of the pipe (input_pipe[1]) will be sent to the process stdin.
        dup2(input_pipe[0], STDIN_FILENO);
        //Now that the input is redirected we can close the pipes
        close(input_pipe[1]);
        close(input_pipe[0]);

        //Exec
        execl("./program", "./program", NULL);

        //In case exec fails
        printf("Failed to execute program!\n");
        exit(1);
    } else {
        //PARENT PROCESS

        int read_bytes;

        //Read from the pipe that is now the child process stdout
        while((read_bytes = read(output_pipe[0], process_line, sizeof(process_line))) > 0){
            //Check what was read and respond accordingly
            printf("[PROGRAM OUTPUT]: %.*s", read_bytes, process_line);
            if(strcmp(process_line, "Hi, what is your name?\n") == 0){
                printf("[ANSWER]: Mike\n");
                write(input_pipe[1], "Mike\n", 5);
            } else if (strcmp(process_line, "What is the magic number?\n") == 0){
                printf("[ANSWER]: 41\n");
                write(input_pipe[1], "41\n", 3);
            } else {
                if(strcmp(process_line, "Thanks!\n") == 0){
                    printf("You're welcome!\n");
                } else if(strcmp(process_line, "\nYour name is Mike and the magic number is 41!\n") == 0){
                    printf("Done!\n");
                    break;
                } else {
                    printf("???\n");
                }
            }
            //Clears the process line
            memset(process_line, 0, sizeof(process_line));
        }

        //Close the pipes
        close(input_pipe[1]);
        close(input_pipe[0]);
        close(output_pipe[1]);
        close(output_pipe[0]);

        printf("Waiting child process!\n");
        wait(NULL);
    }
    return 0;
}

It's a bit simplistic and maybe you'll have to change the code to fit your needs, but it's an example of how to use pipes to read a programs stdout and write to its stdin.

First you create both pipes (they are unidirectional, so you will need one for the stdout and another one for the stdin), use the fork to create the child process, duplicate the pipes to have the file descriptor number of the stdin and stdout (remembering to have the write side of the pipe on the stdout and the read side of the pipe on the stdin) and execute the program itself, while on the parent process you'll just use the other end of those pipes to read the programs output and write to its input, using the read and write system calls.

If you're not familiar with fork, exec, pipe and dup2 they might be a little hard to understand at first, but hopefully the comments will help guide you through the code (and don't forget to also read the man pages).

Upvotes: 1

Abhijit Pritam Dutta
Abhijit Pritam Dutta

Reputation: 5591

Here you need inter process communication between two processes. There are lots of options for inter process communication. But for your requirement easiest method will of Queue. Create two queues for example question_q and answer_q (check how to create queue in unix and how to read a queue and how to drop message to a queue ). Now your above programme will drop the question in the question_q which will read by other process which responds to every question of above process and drop the answer as Bob to answer_q which will again read by your another process. I think this will help you.

Upvotes: 1

Related Questions