目录
〇,前言
因为是一边设计一边写代码一边写博客,所以本文的中间代码很多都不是最新版本,
代码以最终完整版为准。
一,游戏数据
1,公共宝石
初始数量:红白黑绿蓝各4个,黄色万能宝石5个
2,公共牌
绿色低分牌,黄色中分牌,蓝色高分牌
牌的位置分为供应堆、牌池各色4张
3,贵族牌
4,个人数据
(1)个人牌:个人已购牌堆、个人暂扣牌堆
(2)个人宝石:6色宝石
#include<iostream>
using namespace std;
typedef enum {
YELLOW,RED,WHITE,BLACK,GREEN,BLUE
}Color;
typedef struct {
int x; //待补充
}Card;
typedef struct {
int x; //待补充
}PointCard;
#define MaxTmpCard 3 //最大暂扣牌数,数值待确认
typedef struct {
int jew[6];
int card[5];
Card tmpCard[3];
}Player;
int turn;//0-1
int jew[6];//公共宝石
const int LC = 1, MC = 1, HC = 1;//数值待确认
Card Lcard[LC], Mcard[MC], Hcard[HC];
const int PC = 1;
PointCard Pcard[PC];
Player player[2];
int main()
{
return 0;
}
二,界面设计
void out()
{
cout << "先手: 黄 红 白 黑 绿 蓝 后手: 黄 红 白 黑 绿 蓝\n";
cout << "宝石: ";
for (int i = 0; i < 6; i++)cout << player[0].jew[i] << " ";
cout << " 宝石: ";
for (int i = 0; i < 6; i++)cout << player[1].jew[i] << " ";
cout << "\n已购牌: ";
for (int i = 0; i < 5; i++)cout << player[0].card[i] << " ";
cout << " 已购牌: ";
for (int i = 0; i < 5; i++)cout << player[1].card[i] << " ";
cout << "\n\n公共宝石:黄 红 白 黑 绿 蓝\n ";
for (int i = 0; i < 6; i++)cout << jew[i] << " ";
//公共牌
//贵族牌
}
运行:
三,输入接口
int getColor(char c)
{
if (c == 'R')return RED;
if (c == 'W')return WHITE;
if (c == 'B')return BLACK;
if (c == 'G')return GREEN;
if (c == 'U')return BLUE;
return 0;
}
bool play(int player)
{
out();
cout << "输入操作对应数字:1拿宝石,2拿牌,3扣牌,4买自己的已扣牌\n";
int op;
CIN(op);
if (op == 1) {
cout << "输入最多3个字母:RWBGU分别表示红白黑绿蓝,如RWB表示拿3个宝石,如GG表示拿2个绿宝石\n";
string s;
cin >> s;
s += " ";
int c1, c2, c3;
c1 = getColor(s[0]), c2 = getColor(s[1]), c3 = getColor(s[2]);
}
if (op == 2) {
cout << "输入目标牌所在的行(1-3)列(1-4)\n";
int r, c;
CIN2(r, c);
}
if (op == 3) {
cout << "输入目标牌所在的行(1-3)列(0-4)\n";
int r, c;
CIN2(r, c);
}
if (op == 4) {
cout << "输入目标牌的序号";
int id;
CIN(id);
}
return false;
}
四,总控程序
int main()
{
while (true) {
while (!play(turn));
turn = 1 - turn;
}
return 0;
}
PS:
这里没写游戏结束处理,先把游戏运行过程中的总控写了,先跑起来
五,游戏规则
1,洗牌
需要设置随机种子,不然每次洗牌结果都不变就不好玩了。
template<typename T>
void shuf(T a[], int len)//洗牌
{
srand(time(NULL));
for (int i = 0; i < len * len * 100; i++) {
int x = rand() % len, y = rand() % len;
exchange(a[x], a[y]);
}
}
void init()
{
shuf(Pcard, PC);
shuf(Lcard, LC);
shuf(Mcard, MC);
shuf(Hcard, HC);
}
2,拿宝石
(1)可以拿最多三种不同颜色的宝石,或者两个单色宝石
bool checkJew(int &c1, int &c2, int &c3)//拿宝石的参数校验
{
if (c1 == 0)return false;
if (c2 == 0) {
c3 = 0;
return jew[c1]>0;
}
if (c1 == c2) {
c3 = 0;
return jew[c1] >= 4;
}
if (c3 == c1 || c3 == c2)return false;
if (jew[c1] == 0 || jew[c2] == 0)return false;
if (c3 && jew[c3] == 0)return false;
return true;
}
(2)拿宝石
typedef struct {
int jew[6];
int sumJew;
int card[5];
Card tmpCard[3];
}Player;
void takeJew(int id, int c)
{
player[id].jew[c]++, player[id].sumJew++;
jew[c]--;
}
void takeJew(int id, int c1, int c2, int c3)
{
takeJew(id, c1);
takeJew(id, c2);
takeJew(id, c3);
}
(3)回退宝石
如果拿完之后,宝石数量超过10,那么需要退还宝石
void rebackJew(int id)//退还宝石
{
if (player[id].sumJew <= 10)return;
out();
cout << "宝石总数为" << player[id].sumJew << "个,需要退还" << player[id].sumJew-10 << "个\n";
cout << "请输入白蓝绿红黑各色宝石退还数量,如1 0 1 0 0表示退还1个白宝石和1个绿宝石\n";
int x[5];
for (int i = 0; i < 5; i++)CIN(x[i]);
for (int i = 0; i < 5; i++)if (player[id].jew[i + 1] < x[i] || x[i] < 0)return rebackJew(id);
for (int i = 0; i < 5; i++)player[id].jew[i + 1] -= x[i];
rebackJew(id);
}
(4)拿宝石完整处理
bool op1(int id)//操作1拿宝石
{
cout << "输入最多3个字母:WUGRB分别表示白蓝绿红黑,如RWB表示拿3个宝石,如GG表示拿2个绿宝石\n";
string s;
cin >> s;
s += " ";
int c1, c2, c3;
c1 = getColor(s[0]), c2 = getColor(s[1]), c3 = getColor(s[2]);
if (!checkJew(c1, c2, c3))return false;
takeJew(id, c1, c2, c3);
rebackJew(id);
return true;
}
3,界面
补全界面代码,确认随机函数正常工作。
template<typename T>
void out(T card)
{
int flag = 0;
for (int j = 0; j < 5; j++)if (card.cost[j]) {
cout << card.cost[j] << strColor[j + 1];
flag++;
}
if (flag)cout << " ";
for (int i = 0; i < 5 - flag; i++)cout << " ";
}
void out(Card card[], int num)
{
cout << "有 " << num << "张 ";
for (int i = 0; i < 4 && i < num; i++) {
cout << card[i].point << "分";
cout << strColor[card[i].color] << "色牌 ";
out(card[i]);
}
}
void out()
{
system("cls");
string s = turn ? "轮到后手操作" : "轮到先手操作";
cout << s << "\n先手: 黄 白 蓝 绿 红 黑 后手: 黄 白 蓝 绿 红 黑\n";
cout << "宝石: ";
for (int i = 0; i < 6; i++)cout << player[0].jew[i] << " ";
cout << " 宝石: ";
for (int i = 0; i < 6; i++)cout << player[1].jew[i] << " ";
cout << "\n已购牌: ";
for (int i = 0; i < 5; i++)cout << player[0].card[i] << " ";
cout << " 已购牌: ";
for (int i = 0; i < 5; i++)cout << player[1].card[i] << " ";
cout << "\n\n公共宝石:黄 白 蓝 绿 红 黑\n ";
for (int i = 0; i < 6; i++)cout << jew[i] << " ";
cout << "\n\n贵族牌(每张三分) ";
for (int i = 0; i < pointNum; i++) {
out(Pcard[i]);
}
cout << "\n\n发展卡: 列0 列1 列2 列3 列4\n";
cout << "高分牌";
out(Hcard, highNum);
cout << "\n中分牌";
out(Mcard, midNum);
cout << "\n低分牌";
out(Lcard, lowNum);
}
4,拿牌
在写拿牌的代码的时候,我意识到用3个数组分别存低分牌中分牌高分牌的话,代码不好写,还是用统一的数组来存比较简洁。
int cardNum[3] = { LC,MC,HC };//发展卡数量
Card* card[3] = { Lcard ,Mcard ,Hcard };
这样代码就好写了:
bool checkCard(int id, int r, int c)//拿牌参数校验
{
if (r < 0 || r>=3 || c < 0 || c>=4)return false;
if (c > cardNum[r])return false;
int s = 0;
for (int i = 0; i < 5; i++) {
s = max(s, s + card[r][c].cost[i] - player[id].card[i] - player[id].jew[i + 1]);
}
return s<= player[id].jew[0];
}
void takeCard(int id, int r, int c)//拿牌
{
for (int i = 0; i < 5; i++) {
player[id].jew[i + 1]-=card[r][c].cost[i] - player[id].card[i];
if (player[id].jew[i + 1] < 0)player[id].jew[0] += player[id].jew[i + 1], player[id].jew[i + 1] = 0;
}
player[id].point += card[r][c].point;
player[id].card[card[r][c].color]++;
}
void disCard(int r, int c)//发牌
{
exchange(card[r][c], card[r][--cardNum[r]]);
}
bool op2(int id)//操作2拿牌
{
cout << "输入目标牌所在的行(1-3)列(1-4)\n";
int r, c;
CIN2(r, c);
r = 3 - r, c--;
if (!checkCard(id, r, c))return false;
takeCard(id, r, c);
disCard(r, c);
return true;
}
5,扣牌
扣牌的规则是,如果扣暗置牌堆的牌,是不需要公示的。
如果有万能宝石那就拿1个,如果没有那就仅扣牌不拿宝石。
bool op3(int id)//操作3扣牌
{
cout << "输入目标牌所在的行(1-3)列(0-4)\n";
int r, c;
CIN2(r, c);
r = 3 - r, c = c ? c - 1 : 4;
if (r < 0 || r >= 3 || c < 0 || c > 4 || player[id].tmpNum >= 3)return false;
player[id].tmpCard[player[id].tmpNum++] = card[r][c];
if (jew[0])jew[0]--, player[id].jew[0]++, player[id].sumJew++;
disCard(r, c);
return true;
}
6,购买已扣牌
服用拿牌的接口即可
bool op5(int id)//操作5购买已扣牌
{
cout << "输入目标牌的序号: 1-3";
int x;
CIN(x);
x--;
if (x < 0 || x >= player[id].tmpNum)return false;
if (!checkCardCost(id, player[id].tmpCard[x]))return false;
takeCard(id, player[id].tmpCard[x]);
exchange(player[id].tmpCard[x], player[id].tmpCard[--player[id].tmpNum]);
return true;
}
至此,play函数变成:
typedef bool (*pfun)(int id);
bool play(int id)
{
out();
cout << "\n\n输入操作对应数字:1拿宝石,2拿牌,3扣牌,4查看已扣牌,5购买已扣牌\n";
int op;
CIN(op);
if (op < 1 || op>5)return false;
pfun p[] = { op1,op2,op3,op4,op5 };
return p[--op](id);
}
7,拿贵族牌
每个回合只能拿一张贵族牌
void op6(int id)//操作6拿贵族牌
{
int takeAble[] = { 0,0,0 };
for (int i = 0; i < pointNum; i++) {
takeAble[i] = 1;
for (int j = 0; j < 5; j++)if (player[id].card[j] < Pcard[i].cost[j])takeAble[i] = 0;
}
int s = takeAble[0] + takeAble[1] + takeAble[2];
if (!s)return;
cout << "请拿贵族牌:";
for (int i = 0; i < pointNum; i++) {
cout << i + 1;
if (!takeAble[i])cout << "不";
cout << "可拿 ";
}
int x;
CIN(x);
if (--x < 0 || x>=pointNum || takeAble[x]==0)return op6(id);
exchange(Pcard[x], Pcard[--pointNum]);
player[id].point += 3;
}
8,游戏结束
当一方玩家达到15分及以上,游戏结束,如果先手率先达到15分及以上,那么后手还有最后一次操作。
bool end()
{
if (turn)return false;
return player[0].point >= 15 || player[1].point >= 15;
}
int main()
{
init();
while (!end()) {
while (!play(turn));
turn = 1 - turn;
}
return 0;
}
9,胜负判断
得分高的胜,得分相同的话发展卡少的胜,发展卡也相同的话平局。
int gameRes()//0先手胜 1后手胜 2平局
{
if (player[0].point == player[1].point) {
int s = 0;
for (int i = 0; i < 5; i++)s += player[0].card[i] - player[1].card[i];
return s ? (s > 0 ? 0 : 1) : 2;
}
return player[0].point > player[1].point ? 0 : 1;
}
10,完整代码V1
#include<iostream>
#include<windows.h>
#include<time.h>
using namespace std;
typedef enum {
Y, W, U, G, R, B
}Color;
string strColor[6] = { "黄","白", "蓝", "绿", "红", "黑" };
typedef struct {
int point;
int color;
int cost[5];
}Card;//发展卡
typedef struct {
int cost[5];
}PointCard;//贵族得分牌
typedef struct {
int jew[6];//各色宝石数量,0-5六种颜色
int sumJew;//宝石总数
int card[5];//各色卡牌数量
int tmpNum;//暂扣牌数量
Card tmpCard[3];//暂扣牌,最多三张
int point;//得分
}Player; //玩家数据
const int PC = 10; //贵族得分牌
PointCard Pcard[PC] = {
3,3,3,0,0, 3,3,0,0,3, 3,0,0,3,3, 0,0,3,3,3, 0,3,3,3,0,
4,4,0,0,0, 4,0,0,0,4, 0,0,0,4,4, 0,0,4,4,0, 0,4,4,0,0
};
const int LC = 40, MC = 30, HC = 20; //低分牌,中分牌,高分牌
Card Lcard[LC] = {
1,W,0,0,4,0,0, 1,U,0,0,0,4,0, 1,G,0,0,0,0,4, 1,R,4,0,0,0,0, 1,B,0,4,0,0,0,
0,W,0,3,0,0,0, 0,U,0,0,0,0,3, 0,G,0,0,0,3,0, 0,R,3,0,0,0,0, 0,B,0,0,3,0,0,
0,W,0,0,0,2,1, 0,U,1,0,0,0,2, 0,G,2,1,0,0,0, 0,R,0,2,1,0,0, 0,B,0,0,2,1,0,
0,W,0,1,1,1,1, 0,U,1,0,1,1,1, 0,G,1,1,0,1,1, 0,R,1,1,1,0,1, 0,B,1,1,1,1,0,
0,W,0,2,0,0,2, 0,U,0,0,2,0,2, 0,G,0,2,0,2,0, 0,R,2,0,0,2,0, 0,B,2,0,2,0,0,
0,W,0,2,2,0,1, 0,U,1,0,2,2,0, 0,G,0,1,0,2,2, 0,R,2,0,1,0,2, 0,B,2,2,0,1,0,
0,W,0,1,2,1,1, 0,U,1,0,1,2,1, 0,G,1,1,0,1,2, 0,R,2,1,1,0,1, 0,B,1,2,1,1,0,
0,W,3,1,0,0,1, 0,U,0,1,3,1,0, 0,G,1,3,1,0,0, 0,R,3,1,0,0,1, 0,B,1,0,0,1,3
};
Card Mcard[MC] = {
3,W,6,0,0,0,0, 3,U,0,6,0,0,0, 3,G,0,0,6,0,0, 3,R,0,0,0,6,0, 3,B,0,0,0,0,6,
2,W,0,0,0,5,0, 2,U,0,5,0,0,0, 2,G,0,0,5,0,0, 2,R,0,0,0,0,5, 2,B,5,0,0,0,0,
2,W,0,0,0,5,3, 2,U,5,3,0,0,0, 2,G,0,5,3,0,0, 2,R,3,0,0,0,5, 2,B,0,0,5,3,0,
2,W,0,0,1,4,2, 2,U,2,0,0,1,4, 2,G,4,2,0,0,1, 2,R,1,4,2,0,0, 2,B,0,1,4,2,0,
1,W,0,0,3,2,2, 1,U,0,2,2,3,0, 1,G,2,3,0,0,2, 1,R,2,0,0,2,3, 1,B,3,2,2,0,0,
1,W,2,3,0,3,0, 1,U,0,2,3,0,3, 1,G,3,0,2,3,0, 1,R,0,3,0,2,3, 1,B,3,0,3,0,2
};
Card Hcard[HC] = {
5,W,3,0,0,0,7, 5,U,7,3,0,0,0, 5,G,0,7,3,0,0, 5,R,0,0,7,3,0, 5,B,0,0,0,7,3,
4,W,0,0,0,0,7, 4,U,7,0,0,0,0, 4,G,0,7,0,0,0, 4,R,0,0,7,0,0, 4,B,0,0,0,7,0,
4,W,3,0,0,3,6, 4,U,6,3,0,0,3, 4,G,3,6,3,0,0, 4,R,0,3,6,3,0, 4,B,0,0,3,6,3,
3,W,0,3,3,5,3, 3,U,3,0,3,3,5, 3,G,5,3,0,3,3, 3,R,3,5,3,0,3, 3,B,3,3,5,3,0
};
int turn;//0-1
int jew[6] = { 5,4,4,4,4,4 };//公共宝石
Player player[2];
int pointNum=3;//贵族得分牌数量
int cardNum[3] = { LC,MC,HC };//发展卡数量
Card* card[3] = { Lcard ,Mcard ,Hcard };
template<typename T>
void out(T card)
{
int flag = 0;
for (int j = 0; j < 5; j++)if (card.cost[j]) {
cout << card.cost[j] << strColor[j + 1];
flag++;
}
for (int i = 0; i < 5 - flag; i++)cout << " ";
}
void out(Card card[], int num)
{
cout << "有 " << num << "张 ";
for (int i = 0; i < 4 && i < num; i++) {
cout << card[i].point << "分";
cout << strColor[card[i].color] << "色牌 ";
out(card[i]);
}
}
void out()
{
system("cls");
string s = turn ? "轮到后手操作" : "轮到先手操作";
cout << s << "\n先手: 黄 白 蓝 绿 红 黑 后手: 黄 白 蓝 绿 红 黑\n";
cout << "宝石: ";
for (int i = 0; i < 6; i++)cout << player[0].jew[i] << " ";
cout << " 宝石: ";
for (int i = 0; i < 6; i++)cout << player[1].jew[i] << " ";
cout << "\n已购牌: ";
for (int i = 0; i < 5; i++)cout << player[0].card[i] << " ";
cout << " 已购牌: ";
for (int i = 0; i < 5; i++)cout << player[1].card[i] << " ";
cout << "\n得分: "<< player[0].point;
cout << " 得分: " << player[1].point;
cout << "\n\n公共宝石:黄 白 蓝 绿 红 黑\n ";
for (int i = 0; i < 6; i++)cout << jew[i] << " ";
cout << "\n\n贵族牌(每张三分) ";
for (int i = 0; i < pointNum; i++) {
out(Pcard[i]);
}
cout << "\n\n发展卡: 列0 列1 列2 列3 列4\n";
cout << "高分牌";
out(Hcard, cardNum[2]);
cout << "\n中分牌";
out(Mcard, cardNum[1]);
cout << "\n低分牌";
out(Lcard, cardNum[0]);
}
template<typename T>
void exchange(T& a, T& b)
{
T tmp = a;
a = b, b = tmp;
}
template<typename T>
void shuf(T a[], int len)//洗牌
{
srand(time(NULL));
for (int i = 0; i < len * len * 100; i++) {
int x = rand() % len, y = rand() % len;
exchange(a[x], a[y]);
}
}
void init()
{
turn = 0;
shuf(Pcard, PC);
shuf(Lcard, LC);
shuf(Mcard, MC);
shuf(Hcard, HC);
}
#define CIN(x) while (!(cin >> x)) { \
cin.clear(); \
cin.ignore(); \
}
#define CIN2(x, y) CIN(x)CIN(y)
#define CIN3(x, y, z) CIN(x)CIN(y)CIN(z)
int getColor(char c)
{
if (c == 'W')return W;
if (c == 'U')return U;
if (c == 'G')return G;
if (c == 'R')return R;
if (c == 'B')return B;
return 0;
}
bool checkJew(int &c1, int &c2, int &c3)//拿宝石的参数校验
{
if (c1 == 0)return false;
if (c2 == 0) {
c3 = 0;
return jew[c1]>0;
}
if (c1 == c2) {
c3 = 0;
return jew[c1] >= 4;
}
if (c3 == c1 || c3 == c2)return false;
if (jew[c1] == 0 || jew[c2] == 0)return false;
if (c3 && jew[c3] == 0)return false;
return true;
}
void takeJew(int id, int c)//拿1个宝石
{
if (c == 0)return;
player[id].jew[c]++, player[id].sumJew++;
jew[c]--;
}
void takeJew(int id, int c1, int c2, int c3)//拿宝石
{
takeJew(id, c1);
takeJew(id, c2);
takeJew(id, c3);
}
void rebackJew(int id)//退还宝石
{
if (player[id].sumJew <= 10)return;
out();
cout << "宝石总数为" << player[id].sumJew << "个,需要退还" << player[id].sumJew-10 << "个\n";
cout << "请输入白蓝绿红黑各色宝石退还数量,如1 0 1 0 0表示退还1个白宝石和1个绿宝石\n";
int x[5];
for (int i = 0; i < 5; i++)CIN(x[i]);
for (int i = 0; i < 5; i++)if (player[id].jew[i + 1] < x[i] || x[i] < 0)return rebackJew(id);
for (int i = 0; i < 5; i++)player[id].jew[i + 1] -= x[i];
rebackJew(id);
}
bool op1(int id)//操作1拿宝石
{
cout << "输入最多3个字母:WUGRB分别表示白蓝绿红黑,如RWB表示拿3个宝石,如GG表示拿2个绿宝石\n";
string s;
cin >> s;
s += " ";
int c1, c2, c3;
c1 = getColor(s[0]), c2 = getColor(s[1]), c3 = getColor(s[2]);
if (!checkJew(c1, c2, c3))return false;
takeJew(id, c1, c2, c3);
rebackJew(id);
return true;
}
bool checkCardCost(int id, Card a)//拿牌参数校验
{
int s = 0;
for (int i = 0; i < 5; i++) {
s = max(s, s + a.cost[i] - player[id].card[i] - player[id].jew[i + 1]);
}
return s <= player[id].jew[0];
}
bool checkCard(int id, int r, int c)//拿牌参数校验
{
if (r < 0 || r>=3 || c < 0 || c>=4)return false;
if (c > cardNum[r])return false;
return checkCardCost(id, card[r][c]);
}
void takeCard(int id, Card a)//拿牌
{
for (int i = 0; i < 5; i++) {
player[id].jew[i + 1] -= a.cost[i] - player[id].card[i], player[id].sumJew -= a.cost[i] - player[id].card[i];
if (player[id].jew[i + 1] < 0)player[id].jew[0] += player[id].jew[i + 1], player[id].jew[i + 1] = 0;
}
player[id].point += a.point;
player[id].card[a.color]++;
}
void takeCard(int id, int r, int c)//拿牌
{
takeCard(id, card[r][c]);
}
void disCard(int r, int c)//发牌
{
exchange(card[r][c], card[r][--cardNum[r]]);
}
bool op2(int id)//操作2拿牌
{
cout << "输入目标牌所在的行(1-3)列(1-4)\n";
int r, c;
CIN2(r, c);
r = 3 - r, c--;
if (!checkCard(id, r, c))return false;
takeCard(id, r, c);
disCard(r, c);
return true;
}
bool op3(int id)//操作3扣牌
{
cout << "输入目标牌所在的行(1-3)列(0-4)\n";
int r, c;
CIN2(r, c);
r = 3 - r, c = c ? c - 1 : 4;
if (r < 0 || r >= 3 || c < 0 || c > 4 || player[id].tmpNum >= 3)return false;
player[id].tmpCard[player[id].tmpNum++] = card[r][c];
if (jew[0])jew[0]--, player[id].jew[0]++, player[id].sumJew++;
disCard(r, c);
return true;
}
bool op4(int id)//操作4查看已扣牌
{
system("cls");
cout << "玩家准备查看已扣牌,其他玩家请回避\n";
Sleep(2000);
out(player[id].tmpCard, player[id].tmpNum);
Sleep(5000);
return false;
}
bool op5(int id)//操作5购买已扣牌
{
cout << "输入目标牌的序号: 1-3";
int x;
CIN(x);
x--;
if (x < 0 || x >= player[id].tmpNum)return false;
if (!checkCardCost(id, player[id].tmpCard[x]))return false;
takeCard(id, player[id].tmpCard[x]);
exchange(player[id].tmpCard[x], player[id].tmpCard[--player[id].tmpNum]);
return true;
}
void op6(int id)//操作6拿贵族牌
{
int takeAble[] = { 0,0,0 };
for (int i = 0; i < pointNum; i++) {
takeAble[i] = 1;
for (int j = 0; j < 5; j++)if (player[id].card[j] < Pcard[i].cost[j])takeAble[i] = 0;
}
int s = takeAble[0] + takeAble[1] + takeAble[2];
if (!s)return;
cout << "请拿贵族牌:";
for (int i = 0; i < pointNum; i++) {
cout << i + 1;
if (!takeAble[i])cout << "不";
cout << "可拿 ";
}
int x;
CIN(x);
if (--x < 0 || x>=pointNum || takeAble[x]==0)return op6(id);
exchange(Pcard[x], Pcard[--pointNum]);
player[id].point += 3;
}
typedef bool (*pfun)(int id);
bool play(int id)
{
out();
cout << "\n\n输入操作对应数字:1拿宝石,2拿牌,3扣牌,4查看已扣牌,5购买已扣牌\n";
int op;
CIN(op);
if (op < 1 || op>5)return false;
pfun p[] = { op1,op2,op3,op4,op5 };
if(!p[--op](id))return false;
op6(id);
return true;
}
bool end()
{
if (turn)return false;
return player[0].point >= 15 || player[1].point >= 15;
}
string strRes[3] = { "先手胜","后手胜","平局" };
int gameRes()
{
if (player[0].point == player[1].point) {
int s = 0;
for (int i = 0; i < 5; i++)s += player[0].card[i] - player[1].card[i];
return s ? (s > 0 ? 0 : 1) : 2;
}
return player[0].point > player[1].point ? 0 : 1;
}
int main()
{
init();
while (!end()) {
while (!play(turn));
turn = 1 - turn;
}
cout << strRes[gameRes()];
return 0;
}
六,悔棋功能
1,记录棋谱
把所有的输入全部用字符串记下来即可。
完整代码V1中只有2个地方有输入,一个是CIN宏,一个是op1函数中输入需要拿的宝石颜色。
vector<string>chessbook; //棋谱
string NS = "";
#define CIN(x) do{while (!(cin >> x)) { \
cin.clear(); \
cin.ignore(); \
};\
chessbook.push_back(NS+char(x+'0'));}while(0);
#define CIN2(x, y) CIN(x)CIN(y)
bool op1(int id)//操作1拿宝石
{
cout << "输入最多3个字母:WUGRB分别表示白蓝绿红黑,如RWB表示拿3个宝石,如GG表示拿2个绿宝石\n";
string s;
cin >> s;
s += " ";
int c1, c2, c3;
c1 = getColor(s[0]), c2 = getColor(s[1]), c3 = getColor(s[2]);
if (!checkJew(c1, c2, c3))return false;
takeJew(id, c1, c2, c3);
rebackJew(id);
chessbook.push_back(s);
return true;
}
2,查看棋谱
bool op0(int id)
{
for (int i = 0; i < chessbook.size(); i++)cout << chessbook[i] << endl;
Sleep(3000);
return false;
}
typedef bool (*pfun)(int id);
bool op1(int id)//操作1拿宝石
{
cout << "输入最多3个字母:WUGRB分别表示白蓝绿红黑,如RWB表示拿3个宝石,如GG表示拿2个绿宝石\n";
string s;
cin >> s;
s += " ";
chessbook.push_back(s);
int c1, c2, c3;
c1 = getColor(s[0]), c2 = getColor(s[1]), c3 = getColor(s[2]);
if (!checkJew(c1, c2, c3))return false;
takeJew(id, c1, c2, c3);
rebackJew(id);
return true;
}
3,悔棋操作
需要悔棋的时候,首先查看棋谱:
然后把棋谱copy下来:
1
GBU
1
WUB
1
WGB
1
UGR
2
3
1
3
3
0
1
URB
4
对于五子棋的棋谱,根据需要自己删减文本末尾,然后重新运行程序,直接全部粘贴进去即可。
然而对于璀璨宝石,我们发现结果变了!
原来,每次重新运行都会重新洗牌,所以需要保存开局时的牌的顺序。
这里有2个方案,一个是把洗牌之后的牌记下来,下次直接复原,但是这个就需要和棋谱分开存,因为这个信息不能公开给玩家,所以实现稍微复杂一点,
另外一个方法是控制随机种子,使得两次运行产生的随机数相同。
完整代码V1中,随机方案是用时间作为随机种子,这里,我改成开局输入种子:
unsigned int seed;//随机种子
int main()
{
cout << "输入任意正整数,用来随机洗牌";
cin >> seed;
init();
while (!end()) {
while (!play(turn));
turn = 1 - turn;
}
cout << strRes[gameRes()];
return 0;
}
在输出棋谱之前先输出种子:
bool op0(int id)
{
cout << seed << endl;
for (int i = 0; i < chessbook.size(); i++)cout << chessbook[i] << endl;
Sleep(3000);
return false;
}
这样,除了开局需要输入随机种子之外,其他操作就都是正常的基本操作了。
即查看棋谱,copy棋谱,happy删减,重新运行,全部粘贴,搞定。
4,完整代码V2
#include<iostream>
#include<windows.h>
#include<time.h>
#include<vector>
using namespace std;
typedef enum {
Y, W, U, G, R, B
}Color;
string strColor[6] = { "黄","白", "蓝", "绿", "红", "黑" };
typedef struct {
int point;
int color;
int cost[5];
}Card;//发展卡
typedef struct {
int cost[5];
}PointCard;//贵族得分牌
typedef struct {
int jew[6];//各色宝石数量,0-5六种颜色
int sumJew;//宝石总数
int card[5];//各色卡牌数量
int tmpNum;//暂扣牌数量
Card tmpCard[3];//暂扣牌,最多三张
int point;//得分
}Player; //玩家数据
const int PC = 10; //贵族得分牌
PointCard Pcard[PC] = {
3,3,3,0,0, 3,3,0,0,3, 3,0,0,3,3, 0,0,3,3,3, 0,3,3,3,0,
4,4,0,0,0, 4,0,0,0,4, 0,0,0,4,4, 0,0,4,4,0, 0,4,4,0,0
};
const int LC = 40, MC = 30, HC = 20; //低分牌,中分牌,高分牌
Card Lcard[LC] = {
1,W,0,0,4,0,0, 1,U,0,0,0,4,0, 1,G,0,0,0,0,4, 1,R,4,0,0,0,0, 1,B,0,4,0,0,0,
0,W,0,3,0,0,0, 0,U,0,0,0,0,3, 0,G,0,0,0,3,0, 0,R,3,0,0,0,0, 0,B,0,0,3,0,0,
0,W,0,0,0,2,1, 0,U,1,0,0,0,2, 0,G,2,1,0,0,0, 0,R,0,2,1,0,0, 0,B,0,0,2,1,0,
0,W,0,1,1,1,1, 0,U,1,0,1,1,1, 0,G,1,1,0,1,1, 0,R,1,1,1,0,1, 0,B,1,1,1,1,0,
0,W,0,2,0,0,2, 0,U,0,0,2,0,2, 0,G,0,2,0,2,0, 0,R,2,0,0,2,0, 0,B,2,0,2,0,0,
0,W,0,2,2,0,1, 0,U,1,0,2,2,0, 0,G,0,1,0,2,2, 0,R,2,0,1,0,2, 0,B,2,2,0,1,0,
0,W,0,1,2,1,1, 0,U,1,0,1,2,1, 0,G,1,1,0,1,2, 0,R,2,1,1,0,1, 0,B,1,2,1,1,0,
0,W,3,1,0,0,1, 0,U,0,1,3,1,0, 0,G,1,3,1,0,0, 0,R,3,1,0,0,1, 0,B,1,0,0,1,3
};
Card Mcard[MC] = {
3,W,6,0,0,0,0, 3,U,0,6,0,0,0, 3,G,0,0,6,0,0, 3,R,0,0,0,6,0, 3,B,0,0,0,0,6,
2,W,0,0,0,5,0, 2,U,0,5,0,0,0, 2,G,0,0,5,0,0, 2,R,0,0,0,0,5, 2,B,5,0,0,0,0,
2,W,0,0,0,5,3, 2,U,5,3,0,0,0, 2,G,0,5,3,0,0, 2,R,3,0,0,0,5, 2,B,0,0,5,3,0,
2,W,0,0,1,4,2, 2,U,2,0,0,1,4, 2,G,4,2,0,0,1, 2,R,1,4,2,0,0, 2,B,0,1,4,2,0,
1,W,0,0,3,2,2, 1,U,0,2,2,3,0, 1,G,2,3,0,0,2, 1,R,2,0,0,2,3, 1,B,3,2,2,0,0,
1,W,2,3,0,3,0, 1,U,0,2,3,0,3, 1,G,3,0,2,3,0, 1,R,0,3,0,2,3, 1,B,3,0,3,0,2
};
Card Hcard[HC] = {
5,W,3,0,0,0,7, 5,U,7,3,0,0,0, 5,G,0,7,3,0,0, 5,R,0,0,7,3,0, 5,B,0,0,0,7,3,
4,W,0,0,0,0,7, 4,U,7,0,0,0,0, 4,G,0,7,0,0,0, 4,R,0,0,7,0,0, 4,B,0,0,0,7,0,
4,W,3,0,0,3,6, 4,U,6,3,0,0,3, 4,G,3,6,3,0,0, 4,R,0,3,6,3,0, 4,B,0,0,3,6,3,
3,W,0,3,3,5,3, 3,U,3,0,3,3,5, 3,G,5,3,0,3,3, 3,R,3,5,3,0,3, 3,B,3,3,5,3,0
};
int turn;//0-1
int jew[6] = { 5,4,4,4,4,4 };//公共宝石
Player player[2];
int pointNum=3;//贵族得分牌数量
int cardNum[3] = { LC,MC,HC };//发展卡数量
Card* card[3] = { Lcard ,Mcard ,Hcard };
vector<string>chessbook; //棋谱
unsigned int seed;//随机种子
template<typename T>
void out(T card)
{
int flag = 0;
for (int j = 0; j < 5; j++)if (card.cost[j]) {
cout << card.cost[j] << strColor[j + 1];
flag++;
}
for (int i = 0; i < 5 - flag; i++)cout << " ";
}
void out(Card card[], int num)
{
cout << "有 " << num << "张 ";
for (int i = 0; i < 4 && i < num; i++) {
cout << card[i].point << "分";
cout << strColor[card[i].color] << "色牌 ";
out(card[i]);
}
}
void out()
{
system("cls");
string s = turn ? "轮到后手操作" : "轮到先手操作";
cout << s << "\n先手: 黄 白 蓝 绿 红 黑 后手: 黄 白 蓝 绿 红 黑\n";
cout << "宝石: ";
for (int i = 0; i < 6; i++)cout << player[0].jew[i] << " ";
cout << " 宝石: ";
for (int i = 0; i < 6; i++)cout << player[1].jew[i] << " ";
cout << "\n已购牌: ";
for (int i = 0; i < 5; i++)cout << player[0].card[i] << " ";
cout << " 已购牌: ";
for (int i = 0; i < 5; i++)cout << player[1].card[i] << " ";
cout << "\n得分: "<< player[0].point;
cout << " 得分: " << player[1].point;
cout << "\n\n公共宝石:黄 白 蓝 绿 红 黑\n ";
for (int i = 0; i < 6; i++)cout << jew[i] << " ";
cout << "\n\n贵族牌(每张三分) ";
for (int i = 0; i < pointNum; i++) {
out(Pcard[i]);
}
cout << "\n\n发展卡: 列0 列1 列2 列3 列4\n";
cout << "高分牌";
out(Hcard, cardNum[2]);
cout << "\n中分牌";
out(Mcard, cardNum[1]);
cout << "\n低分牌";
out(Lcard, cardNum[0]);
}
template<typename T>
void exchange(T& a, T& b)
{
T tmp = a;
a = b, b = tmp;
}
template<typename T>
void shuf(T a[], int len)//洗牌
{
for (int i = 0; i < len * len * 100; i++) {
int x = rand() % len, y = rand() % len;
exchange(a[x], a[y]);
}
}
void init()
{
turn = 0;
srand(seed);
shuf(Pcard, PC);
shuf(Lcard, LC);
shuf(Mcard, MC);
shuf(Hcard, HC);
}
string NS = "";
#define CIN(x) do{while (!(cin >> x)) { \
cin.clear(); \
cin.ignore(); \
};\
chessbook.push_back(NS+char(x+'0'));}while(0);
#define CIN2(x, y) CIN(x)CIN(y)
int getColor(char c)
{
if (c == 'W')return W;
if (c == 'U')return U;
if (c == 'G')return G;
if (c == 'R')return R;
if (c == 'B')return B;
return 0;
}
bool checkJew(int &c1, int &c2, int &c3)//拿宝石的参数校验
{
if (c1 == 0)return false;
if (c2 == 0) {
c3 = 0;
return jew[c1]>0;
}
if (c1 == c2) {
c3 = 0;
return jew[c1] >= 4;
}
if (c3 == c1 || c3 == c2)return false;
if (jew[c1] == 0 || jew[c2] == 0)return false;
if (c3 && jew[c3] == 0)return false;
return true;
}
void takeJew(int id, int c)//拿1个宝石
{
if (c == 0)return;
player[id].jew[c]++, player[id].sumJew++;
jew[c]--;
}
void takeJew(int id, int c1, int c2, int c3)//拿宝石
{
takeJew(id, c1);
takeJew(id, c2);
takeJew(id, c3);
}
void rebackJew(int id)//退还宝石
{
if (player[id].sumJew <= 10)return;
out();
cout << "宝石总数为" << player[id].sumJew << "个,需要退还" << player[id].sumJew-10 << "个\n";
cout << "请输入白蓝绿红黑各色宝石退还数量,如1 0 1 0 0表示退还1个白宝石和1个绿宝石\n";
int x[5];
for (int i = 0; i < 5; i++)CIN(x[i]);
for (int i = 0; i < 5; i++)if (player[id].jew[i + 1] < x[i] || x[i] < 0)return rebackJew(id);
for (int i = 0; i < 5; i++)player[id].jew[i + 1] -= x[i];
rebackJew(id);
}
bool op1(int id)//操作1拿宝石
{
cout << "输入最多3个字母:WUGRB分别表示白蓝绿红黑,如RWB表示拿3个宝石,如GG表示拿2个绿宝石\n";
string s;
cin >> s;
s += " ";
chessbook.push_back(s);
int c1, c2, c3;
c1 = getColor(s[0]), c2 = getColor(s[1]), c3 = getColor(s[2]);
if (!checkJew(c1, c2, c3))return false;
takeJew(id, c1, c2, c3);
rebackJew(id);
return true;
}
bool checkCardCost(int id, Card a)//拿牌参数校验
{
int s = 0;
for (int i = 0; i < 5; i++) {
s = max(s, s + a.cost[i] - player[id].card[i] - player[id].jew[i + 1]);
}
return s <= player[id].jew[0];
}
bool checkCard(int id, int r, int c)//拿牌参数校验
{
if (r < 0 || r>=3 || c < 0 || c>=4)return false;
if (c > cardNum[r])return false;
return checkCardCost(id, card[r][c]);
}
void takeCard(int id, Card a)//拿牌
{
for (int i = 0; i < 5; i++) {
player[id].jew[i + 1] -= a.cost[i] - player[id].card[i], player[id].sumJew -= a.cost[i] - player[id].card[i];
if (player[id].jew[i + 1] < 0)player[id].jew[0] += player[id].jew[i + 1], player[id].jew[i + 1] = 0;
}
player[id].point += a.point;
player[id].card[a.color]++;
}
void takeCard(int id, int r, int c)//拿牌
{
takeCard(id, card[r][c]);
}
void disCard(int r, int c)//发牌
{
exchange(card[r][c], card[r][--cardNum[r]]);
}
bool op2(int id)//操作2拿牌
{
cout << "输入目标牌所在的行(1-3)列(1-4)\n";
int r, c;
CIN2(r, c);
r = 3 - r, c--;
if (!checkCard(id, r, c))return false;
takeCard(id, r, c);
disCard(r, c);
return true;
}
bool op3(int id)//操作3扣牌
{
cout << "输入目标牌所在的行(1-3)列(0-4)\n";
int r, c;
CIN2(r, c);
r = 3 - r, c = c ? c - 1 : 4;
if (r < 0 || r >= 3 || c < 0 || c > 4 || player[id].tmpNum >= 3)return false;
player[id].tmpCard[player[id].tmpNum++] = card[r][c];
if (jew[0])jew[0]--, player[id].jew[0]++, player[id].sumJew++;
disCard(r, c);
return true;
}
bool op4(int id)//操作4查看已扣牌
{
system("cls");
cout << "玩家准备查看已扣牌,其他玩家请回避\n";
Sleep(2000);
out(player[id].tmpCard, player[id].tmpNum);
Sleep(5000);
return false;
}
bool op5(int id)//操作5购买已扣牌
{
cout << "输入目标牌的序号: 1-3";
int x;
CIN(x);
x--;
if (x < 0 || x >= player[id].tmpNum)return false;
if (!checkCardCost(id, player[id].tmpCard[x]))return false;
takeCard(id, player[id].tmpCard[x]);
exchange(player[id].tmpCard[x], player[id].tmpCard[--player[id].tmpNum]);
return true;
}
void op6(int id)//操作6拿贵族牌
{
int takeAble[] = { 0,0,0 };
for (int i = 0; i < pointNum; i++) {
takeAble[i] = 1;
for (int j = 0; j < 5; j++)if (player[id].card[j] < Pcard[i].cost[j])takeAble[i] = 0;
}
int s = takeAble[0] + takeAble[1] + takeAble[2];
if (!s)return;
cout << "请拿贵族牌:";
for (int i = 0; i < pointNum; i++) {
cout << i + 1;
if (!takeAble[i])cout << "不";
cout << "可拿 ";
}
int x;
CIN(x);
if (--x < 0 || x>=pointNum || takeAble[x]==0)return op6(id);
exchange(Pcard[x], Pcard[--pointNum]);
player[id].point += 3;
}
bool op0(int id)
{
cout << seed << endl;
for (int i = 0; i < chessbook.size(); i++)cout << chessbook[i] << endl;
Sleep(3000);
return false;
}
typedef bool (*pfun)(int id);
bool play(int id)
{
out();
cout << "\n\n输入操作对应数字:0查看棋谱,1拿宝石,2拿牌,3扣牌,4查看已扣牌,5购买已扣牌\n";
int op;
CIN(op);
if (op < 0 || op>5)return false;
pfun p[] = { op0,op1,op2,op3,op4,op5 };
if(!p[op](id))return false;
op6(id);
return true;
}
bool end()
{
if (turn)return false;
return player[0].point >= 15 || player[1].point >= 15;
}
string strRes[3] = { "先手胜","后手胜","平局" };
int gameRes()
{
if (player[0].point == player[1].point) {
int s = 0;
for (int i = 0; i < 5; i++)s += player[0].card[i] - player[1].card[i];
return s ? (s > 0 ? 0 : 1) : 2;
}
return player[0].point > player[1].point ? 0 : 1;
}
int main()
{
cout << "输入任意正整数,用来随机洗牌\n";
cin >> seed;
init();
while (!end()) {
while (!play(turn));
turn = 1 - turn;
}
cout << strRes[gameRes()];
return 0;
}
七,BUG修复、代码优化
1,新增可拿牌提示
bool checkCardCost(int id, Card a);//拿牌参数校验
void out(Card card[], int num)
{
cout << "有 " << num << "张 ";
for (int i = 0; i < 4 && i < num; i++) {
if (checkCardCost(turn, card[i]))cout << "√";
else cout << " ";
cout << card[i].point << "分";
cout << strColor[card[i].color] << "色牌 ";
out(card[i]);
}
}
2,新增显示宝石和牌的总数、显示扣牌数
void out()
{
system("cls");
string s = turn ? "轮到后手操作" : "轮到先手操作";
cout << s << "\n先手: 黄 白 蓝 绿 红 黑 后手: 黄 白 蓝 绿 红 黑\n";
cout << "宝石: ";
for (int i = 0; i < 6; i++)cout << player[0].jew[i] << " ";
cout << " 宝石: ";
for (int i = 0; i < 6; i++)cout << player[1].jew[i] << " ";
cout << "\n已购牌: ";
for (int i = 0; i < 5; i++)cout << player[0].card[i] << " ";
cout << " 已购牌: ";
for (int i = 0; i < 5; i++)cout << player[1].card[i] << " ";
cout << "\n总数: " << player[0].jew[0]<<" ";
for (int i = 0; i < 5; i++)cout << player[0].jew[i+1]+player[0].card[i] << " ";
cout << " 总数: " << player[1].jew[0] << " ";
for (int i = 0; i < 5; i++)cout << player[1].jew[i+1]+player[1].card[i] << " ";
cout << "\n得分: "<< player[0].point;
cout << " 得分: " << player[1].point;
cout << "\n已扣牌数: " << player[0].tmpNum;
cout << " 已扣牌数: " << player[1].tmpNum;
cout << "\n\n公共宝石:黄 白 蓝 绿 红 黑\n ";
for (int i = 0; i < 6; i++)cout << jew[i] << " ";
cout << "\n\n贵族牌(每张三分) ";
for (int i = 0; i < pointNum; i++) {
out(Pcard[i]);
}
cout << "\n\n发展卡: 列0 列1 列2 列3 列4\n";
cout << "高分牌";
out(Hcard, cardNum[2]);
cout << "\n中分牌";
out(Mcard, cardNum[1]);
cout << "\n低分牌";
out(Lcard, cardNum[0]);
}
3,新增大小写兼容
int getColor(char c)
{
if (c == 'W'||c=='w')return W;
if (c == 'U'||c=='u')return U;
if (c == 'G'||c=='g')return G;
if (c == 'R'||c=='r')return R;
if (c == 'B'||c=='b')return B;
return 0;
}
4,修复退还宝石BUG
void rebackJew(int id)//退还宝石
{
if (player[id].sumJew <= 10)return;
out();
cout << "宝石总数为" << player[id].sumJew << "个,需要退还" << player[id].sumJew-10 << "个\n";
cout << "请输入白蓝绿红黑各色宝石退还数量,如1 0 1 0 0表示退还1个白宝石和1个绿宝石\n";
int x[5];
for (int i = 0; i < 5; i++)CIN(x[i]);
for (int i = 0; i < 5; i++)if (player[id].jew[i + 1] < x[i] || x[i] < 0)return rebackJew(id);
for (int i = 0; i < 5; i++)player[id].jew[i + 1] -= x[i], player[id].sumJew-=x[i],jew[i + 1] += x[i];
rebackJew(id);
}
5,修复BUG——拿牌的时候宝石没有退还供应堆
void takeCard(int id, Card a)//拿牌
{
for (int i = 0; i < 5; i++) {
if (a.cost[i] <= player[id].card[i])continue;
int tc = a.cost[i] - player[id].card[i];
player[id].sumJew -= tc;
if (player[id].jew[i + 1] >= tc) {
player[id].jew[i + 1] -= tc, jew[i + 1] += tc;
} else {
player[id].jew[0] -= tc - player[id].jew[i + 1], jew[i+1] += tc - player[id].jew[i + 1];
jew[i + 1] += player[id].jew[i + 1], player[id].jew[i + 1] = 0;
}
}
player[id].point += a.point;
player[id].card[a.color-1]++;
}
6,修复BUG——扣牌之后没有校验宝石数
bool op3(int id)//操作3扣牌
{
cout << "输入目标牌所在的行(1-3)列(0-4)\n";
int r, c;
CIN2(r, c);
r = 3 - r, c = c ? c - 1 : 4;
if (r < 0 || r >= 3 || c < 0 || c > 4 || player[id].tmpNum >= 3)return false;
player[id].tmpCard[player[id].tmpNum++] = card[r][c];
if (jew[0])jew[0]--, player[id].jew[0]++, player[id].sumJew++;
rebackJew(id);
disCard(r, c);
return true;
}
7,完整代码V3
#include<iostream>
#include<windows.h>
#include<time.h>
#include<vector>
using namespace std;
typedef enum {
Y, W, U, G, R, B
}Color;
string strColor[6] = { "黄","白", "蓝", "绿", "红", "黑" };
typedef struct {
int point;
int color;
int cost[5];
}Card;//发展卡
typedef struct {
int cost[5];
}PointCard;//贵族得分牌
typedef struct {
int jew[6];//各色宝石数量,0-5六种颜色
int sumJew;//宝石总数
int card[5];//各色卡牌数量
int tmpNum;//暂扣牌数量
Card tmpCard[3];//暂扣牌,最多三张
int point;//得分
}Player; //玩家数据
const int PC = 10; //贵族得分牌
PointCard Pcard[PC] = {
3,3,3,0,0, 3,3,0,0,3, 3,0,0,3,3, 0,0,3,3,3, 0,3,3,3,0,
4,4,0,0,0, 4,0,0,0,4, 0,0,0,4,4, 0,0,4,4,0, 0,4,4,0,0
};
const int LC = 40, MC = 30, HC = 20; //低分牌,中分牌,高分牌
Card Lcard[LC] = {
1,W,0,0,4,0,0, 1,U,0,0,0,4,0, 1,G,0,0,0,0,4, 1,R,4,0,0,0,0, 1,B,0,4,0,0,0,
0,W,0,3,0,0,0, 0,U,0,0,0,0,3, 0,G,0,0,0,3,0, 0,R,3,0,0,0,0, 0,B,0,0,3,0,0,
0,W,0,0,0,2,1, 0,U,1,0,0,0,2, 0,G,2,1,0,0,0, 0,R,0,2,1,0,0, 0,B,0,0,2,1,0,
0,W,0,1,1,1,1, 0,U,1,0,1,1,1, 0,G,1,1,0,1,1, 0,R,1,1,1,0,1, 0,B,1,1,1,1,0,
0,W,0,2,0,0,2, 0,U,0,0,2,0,2, 0,G,0,2,0,2,0, 0,R,2,0,0,2,0, 0,B,2,0,2,0,0,
0,W,0,2,2,0,1, 0,U,1,0,2,2,0, 0,G,0,1,0,2,2, 0,R,2,0,1,0,2, 0,B,2,2,0,1,0,
0,W,0,1,2,1,1, 0,U,1,0,1,2,1, 0,G,1,1,0,1,2, 0,R,2,1,1,0,1, 0,B,1,2,1,1,0,
0,W,3,1,0,0,1, 0,U,0,1,3,1,0, 0,G,1,3,1,0,0, 0,R,3,1,0,0,1, 0,B,1,0,0,1,3
};
Card Mcard[MC] = {
3,W,6,0,0,0,0, 3,U,0,6,0,0,0, 3,G,0,0,6,0,0, 3,R,0,0,0,6,0, 3,B,0,0,0,0,6,
2,W,0,0,0,5,0, 2,U,0,5,0,0,0, 2,G,0,0,5,0,0, 2,R,0,0,0,0,5, 2,B,5,0,0,0,0,
2,W,0,0,0,5,3, 2,U,5,3,0,0,0, 2,G,0,5,3,0,0, 2,R,3,0,0,0,5, 2,B,0,0,5,3,0,
2,W,0,0,1,4,2, 2,U,2,0,0,1,4, 2,G,4,2,0,0,1, 2,R,1,4,2,0,0, 2,B,0,1,4,2,0,
1,W,0,0,3,2,2, 1,U,0,2,2,3,0, 1,G,2,3,0,0,2, 1,R,2,0,0,2,3, 1,B,3,2,2,0,0,
1,W,2,3,0,3,0, 1,U,0,2,3,0,3, 1,G,3,0,2,3,0, 1,R,0,3,0,2,3, 1,B,3,0,3,0,2
};
Card Hcard[HC] = {
5,W,3,0,0,0,7, 5,U,7,3,0,0,0, 5,G,0,7,3,0,0, 5,R,0,0,7,3,0, 5,B,0,0,0,7,3,
4,W,0,0,0,0,7, 4,U,7,0,0,0,0, 4,G,0,7,0,0,0, 4,R,0,0,7,0,0, 4,B,0,0,0,7,0,
4,W,3,0,0,3,6, 4,U,6,3,0,0,3, 4,G,3,6,3,0,0, 4,R,0,3,6,3,0, 4,B,0,0,3,6,3,
3,W,0,3,3,5,3, 3,U,3,0,3,3,5, 3,G,5,3,0,3,3, 3,R,3,5,3,0,3, 3,B,3,3,5,3,0
};
int turn;//0-1
int jew[6] = { 5,4,4,4,4,4 };//公共宝石
Player player[2];
int pointNum=3;//贵族得分牌数量
int cardNum[3] = { LC,MC,HC };//发展卡数量
Card* card[3] = { Lcard ,Mcard ,Hcard };
vector<string>chessbook; //棋谱
unsigned int seed;//随机种子
template<typename T>
void out(T card)
{
int flag = 0;
for (int j = 0; j < 5; j++)if (card.cost[j]) {
cout << card.cost[j] << strColor[j + 1];
flag++;
}
for (int i = 0; i < 5 - flag; i++)cout << " ";
}
bool checkCardCost(int id, Card a);//拿牌参数校验
void out(Card card[], int num)
{
cout << "有 " << num << "张 ";
for (int i = 0; i < 4 && i < num; i++) {
if (checkCardCost(turn, card[i]))cout << "√";
else cout << " ";
cout << card[i].point << "分";
cout << strColor[card[i].color] << "色牌 ";
out(card[i]);
}
}
void out()
{
system("cls");
string s = turn ? "轮到后手操作" : "轮到先手操作";
cout << s << "\n先手: 黄 白 蓝 绿 红 黑 后手: 黄 白 蓝 绿 红 黑\n";
cout << "宝石: ";
for (int i = 0; i < 6; i++)cout << player[0].jew[i] << " ";
cout << " 宝石: ";
for (int i = 0; i < 6; i++)cout << player[1].jew[i] << " ";
cout << "\n已购牌: ";
for (int i = 0; i < 5; i++)cout << player[0].card[i] << " ";
cout << " 已购牌: ";
for (int i = 0; i < 5; i++)cout << player[1].card[i] << " ";
cout << "\n总数: " << player[0].jew[0]<<" ";
for (int i = 0; i < 5; i++)cout << player[0].jew[i+1]+player[0].card[i] << " ";
cout << " 总数: " << player[1].jew[0] << " ";
for (int i = 0; i < 5; i++)cout << player[1].jew[i+1]+player[1].card[i] << " ";
cout << "\n得分: "<< player[0].point;
cout << " 得分: " << player[1].point;
cout << "\n已扣牌数: " << player[0].tmpNum;
cout << " 已扣牌数: " << player[1].tmpNum;
cout << "\n\n公共宝石:黄 白 蓝 绿 红 黑\n ";
for (int i = 0; i < 6; i++)cout << jew[i] << " ";
cout << "\n\n贵族牌(每张三分) ";
for (int i = 0; i < pointNum; i++) {
out(Pcard[i]);
}
cout << "\n\n发展卡: 列0 列1 列2 列3 列4\n";
cout << "高分牌";
out(Hcard, cardNum[2]);
cout << "\n中分牌";
out(Mcard, cardNum[1]);
cout << "\n低分牌";
out(Lcard, cardNum[0]);
}
template<typename T>
void exchange(T& a, T& b)
{
T tmp = a;
a = b, b = tmp;
}
template<typename T>
void shuf(T a[], int len)//洗牌
{
for (int i = 0; i < len * len * 100; i++) {
int x = rand() % len, y = rand() % len;
exchange(a[x], a[y]);
}
}
void init()
{
turn = 0;
srand(seed);
shuf(Pcard, PC);
shuf(Lcard, LC);
shuf(Mcard, MC);
shuf(Hcard, HC);
}
string NS = "";
#define CIN(x) do{while (!(cin >> x)) { \
cin.clear(); \
cin.ignore(); \
};\
chessbook.push_back(NS+char(x+'0'));}while(0);
#define CIN2(x, y) CIN(x)CIN(y)
int getColor(char c)
{
if (c == 'W'||c=='w')return W;
if (c == 'U'||c=='u')return U;
if (c == 'G'||c=='g')return G;
if (c == 'R'||c=='r')return R;
if (c == 'B'||c=='b')return B;
return 0;
}
bool checkJew(int &c1, int &c2, int &c3)//拿宝石的参数校验
{
if (c1 == 0)return false;
if (c2 == 0) {
c3 = 0;
return jew[c1]>0;
}
if (c1 == c2) {
c3 = 0;
return jew[c1] >= 4;
}
if (c3 == c1 || c3 == c2)return false;
if (jew[c1] == 0 || jew[c2] == 0)return false;
if (c3 && jew[c3] == 0)return false;
return true;
}
void takeJew(int id, int c)//拿1个宝石
{
if (c == 0)return;
player[id].jew[c]++, player[id].sumJew++;
jew[c]--;
}
void takeJew(int id, int c1, int c2, int c3)//拿宝石
{
takeJew(id, c1);
takeJew(id, c2);
takeJew(id, c3);
}
void rebackJew(int id)//退还宝石
{
if (player[id].sumJew <= 10)return;
out();
cout << "宝石总数为" << player[id].sumJew << "个,需要退还" << player[id].sumJew-10 << "个\n";
cout << "请输入白蓝绿红黑各色宝石退还数量,如1 0 1 0 0表示退还1个白宝石和1个绿宝石\n";
int x[5];
for (int i = 0; i < 5; i++)CIN(x[i]);
for (int i = 0; i < 5; i++)if (player[id].jew[i + 1] < x[i] || x[i] < 0)return rebackJew(id);
for (int i = 0; i < 5; i++)player[id].jew[i + 1] -= x[i], player[id].sumJew-=x[i],jew[i + 1] += x[i];
rebackJew(id);
}
bool op1(int id)//操作1拿宝石
{
cout << "输入最多3个字母:WUGRB分别表示白蓝绿红黑,如RWB表示拿3个宝石,如GG表示拿2个绿宝石\n";
string s;
cin >> s;
s += " ";
chessbook.push_back(s);
int c1, c2, c3;
c1 = getColor(s[0]), c2 = getColor(s[1]), c3 = getColor(s[2]);
if (!checkJew(c1, c2, c3))return false;
takeJew(id, c1, c2, c3);
rebackJew(id);
return true;
}
bool checkCardCost(int id, Card a)//拿牌参数校验
{
int s = 0;
for (int i = 0; i < 5; i++) {
s = max(s, s + a.cost[i] - player[id].card[i] - player[id].jew[i + 1]);
}
return s <= player[id].jew[0];
}
bool checkCard(int id, int r, int c)//拿牌参数校验
{
if (r < 0 || r>=3 || c < 0 || c>=4)return false;
if (c > cardNum[r])return false;
return checkCardCost(id, card[r][c]);
}
void takeCard(int id, Card a)//拿牌
{
for (int i = 0; i < 5; i++) {
if (a.cost[i] <= player[id].card[i])continue;
int tc = a.cost[i] - player[id].card[i];
player[id].sumJew -= tc;
if (player[id].jew[i + 1] >= tc) {
player[id].jew[i + 1] -= tc, jew[i + 1] += tc;
} else {
player[id].jew[0] -= tc - player[id].jew[i + 1], jew[i+1] += tc - player[id].jew[i + 1];
jew[i + 1] += player[id].jew[i + 1], player[id].jew[i + 1] = 0;
}
}
player[id].point += a.point;
player[id].card[a.color-1]++;
}
void takeCard(int id, int r, int c)//拿牌
{
takeCard(id, card[r][c]);
}
void disCard(int r, int c)//发牌
{
exchange(card[r][c], card[r][--cardNum[r]]);
}
bool op2(int id)//操作2拿牌
{
cout << "输入目标牌所在的行(1-3)列(1-4)\n";
int r, c;
CIN2(r, c);
r = 3 - r, c--;
if (!checkCard(id, r, c))return false;
takeCard(id, r, c);
disCard(r, c);
return true;
}
bool op3(int id)//操作3扣牌
{
cout << "输入目标牌所在的行(1-3)列(0-4)\n";
int r, c;
CIN2(r, c);
r = 3 - r, c = c ? c - 1 : 4;
if (r < 0 || r >= 3 || c < 0 || c > 4 || player[id].tmpNum >= 3)return false;
player[id].tmpCard[player[id].tmpNum++] = card[r][c];
if (jew[0])jew[0]--, player[id].jew[0]++, player[id].sumJew++;
rebackJew(id);
disCard(r, c);
return true;
}
bool op4(int id)//操作4查看已扣牌
{
system("cls");
cout << "玩家准备查看已扣牌,其他玩家请回避\n";
Sleep(2000);
out(player[id].tmpCard, player[id].tmpNum);
Sleep(5000);
return false;
}
bool op5(int id)//操作5购买已扣牌
{
cout << "输入目标牌的序号: 1-3";
int x;
CIN(x);
x--;
if (x < 0 || x >= player[id].tmpNum)return false;
if (!checkCardCost(id, player[id].tmpCard[x]))return false;
takeCard(id, player[id].tmpCard[x]);
exchange(player[id].tmpCard[x], player[id].tmpCard[--player[id].tmpNum]);
return true;
}
void op6(int id)//操作6拿贵族牌
{
int takeAble[] = { 0,0,0 };
for (int i = 0; i < pointNum; i++) {
takeAble[i] = 1;
for (int j = 0; j < 5; j++)if (player[id].card[j] < Pcard[i].cost[j])takeAble[i] = 0;
}
int s = takeAble[0] + takeAble[1] + takeAble[2];
if (!s)return;
cout << "请拿贵族牌:";
for (int i = 0; i < pointNum; i++) {
cout << i + 1;
if (!takeAble[i])cout << "不";
cout << "可拿 ";
}
int x;
CIN(x);
if (--x < 0 || x>=pointNum || takeAble[x]==0)return op6(id);
exchange(Pcard[x], Pcard[--pointNum]);
player[id].point += 3;
}
bool op0(int id)
{
cout << seed << endl;
for (int i = 0; i < chessbook.size(); i++)cout << chessbook[i] << endl;
Sleep(3000);
return false;
}
typedef bool (*pfun)(int id);
bool play(int id)
{
out();
cout << "\n\n输入操作对应数字:0查看棋谱,1拿宝石,2拿牌,3扣牌,4查看已扣牌,5购买已扣牌\n";
int op;
CIN(op);
if (op < 0 || op>5)return false;
pfun p[] = { op0,op1,op2,op3,op4,op5 };
if(!p[op](id))return false;
op6(id);
return true;
}
bool end()
{
out();
cout << endl;
if (turn)return false;
return player[0].point >= 15 || player[1].point >= 15;
}
string strRes[3] = { "先手胜","后手胜","平局" };
int gameRes()
{
if (player[0].point == player[1].point) {
int s = 0;
for (int i = 0; i < 5; i++)s += player[0].card[i] - player[1].card[i];
return s ? (s > 0 ? 0 : 1) : 2;
}
return player[0].point > player[1].point ? 0 : 1;
}
int main()
{
cout << "输入任意正整数,用来随机洗牌\n";
cin >> seed;
init();
while (!end()) {
while (!play(turn));
turn = 1 - turn;
}
cout << strRes[gameRes()];
return 0;
}
实战棋谱:
9
1
ugb
1
urb
1
wug
1
urb
1
wub
1
wbr
1
wgr
2 3 3
2 3 3
1
ubg
1
wub
2 3 3
2 3 3
1
ubr
2 3 1
2 3 3
1
urw
1
bug
2 3 1
1
ubw
1
ubw
1
ubr
2 3 1
1
bwu
2 3 3
2 3 2
1
ubr
1
wub
2 3 1
2 3 1
2 3 1
2 3 1
1
uwb
1
uwb
1
ubw
2 2 4
2 2 2
1
wbu
1
wug
2 3 2
1
wub
2 2 4
2 2 3
2 3 2
2 2 3
1
wur
2 3 2
3
1
wgu
2 2 3
2 3 4
1
ruw
1
ugr
2 2 4
2 2 4
2 1 3
2 2 3
2 2 4
后手胜
严格对比代码逻辑和璀璨宝石的规则,有几点区别:
(1)支付宝石时,默认支付普通宝石,普通宝石不够时才支付万能宝石。
实际规则是,随时都可以支付万能宝石而不支付普通宝石,
理论上有可能存在一些场景,支付万能宝石而不支付普通宝石是有好处的,因为支付了普通宝石的话,轮到对方对方可能刚好需要它就把它拿走了。
我只能说有可能存在,是不是真的存在不确定,毕竟最优策略这种事本就是超级复杂的事情。
(2)退宝石的时候只让玩家退普通宝石,没提供退万能宝石的选项
这个设定的理由和可能存在的场景同上
(3)扣牌时,默认只要有黄色万能宝石就直接取一个。
实际规则是,即使有万能宝石,也可以选择只扣牌而不拿万能宝石。
不过,因为拿万能宝石的时候可以回退普通宝石,拿普通宝石的时候也可以回退万能宝石,所以问题还是归结为退宝石的操作,
对于宝石少于10个的情况,拿一个万能宝石一定不会比不拿要差。