线性表之俄罗斯轮盘赌小游戏(C语言实现,详细注释版)

在我们学习了线性表一段时间后,来试图实现“俄罗斯轮盘赌”这个小游戏,很多人应该都在电影里见过图1这样的游戏场景。游戏的道具是一把左轮手枪,其规则也很简单:在左轮手枪中的 6 个弹槽中随意放入一颗或者多颗子弹,在任意旋转转轮之后,关上转轮。游戏的参加者轮流把手枪对着自己,扣动扳机:中枪或是怯场,即为输的一方;坚持到最后的即为胜者。
在这里插入图片描述

图1 俄罗斯轮盘赌

解题思路

解决此似问题的核心在于建立轮流循环机制,使用线性表的顺序存储结构和链式存储结构都能实现,根据游戏规则,采用顺序存储结构时,必须使数组的首尾建立连接,即当需要从数组中最后一个位置寻找下一个位置时,要能够跳转到数组的第一个位置(使用取余运算可以解决)。采用链式存储结构时,只需将链表首尾相连,使用循环链表即可轻松解决问题。

同时我们应该明白,采用链式存储结构对于求此类问题是最容易理解的,同时也避免了当参与人数较多时,不必像顺序存储结构那样,因为删除某个游戏成员而频繁地移动其他游戏成员数据。

顺序存储结构模拟轮盘赌

具体C语言实现代码如下:

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

typedef struct GameMan{
    int number;
}GameMan;

int main(){
    int PersonNum;//游戏人数 
    int round=1;//游戏回合 
    int PersonPos=1;//起始人位置 
    int BulletPos;//子弹位置 
	int i;//中枪人位置
    srand((int)time(0));//使用当前时间作为rand()函数的随机数的种子
	printf("请输入本次游戏人数(<100): ");
    scanf("%d",&PersonNum);
    printf("\n为编号为 1-%d 的游戏人员分配位置!\n\n",PersonNum);
    GameMan GameMans[100];//存储游戏人员编号的数组
    for (int j=1;j<=PersonNum;j++) {//依次为参加者分配编号
        GameMans[j].number=j;
    }
    //当只剩余一个人时,此场结束
    while (PersonNum!=1) {
        BulletPos=rand()%6+1;//左轮旋转后的子弹位置(利用随机数1~6表示) 
		printf("第 %d 轮游戏,从编号为 %d 的人开始,枪在第 %d 次扣动扳机时会响!\n\n",round,GameMans[PersonPos].number,BulletPos);
        for (i=PersonPos;i<PersonPos+BulletPos-1;i++);//找到每轮退出的人的位置 i
        //由于参与者排成的是环,当人数少时可能会回到开头,所以需要对求得 i 值进行取余处理
        //当 i=0时,实际上指的是位于数组结尾的参与者,需要重新调整 i 的值
        if(!(i=i%PersonNum)){i=PersonNum;PersonPos=1;}
		else PersonPos=i;//PersonPos表示的是下一轮开始的位置
        printf("编号为 %d 的赌徒退出赌博,剩余赌徒编号依次为:",GameMans[i].number);
        //使用顺序存储时,如果删除元素,需要将其后序位置的元素进行全部前移
        PersonNum--;//此时参与人数减一 
		//先将i位置后成员向前依次移动     
        for (int j=i;j<=PersonNum;j++) {
            GameMans[j]=GameMans[j+1];
        }
		//再打印剩余成员 
		for (int k=1; k<=PersonNum; k++) {
            printf("%d ",GameMans[k].number);
        }
        printf("\n\n");  
        round++;//到回合数加一 
    }
    printf("最终胜利的游戏人员编号是:%d \n\n",GameMans[1].number);
}

程序运行结果如下:

请输入本次游戏人数(<100): 5

为编号为 1-5 的游戏人员分配位置!

第 1 轮游戏,从编号为 1 的人开始,枪在第 1 次扣动扳机时会响!

编号为 1 的赌徒退出赌博,剩余赌徒编号依次为:2 3 4 5

第 2 轮游戏,从编号为 2 的人开始,枪在第 2 次扣动扳机时会响!

编号为 3 的赌徒退出赌博,剩余赌徒编号依次为:2 4 5

第 3 轮游戏,从编号为 4 的人开始,枪在第 6 次扣动扳机时会响!

编号为 2 的赌徒退出赌博,剩余赌徒编号依次为:4 5

第 4 轮游戏,从编号为 4 的人开始,枪在第 5 次扣动扳机时会响!

编号为 4 的赌徒退出赌博,剩余赌徒编号依次为:5

最终胜利的游戏人员编号是:5

请按任意键继续. . .

链式存储结构模拟轮盘赌

具体C语言实现代码如下:

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

//链表节点单元 
typedef struct GameMan{
    int Man;
    struct GameMan * next;
}GameMan;

//建立游戏人员循环链表
void InitGameManLine(GameMan **GameMans,int PersonNum){
    *GameMans=(GameMan *)malloc(sizeof(GameMan));//头指针指向首元节点 
    //节点初始化 
	(*GameMans)->next=NULL;
    (*GameMans)->Man=1;
    GameMan *tail=*GameMans;//指向链表尾 
    for (int i=2;i<=PersonNum;i++){
        GameMan *newnode=(GameMan *)malloc(sizeof(GameMan));//申请新节点 
        //节点初始化 
		newnode->next=NULL;
        newnode->Man=i;
        tail->next=newnode;//将新节点链接到链表尾 
        tail=tail->next;//移动tail到尾指针 
    }
    tail->next=*GameMans;//将链表成环
}

//输出链表中所有游戏成员 
void display(GameMan *GameMans){
    GameMan *temp=GameMans;
    while (temp->next!=GameMans){
        printf("%d ",temp->Man);
        temp=temp->next;
    }
    printf("%d\n\n",temp->Man);
}

int main() {
    GameMan *GameMans=NULL;//游戏成员链表头指针
	int round=1; 
    int PersonNum;
	int BulletPos;
	srand((int)time(0));//使用当前时间作为rand()函数的随机数的种子 
	printf("请输入本次游戏人数(<100): ");
    scanf("%d",&PersonNum);
    printf("\n为编号为 1-%d 的游戏人员分配位置!\n\n",PersonNum);
    InitGameManLine(&GameMans,PersonNum);
    GameMan* lineNext=GameMans;//用于记录每轮开始的位置
    //仅当链表中只含有一个结点时,即头结点时,退出循环
    while(GameMans->next!=GameMans){
        BulletPos=rand()%6+1;
        printf("第 %d 轮游戏,从编号为 %d 的人开始,枪在第 %d 次扣动扳机时会响!\n\n",round,lineNext->Man,BulletPos);
        GameMan *temp=lineNext;
        //遍历循环链表,找到将要删除结点的上一个结点
        for (int i=1;i<BulletPos-1;i++){
            temp=temp->next;
        }
        //如果子弹位置BulletPos==1,则要找到当前节点的上一节点 
        if(BulletPos==1){
        	while(temp->next!=lineNext){
	        	temp=temp->next;
	        }
        } 
        printf("编号为 %d 的赌徒退出赌博,剩余赌徒编号依次为:",temp->next->Man);
        //将要删除结点从链表中删除,并释放其占用空间
		GameMan * del=temp->next;//记录删除节点 
        temp->next=temp->next->next;//从链表中移除该节点 
        if(del==GameMans)GameMans=GameMans->next;//如果删除的是头节点,将头节点的下一节点作为头节点 
        free(del);//释放del节点 
        display(GameMans);
        //下一轮开始的位置
        lineNext=temp->next;
        round++;//回合次数加一
    }
    printf("最终胜利的游戏人员编号是:%d \n\n",GameMans->Man);
    return 0;
}

程序运行结果如下:

请输入本次游戏人数(<100): 5

为编号为 1-5 的游戏人员分配位置!

第 1 轮游戏,从编号为 1 的人开始,枪在第 3 次扣动扳机时会响!

编号为 3 的赌徒退出赌博,剩余赌徒编号依次为:1 2 4 5

第 2 轮游戏,从编号为 4 的人开始,枪在第 3 次扣动扳机时会响!

编号为 1 的赌徒退出赌博,剩余赌徒编号依次为:2 4 5

第 3 轮游戏,从编号为 2 的人开始,枪在第 4 次扣动扳机时会响!

编号为 2 的赌徒退出赌博,剩余赌徒编号依次为:4 5

第 4 轮游戏,从编号为 4 的人开始,枪在第 4 次扣动扳机时会响!

编号为 5 的赌徒退出赌博,剩余赌徒编号依次为:4

最终胜利的游戏人员编号是:4

请按任意键继续. . .

发布了12 篇原创文章 · 获赞 17 · 访问量 8071

猜你喜欢

转载自blog.csdn.net/u010067603/article/details/105144914