目录
一,规则
正确的一组牌是指,四个特征都不同的三张牌。
还有另外一个版本,如果三张牌完全相同也可以,这感觉像是不限牌数不限轮次的玩法,可能是看谁先玩到一个分数。
接下来我将实现无限版。
二,图片制作
首先利用PPT快速画出27张图
此处已经用opencv做过resize了
然后再用opencv生成其他图:
int main()
{
for (int k = 1; k <= 27; k++)
{
string s = to_string(k);
Mat img = imread("D:/set/img (" + s + ").png", 1);
Mat img2 = Mat(Size(img.cols, img.rows * 2), img.type());
for (int i = 0; i < img2.rows; i++)for (int j = 0; j < img.cols; j++)
{
img2.at<Vec3b>(i, j) = img.at<Vec3b>(i % img.rows, j);
}
s = "D:/set/" + to_string(k+100) + ".png";
imwrite(s, img2);
}
return 0;
}
同理得到三个元素的27张图,一共81张图
然后全部变成同尺寸的图
全都是宽400高660pixel的图片。
三,代码V1
利用81张图片做成小游戏。
每次如果无解就加3张牌,有解的话去掉这3张牌之后,如果少于12张就补3张。
完整代码:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<map>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/core/mat.hpp>
using namespace std;
using namespace cv;
#pragma comment(lib,"../x64/vc14/lib/opencv_world452.lib")
#pragma comment(lib,"../x64/vc14/lib/opencv_world452d.lib")
int row = 3;
int theRatio = 4;
int w = 400/ theRatio, h = 660/ theRatio, type = 16;
vector<int>v;
Mat imgs;
Mat allImg[81];
void draw(int k, int n)
{
int col = v.size() / row, r = k / col, c = k % col;
Mat img = allImg[n];
for (int i = 0; i < img.rows; i++)for (int j = 0; j < img.cols; j++)
{
imgs.at<Vec3b>(i + r * h, j + c * w) = img.at<Vec3b>(i, j);
}
}
void drawAll()//根据v来显示所有图片
{
int col = v.size() / row;
imgs = Mat(Size(w * col, h * row), type);
for (int i = 0; i < row * col; i++)draw(i, v[i]);
}
void Init()
{
for (int i = 0; i < 81; i++) {
allImg[i] = imread("D:/set/img (" + to_string(i+1) + ").png", 1);
resize(allImg[i], allImg[i], Size(w, h), 0, 0);
}
int col = v.size() / row;
drawAll();
}
void add3()
{
v.push_back(rand() % 81);
v.push_back(rand() % 81);
v.push_back(rand() % 81);
}
void Play()
{
imshow("img", imgs);
int a, b, c;
waitKey(0);
cout << "输入3张牌的序号(1-"<<v.size()<<"),0 代表无解\n";
cin >> a;
if (a <= 0 || a > v.size()) {
add3();
return Init();
}
cin >> b >> c;
if (b <= 0 || b > v.size())return Play();
if (c <= 0 || c > v.size())return Play();
a--, b--, c--;
vector<int>id = { a,b,c };
sort(id.begin(), id.end());
v.erase(v.begin() + id[2]);
v.erase(v.begin() + id[1]);
v.erase(v.begin() + id[0]);
if (v.size() < 12)add3();
drawAll();
}
int main()
{
srand((unsigned)time(NULL));
while(v.size() < 12)v.push_back(rand() % 81);
int col = v.size() / row;
imgs = Mat(Size(w * col, h * row), type);
Init();
while(true)Play();
return 0;
}
四,代码V2
作为电子版游戏,相对实体版的优势在于可以做校验,所以可以补充一下校验。
把发牌机制改成自动校验,无解时就自动发牌。
同时修复了bug,每次补牌之后都把牌打乱,因为新补的牌里面肯有一张是正确牌组的一员,不打乱的话新补的牌都在最后一行右边。
完整代码:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<map>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui.hpp>
#include<opencv2/core/mat.hpp>
using namespace std;
using namespace cv;
#pragma comment(lib,"../x64/vc14/lib/opencv_world452.lib")
#pragma comment(lib,"../x64/vc14/lib/opencv_world452d.lib")
int row = 3;
int theRatio = 4;
int w = 400 / theRatio, h = 660 / theRatio, type = 16;
vector<int>v;
Mat imgs;
Mat allImg[81];
void add3()
{
v.push_back(rand() % 81);
v.push_back(rand() % 81);
v.push_back(rand() % 81);
}
void draw(int k, int n)
{
int col = v.size() / row, r = k / col, c = k % col;
Mat img = allImg[n];
for (int i = 0; i < img.rows; i++)for (int j = 0; j < img.cols; j++)
{
imgs.at<Vec3b>(i + r * h, j + c * w) = img.at<Vec3b>(i, j);
}
}
bool check(int a, int b, int c) // 检查第a b c张牌, 范围是0-80
{
if (a == b && b == c)return true;//三张牌完全相同
// 检查3张牌的4个属性都不同
int s = 81;
while (s > 1) {
s /= 3;
if (a / s == b / s || b / s == c / s || a / s == c / s)return false;
a %= s, b %= s, c %= s;
}
return true;
}
bool check()
{
for (int i = 0; i < v.size(); i++)for (int j = i + 1; j < v.size(); j++)for (int k = j + 1; k < v.size(); k++) {
if (check(v[i], v[j], v[k]))return true;
}
return false;
}
void fresh()
{
while (!check())add3();
for (int i = 0; i < 50; i++)
{
int a = rand() % v.size(), b = rand() % v.size();
int tmp = v[a];
v[a] = v[b], v[b] = tmp;
}
int col = v.size() / row;
imgs = Mat(Size(w * col, h * row), type);
for (int i = 0; i < row * col; i++)draw(i, v[i]);
}
void Init()
{
for (int i = 0; i < 81; i++) {
allImg[i] = imread("D:/set/img (" + to_string(i + 1) + ").png", 1);
resize(allImg[i], allImg[i], Size(w, h), 0, 0);
}
int col = v.size() / row;
fresh();
}
void Play()
{
imshow("img", imgs);
int a, b, c;
waitKey(0);
cout << "输入3张牌的序号(1-" << v.size() << ")\n";
cin >> a >> b >> c;
a--, b--, c--;
vector<int>id = { a,b,c };
sort(id.begin(), id.end());
a = id[0], b = id[1], c = id[2];
if (a < 0 || a >= v.size())return;
if (b < 0 || b >= v.size())return;
if (c < 0 || c >= v.size())return;
if (a == b || b == c)return;
if (!check(v[a], v[b], v[c]))return;
v.erase(v.begin() + c);
v.erase(v.begin() + b);
v.erase(v.begin() + a);
fresh();
}
int main()
{
srand((unsigned)time(NULL));
while (v.size() < 12)v.push_back(rand() % 81);
int col = v.size() / row;
imgs = Mat(Size(w * col, h * row), type);
Init();
while (true)Play();
return 0;
}