基本的十字繡線性產生中提供了判斷下一步可以畫的位置並且逐步產生的函數。以這些基本函數為基礎,可以進行更多變化的圖案設計。
為了方便的擴充,可以把線性產生寫成一個類,以後的修改繼承這個類。
標頭檔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); //帶種子參數的runvoid 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();}