| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 7779 人关注过本帖
标题:C语言小游戏:剪刀石头布
只看楼主 加入收藏
汉家萌妹子
Rank: 2
等 级:论坛游民
威 望:5
帖 子:56
专家分:74
注 册:2018-8-21
结帖率:100%
收藏
 问题点数:0 回复次数:10 
C语言小游戏:剪刀石头布
c语言小游戏:剪刀石头布
 剪刀石头布是一种简单而有趣的小游戏,规则很简单,通过剪刀,石头,布三种手势判断胜负,即剪刀胜布,布胜石头,石头胜剪刀。具体关系如下表所示:
+------+------+------+----+
|      | 剪刀 | 石头 | 布 |
+------+------+------+----+
| 剪刀 |    |    | 胜 |
+------+------+------+----+
| 石头 |    |    | 败 |
+------+------+------+----+
| 布   |    |    | 平 |
+------+------+------+----+
 下面用c语言来开发这么一个卡牌游戏,游戏规则如下:
 1.有分别代表剪刀,石头,布的三类卡牌,各三十张
 2.三十张牌洗牌之后,分发给甲乙两位玩家,每人持15张
 3.每回合,双方玩家各持一张牌公开
 4.比较公开牌的胜负,胜利的一方可以把牌在拿回手中
 5.如果双方出的牌一样,则都不能拿回手中
 6.最后手上卡牌先用完的一方为失败方
 大致规则如以上所示,为了增加游戏的趣味性,我决定在加两类道具:
 1.炸弹牌,可以和任何牌打平
 2.护身符,消耗一张护身符牌,可以把被消灭的牌再次拿回手中
 游戏源码请参见网址:https://
 该源码已添加详细的注释,可直接下载或使用git工具同步到本地。
搜索更多相关主题的帖子: C语言 小游戏 游戏 规则 源码 
2018-08-24 10:43
Mr_doge
Rank: 5Rank: 5
等 级:贵宾
威 望:10
帖 子:159
专家分:385
注 册:2018-6-28
收藏
得分:0 
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/*
    游戏规则表,以游戏人类玩家为基准,1代表胜利,0代表平局,-1代表失败,具体逻辑如下所示:
    +------+------+------+----+
    |      | 剪刀 | 石头 | 布 |
    +------+------+------+----+
    | 剪刀 |    |    | 胜 |
    +------+------+------+----+
    | 石头 |    |    | 败 |
    +------+------+------+----+
    | 布   |    |    | 平 |
    +------+------+------+----+

*/
const char game[3][3] =
{
    { 0,-1,1 },
    { 1,0,-1 },
    { -1,1,0 }
};

/*
    这是游戏的打印信息,通过查表输出道具名称
*/
const char *mess[5] = { "剪刀","石头","布" ,"炸弹","护身符" };

/*
    卡牌信息,总共30张牌,剪刀,石头,布各10张,将在init函数中进行初始化
*/
char cards[30];

/*
    player1表示人类玩家,player2表示电脑玩家。
    这是一个数组,其中索引0保存剪刀牌的数量,索引1保存石头牌的数量,索引2保存布牌数量,索引3保存炸弹牌数量,索引4保存护身符牌数量
*/
char player1[5];
char player2[3];

/*
    初始化卡牌信息,逻辑如下:
    设定一个30次的循环,每一次循环体里面,都将循环次数除以3,并把结果赋值给数组的某个索引。
    由于是整型除法,i小于10,结果为0,表示剪刀;i大于10,小于20,结果为1,表示石头;i大于20,小于30,结果为2,表示布。

    洗牌逻辑如下:
    1.以当前时间为随机数种子,初始化随机数
    2.设定100次的循环次数
    3.每次循环,获取a和b两个随机数,用整数30取模后,作为数组索引把卡组的两处牌交换
*/
void init_cards()
{
    int a, b, c, i;
    for (i = 0; i<30; i++)
        cards[i] = i / 10;

    srand((unsigned int)time(NULL));
    for (i = 0; i<100; i++)
    {
        a = rand() % 30;
        b = rand() % 30;
        c = cards[a];
        cards[a] = cards[b];
        cards[b] = c;
    }
}

/*
    发牌函数,前15张给玩家1,后15张给玩家2。
*/

void give_cards()
{
    int a, i;
    for (i = 0; i<15; i++)
    {
        a = cards[i];
        player1[a]++;
    }
    player1[3] = 3;
    player1[4] = 3;

    for (i = 15; i<30; i++)
    {
        a = cards[i];
        player2[a]++;
    }
}

/*
    获取玩家1出的牌,可以出示的牌,分别是剪刀,石头,布和炸弹,对应编号分别是1,2,3,4.
    当输入1,2,3,4以外的数字时,会报输入信息错误
    如果输入为合法信息,则判断对应牌信息是否为0,为0则提示玩家没有这张牌,并让玩家重新输入
    由于输入的是字符串,在ascii码中,0到9的十六进制码分别是0x30到0x39,所以返回的时候减去0x31
*/
char get_player1_card()
{
    char card=0;
    //while (card = getchar())
    while(card!=EOF)
    {
        scanf("%c",&card);
        fflush(stdin);//fflush()函数,包含于stdio.h 此处为清空输入缓冲区
        if (card != '1' && card != '2' && card != '3' && card != '4')
        {
            printf("输入错误,请重新出牌\n");
            continue;
        }

        if (player1[card - 0x31] <= 0)
        {
            printf("你没有这张牌,请重新出牌\n");
            continue;
        }
        break;
    }
    return card - 0x31;
}

/*
    玩家2出牌,由于玩家2是电脑玩家,出牌通过随机数推进,过程与玩家1出牌类似
*/
char get_player2_card()
{
    char card;
    while (card = rand() % 3)
    {
        if (card != 0 && card != 1 && card != 2)
        {
            continue;
        }

        if (player1[card] <= 0)
        {
            continue;
        }
        break;
    }
    return card;
}

/*
    护身符牌,当玩家1遇到失败或者平局时,如果玩家1拥有护身符牌,则会自动询问是否使用护身符牌,如果选择是,则消耗一张护身符牌,把失败的牌拿回手中。
*/
void amulet(char card)
{
    char ch;
    if (player1[4] > 0)
    {
        printf("你有%d张护身符,是否使用?(y/N)\n", player1[4]);
    a:
        scanf("%c",&ch);
        fflush(stdin);//fflush()函数,包含于stdio.h 此处为清空输入缓冲区
        if (ch == 'y' || ch == 'Y')
        {
            player1[card]++;
            player1[4]--;
            getchar();
        }
        else if (ch == 'n' || ch == 'N')
            {
             getchar();
            }
        else
        {
            if (ch == '\n')
                return;
            printf("输入错误,请重新输入!\n");
            goto a;
        }
    }
}

/*
    运行游戏,在运行前,先初始化游戏信息,包括洗牌和发牌。
    游戏开始时,先获取双方出的牌,如果玩家1出了炸弹,则这一局按平局算
    如果玩家1遇到失败或者平局,当手上有护身符牌时,会询问是否使用,如果玩家1选择使用,则可把失败的那一张牌拿回,并消耗一张护身符牌
    当任意一方的牌数为0时,则那一方算失败方
*/
void run_game()
{
    char a, b;
    init_cards();
    give_cards();
    printf("你剩余15张牌\n");
    printf("对方剩余15张牌\n");
    printf("\n");

    while (1)
    {
        printf("剪刀:%d\n", player1[0]);
        printf("石头:%d\n", player1[1]);
        printf("布:%d\n", player1[2]);
        printf("炸弹:%d\n", player1[3]);
        printf("护身符:%d\n", player1[4]);
        printf("\n");

        printf("请出牌:\n");
        printf("\t1.剪刀\n");
        printf("\t2.石头\n");
        printf("\t3.布\n");
        printf("\t4.炸弹\n");
        a = get_player1_card();
        b = get_player2_card();
        system("cls");
        printf("%s vs %s\n", mess[a], mess[b]);
        if (a == 3)
        {
            player1[a]--;
            player2[b]--;
            printf("你使用了炸弹!\n");
            goto a;
        }
        switch (game[a][b])
        {
        case -1:
            player1[a]--;
            printf("败!\n");
            amulet(a);
            break;
        case 0:
            player1[a]--;
            player2[b]--;
            printf("平!\n");
            amulet(a);
            break;
        case 1:
            player2[b]--;
            printf("胜!\n");
            break;
        default:
            break;
        }
    a:
        a = player1[0] + player1[1] + player1[2];
        b = player2[0] + player2[1] + player2[2];
        if (a <= 0)
        {
            printf("你输了!\n");
            break;
        }
        else if (b <= 0)
        {
            printf("你赢了!\n");
            break;
        }
        else
        {
            printf("\n");
            printf("你剩余%d张牌\n", a);
            printf("对方剩余%d张牌\n", b);
            printf("\n");
        }
    }
}

/*
    main函数,游戏的入口函数
*/
int main()
{
    run_game();
    system("pause");
    return 0;
}
个人编译环境
win10 MinGW+codeblocks c99
已知的部分问题:
1、for函数内声明变量c99及之前的编译器可能不支持。
2、读取用户输入的卡片序号及用户输入的护身符y\n有复数不正确字符时会出现各种情况,之后会存在缓冲区字符滞留问题。
修改了问题1相关部分。
问题2只改动部分,选择了scanf函数读入字符并使用stdio.h包含的fflush()函数一定程度缓解字符缓冲滞留问题(百度真是个好东西),但是错误、复数字符导致的错误识别这方面,相关代码恕个人太菜,没有更好的解决方式,也许可以用switch case语句进行输入识别解决。
其他方面的优化因个人水平,无法给出更可靠的建议。
但是fflush()函数于不同编译器有不同作用方式,也可以使用while函数不断循环读取的方式解决····(好麻烦的感觉)

[此贴子已经被作者于2018-9-4 11:23编辑过]

2018-09-04 11:12
汉家萌妹子
Rank: 2
等 级:论坛游民
威 望:5
帖 子:56
专家分:74
注 册:2018-8-21
收藏
得分:0 
没人说一句吗?
2018-09-05 20:00
幻紫灵心
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:山咔咔里面
等 级:贵宾
威 望:53
帖 子:396
专家分:2640
注 册:2018-3-30
收藏
得分:0 
编译了一下,发现编译错误,,把for里面的int i=0;改成了i=0;再在前面int i;这样就可以编译通过了。
玩了一下。。老是输是什么鬼!!!!!!!气死我了

saber,别哭.
2018-09-06 08:51
lin5161678
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:45
帖 子:1136
专家分:3729
注 册:2011-12-3
收藏
得分:0 
洗牌算法待改进

https://zh.
2018-09-06 09:32
wmf2014
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:216
帖 子:2039
专家分:11273
注 册:2014-12-6
收藏
得分:0 
赞一下!

能编个毛线衣吗?
2018-09-06 10:30
峰哥不是
Rank: 2
等 级:论坛游民
威 望:1
帖 子:28
专家分:75
注 册:2013-11-19
收藏
得分:0 
赞一下

纸上得来终觉浅,绝知此事要躬行
2018-09-06 13:37
豆豆的滴
Rank: 9Rank: 9Rank: 9
来 自:湖南
等 级:贵宾
威 望:33
帖 子:368
专家分:1087
注 册:2018-5-7
收藏
得分:0 
有点强
2018-09-07 14:53
喔喔我
Rank: 1
等 级:新手上路
帖 子:13
专家分:2
注 册:2018-12-8
收藏
得分:0 
666
2018-12-30 12:16
WatchCurtai
Rank: 2
等 级:论坛游民
帖 子:5
专家分:38
注 册:2018-10-24
收藏
得分:0 
牛逼
2018-12-31 15:21
快速回复:C语言小游戏:剪刀石头布
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.204614 second(s), 10 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved