數獨小遊戲
阿新 • • 發佈:2018-06-24
背景 farm mod OS stock ttr tps 功能 不同
寫了個小遊戲,畫面非常簡陋,但基本的功能實現了
下面是學習WindowsAPI時參考的文章,雖說幾乎沒看懂。。。
[https://blog.csdn.net/farmwang/article/details/50603608]
[https://blog.csdn.net/celte/article/details/10243309]
[https://blog.csdn.net/m0_37801033/article/details/71540942]
單獨繪制數獨邊框時:(我對顏色搭配實在沒啥心得。。。還湊活吧)
單獨繪制數獨界面時:
main.cpp:
#include <iostream> #include "soduko.h" using namespace std; int main() { system("title 數獨"); system("mode con cols=80 lines=35"); soduko matrixone("sodukosamples"); matrixone.play(); return 0; }
soduko.h:
#ifndef SODUKO_H_INCLUDED #define SODUKO_H_INCLUDED #include <iostream> #include <windows.h> #include <cstring> #include <string> #include <fstream> #include <sstream> #include <conio.h> using namespace std; //程序中的數字如果可能造成歧義,盡可能用變量名代替 const int line_basement=12,col_basement=30,region_intverl=2,conorcolor=7,errcolor=4,norcolor=3; const int ONC=800,SBC=240; const int HIGH_BITSIZE=16,WEIGHT_BITSIZE=8; class soduko { public: soduko(string); ~soduko(); void play();//主體函數 void finderrws(int,int);//尋找錯誤,並為錯誤設置狀態 void relieverr();//當錯誤被修正時,解除錯誤狀態 bool finderr(int [9][9],int,int);//判斷是否存在錯誤,因為功能與性質的不同不能和finderrws函數合並,感覺有點別扭 void show(int,int,int);//在當前所在的位置顯示 void showsame(int,int,int);//當前不是空格時,顯示所有與當前數字相同的數字 void solvanswer(int [9][9]);//計算數獨答案 private: int sodukodata[9][9]; int statepara[9][9][4];//position x , position y , color , if can be changed // }; #endif // SODUKO_H_INCLUDED
soduko.cpp:
#include "soduko.h" //problem : cannot use "show_same" to relieve the block with SBC//has been overcome /***********************************外部函數區(WindowsAPI)***************************************/ HANDLE hout=GetStdHandle(STD_OUTPUT_HANDLE);//獲取當前窗口句柄(也就是獲取窗口狀態) COORD position; void hide()//隱藏光標 { CONSOLE_CURSOR_INFO cursor_info={1,0}; SetConsoleCursorInfo(hout, &cursor_info); } void SetCurPos(const int x, const int y)//設置光標位置 { position.X = x; position.Y = y; SetConsoleCursorPosition(hout, position); } void SetColor(int colorID)//設置文本顏色 { SetConsoleTextAttribute(hout, colorID); } void SetBackColor()//設置文本背景色 { SetConsoleTextAttribute(hout, //BACKGROUND_BLUE | BACKGROUND_INTENSITY| BACKGROUND_GREEN | BACKGROUND_RED ); } //下面兩個函數原諒我現學現賣,另外,它們沒有也不應該出現在程序的正常線程中,因為一些問題尚未解決 void music() { //播放音樂,需要在鏈接器中添加"winmm",支持wav格式,其他格式似乎不支持 //如果文件不在工程/項目目錄下,添加確切位置 //還有,播放音樂時不能進行其他操作,所以不能加入遊戲中(除非有暫停和繼續播放音樂的函數。。。) PlaySound("Baptism.wav",NULL,SND_SYNC); } //繪制數獨的邊框,但是只學得懵懵懂懂,單獨列出還行,作為遊戲的一部分就慘不忍睹 //另外,需要在鏈接器中添加"gdi32",因為調用了GDI圖形接口 //還有,我在編譯這個函數時(單獨的項目),發現總是畫不出來,還得碰運氣。。。 //作為經驗之談,編譯出現"undefined reference to ......"之類錯誤的,都是沒有在鏈接器中添加相應的鏈接 //最後,這個函數還沒有正式移入這個程序中,所以沒有優化邏輯和細節,造成數字較多,比較臃腫 void drawframe() { HPEN hPen;//定義畫筆 HBRUSH hBrush;//定義畫刷 HWND wnd=FindWindow(NULL,"數獨");//不知道獲得當前窗口設備句柄的函數,還好找到了這個,獲得窗口名為“數獨”的窗口的設備句柄 HDC dc=GetDC(wnd);//這個。。。真不懂,大概是獲取什麽東西 POINT ipion[]={{256,192}};//起始點,不怎麽懂 int posx[]={256,256,272,272,304,304,320,320,352,352,368,368, 240,384,384,240,240,384,384,240,240,384,384,240}; int posy[]={192,336,336,192,192,336,336,192,192,336,336,192, 208,208,224,224,256,256,272,272,304,304,320,320}; int ppx[]={288,288,336,336,240,384,384,246}; int ppy[]={192,336,336,192,240,240,288,288}; //繪制矩形 hPen = (HPEN)(GetStockObject(NULL_PEN)); hPen = CreatePen(PS_SOLID, 5, RGB(128, 128, 128)); SelectObject(dc, hPen); Rectangle(dc,237,189,388,340); DeleteObject(hPen);//釋放畫筆 //連線(細線)//之所以沒有用矩形來代替連線,是因為函數繪制的矩形實際上不是由線組成,而是一個面,所以多重矩形並不能組成網格 hPen = CreatePen(PS_SOLID, 3, RGB(128, 128, 128)); SelectObject(dc, hPen); MoveToEx(dc,ppx[0],ppy[0],ipion); for(int i=1;i<4;i++) LineTo(dc,ppx[i],ppy[i]); MoveToEx(dc,ppx[4],ppy[4],ipion); for(int i=5;i<8;i++) LineTo(dc,ppx[i],ppy[i]); DeleteObject(hPen); //連線(粗線) hPen = CreatePen(PS_DOT, 1, RGB(128, 128, 128)); SelectObject(dc, hPen); hBrush = (HBRUSH)(GetStockObject(BLACK_BRUSH)); SelectObject(dc,hBrush); MoveToEx(dc,posx[0],posy[0],ipion); for(int i=1;i<12;i++) LineTo(dc, posx[i], posy[i]); MoveToEx(dc,posx[12],posy[12],ipion); for(int i=13;i<24;i++) LineTo(dc, posx[i], posy[i]); DeleteObject(hPen); } /************************************************************************************/ soduko::soduko(string textdata) { //數獨的數據存儲在文件中 //格式為:文件中數據與數獨的顯示相似,數據為整型,用空格分開 //數獨未填寫空格用0表示,其余依舊為1~9 int a=textdata.size(); string judgeprinciple=textdata.substr(a-4,4); if(judgeprinciple!=".txt")textdata+=".txt"; ifstream input(textdata); if(!input) cout<<"Error! Cannot open the file!"<<endl; string s; for(int i=0;i<9;i++) { getline(input,s); istringstream scin(s); for(int j=0;j<9;j++) scin>>sodukodata[i][j]; } for(int i=0;i<9;i++) { for(int j=0;j<9;j++) { //設置狀態(位置,顏色,是否可變) statepara[i][j][0]=j*region_intverl+col_basement;//position x statepara[i][j][1]=i+line_basement;//position y if(sodukodata[i][j]==0) { statepara[i][j][2]=norcolor;//normal color = blue statepara[i][j][3]=1;//can be changed } else { statepara[i][j][2]=conorcolor;//normal color = white statepara[i][j][3]=0;//can not be changed } } } } soduko::~soduko(){}; void soduko::play() { //calculate answer//采取的計算方法一點也不高明,但勝在簡單(按照人的正常思路計算比較復雜) int answer[9][9]; for(int i=0;i<9;i++) for(int j=0;j<9;j++) answer[i][j]=sodukodata[i][j]; solvanswer(answer); //draw the begin view //drawframe(); //music(); for(int i=0;i<9;i++) for(int j=0;j<9;j++) show(i,j,ONC); //original position of choose show(0,0,SBC); showsame(0,0,SBC); SetCurPos(statepara[0][0][0],statepara[0][0][1]); hide(); //main int active_x=0,active_y=0; char numget; while((numget=getch())) { showsame(active_x,active_y,ONC); if(numget>48&&numget<58&&statepara[active_x][active_y][3]!=0) { sodukodata[active_x][active_y]=numget-48; show(active_x,active_y,SBC); } else if(numget==8&&statepara[active_x][active_y][3]!=0) { sodukodata[active_x][active_y]=0; show(active_x,active_y,SBC); } else { show(active_x,active_y,ONC); switch(numget) { case 72: if(active_x>0) active_x--; break;//up//明明是UP為什麽是x變化呢?這個問題交給讀者了 case 75: if(active_y>0) active_y--; break;//left case 80: if(active_x<8) active_x++; break;//down case 77: if(active_y<8) active_y++; break;//right default:break; } } hide(); showsame(active_x,active_y,SBC); relieverr(); finderrws(active_x,active_y); show(active_x,active_y,SBC); //relocate active position SetColor(statepara[active_x][active_y][2]); SetCurPos(statepara[active_x][active_y][0],statepara[active_x][active_y][1]); //judge win int win=1; for(int i=0;i<9;i++) { for(int j=0;j<9;j++) if(sodukodata[i][j]!=answer[i][j]) { win=0; break; } if(win==0)break; } if(win==1) { SetCurPos(col_basement,3); SetColor(conorcolor); cout<<"congratulation! You win the game!"<<endl; break; } } } void soduko::finderrws(int line,int ver) { //find out same number and show them int linp=line/3*3,verp=ver/3*3; for(int i=0;i<9;i++) { if(i!=ver&&sodukodata[line][i]!=0) if(sodukodata[line][ver]==sodukodata[line][i]) { show(line,ver,errcolor); show(line,i,errcolor); } if(i!=line&&sodukodata[i][ver]!=0) if(sodukodata[line][ver]==sodukodata[i][ver]) { show(line,ver,errcolor); show(i,ver,errcolor); } } for(int i=linp;i<linp+3;i++) for(int j=verp;j<verp+3;j++) if((i!=line||j!=ver)&&sodukodata[i][j]!=0) if(sodukodata[line][ver]==sodukodata[i][j]) { show(line,ver,errcolor); show(i,j,errcolor); } } bool soduko::finderr(int data[9][9],int line,int ver) { int linp=line/3*3,verp=ver/3*3; for(int i=0;i<9;i++) { if(i!=ver&&data[line][i]!=0) if(data[line][ver]==data[line][i]) return false; if(i!=line&&data[i][ver]!=0) if(data[line][ver]==data[i][ver]) return false; } for(int i=linp;i<linp+3;i++) for(int j=verp;j<verp+3;j++) if((i!=line||j!=ver)&&sodukodata[i][j]!=0) if(data[line][ver]==data[i][j]) return false; return true; } void soduko::relieverr() { for(int i=0;i<9;i++) for(int j=0;j<9;j++) if(statepara[i][j][2]==errcolor&&finderr(sodukodata,i,j)) { if(statepara[i][j][3]==1) show(i,j,norcolor); else show(i,j,conorcolor); } } void soduko::show(int xt,int yt,int color) { if(color==SBC) SetBackColor(); else { if(color!=ONC) statepara[xt][yt][2]=color; SetColor(statepara[xt][yt][2]); } SetCurPos(statepara[xt][yt][0],statepara[xt][yt][1]); if(sodukodata[xt][yt]!=0) cout<<sodukodata[xt][yt]<<" ";//說實話,不論加不加這個空格,都感覺有些別扭 else cout<<" ";//這是兩個空格 } void soduko::showsame(int x,int y,int order) { if(sodukodata[x][y]!=0) { for(int i=0;i<9;i++) for(int j=0;j<9;j++) if(sodukodata[i][j]==sodukodata[x][y]&&i!=x&&j!=y) { if(order!=SBC) order=statepara[i][j][2]; show(i,j,order); } } } //這個函數解數獨的方法是:建立指針數組,將所有空格的指針按序存入數組 //用指針數組按序試數並記錄當前所試的數,沒有發現錯誤時試下一個 //當所有數字填入都出現錯誤時,抹去當前數字的記錄,返回上一個,繼續從上一次記錄開始試數 //按這種方法一定能找到唯一解,只要數獨有解 void soduko::solvanswer(int soduko[9][9]) { int numl=0,actnuml=0; for(int i=0;i<9;i++) for(int j=0;j<9;j++) if(soduko[i][j]==0)numl++; int *emptyspace[numl]; int poslines[numl],posvert[numl]; for(int i=0;i<9;i++) for(int j=0;j<9;j++) if(soduko[i][j]==0) { poslines[actnuml]=i; posvert[actnuml]=j; emptyspace[actnuml++]=&soduko[i][j]; } actnuml=0; while(actnuml<numl) { int pl=0,drt=*emptyspace[actnuml]; for(int i=drt+1;i<=9;i++) { *emptyspace[actnuml]=i; if(finderr(soduko,poslines[actnuml],posvert[actnuml])) { pl=1; break; } } if(pl==1) actnuml++; else { *emptyspace[actnuml]=0; actnuml--; } } }
數獨小遊戲