两个C程序互相交互,玩猜谜游戏

时间:2017-10-14 21:10:07

标签: c

所以,对于我的班级,我应该首先创建一个猜测游戏,从用户那里获取输入并根据他们的名字,告诉他们他们是否接近魔术数字。这是我的计划。

#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);
}

它有效,但现在我必须编写另一个响应它的程序。

我的任务是编写一个“播放”猜测的简单C程序 游戏由我的程序提问者运行。 它必须以适当的答案回应上述两个提示, 也就是名字和数字。如果程序提供相同的名称,则可以 并且每次编号。

例如:(我的程序以粗体输出,其斜体输入)

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

如果您的程序收到问题中描述的提示以外的输入字符串 如上图2所示,它应回复三个问号(???)然后退出。例如:

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

说明也说要将其作为单个.c文件转换,但我不完全确定如何在不使用标题的情况下执行此操作?非常感谢任何帮助或提示。

2 个答案:

答案 0 :(得分:1)

这里需要两个进程之间的进程间通信。进程间通信有很多选项。但是对于你的要求最简单的Queue方法。创建两个队列,例如question_qanswer_q(检查如何在unix中创建队列以及如何读取队列以及如何将消息丢弃到队列中)。现在,您的上述程序会将问题放在question_q中,该问题将由其他流程读取,该流程会响应上述流程的每个问题,并将答案删除为Bobanswer_q,这将再次由你的另一个过程。我想这会对你有帮助。

答案 1 :(得分:1)

正如Jonathan Leffler评论的那样,你需要两个管道:一个用于读取程序 stdout ,另一个用于写入 stdin

这是一个小例子:

<强> 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;
}

请注意,在程序中我不断刷新 stdout ,因为当它指向非交互式设备时它会被完全缓冲,这意味着它会等待所有在实际冲洗之前要累积的输出。如果我没有刷新程序中的每个printf,那么交互程序就会等待问题,而程序本身会等待答案,然后将问题刷新到 stdout 管。

<强> 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;
}

它有点简单,也许您必须更改代码以满足您的需求,但它是如何使用管道来读取程序的示例 stdout 并写入 stdin

首先创建两个管道(它们是单向的,因此您需要一个用于 stdout ,另一个用于 stdin ),使用fork创建子进程,复制管道以获得 stdin stdout 的文件描述符编号(记住在 stdout上有管道的写入端 stdin 上管道的读取端)并执行程序本身,而在父进程上,您只需使用这些管道的另一端来读取程序输出并使用readwrite系统调用写入其输入。

如果您不熟悉forkexecpipedup2,最初可能会有点难以理解,但希望这些评论将帮助指导您完成代码(并且不要忘记阅读man pages)。