c语言命令行-勇者斗恶龙

时间:2022-05-28 17:41:03

一、背景

马上过春节了,在家闲暇时间,看到了别人php写的一个命令行游戏,直接拿过来用c语音实现了一下哈。

二、相关知识

1、CLI颜色打印方法,使用printf控制就行,以下从网上收录了一些常用的颜色码:
打印格式为:
printf("\033[字背景颜色;字体颜色m字符串\033[0m");
40: 黑 30: 黑
41: 红 31: 红
42: 绿 32: 绿
43: 黄 33: 黄
44: 蓝 34: 蓝
45: 紫 35: 紫
46: 深绿 36: 深绿
47: 白色 37: 白色
2、CLI的控制码
\033[0m 关闭所有属性
\033[1m 设置高亮度
\03[4m 下划线
\033[5m 闪烁
\033[7m 反显
\033[8m 消隐
\033[30m -- \033[37m 设置前景色
\033[40m -- \033[47m 设置背景色
\033[nA 光标上移n行
\03[nB 光标下移n行
\033[nC 光标右移n行
\033[nD 光标左移n行
\033[y;xH设置光标位置
\033[2J 清屏
\033[K 清除从光标到行尾的内容
\033[s 保存光标位置
\033[u 恢复光标位置
\033[?25l 隐藏光标
\33[?25h 显示光标

三、实现

其实这个idea是网上参考的哦,梳理出来思路如下:
1、定义血量HP、魔法MP,勇士发动攻击则需要消耗MP;
2、战斗方式为回合制,勇士和恶龙分别选择攻击方式进行PK;

基础定义:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define HP_MAX 20
#define MP_MAX 20
#define LOGGREEN(fmt, args...)		printf("\033[40;32m"fmt"\033[0m", ##args); 
#define LOGYELLOW(fmt, args...)		printf("\033[40;33m"fmt"\033[0m", ##args); 
#define LOGBLUE(fmt, args...)		printf("\033[40;36m"fmt"\033[0m", ##args); 
#define LOGD(fmt, args...);			printf(fmt, ##args);
#define LOGX(fmt, args...);			offset += snprintf(msg + offset, 1000 - offset, fmt, ##args);
static char msg[1000] = {0};
static int offset = 0;
typedef enum cmd_enum
{
    ROLE_YOU        = 1,
    ROLE_DRAGON     = 2,
    CMD_ENUM_MIN    = '0',
    CMD_ENUM_ATTACK = '1',
    CMD_ENUM_POWER  = '2',
    CMD_ENUM_DODGE  = '3',
    CMD_ENUM_THUMP  = '4',
    CMD_ENUM_MAX,
} CMD_ENUM;
typedef struct instance_t
{
    char name[16];
    int role;
    int dodge;
    int hp;
    int mp;
    struct instance_t *peer;
} INSTANCE_T;

然后定义四个动作对应玩家可选的四个攻击模式:
void dsp_usage()
{
    LOGD("\n\n选项:\n");
    LOGD("\t1.攻击:使用攻击需消耗1MP 伤害1HP\n");
    LOGD("\t2.蓄力:使用蓄力可增加1MP 伤害0HP\n");
    LOGD("\t3.闪避:使用躲闪需消耗0MP 伤害0HP  躲避攻击\n");
    LOGD("\t4.重击:使用重击需消耗2MP 伤害2HP  防御无效\n");
}
int main(void)
{
    char str_opt = 0;
    int opt = 0;
    int ret = 0;
    void (*do_callback)(INSTANCE_T *pinst);
    INSTANCE_T inst1 = {{0}, 0};
    INSTANCE_T inst2 = {{0}, 0};

    strcpy(inst1.name, "勇士");
    inst1.hp   = 10;
    inst1.mp   = 0;
    inst1.peer = &inst2;
    inst1.role = ROLE_YOU;

    strcpy(inst2.name, "恶龙");
    inst2.hp   = 20;
    inst2.mp   = 3;
    inst2.peer = &inst1;
    inst2.role = ROLE_DRAGON;
    srandom((unsigned int)time(NULL));
    
    dsp_usage();
    while ( (str_opt = getchar()) != EOF ) {
        switch ( str_opt ) {
            case CMD_ENUM_ATTACK:	
                do_attack(&inst1);
                break;
            case CMD_ENUM_POWER:	
                do_power(&inst1);
                break;
            case CMD_ENUM_DODGE:	
                do_dodge(&inst1);
                break;
            case CMD_ENUM_THUMP:	
                do_thump(&inst1);
                break;
            case 'q':
                LOGD("Game over\n");
                exit(0);
            default:
                continue;
        }

        switch ( (random() & 0x3) + '1' ) {
            case CMD_ENUM_ATTACK:	
                do_attack(&inst2);
                break;
            case CMD_ENUM_POWER:	
                do_power(&inst2);
                break;
            case CMD_ENUM_DODGE:	
                do_dodge(&inst2);
                break;
            case CMD_ENUM_THUMP:	
                do_thump(&inst2);
                break;
            default:	
                break;
        }
        dsp_title(&inst1, &inst2);
        dsp_usage();
    }
    LOGD("Game over\n");
    exit(0);
}

四种攻击模式的实现:
void do_attack(INSTANCE_T *pinst)
{
    LOGX("%s准备攻击,", pinst->name);
    if ( 0 == pinst->mp ) {
        LOGX("MP不足!\n");
        return;
    }
    pinst->mp--;
    if ( 0 == pinst->peer->dodge ) {
        pinst->peer->hp--;
        LOGX("发动攻击!造成掉血1点!\n");
    }
    else {
        LOGX("我勒个去!攻击被%s闪避了!\n", pinst->peer->name);
    }
    pinst->peer->dodge = 0;
}
void do_power(INSTANCE_T *pinst)
{
    LOGX("%s准备蓄力,", pinst->name);
    pinst->mp++;
    LOGX("MP:%d\n", pinst->mp);
}
void do_dodge(INSTANCE_T *pinst)
{
    LOGX("%s准备闪避,", pinst->name);
    pinst->dodge = 0;
    LOGX("下回合生效!\n");
}
void do_thump(INSTANCE_T *pinst)
{
    LOGX("%s准备大招,", pinst->name);
    if ( pinst->role == ROLE_YOU ) {
        if ( pinst->mp < 2 ) {
            LOGX("MP不足!\n");
        }
        else {
            if ( 0 == pinst->peer->dodge ) {
                pinst->peer->hp -= 2;
                LOGX("Avada Kedavra!!!!\n");
            }
            else {
                LOGX("我勒个去!大招你也躲避了!\n");
            }
            pinst->mp = 0;
        }
    }
    else {
        if ( pinst->mp < 3 ) {
            LOGX("巨龙在发呆...\n");
        }
        else {
            LOGX("发动火焰吐吸!无法闪避!\n");
            pinst->mp = 0;
            pinst->peer->hp -= 4;
        }
    }
    pinst->peer->dodge = 0;
}

最后,再做一个屏幕输出的显示。
void dsp_title(INSTANCE_T *pinst1, INSTANCE_T *pinst2)
{
    int ix = 0;
    printf("\033[2J");
    LOGGREEN("+----------------------------------------+");
    LOGGREEN("+----------------------------------------+\n");
    
    LOGGREEN("|     YOU HP: %2d: ", pinst1->hp);
    for ( ix = 1; ix <= HP_MAX; ix++ ) {
        if ( ix <= pinst1->hp ) {
            LOGGREEN("=");
        }
        else {
            LOGGREEN(" ");
        }
    }
    LOGGREEN("   |");
    LOGGREEN("| DRANGON HP: %2d: ", pinst2->hp);
    for ( ix = 1; ix <= HP_MAX; ix++ ) {
        if ( ix <= pinst2->hp ) {
            LOGGREEN("=");
        }
        else {
            LOGGREEN(" ");
        }
    }
    LOGGREEN("   |\n");
    LOGGREEN("|         MP: %2d: ", pinst1->mp);
    for ( ix = 1; ix <= MP_MAX; ix++ ) {
        if ( ix <= pinst1->mp ) {
            LOGGREEN("=");
        }
        else {
            LOGGREEN(" ");
        }
    }
    LOGGREEN("   |");
    LOGGREEN("|         MP: %2d: ", pinst2->mp);
    for ( ix = 1; ix <= MP_MAX; ix++ ) {
        if ( ix <= pinst2->mp ) {
            LOGGREEN("=");
        }
        else {
            LOGGREEN(" ");
        }
    }
    LOGGREEN("   |\n");
    LOGGREEN("+----------------------------------------+");
    LOGGREEN("+----------------------------------------+\n");
    LOGYELLOW("%s", msg);
    offset = 0;
    if ( pinst1->hp <= 0 ) {
        exit(0);
        LOGD("噢,你挂了!\n");
    }
    else if ( pinst2->hp <= 0 ) {
        exit(0);
        LOGD("恭喜勇士,你获得了胜利\n");
    }
}

四、总结
巨龙AI明显不太够,玩家太强了哈哈!好吧,这是个有趣的自娱自乐游戏!
大家新村快乐、鸡年吉祥!