C++模拟电脑过五关
起因
一日见家人无聊排扑克过五关以消磨时间,便萌生这样的想法:打扑克过五关确实不失为消磨时间的一个好方法,但要自己动手就很麻烦,而且感觉这个游戏只是这么玩,确实是很智障,何不自己动手写个代码模拟呢?又能练练自己的编程能力。于是便有了这篇文章
实现工具
C++ STL 控制台程序
代码实现需要考虑的一些问题
我们把整个过程进行抽象概括,首先是洗牌,然后是不停的发牌,看看是否可以收牌,如果自己手上的牌发完这一局便失败了。下面是细节阐述:
(1)发牌这个过程显然可以用一个队列去存储,发牌便是出队的过程,收牌便是入队的过程。源代码中为:queue<unsigned int>deal_cards
(2)在计算的过程中,实际上我们将11,12,13(J,Q,K)视为10来计算,也就是说数值大小可能与其面值不同,这里我们借助一个映射map来处理:
map<unsigned int, unsigned int>value;
·
·
·
for (unsigned int i = 1; i <= 10; i++) {
value[i] = i;
}
value[11] = value[12] = value[13] = 10;
(3)五关的存储:这里的存储结构不能选择 queue 而应该是 deque 原因很直观,我们有时从队头收牌,有时从队尾收牌,有时同时从队头队尾收牌。源代码中选择用 vector<deque>card_group 进行存储。这里有一个难点,我们首先得初始化这个向量,使其大小为5,在后续的操作中,切记vector[ ]中[ ]只能是访问,不能进行修改!!要修改我们只能借助迭代器 vector<deque>::iterator iter 进行后续修改
(4)前两轮不会收牌,我们可以直接先进行前两轮,无需任何判断
(5)第三轮起,开始判断是否需要收牌。这一组的牌数为0时,直接跳到下一组;牌数为1或2时,直接发一张牌。牌数大于2时,这时候就要小心了。要两个需要注意的地方:一是前面说到的不同的收牌方式,共三种:第一张+最后一张+发的牌;第一张+第二张+发的牌;最后一张+倒数第二张+发的牌;二是要是我们进行计算后,发现确实能收牌,我们将牌收完之后,就直接到下一组了吗?不不不,或许我们还能再收一次牌,发一张牌,收6张牌的情况并不少见吧?这才是整个模拟过程中最有意思的一部分。这里我的解决方案是引进一个逻辑变量 repeat_inspect 来指示我们是否需要进行重复检查。具体用法见源代码。
源代码
#include<iostream>
#include<functional>
#include<time.h>
#include<vector>
#include<map>
#include<queue>
#include<algorithm>
#include<Windows.h>
#include<deque>
#include<iterator>
using namespace std;
queue<unsigned int>deal_cards;
vector<deque<unsigned int>>card_group;
map<unsigned int, unsigned int>value;
void gotoxy(short x, short y)
{
HANDLE hCONSOLE = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coordScreen = { x,y };
SetConsoleCursorPosition(hCONSOLE, coordScreen);
}
void display()
{
system("cls");
for (int i = 0; i < 5; i++) {
for (int j = 0; j < card_group[i].size(); j++) {
gotoxy(2 + i * 5, (j + 1) * 2);
cout << card_group[i].at(j);
}
}
}
void initialization()
{
for (unsigned int i = 1; i <= 10; i++) {
value[i] = i;
}
value[11] = value[12] = value[13] = 10;
vector<unsigned int>temp;
for (unsigned int i = 1; i <= 13; i++)
{
for (int j = 1; j <= 4; j++) {
temp.push_back(i);
}
}
srand((unsigned int)time(0));
random_shuffle(temp.begin(), temp.end());
for (int i = 0; i < temp.size(); i++) {
deal_cards.push(temp[i]);
}
//deal_cards.pop();
}
void run()
{
vector<deque<unsigned int>>::iterator iter;
for (int i = 0; i < 5; i++) {
deque<unsigned int>temp;
temp.push_back(deal_cards.front());
deal_cards.pop();
card_group.push_back(temp);
}
display();
Sleep(1000);
for (iter = card_group.begin(); iter != card_group.end(); iter++) {
(*iter).push_back(deal_cards.front());
deal_cards.pop();
}
display();
Sleep(1000);
int group = 0;
unsigned int card;
bool repeat_inspect=false;
while (!deal_cards.empty()) {
iter = card_group.begin();
iter += group;
switch ((*iter).size()) {
case 0:
repeat_inspect = false;
group = (group + 1) % 5;
break;
case 1:
if (!repeat_inspect) {
(*iter).push_back(deal_cards.front());
deal_cards.pop();
display();
Sleep(50);
}
else {
repeat_inspect = false;
}
group = (group + 1) % 5;
break;
case 2:
if (repeat_inspect) {
repeat_inspect = false;
}
else {
card = deal_cards.front();
deal_cards.pop();
if ((value[card] + value[(*iter).front()] + value[(*iter).back()]) % 10 == 0) {
deal_cards.push((*iter).front());
(*iter).pop_front();
deal_cards.push((*iter).front());
(*iter).pop_front();
deal_cards.push(card);
}
else
{
(*iter).push_back(card);
}
display();
Sleep(50);
}
group = (group + 1) % 5;
break;
default:
if (repeat_inspect) {
if ((value[(*iter).front()] + value[(*iter).at(1)] + value[(*iter).back()]) % 10 == 0) {
deal_cards.push((*iter).front());
(*iter).pop_front();
deal_cards.push((*iter).front());
(*iter).pop_front();
deal_cards.push((*iter).back());
(*iter).pop_back();
}
else if ((value[(*iter).front()] + value[(*iter).at((*iter).size()-2)] + value[(*iter).back()]) % 10 == 0) {
deal_cards.push((*iter).front());
(*iter).pop_front();
deal_cards.push((*iter).back());
(*iter).pop_back();
deal_cards.push((*iter).back());
(*iter).pop_back();
}
else {
repeat_inspect = false;
group = (group + 1) % 5;
}
}
else {
card = deal_cards.front();
deal_cards.pop();
if ((value[card] + value[(*iter).front()] + value[(*iter).back()]) % 10 == 0) {
repeat_inspect = true;
deal_cards.push((*iter).front());
(*iter).pop_front();
deal_cards.push((*iter).back());
(*iter).pop_back();
deal_cards.push(card);
}
else if ((value[card] + value[(*iter).front()] + value[(*iter).at(1)]) % 10 == 0) {
repeat_inspect = true;
deal_cards.push((*iter).front());
(*iter).pop_front();
deal_cards.push((*iter).front());
(*iter).pop_front();
deal_cards.push(card);
}
else if ((value[card] + value[(*iter).back()] + value[(*iter).at((*iter).size() - 2)]) % 10 == 0) {
repeat_inspect = true;
deal_cards.push((*iter).back());
(*iter).pop_back();
deal_cards.push((*iter).back());
(*iter).pop_back();
deal_cards.push(card);
}
else {
(*iter).push_back(card);
group = (group + 1) % 5;
display();
Sleep(50);
}
}
break;
}
}
gotoxy(100, 60);
}
int main()
{
initialization();
run();
}
代码不足之处
由于技术水平,我无法完美解决一种情况:发一次牌后发现有两种不同的收牌方式。源代码中我是按一定顺序判断收牌的,所有会存在优先级。如果真的要模拟人的那种收牌的随机性,存储上将是个很大的考验。当然了,这对你们这些大佬来说,应该也不会是难事吧[doge]