编写C程序,使用Linux中的IPC的消息队列机制,完成 “石头、剪子、布”的游戏。创建三个进程:一个进程为裁判进程,另外两个进程为选手进程裁判进程将对手的出招和胜负结果通知选手。比赛可以采取多盘(如100盘)定胜负,由裁判宣布最后结果。每次出招由裁判限定时间,超时判负。 每盘结果可以存放在文件或其他数据结构中。比赛结束,可以打印每盘的胜负情况和总的结果。
时间: 2024-03-10 16:45:04 浏览: 160
好的,我可以帮您解答这个问题。
下面是一个使用消息队列进行进程间通信的石头、剪子、布游戏程序,它包含三个进程:一个裁判进程和两个选手进程。裁判进程为选手进程分别创建消息队列,并负责通知选手出招和比较胜负。每次出招有一个限定时间,超时判负。每盘结果保存在文件中,比赛结束后可以打印每盘的胜负情况和总的结果。
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
#define MSG_SIZE 128
#define MSG_TYPE 1
#define TIMEOUT 5
#define ROUNDS 100
struct msgbuf {
long mtype;
char mtext[MSG_SIZE];
};
void handle_timeout(int sig) {
// 空函数,用于捕捉SIGALRM信号
}
int main() {
int msqid[2];
pid_t pid[2];
struct msgbuf msg[2];
key_t key[2];
FILE* fp;
int i, j, k;
int score[2] = {0, 0};
int round = 0;
char result[ROUNDS];
// 创建一个唯一的键值,用于访问消息队列
for (i = 0; i < 2; i++) {
if ((key[i] = ftok(".", 'A' + i)) == -1) {
perror("ftok");
exit(1);
}
}
// 创建两个选手进程
for (i = 0; i < 2; i++) {
pid[i] = fork();
if (pid[i] == -1) {
perror("fork");
exit(1);
} else if (pid[i] == 0) {
// 子进程
srand(time(NULL) + i);
while (1) {
// 等待裁判通知出招
msgrcv(msqid[i], &msg[i], MSG_SIZE, MSG_TYPE, 0);
// 生成游戏选择
int choice = rand() % 3;
if (choice == 0) {
strcpy(msg[i].mtext, "石头");
} else if (choice == 1) {
strcpy(msg[i].mtext, "剪子");
} else {
strcpy(msg[i].mtext, "布");
}
// 将消息类型设置为2,表示这是选手的响应消息
msg[i].mtype = MSG_TYPE + 1;
msgsnd(msqid[i], &msg[i], strlen(msg[i].mtext) + 1, 0);
}
}
}
// 创建文件,用于保存每盘的结果
fp = fopen("result.txt", "w");
if (fp == NULL) {
perror("fopen");
exit(1);
}
// 创建消息队列
for (i = 0; i < 2; i++) {
if ((msqid[i] = msgget(key[i], 0666 | IPC_CREAT)) == -1) {
perror("msgget");
exit(1);
}
}
// 游戏循环
signal(SIGALRM, handle_timeout);
while (1) {
// 设置定时器
alarm(TIMEOUT);
// 等待选手出招
for (i = 0; i < 2; i++) {
printf("选手%d,请出招(石头/剪子/布):\n", i + 1);
fgets(msg[i].mtext, MSG_SIZE, stdin);
msg[i].mtype = MSG_TYPE;
msgsnd(msqid[i], &msg[i], strlen(msg[i].mtext) + 1, 0);
}
// 等待选手响应
for (i = 0; i < 2; i++) {
msgrcv(msqid[i], &msg[i], MSG_SIZE, MSG_TYPE + 1, 0);
}
// 取消定时器
alarm(0);
// 比较胜负
printf("选手1出了:%s\n", msg[0].mtext);
printf("选手2出了:%s\n", msg[1].mtext);
if (strcmp(msg[0].mtext, msg[1].mtext) == 0) {
printf("平局!\n");
result[round] = 'D';
} else if ((strcmp(msg[0].mtext, "石头") == 0 && strcmp(msg[1].mtext, "剪子") == 0) ||
(strcmp(msg[0].mtext, "剪子") == 0 && strcmp(msg[1].mtext, "布") == 0) ||
(strcmp(msg[0].mtext, "布") == 0 && strcmp(msg[1].mtext, "石头") == 0)) {
printf("选手1胜利!\n");
score[0]++;
result[round] = 'A';
} else {
printf("选手2胜利!\n");
score[1]++;
result[round] = 'B';
}
// 将结果保存到文件中
fprintf(fp, "第%d盘:选手1 %s vs 选手2 %s,胜者为%s\n", round + 1, msg[0].mtext, msg[1].mtext, (result[round] == 'A') ? "选手1" : ((result[round] == 'B') ? "选手2" : "平局"));
fflush(fp);
// 判断胜负
if (score[0] == ROUNDS / 2 + 1) {
printf("选手1获胜!\n");
break;
} else if (score[1] == ROUNDS / 2 + 1) {
printf("选手2获胜!\n");
break;
}
round++;
}
// 打印每盘的胜负情况和总的结果
printf("每盘胜负结果:\n");
for (i = 0; i < round + 1; i++) {
printf("第%d盘:选手1 %s vs 选手2 %s,胜者为%s\n", i + 1, (i < round) ? msg[0].mtext : "-", (i < round) ? msg[1].mtext : "-", (result[i] == 'A') ? "选手1" : ((result[i] == 'B') ? "选手2" : "平局"));
}
printf("总的结果:选手1 %d胜%d负,选手2 %d胜%d负\n", score[0], ROUNDS - score[0], score[1], ROUNDS - score[1]);
// 删除消息队列
for (i = 0; i < 2; i++) {
if (msgctl(msqid[i], IPC_RMID, NULL) == -1) {
perror("msgctl");
exit(1);
}
}
// 等待子进程结束
for (i = 0; i < 2; i++) {
if (waitpid(pid[i], NULL, 0) == -1) {
perror("waitpid");
exit(1);
}
}
// 关闭文件
fclose(fp);
return 0;
}
```
这个程序使用了三个进程来实现石头、剪子、布游戏,它们通过消息队列进行通信。裁判进程为选手进程分别创建消息队列,并负责通知选手出招和比较胜负。每次出招有一个限定时间,超时判负。每盘结果保存在文件中,比赛结束后可以打印每盘的胜负情况和总的结果。
注意,为了实现限定时间,我们使用了SIGALRM信号和alarm函数。当定时器超时时,会向程序发送SIGALRM信号,我们可以在程序中捕捉该信号并执行相应的处理函数。
阅读全文