程序实践:命令行之连连看
生活随笔
收集整理的這篇文章主要介紹了
程序实践:命令行之连连看
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
命令行之連連看
程序實踐周課題,VC++6.0上可編譯執行
游戲截圖:
#include <cstdio>#include <cstring> #include <iostream> #include <windows.h> #include <time.h> #include <algorithm> using namespace std; int dirx[4] = {1,-1,0,0}; int diry[4] = {0,0,1,-1}; //四個方向,DFS函數中要使用 bool vis[15][15]; //標記該點是否已經被訪問,DFS中使用 char map[15][15]; //二維字符數組表示連連看矩陣 bool Hash[105]; //hash數組用來標記,去重 int num, level; //num游戲記錄人數。 level游戲等級 char choose[100]; //提取對應操作的字符 struct Players //結構體存游戲者的帳號,得分,排名 {char name[50];int score;int rank; }; struct Data {int n;struct Players player[100]; }data[4];bool cmp(Players a, Players b) {return a.score < b.score; }void set_rank(int l) {int tmp;if (l == 4)tmp = 0;else if (l == 6)tmp = 1;else if (l == 8)tmp = 2;else if (l == 10)tmp = 3;for(int i = 0; i < data[tmp].n; i++){data[tmp].player[i].rank = i + 1;if(data[tmp].player[i].score == data[tmp].player[i + 1].score){data[tmp].player[i + 1].rank = data[tmp].player[i].rank;i++;}} }void menu() //菜單 {HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);printf("\n\n *********************************\n");SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);printf(" ***** 歡迎進入 連連看 *****\n");SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);printf(" ***** C - 選擇游戲等級 *****\n");printf(" ***** T - 有時間限定 *****\n");printf(" ***** N - 無時間限定 *****\n");printf(" ***** R - 玩家排名 *****\n");printf(" ***** E - 游戲結束 *****\n");printf(" *********************************\n\n");if(level == 0)printf(" ***** 游戲等級 : 未選 *****\n");else if(level == 4)printf(" ***** 游戲等級 : 低級 *****\n");else if(level == 6)printf(" ***** 游戲等級 : 中級 *****\n");else if(level == 8)printf(" ***** 游戲等級 : 高級 *****\n");else if(level == 10)printf(" ***** 游戲等級 : 特高 *****\n");printf("\n輸入操作 : ");scanf("%s", &choose);//printf("choose = %c\n", choose);//system("PAUSE");system("CLS"); //清屏函數//清屏后顯示菜單}void ChooseMenu() {int tmp;//設4個等級。通過選擇游戲難度初始化levelprintf("\n\n ********************************\n");printf(" ***** 選擇等級 *****\n");printf(" ***** 1 - 低級 *****\n"); // 4 * 4printf(" ***** 2 - 中級 *****\n"); // 6 * 6printf(" ***** 3 - 高級 *****\n"); // 8 * 8printf(" ***** 4 - 特高 *****\n"); // 10 * 10printf(" ********************************\n");printf(" \n游戲等級 : ");scanf("%d", &tmp);while(tmp != 1 && tmp != 2 && tmp != 3 && tmp != 4){printf(" 請選擇正確的游戲等級 1 , 2 , 3 , 4\n");printf(" \n游戲等級 : ");scanf("%d", &tmp);}if (tmp == 1)level = 4;else if (tmp == 2)level = 6;else if (tmp == 3)level = 8;else if (tmp == 4)level = 10;getchar(); }void init_map() //初始化游戲矩陣 {int i, j;char get[105]; //get數組用來得到隨機字符memset(Hash, false, sizeof(Hash)); //初始化hash數組srand((unsigned)time(NULL)); //設置隨機數種子//隨機生成一半的字符。由于要保證兩兩配對for(i = 0; i < (level * level) / 2; i++) {get[i] = 65 + rand() % 26; //隨機生成前一半get[i + (level * level) / 2] = get[i]; //將前一半的值賦給后一半}int index; //在get中隨機產生的數組下標bool flag; //標記是否找到一個新的字符srand((unsigned)time(NULL)); //設置隨機數種子for(i = 1; i <= level; i++){for(j = 1; j <= level; j++){flag = false; //flag每次先賦值為falsewhile(true) //死循環{index = 0 + rand() % (level * level); //隨機生成get數組中的下標if(!Hash[index]) // 假設該點沒有被使用{ map[i][j] = get[index]; //將它的值賦給mapHash[index] = true; //將它標記為已使用flag = true; //找到一個字符flag設為true}if(flag) //假設找到則退出for循環break;}}}//在連連看矩陣周圍加一圈空格,用來消除邊界元素for(i = 0; i <= level + 1; i++)map[0][i] = map[level + 1][i] = map[i][0] = map[i][level +1] = ' '; }void show_map() //顯示矩陣 {HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);printf("\n\n\n");int i, j;SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);printf(" ");for(i = 1; i <= level; i++)printf("%4d", i);SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN);printf(" 游戲選擇");printf("\n\n");for(i = 1; i <= level; i++){SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN);printf(" ");for(j = 1; j <= level; j++)printf("%4c", map[i][j]);SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_RED);printf("%4d", i);SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN);if (i == 1)printf(" T - 提示\n\n");else if (i == 2)printf(" R - 洗牌\n\n");else if (i == 3)printf(" C - 繼續\n\n");elseprintf("\n\n");}SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | FOREGROUND_GREEN); }bool IsWin() //推斷是否結束 {int i, j;for(i = 1; i <= level; i++)for(j = 1; j <= level; j++)if(map[i][j] != ' ') //假設矩陣中有一個不是空格則說明沒有結束return false;return true; }bool DFS(int x1, int y1, int x2, int y2, int turn, int dir) {//轉向次數大于2則返回false。這里大于3是由于dir初始為-1也就是第一次選方向時//就已經讓turn加1了,if(turn > 3)return false;//轉向兩次后不能沿某一方向到終點,返回falseif(turn == 3 && (x2 != x1 && y2 != y1))return false;//到達終點,返回trueif(x1 == x2 && y1 == y2)return true;for(int i = 0; i < 4; i++) //四個方向遍歷{int xx = x1 + dirx[i];int yy = y1 + diry[i];//若該點有字符且不是終點則換方向if(map[xx][yy] != ' ' && !(xx == x2 && yy == y2))continue;//推斷是否出界,是否已經訪問if(xx < 0 || yy < 0 || xx > level + 1 || yy > level + 1 || vis[xx][yy])continue; //將該點設為已訪問vis[xx][yy] = true;//若當前方向與之前方向不同,轉向次數+1,繼續搜索if(DFS(xx, yy, x2, y2, turn + (dir != i), i))return true;//若從該點的dfs不成功,將該點設為未訪問vis[xx][yy] = false;}return false; }bool judge(int x1, int y1, int x2, int y2) {memset(vis, false, sizeof(vis)); //初始化vis數組用于DFSvis[x1][y1] = true; //將起點標記為已訪問//特判幾種不能消除的情況if(x1 == x2 && y1 == y2){printf("\n 輸入的兩點坐標同樣,請保證兩點的坐標不同\n\n");return false;}if(map[x1][y1] == ' ' || map[x2][y2] == ' '){printf("\n 兩點之中有沒有圖案的點,請保證兩點都有圖案\n\n");return false;}if(map[x1][y1] != map[x2][y2]){printf("\n 兩點圖案不同。請保證兩點圖案同樣\n\n");return false;}if(DFS(x1, y1, x2, y2, 0, -1)){printf("\n 這兩點能夠消除\n\n");return true;}else{printf("這兩點不能消除。請重試\n\n");return false;} } //該函數在total_judge()中被調用。功能與judge相似 //不輸出中文提示 bool judge2(int x1, int y1, int x2, int y2) {memset(vis, false, sizeof(vis));vis[x1][y1] = true;if(x1 == x2 && y1 == y2)return false;if(map[x1][y1] == ' ' || map[x2][y2] == ' ')return false;if(map[x1][y1] != map[x2][y2])return false;if(DFS(x1, y1, x2, y2, 0, -1))return true;return false; }bool total_judge() //全盤判定,用于推斷是否還有可行解 {int i, j, ii, jj;bool vis2[15][15]; //標記該點是否被訪問memset(vis2, false, sizeof(vis2)); //初始化vis2int x1, y1, x2, y2; //記錄兩個點的坐標for(i = 1; i <= level; i++){for(j = 1; j <= level; j++){//假設該點不是空格,而且沒有被訪問if(map[i][j] != ' ' && !vis2[i][j]){vis2[i][j] = true; //將其設為已訪問//找到一個點A賦值x1 = i; y1 = j;//printf("x1 = %d y1 = %d\n", x1, y1);//枚舉點找到與A點字符同樣的一個點for(ii = 1; ii <= level; ii++){for(jj = 1; jj <= level; jj++){if(map[ii][jj] == map[x1][y1] && !vis2[ii][jj]){//假設找到一個點與A點不是同一點而且圖案同樣//將其標記為已訪問vis2[ii][jj] = true;//記為B點并賦值x2 = ii;y2 = jj;//printf("x2 = %d y2 = %d\n", x2, y2);//推斷A,B是否能被消除//找到一個可行解則說明游戲能夠繼續不用restartif(judge2(x1, y1, x2, y2))return true;}}}}}}//假設沒找到可行解。則須要restartreturn false; }bool Tip() //全盤判定,用于推斷是否還有可行解 {int i, j, ii, jj;bool vis2[15][15]; //標記該點是否被訪問memset(vis2, false, sizeof(vis2)); //初始化vis2int x1, y1, x2, y2; //記錄兩個點的坐標for(i = 1; i <= level; i++){for(j = 1; j <= level; j++){//假設該點不是空格,而且沒有被訪問if(map[i][j] != ' ' && !vis2[i][j]){vis2[i][j] = true; //將其設為已訪問//找到一個點A賦值x1 = i; y1 = j;//枚舉點找到與A點字符同樣的一個點for(ii = 1; ii <= level; ii++){for(jj = 1; jj <= level; jj++){if(map[ii][jj] == map[x1][y1] && !vis2[ii][jj]){//假設找到一個點與A點不是同一點而且圖案同樣//將其標記為已訪問vis2[ii][jj] = true;//記為B點并賦值x2 = ii;y2 = jj;//推斷A,B是否能被消除//找到一個可行解則說明游戲能夠繼續不用restartif(judge2(x1, y1, x2, y2)){//輸出可行解printf("\n 提示 :\n x1 = %d, y1 = %d\n x2 = %d, y2 = %d\n", x1, y1, x2, y2);return true;}}}}}}}return false; }void Restart() //洗牌函數 {int i, j;bool hash2[105], flag;char re[105];int cnt = 0, index2;memset(re, 0, sizeof(re));memset(hash2, false, sizeof(hash2));for(i = 1; i <= level; i++)for(j = 1; j <= level; j++)if(map[i][j] != ' ') re[cnt++] = map[i][j]; //提取實用字符srand((unsigned)time(NULL));for(i = 1; i <= level; i++){for(j = 1; j <= level; j++){if (map[i][j] != ' '){flag = false;while (true){index2 = 0 + rand() % cnt;if (!hash2[index2]){hash2[index2] = true;map[i][j] = re[index2];flag = true;}if (flag)break;}}}} }void Rank() {printf("\n\n");for (int i = 0; i < 4; i++){if (i == 0){printf(" 低級:\n");printf(" 排名 賬號 成績(秒)\n");for (int j = 0; j < data[i].n; j++)printf(" %d %s %d\n", data[i].player[j].rank, data[i].player[j].name, data[i].player[j].score / 1000);printf("\n");}if (i == 1){printf(" 中級:\n");printf(" 排名 賬號 成績(秒)\n");for (int j = 0; j < data[i].n; j++)printf(" %d %s %d\n", data[i].player[j].rank, data[i].player[j].name, data[i].player[j].score / 1000);printf("\n");}if (i == 2){printf(" 高級:\n");printf(" 排名 賬號 成績(秒)\n");for (int j = 0; j < data[i].n; j++)printf(" %d %s %d\n", data[i].player[j].rank, data[i].player[j].name, data[i].player[j].score / 1000);printf("\n");}if (i == 3){printf(" 特高:\n");printf(" 排名 賬號 成績(秒)\n");for (int j = 0; j < data[i].n; j++)printf(" %d %s %d\n", data[i].player[j].rank, data[i].player[j].name, data[i].player[j].score / 1000);printf("\n");}}system("PAUSE"); }int GameMenuChoose() {printf("\n 輸入操作 : ");char tmp;getchar();scanf("%c", &tmp);if (tmp == 'T'){Tip();return 1;}if (tmp == 'R'){system("CLS");Restart();show_map();return 1;}if (tmp == 'C')return 0;return 0; }void play() //游戲函數 {int x1, y1, x2, y2;while (GameMenuChoose());printf("\n 請輸入兩點坐標\n");printf("\n 一 : ");scanf("%d %d", &x1, &y1);printf("\n 二 : ");scanf("%d %d", &x2, &y2);if (judge(x1, y1, x2, y2)) //假設能夠消除,把兩點的值設為空格{map[x1][y1] = ' ';map[x2][y2] = ' ';} }void Start() {system("CLS");init_map(); //初始化游戲界面while (!IsWin()) //假設游戲沒有結束則一直play{while (!total_judge()) //若沒有可行解,則一直洗牌直到有可行解{Restart();show_map();}show_map();play();system("PAUSE");system("CLS");}system("CLS");printf("Good Job!\n");system("PAUSE");system("CLS"); }void ReadInMemory(Data *u) {FILE *fp;fp = fopen("data.txt", "rb");if (fp == NULL)return;fread(u, sizeof(struct Data), 1, fp);fclose(fp); }void WriteToFile(Data * u) {FILE *fp;fp = fopen("data.txt", "wb");if (fp == NULL)return;fwrite(u, sizeof(struct Data), 1, fp);fclose(fp); }void SetData(int l,int e, int s, char *a) {if (l == 4){data[0].n++;data[0].player[data[0].n].score = (int)e - s;strcpy(data[0].player[data[0].n].name, a);sort(data[0].player, data[0].player + data[0].n, cmp);}else if (l == 6){data[1].n++;data[1].player[data[1].n].score = (int)e - s;strcpy(data[1].player[data[1].n].name, a);sort(data[1].player, data[1].player + data[1].n, cmp);}else if (l == 8){data[2].n++;data[2].player[data[2].n].score = (int)e - s;strcpy(data[2].player[data[2].n].name, a);sort(data[2].player, data[2].player + data[2].n, cmp);}else if (l == 10){data[3].n++;data[3].player[data[3].n].score = (int)e - s;strcpy(data[3].player[data[3].n].name, a);sort(data[3].player, data[3].player + data[3].n, cmp);} }int main() {//system("title 連連看");level = 0; Loop:char tmp_name[20];ReadInMemory(data);menu();if(choose[0] == 'E')return 0;if(choose[0] == 'R'){Rank();system("CLS");goto Loop;}if(choose[0] == 'C'){system("CLS");ChooseMenu();system("PAUSE");system("CLS");goto Loop;}if (level == 0 && (choose[0] == 'N' || choose[0] == 'T')){while (choose[0] != 'C'){system("CLS");printf("\n\n 請先選擇游戲等級\n");ChooseMenu();system("PAUSE");if (level != 0){system("CLS");break;}}goto Loop;}if (choose[0] == 'N'){Start();goto Loop;}if (choose[0] == 'T'){printf("請輸入username\n");cin >> tmp_name;clock_t st = clock();Start();clock_t ed = clock();SetData(level, st, ed, tmp_name);set_rank(level);WriteToFile(data);goto Loop;}if(strlen(choose) != 1 || choose[0] != 'E' || choose[0] != 'R' || choose[0] != 'C' || choose[0] != 'N' || choose[0] != 'T'){printf("非法輸入,請看清菜單選項\n");system("PAUSE");system("CLS");goto Loop;}return 0; }
轉載于:https://www.cnblogs.com/jhcelue/p/6930223.html
總結
以上是生活随笔為你收集整理的程序实践:命令行之连连看的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: textview点击展开全部或收起,内容
- 下一篇: Nachos编译与使用--Nachos配