C++炸金花

· · 科技·工程

#include<windows.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<string>
#include<random>
#include<vector>
#include<queue>
#include<cmath>
#include<ctime>
#include<map>
#define intt long long
#define intu unsigned long long
#define dle double
#define dlel long double
using namespace std;
const int Imax=0x7fffffff;
const long long LLmax=0x7fffffffffffffff;
mt19937 Rand(time(0));
const string number[15] = {
    "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"
};
const string color[5] = {
    "黑桃", "红桃", "梅花", "方片"
};
struct Card {
    string color,number;
};
struct Cards {
    Card card[5];
};
struct Player {
    Cards _card_;
    int money;
    bool have_saw;//是否看过牌
    bool have_run;//是否逃跑
};
Player players[15];
vector<Card> cards;
int now_player,player_number;
int now_money;
int last_money;
int _choice;
int __;
void print() {//打印输出
    printf("%d 轮后开牌\n上家押的钱数:%d  本局总钱数:%d\n", player_number - __, last_money, now_money);
    for (int i = 1; i <= player_number; i++) {
        printf("玩家 %2d: 剩余钱数: %d  ", i, players[i].money);
        if (players[i].money <= 0) {
            puts("破产");
        } else if (players[i].have_run) {
            puts("逃跑");
        } else if (players[i].have_saw) {
            puts("看过牌");
        } else {
            puts("未看牌");
        }
    }
}
int operator < (Card _x, Card _y) {//两张牌比大小
    if (_x.number == _y.number) {//数字相同就比花色
        int _x_id = 0, _y_id = 0;
        while (color[_x_id] != _x.color) {
            _x_id++;
        }
        while (color[_y_id] != _y.color) {
            _y_id++;
        }
        return _x_id > _y_id;
    }
    //数字不相同就比数字
    int _x_id = 0, _y_id = 0;
    while (number[_x_id] != _x.number) {
        _x_id++;
    }
    while (number[_y_id] != _y.number) {
        _y_id++;
    }
    return _x_id < _y_id;
}
void init() {
    for (int i = 0; i < 4; i ++) {//初始化牌堆
        for (int j = 0; j < 13; j++) {
            cards.push_back((Card){color[i], number[j]});
        }
    }
    for (int i = 1; i <= player_number; i++) {
        for (int j = 1; j <= 3; j++) {
            int _size = cards.size();
            int choice = Rand() % _size;
            players[i]._card_.card[j] = cards[choice];
            cards.erase(cards.begin() + choice);
        }
        sort(players[i]._card_.card + 1, players[i]._card_.card + 4);//提前排好序
    }
}
string next_card(Card _card) {
    if(_card.number == "A") return "Nothing";
    int position = 0;
    while (number[position] != _card.number) {
        position ++;
    }
    return number[position + 1];
}
int check_baozi(Cards _card) {//检查是否为豹子
    return _card.card[1].number == _card.card[2].number && _card.card[2].number == _card.card[3].number;
}
int check_shunzi(Cards _card) {//检查是否为顺子
    return _card.card[2].number == next_card(_card.card[1]) && _card.card[3].number == next_card(_card.card[2]);
}
int check_tonghua(Cards _card) {//检查是否为同花
    return _card.card[1].color == _card.card[2].color && _card.card[2].color == _card.card[3].color;
}
int check_duizi(Cards _card) {//检查是否有对子
    return _card.card[1].number == _card.card[2].number || _card.card[2].number == _card.card[3].number;
}
int type(Cards _card) {//牌的类型
    if (check_baozi(_card)) {//豹子
        return 6;
    } else if (check_shunzi(_card) && check_tonghua(_card)) {//同花顺
        return 5;
    } else if (check_shunzi(_card)) {//顺子
        return 4;
    } else if (check_tonghua(_card)) {//同花
        return 3;
    } else if(check_duizi(_card)) { //对子
        return 2;
    } else {
        return 1;
    }
    return 0;

}
int operator < (Cards _x, Cards _y) {
    //235 比 AAA 大
    if (_x.card[1].number == "2" && _x.card[2].number == "3" && _x.card[3].number == "5") {
        if (_y.card[1].number == "A" && _y.card[2].number == "A" && _y.card[3].number == "A") {
            return 0;
        }
    }
    if (type(_x) != type(_y)) {//牌型不一样就直接判断大小
        return type(_x) < type(_y);
    } else if (type(_x) == 6) {//豹子比大小
        return _x.card[1] < _y.card[1];
    } else if (type(_x) == 5 || type(_x) == 4) {//同花顺(顺子)比大小
        return _x.card[3] < _y.card[3];
    } else if (type(_x) == 3) {//同花比大小
        for (int i = 3; i >= 1; i--) {//从大到小逐一比较
            if (_x.card[i].number != _y.card[i].number) {
                return _x.card[i] < _y.card[i];
            }
        }
        return _x.card[3] < _y.card[3];//数字一样就比花色
    } else if (type(_x) == 2) {//对子比大小
        Card _x_card, _y_card, _x_other, _y_other;//_x_card 和 _y_card 都取对子的较大者
        if (_x.card[1].number == _x.card[2].number) {
            _x_card.number = _x.card[2].number;
            _x_card.color = _x.card[2].color;
            _x_other.number = _x.card[3].number;
            _x_other.color = _x.card[3].color;
        } else {
            _x_card.number = _x.card[3].number;
            _x_card.color = _x.card[3].color;
            _x_other.number = _x.card[1].number;
            _x_other.color = _x.card[1].color;
        }
        if (_y.card[1].number == _y.card[2].number) {
            _y_card.number = _y.card[2].number;
            _y_card.color = _y.card[2].color;
            _y_other.number = _y.card[3].number;
            _y_other.color = _y.card[3].color;
        } else {
            _y_card.number = _y.card[3].number;
            _y_card.color = _y.card[3].color;
            _y_other.number = _y.card[1].number;
            _y_other.color = _y.card[1].color;
        }
        if (_x_card.number == _y_card.number) {//对子数字相同就比剩下的数字
            if (_x_other.number == _y_other.number) {//剩下的数字还一样就比对子的花色
                //由于两人各 2 张,共 4 张,必有黑桃,黑桃在哪家,哪家就大
                return _y_card.color == "黑桃";
            }
            //剩下的数字不一样就比剩下牌的数字
            return _x_other < _y_other;
        }
        //对子数字不同就必对子数字
        return _x_card < _y_card;
    } else {//散牌比大小
        //与同花相同
        for (int i = 3; i >= 1; i--) {//从大到小逐一比较
            if (_x.card[i].number != _y.card[i].number) {
                return _x.card[i] < _y.card[i];
            }
        }
        return _x.card[3] < _y.card[3];//数字一样就比花色
    }
    return 0;//防 Warning,不会执行到这里
}
int hashh(Cards _card) {//算牌力
    if (type(_card) == 1) {//散牌
        if (_card.card[3].number == "A" || _card.card[3].number == "K") {//有 K 或 A 可以高一点
            return 500;
        } else {//否则最好尽快跑路
            return 100;
        }
    } else if (type(_card) == 2) {//对子,常规牌
        if (_card.card[1].number == _card.card[2].number) {
            if((Card){"黑桃","8"} < _card.card[2]) {//比较大的对子
                return 3000;
            } else {//小对子
                return 1000;
            }
        }
    } else if (type(_card) == 3) {//同花,稀有牌
        return 8000;
    } else if (type(_card) == 4) {//顺子,超稀有
        return 20000;
    } else if (type(_card) == 5) {//同花顺,超级稀有
        return 60000;
    }
    return 100000;//豹子,终极稀有
}
bool check(int number) {//number% 的概率是否中了
    return Rand() % 100 <= number;
}
int random(int L, int R) {//在 [L,R] 中生成随机数
    return Rand() % (R - L + 1) + L;
}
void play(int id) {//编号为 id 的玩家进行游戏
    system("cls");
    print();
    if (id == 1) {//编号为 1 的玩家为真人玩家
        if (!players[id].have_saw) {//没看过牌可以选择看牌
            puts("您是否选择看牌?(请输入 0 或 1)");
            scanf("%d", &_choice);
            if (_choice == 1) {
                players[id].have_saw = 1;
            }
        }
        if (players[id].have_saw) {
            puts("\n您的牌是:");
            for (int i = 1; i <= 3; i++) {
                cout << players[id]._card_.card[i].color << players[id]._card_.card[i].number << " ";
            }
            putchar('\n');
        }
        puts("您是否选择逃跑?(请输入 0 或 1)");
        scanf("%d", &_choice);
        if (_choice == 1) {
            players[id].have_run = 1;
            now_player--;
            return;
        }
        int money_number;
        printf("\n请输入您要押的钱数(不得少于上家),上家押的钱数为:%d\n", last_money);
        scanf("%d", &money_number);
        while (money_number < last_money || players[id].money < money_number) {
            puts("输入有误,请重新输入");
            Sleep(2000);
            system("cls");
            print();
            if (!players[id].have_saw) {
                puts("您是否选择看牌?(请输入 0 或 1)");
                scanf("%d", &_choice);
                if (_choice == 1) {
                    players[id].have_saw = 1;
                }
            }
            if (players[id].have_saw) {
                puts("\n您的牌是:");
                for (int i = 1; i <= 3; i++) {
                    cout << players[id]._card_.card[i].color << players[id]._card_.card[i].number << " ";
                }
                putchar('\n');
            }
            puts("您是否选择逃跑?(请输入 0 或 1)");
            scanf("%d", &_choice);
            if (_choice == 1) {
                players[id].have_run = 1;
                now_player--;
                return;
            }
            printf("\n请输入您要押的钱数(不得少于上家),上家押的钱数为:%d\n", last_money);
            scanf("%d", &money_number);
        }
        players[id].money -= money_number;
        last_money = money_number;
        now_money += money_number;
    } else {//否则是人机
        Sleep(2000);
        if (players[id].money < last_money) {//钱不够直接跑
            printf("玩家 %d 逃跑\n", id);
            players[id].have_run = 1;
            now_player--;
            return;
        }
        if (!players[id].have_saw) {
            if (check(25)) {//有 25% 的概率看牌
                printf("玩家 %d 看牌\n", id);
                players[id].have_saw = 1;
                Sleep(2000);
            }
        }
        if (players[id].have_saw) {//看过牌可以根据牌力选择是否逃跑
            if (hashh(players[id]._card_) < now_money) {//牌力不够
                if (check(40)) {//40% 的概率逃跑
                    printf("玩家 %d 逃跑\n", id);
                    players[id].have_run = 1;
                    now_player--;
                    return;
                }
            }
        }
        if (check(3)) {//3% 的概率逃跑
            printf("玩家 %d 逃跑\n", id);
            players[id].have_run = 1;
            now_player--;
            return;
        }
        int money_number = last_money + random(0, 100);
        if (players[id].have_saw) {//看过牌可以根据牌力押钱
            if (hashh(players[id]._card_) > now_money * 5) {//超了 5 倍
                money_number = random(last_money, last_money + 2000);
            } else if (hashh(players[id]._card_) > now_money * 3) {//超了 3 倍
                money_number = random(last_money, last_money + 800);
            } else if (hashh(players[id]._card_) > now_money * 2) {//超了 2 倍
                money_number = random(last_money, last_money + 500);
            } else {
                money_number = random(last_money, last_money + 100);
            }
        }
        while (check(30)) {//30% 的概率加随机数
            money_number += random(0, 50);
        }
        while (money_number > players[id].money) {//钱不够
            money_number--;
        }
        printf("玩家 %d 押 %d 元\n", id, money_number);
        players[id].money -= money_number;
        last_money = money_number;
        now_money += money_number;
    }
}
void open_card() {//开牌
    system("cls");
    puts("清算时刻");
    Sleep(2000);
    int max_id = -1;
    for (int i = 1; i <= player_number; i++) {
        if (players[i].money <= 0) {
            printf("玩家 %d 破产\n", i);
        } else if (players[i].have_run) {
            printf("玩家 %d 逃跑\n", i);
        } else {
            Sleep(1000);
            printf("玩家 %d 的牌:", i);
            Sleep(2000);
            for (int j = 1; j <= 3; j++) {
                cout << players[i]._card_.card[j].color << players[i]._card_.card[j].number << " ";
            }
            if (max_id == -1) {
                max_id = i;
            } else {
                if (players[max_id]._card_ < players[i]._card_) {
                    max_id = i;
                }
            }
            putchar('\n');
        }
    }
    Sleep(1000);
    printf("玩家 %d 获胜\n", max_id);
    players[max_id].money += now_money;
    Sleep(4000);
}
void Main() {//程序核心实现
    puts("请输入人数(最少为 2 且最多为 10):");
    scanf("%d", &player_number);
    while (player_number < 2 || player_number > 10) {//输入有误
        system("cls");
        puts("输入有误,请重新输入游戏人数:");
        scanf("%d", &player_number);
    }
    for (int i = 1; i <= player_number; i++) {
        players[i].money = 10000;
    }
    while (1) {
        init();
        __ = last_money = now_money = 0;
        for (int i = 1; i <= player_number; i++) {
            players[i].have_saw = players[i].have_run = 0;
        }
        now_player = player_number;
        bool have_open_card = 0;
        while (__ < player_number) {
            for (int i = 1; i <= player_number; i++) {
                if (now_player == 1) {
                    open_card();
                    have_open_card = 1;
                    break;
                }
                if (players[i].have_run || !players[i].money) {
                    continue;
                } else {
                    play(i);
                }
                Sleep(3000);
            }
            if (have_open_card) {
                break;
            }
            __++;
        }
        if (!have_open_card) {
            open_card();
        }
    }
}
int main() {
    Main();
    return 0;
}