C++生成十字绣图案(二) 面向对象

时间:2023-03-09 09:03:29
C++生成十字绣图案(二) 面向对象

基本的十字绣线性生成中提供了判断下一步可以画的位置并且逐步生成的函数。以这些基本函数为基础,可以进行更多变化的图案设计。

为了方便的扩展,可以把线性生成写成一个类,以后的修改继承这个类。

头文件BasicBoard.h

//基本的生成函数,有run和mutiRun两种运行方式。
//run会按照朝着四个方向延伸且不和其他已有图案碰撞的方式生成图像。生成到没有可以画的点就停止
//mutiRun则是在run的基础上,在可以找到新的起点的时候继续画图,直到没有起点 #include <iostream>
#include <set>
#include <list>
#include <ctime>
#include <cstdlib>
#include <string>
#include <windows.h> #define ROW 51 //行数
#define COL 51 //列数
#define seedX ROW/2 //初始行号
#define seedY COL/2 //初始列号
#define random(x) (rand()%x) //随机数 using namespace std; struct point
{
int x;
int y;
};
struct compare //set的排序函数
{
bool operator()(const point &p1,const point &p2)const
{
//return p1.x * COL + p1.y < p2.x * COL + p2.y;
return p1.x==p2.x ? p1.y<p2.y: p1.x<p2.x;
}
}; class BasicBoard
{
public:
void run();//运行并画图
void run(int x, int y); //带种子参数的run
void mutiRun();//运行一次之后找新的起点继续运行,直到没有起点
void init();
void print();
void print(set<point,compare> pl);
bool isNext(int x, int y, char dir);
void findAndErase(point p, set<point,compare> &nextSet);
virtual void setNextSet(point seed, set<point,compare> &nextSet);
set<point,compare>::iterator getNextIter(set<point,compare> &nextSet);
virtual void drawNext(set<point,compare> &nextSet); virtual void generate(point &seed);
virtual bool getSeed(point &seed); //获取可以开始的位置,该位置周围8个格子均为空
void printAs();//输出
protected:
int b[ROW][COL];
};

实现文件BasicBoard.cpp

#include "BasicBoard.h"
void BasicBoard::run()
{
init();
point seed;
seed.x = seedX;
seed.y = seedY;
generate(seed);
printAs();
}
void BasicBoard::run(int x, int y)
{
init();
point seed;
seed.x = x;
seed.y = y;
generate(seed);
printAs();
}
void BasicBoard::mutiRun()
{
init();
point seed;
while(getSeed(seed))
{
generate(seed);
}
printAs();
}
void BasicBoard::init() //初始化,全部置0
{
for(int i=0;i<ROW;i++)
{
for(int j=0;j<COL;j++)
{
b[i][j]=0;
}
}
} void BasicBoard::print() //打印画布01序列
{
for(int i=0;i<ROW;i++)
{
for(int j=0;j<COL;j++)
{
cout<<b[i][j];
}
cout<<endl;
}
}
void BasicBoard::printAs() //以方块形式打印图案
{
string b2[ROW][COL];
int count = 0;
for(int i=0; i<ROW; i++)
{
for(int j=0; j<COL; j++)
{
if(b[i][j])
{
b2[i][j]="■";
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0xF1);
/*输出颜色说明。导入windows.h,使用SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0x71)。参数中的16进制数字第一位表示背景颜色,第二位表示文字颜色,代码含义为
0 = 黑色 8 = 灰色
1 = 蓝色 9 = 淡蓝色
2 = 绿色 A = 淡绿色
3 = 湖蓝色 B = 淡浅绿
4 = 红色 C = 淡红色
5 = 紫色 D = 淡紫色
6 = 黄色 E = 淡黄色
7 = 白色 F = 亮白色
如果背景为“白色”,会显示cmd默认的颜色
*/ count++;
}
else
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),0xF9);
b2[i][j]="□";
}
cout<<b2[i][j];
} cout<<count<<endl;
} }
void BasicBoard::print(set<point,compare> pl) //测试函数,打印set中的值
{
set<point,compare>::iterator iter = pl.begin();
for(; iter!=pl.end(); iter++)
{
cout<<iter->x<<","<<iter->y<<" - ";
}
cout<<endl;
} bool BasicBoard::isNext(int x, int y, char dir) //判断某个位置是不是可以画下一笔 {
if(0<x && ROW-1>x && 0<y && COL-1>y)
{
int temp = 0;
switch(dir)
{
case 'U':
{ temp = b[x-1][y-1]+b[x-1][y]+b[x-1][y+1]+b[x][y-1]+b[x][y]+b[x][y+1]; break;
}
case 'D':
{
temp = b[x][y-1]+b[x][y]+b[x][y+1]+b[x+1][y-1]+b[x+1][y]+b[x+1][y+1];
break;
}
case 'L':
{
temp = b[x-1][y-1]+b[x-1][y]+b[x][y-1]+b[x][y]+b[x+1][y-1]+b[x+1][y];
break;
}
case 'R':
{
temp = b[x-1][y]+b[x-1][y+1]+b[x][y]+b[x][y+1]+b[x+1][y]+b[x+1][y+1];
break;
}
}
if(temp==0)
return true;
}
return false;
}
void BasicBoard::findAndErase(point p, set<point,compare> &nextSet) //新添加点之后,删除候选列表中不能继续画的点
{
set<point,compare>::iterator iterErase;
iterErase = nextSet.find(p);
if(iterErase != nextSet.end())
{
nextSet.erase(iterErase);
}
}
void BasicBoard::setNextSet(point seed, set<point,compare> &nextSet) //设置候选列表
{
int x = seed.x;//x为行,y为列
int y = seed.y; point p;
p.x = x-1;
p.y = y;
if(isNext(x-1,y,'U'))
{
nextSet.insert(p);
}
else
{
findAndErase(p,nextSet);
}
p.x = x+1;
p.y = y;
if(isNext(x+1,y,'D'))
{ nextSet.insert(p);
}
else
{
findAndErase(p,nextSet);
}
p.x = x;
p.y = y-1;
if(isNext(x,y-1,'L'))
{
nextSet.insert(p);
}
else
{
findAndErase(p,nextSet);
}
p.x = x;
p.y = y+1;
if(isNext(x,y+1,'R'))
{
nextSet.insert(p);
}
else
{
findAndErase(p,nextSet);
}
p.x = x-1;
p.y = y-1;
findAndErase(p,nextSet); //角上相邻的
p.x = x+1;
p.y = y-1;
findAndErase(p,nextSet);
p.x = x-1;
p.y = y+1;
findAndErase(p,nextSet);
p.x = x+1;
p.y = y+1;
findAndErase(p,nextSet); } //通过随机数获取下一步的位置。种子在main中生成
set<point,compare>::iterator BasicBoard::getNextIter(set<point,compare> &nextSet)
{
int count = nextSet.size();
set<point,compare>::iterator iterNext = nextSet.begin();
int pos = int(random(count)); for(int i = 0; i<pos; i++)
{
iterNext++;
}
return iterNext;
}
//画下一格:从候选里面选出一个;更改b的值;判断它四个正方向的候选,如果是候选加入,不是候选尝试查找删除;判断它四个斜方向,从候选列表删除。
void BasicBoard::drawNext(set<point,compare> &nextSet)
{ set<point,compare>::iterator iterNext;
iterNext = getNextIter(nextSet);
point next;
next.x = iterNext->x;
next.y = iterNext->y;
b[next.x][next.y]=1;
nextSet.erase(iterNext);
setNextSet(next, nextSet);
} void BasicBoard::generate(point &seed)
{
b[seed.x][seed.y]=1;
set<point,compare> nextSet; setNextSet(seed,nextSet);
while(!nextSet.empty())
{
drawNext(nextSet);
}
} //生成新的种子。方法是找到所有可以做种子的点然后随机选一个。
bool BasicBoard::getSeed(point &seed)
{ list<point> seedList;
int count = 0;
for(int x = 1; x<ROW-1; x++)
{
for(int y = 1; y<COL-1; y++)
{
if(b[x-1][y-1]+b[x-1][y]+b[x-1][y+1]+b[x][y-1]+b[x][y]+b[x][y+1]+b[x+1][y-1]+b[x+1][y]+b[x+1][y+1]==0)
{
seed.x = x;
seed.y = y;
seedList.push_back(seed);
count++;
}
}
}
if(count==0)
{ return false;}
list<point>::iterator iter = seedList.begin();
int pos = int(random(count)); for(int i = 0; i<pos; i++)
{
iter++;
}
seed.x = iter->x;
seed.y = iter->y;
return true;
}

main函数

#include "BasicBoard.h"

void main()
{
srand(unsigned(time(0)));
BasicBoard b;
b.run();
}