编写C程序,使用Linux中的IPC机制,完成 “石头、剪子、布”的游戏;
时间: 2024-05-13 16:14:33 浏览: 182
利用C语言编写“剪刀石头布”小游戏
这里提供一种使用共享内存和信号量实现的方法:
先定义游戏规则:
1. 石头胜剪子,剪子胜布,布胜石头;
2. 两方同时出拳,如果出拳相同则为平局;
3. 每局比赛结束后,双方可以选择继续游戏或退出。
接下来,我们可以编写一个双方都可以运行的程序,代码如下:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <time.h>
#define SHM_SIZE 1024
#define SEM_NUM 2
enum {
ROCK = 1,
SCISSORS,
PAPER,
QUIT
};
union semun {
int val;
struct semid_ds *buf;
unsigned short *array;
};
void set_semvalue(int sem_id, int sem_num, int value)
{
union semun sem_union;
sem_union.val = value;
if (semctl(sem_id, sem_num, SETVAL, sem_union) == -1) {
perror("Error: semctl SETVAL failed");
exit(EXIT_FAILURE);
}
}
void del_semvalue(int sem_id, int sem_num)
{
union semun sem_union;
if (semctl(sem_id, sem_num, IPC_RMID, sem_union) == -1) {
perror("Error: semctl IPC_RMID failed");
exit(EXIT_FAILURE);
}
}
int semaphore_p(int sem_id, int sem_num)
{
struct sembuf sem_buf;
sem_buf.sem_num = sem_num;
sem_buf.sem_op = -1;
sem_buf.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_buf, 1) == -1) {
perror("Error: semaphore_p failed");
exit(EXIT_FAILURE);
}
return 0;
}
int semaphore_v(int sem_id, int sem_num)
{
struct sembuf sem_buf;
sem_buf.sem_num = sem_num;
sem_buf.sem_op = 1;
sem_buf.sem_flg = SEM_UNDO;
if (semop(sem_id, &sem_buf, 1) == -1) {
perror("Error: semaphore_v failed");
exit(EXIT_FAILURE);
}
return 0;
}
int main(int argc, char **argv)
{
int shm_id, sem_id, *shared_memory, selection, result;
key_t shm_key, sem_key;
char buffer[BUFSIZ];
srand(time(NULL));
if (argc != 2) {
printf("Usage: %s <key>\n", argv[0]);
exit(EXIT_FAILURE);
}
/* 创建共享内存 */
shm_key = atoi(argv[1]);
if ((shm_id = shmget(shm_key, SHM_SIZE, 0666)) == -1) {
perror("Error: shmget failed");
exit(EXIT_FAILURE);
}
/* 连接共享内存 */
if ((shared_memory = shmat(shm_id, NULL, 0)) == (void *)-1) {
perror("Error: shmat failed");
exit(EXIT_FAILURE);
}
/* 创建信号量 */
sem_key = ftok("/tmp", atoi(argv[1]));
if ((sem_id = semget(sem_key, SEM_NUM, 0666)) == -1) {
perror("Error: semget failed");
exit(EXIT_FAILURE);
}
/* 初始化信号量 */
set_semvalue(sem_id, 0, 0);
set_semvalue(sem_id, 1, 0);
while (1) {
printf("Please make your selection (1. Rock, 2. Scissors, 3. Paper, 4. Quit): ");
fgets(buffer, BUFSIZ, stdin);
selection = atoi(buffer);
if (selection == QUIT) {
break;
}
/* 等待对方出拳 */
semaphore_p(sem_id, 0);
/* 获取对方出拳的结果 */
result = *shared_memory;
/* 判断胜负 */
if (result == selection) {
printf("It's a tie!\n");
} else if ((result == ROCK && selection == SCISSORS) ||
(result == SCISSORS && selection == PAPER) ||
(result == PAPER && selection == ROCK)) {
printf("You lose!\n");
} else {
printf("You win!\n");
}
/* 继续游戏或退出 */
printf("Do you want to continue? (y/n) ");
fgets(buffer, BUFSIZ, stdin);
if (buffer[0] == 'n' || buffer[0] == 'N') {
break;
}
/* 准备出拳 */
selection = rand() % 3 + 1;
*shared_memory = selection;
/* 通知对方已经出拳 */
semaphore_v(sem_id, 1);
}
/* 断开共享内存 */
if (shmdt(shared_memory) == -1) {
perror("Error: shmdt failed");
exit(EXIT_FAILURE);
}
/* 删除信号量 */
del_semvalue(sem_id, 0);
del_semvalue(sem_id, 1);
return 0;
}
```
程序中使用了共享内存和信号量两种 IPC 机制。程序开始时创建共享内存和信号量,然后进入一个循环,每次循环中先让用户输入自己的选择,然后等待对方出拳。当收到对方出拳的信号后,程序获取对方出拳的结果,并根据游戏规则判断胜负,然后让用户选择是否继续游戏。如果用户选择继续游戏,程序会随机产生自己的出拳结果,并将结果写入共享内存中,然后通知对方已经出拳。如果用户选择退出,程序会断开共享内存和删除信号量。
注意:这个程序中的信号量必须按照特定的顺序操作,否则会导致死锁。具体来说,当一个进程需要等待另一个进程的信号时,它必须先 P 第一个信号量,然后再 V 第二个信号量。当另一个进程需要等待它的信号时,它必须先 P 第二个信号量,然后再 V 第一个信号量。这样做可以保证两个进程不会同时进入等待状态。
阅读全文