9*9數獨遊戲C++開發

前言

  這一段時間學了不少東西,想找個項目歷練一下,就去牛客上翻了翻,看到這個我小時候經常玩的遊戲,就想開發一下試試。因爲第一次做項目,不知道如何做,就去牛客此項目下的評論區看了下別人的作品,發現算法有錯,不能正常玩,決定自己開發一個能玩的遊戲。

遊戲介紹

  數獨是源自18世紀瑞士的一種數學遊戲。是一種運用紙、筆進行演算的邏輯遊戲。玩家需要根據9×9盤面上的已知數字,推理出所有剩餘空格的數字,並滿足以下規則:

  1. 每一行的9個空格不重複的填放1~9的數字
  2. 每一列的9個空格不重複的填放1~9的數字
  3. 每一個粗線宮內的9個空格不重複的填放1~9的數字
    在這裏插入圖片描述

  數獨盤面是個九宮,每一宮又分爲九個小格。在這八十一格中給出一定的已知數字和解題條件,利用邏輯和推理,在其他的空格上填入1~9的數字。使1~9每個數字在每一行、每一列和每一宮中都只出現一次,所以又稱“九宮格”。

設計思路

  爲了確保遊戲能夠正確的玩,即生成有效的地圖。我將遊戲的製作分成了兩部分,遊戲算法設計和文字界面設計。遊戲算法設計是爲了保證能生成有效地圖,確保玩家玩的遊戲有解。文字界面設計是爲了讓此遊戲更美觀,讓玩家玩起了更舒適。

算法實現

  爲了確保生成有效地圖,我將地圖的9個宮進行標記。在這裏插入圖片描述
  按以下的算法生成有效的地圖:

  1. 首先生成9*9的全排列,存儲起來。存儲方式採用char **initable;
  2. 生成一個在0~initable.size()-1之間的隨機數,排放在’1’位置。
  3. 根據’1’位置,找出符合的’2’位置的數量,將下標放入vector query;
  4. 生成一個在0~query.size()-1之間的隨機數,在initable中查找並放入’2’位置,清空query;
  5. 根據’1’、'2’位置找出符合’3’位置的個數,將下標放入query;
  6. 生成一個在0~query.size()-1之間的隨機數,在initable中查找並放入‘3’位置,清空query;
  7. 同理找出’4’、'7’位置
  8. 根據’2’與’4’的位置找出符合’5’位置的個數,放入query;
  9. 生成一個在0~query.size()-1之間的隨機數,在initable中查找並放入’5’位置,清空query;
  10. 根據’3’、‘4’、'5’確定’6’的位置的個數,放入vectorquery1;如果query1爲空,返回第9步。否則執行第11步
  11. 根據’2’、‘5’、'7’確定’8’的位置的個數,放入vectorquery2;如果query2爲空,返回第9步。否則執行第12步
  12. 對query1與query2進行嵌套循環,採用dfs查詢在’9’的位置是否存在符合遊戲規則的答案,如果沒有符合規則的地圖返回第2步。

文字界面

  因爲第一次做項目,對於文字界面完全是個小白,所以在開始項目的第一天我先學習了Linux的ncurses庫。筆記鏈接:Linux下curses函數庫的詳細介紹
  利用ncurses庫設計了遊戲界面,控制好光標即可,其他沒什麼好介紹的,看遊戲源碼即可。

總結

  經過兩天的努力,完成從設計到開發的全部過程,成果可見。遊戲開發創新之處在於算法的設計,拋棄傳統的隨機地圖生成算法,提出新的有效地圖生成算法,新的算法速度可觀,可在很快的時間內生成一副有效地圖。
  爲了減少單個有效地圖生成的時間,我將排列表的生成放在了init()函數內,其原因是生成排列表的時間在30ms以內,玩家按下s或着q的時間內,這個排列表已經完成。
  因爲第一次開發項目,對擴展性不太瞭解,所以這個遊戲的可擴展性很差,目前我瞭解到一些提高可擴展性的方法,其中模板機智、常量定義等都是常用的方法。
  遊戲開發體會:對於算法問題需要仔細的思考;對於技術問題,需要認真的學習;對於代碼,需要多加註釋。

遇到的問題

  在開發的過程中遇到了不少問題,彙總如下:

  1. static的理解:static的生命週期是進程。
  2. vector越界:代碼中:0~query.size(); VS報錯:vector subscript out of range。更改爲:0~query.size()-1;
  3. 數組越界原因:由於定義char table[11][11],訪問table[14][14]導致越界,錯誤提示:Run-Time Check Failure #2 - Stack around the variable ‘s’ was corrupted.
  4. ncurses中文字符使用:
    4.1. 安裝 sudo apt-get install libncursesw5 libncursesw5-dev
    4.2. 使用setlocale函數設置locale setlocale(LC_ALL,"");
    4.3. 編譯 g++ sudo.o main.o -lncursesw -o main 使用-lncursesw鏈接
  5. sleep()函數:在頭文件 unistd.h 中
  6. Linux中vim粘貼省略縮進:在vim中輸入:set paste
  7. 類中數據成員的初始化問題:因爲沒有對curtable初始話,導致生成地圖有誤。
  8. 位置初始化:因爲使用judgeans()導致當前光標移動,在跳出此函數時需要光標回到此位置。
  9. addch()函數:在添加字符之後光標向後移動一個,爲了光標導航,需要光標調回原位置,即減一回到原位置。
  10. 刪除字符剩餘加一:遊戲的輸贏規則是根據剩餘未填個數判斷,當清空一個單元格的數字時,剩餘字符加一。

給出源碼之前在來一張遊戲截圖吧~~~
在這裏插入圖片描述

源碼:

//main.cpp
#include<iostream>
#include<ctime>
#include<cstdio>
#include"sudo.h"

int main()
{
	sudo s;
	s.init();
	s.run();
	return 0;
}
#makefile
All:sudo.o main.o main clean
  
src = $(wildcard ./*.cpp)
obj = $(patsubst %.cpp, %.o, $(src))
main:$(obj)
        g++ $^ -lncursesw -o $@
%.o:%.cpp
        g++ $< -c -o $@
clean:
        rm -f $(obj)
//sudo.h
#pragma once
#include<vector>
using namespace std;
class sudo
{
public:
	void init();//初始化遊戲的界面
	void inittable(int cnt);//初始化9*9全排列
	int random(int L, int R);//生成隨機數
	void getcellr(int sx, int ex, int sy, int ey, int* hashr1, int* hashr2, int* hashr3);//獲取行信息
	void getcellc(int sx, int ex, int sy, int ey, int* hashc1, int* hashc2, int* hashc3);//獲取列信息

	int Nextcell(vector<int>& cellr, vector<int>& cellc);//根據目前的表格,查找下一個表格
	void drawcell(int sx, int ex, int sy, int ey, int index);//繪製一個單元格
	void setcell();//設置所有的單元格
	bool judge(int x, int y, int k);//判斷(x,y)位置放k是否可行
	bool dfs(int cnt);//判斷是否存在答案
	void draw();//畫遊戲的圖
	bool judgeans(const int& my, const int& mx, char ch);//判斷當前位置能否放ch
	bool judgemove(const int& my, const int& mx, const int& cury, const int& curx);//判斷當前位置是否越界
	void run();//執行
	void test();//測試
	void printwin();//打印youwin
	void printlost();//打印youlost
public:
	sudo();
	virtual ~sudo();

private:
	char** initable;
	int remind;//剩餘個數
	int numbers;
	char** table;//答案地圖
	char** curtable;//當前地圖的值不能清楚
};
//sudo.cpp
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cstddef>
#include<random>
#include<unistd.h>
#include<ctime>
#include <locale.h>
#include<ncurses.h>
#include<algorithm>
using namespace std;
#include "sudo.h"

const int MAX = 362879;
const int MIN = 0;

void sudo::test()//測試
{
	for (int i = 0; i < 9; i++)
	{
		for (int j = 0; j < 9; j++)
			printf("%c", table[i][j]);
		printf("\n");
	}
	return;
}
/*
		Welcome to Sudoku  			17
Please enter s to start the game or q to exit game	50
		author: 葫蘆娃兄弟的混天綾			26
		  version:1.0.0				13
*/
void sudo::init()//初始化遊戲的界面
{
	setlocale(LC_ALL, "");
	initscr();
	cbreak();
	noecho();
	int y, x;
	char ch;
	getmaxyx(stdscr, y, x);
	mvprintw(y / 2 - 1, (x - 17) / 2, "Welcome to Sudoku");
	mvprintw(y / 2, (x - 50) / 2, "Please enter s to start the game or q to exit game");
	mvprintw(y / 2 + 1, (x - 26) / 2, "author: 葫蘆娃兄弟的混天綾");
	mvprintw(y / 2 + 2, (x - 13) / 2, "version:1.0.0");
	inittable(0);
	ch = getch();
	while (ch != 's' && ch != 'S')
	{
		if (ch == 'q' || ch == 'Q')
		{
			endwin();
			exit(0);
		}
		beep();
		ch = getch();
	}
	return;
}
void sudo::inittable(int cnt)//初始化9*9全排列
{
	static bool used[11] = { false };
	static char ttable[11];
	if (cnt == 9)
	{
		ttable[cnt] = '\0';
		strcpy(initable[numbers], ttable);
		numbers++;
		return;
	}
	for (int i = 1; i <= 9; i++)
	{
		if (!used[i])
		{
			used[i] = true;
			ttable[cnt] = '0' + i;
			inittable(cnt + 1);
			ttable[cnt] = '\0';
			used[i] = false;
		}
	}
}
int sudo::random(int L, int R)//生成隨機數
{
	static default_random_engine e(unsigned(time(0)));
	uniform_int_distribution<unsigned> u(L, R);
	return u(e);

}
void sudo::drawcell(int sx, int ex, int sy, int ey, int index)//繪製一個單元格
{
	for (int i = sx; i < ex; i++)
	{
		for (int j = sy; j < ey; j++)
		{
			table[i][j] = *(*(initable + index) + (i - sx) * 3 + (j - sy));
		}
	}
	return;
}
void sudo::getcellr(int sx, int ex, int sy, int ey, int* hashr1, int* hashr2, int* hashr3)//獲取單元格行信息
{
	for (int i = sx; i < ex; i++)
		for (int j = sy; j < ey; j++)
		{
			if (i - sx == 0)	hashr1[table[i][j] - '0']++;
			else if (i - sx == 1)hashr2[table[i][j] - '0']++;
			else if (i - sx == 2)hashr3[table[i][j] - '0']++;
		}
}
void sudo::getcellc(int sx, int ex, int sy, int ey, int* hashc1, int* hashc2, int* hashc3)//獲取單元格列信息
{
	for (int i = sx; i < ex; i++)
		for (int j = sy; j < ey; j++)
		{
			if (j - sy == 0)	hashc1[table[i][j] - '0']++;
			else if (j - sy == 1)hashc2[table[i][j] - '0']++;
			else if (j - sy == 2)hashc3[table[i][j] - '0']++;
		}
}
int sudo::Nextcell(vector<int>& cellr, vector<int>& cellc)//根據目前的表格,查找下一個表格
{
	vector<int> query;//存放在query內
	int hashr1[11] = { 0 }, hashr2[11] = { 0 }, hashr3[11] = { 0 };
	int hashc1[11] = { 0 }, hashc2[11] = { 0 }, hashc3[11] = { 0 };
	for (size_t i = 0; i < cellr.size(); i++)//獲取哪一個單元格的行信息
	{
		switch (cellr[i])
		{
		case 1:
			getcellr(0, 3, 0, 3, hashr1, hashr2, hashr3);
			break;
		case 2:
			getcellr(0, 3, 3, 6, hashr1, hashr2, hashr3);
			break;
		case 3:
			getcellr(0, 3, 6, 9, hashr1, hashr2, hashr3);
			break;
		case 4:
			getcellr(3, 6, 0, 3, hashr1, hashr2, hashr3);
			break;
		case 5:
			getcellr(3, 6, 3, 6, hashr1, hashr2, hashr3);
			break;
		case 6:
			getcellr(3, 6, 6, 9, hashr1, hashr2, hashr3);
			break;
		case 7:
			getcellr(6, 9, 0, 3, hashr1, hashr2, hashr3);
			break;
		case 8:
			getcellr(6, 9, 3, 6, hashr1, hashr2, hashr3);
			break;
		}
	}
	for (size_t i = 0; i < cellc.size(); i++)//獲取哪一個單元格的列信息
	{
		switch (cellc[i])
		{
		case 1:
			getcellc(0, 3, 0, 3, hashc1, hashc2, hashc3);
			break;
		case 2:
			getcellc(0, 3, 3, 6, hashc1, hashc2, hashc3);
			break;
		case 3:
			getcellc(0, 3, 6, 9, hashc1, hashc2, hashc3);
			break;
		case 4:
			getcellc(3, 6, 0, 3, hashc1, hashc2, hashc3);
			break;
		case 5:
			getcellc(3, 6, 3, 6, hashc1, hashc2, hashc3);
			break;
		case 6:
			getcellc(3, 6, 6, 9, hashc1, hashc2, hashc3);
			break;
		case 7:
			getcellc(6, 9, 0, 3, hashc1, hashc2, hashc3);
			break;
		case 8:
			getcellc(6, 9, 3, 6, hashc1, hashc2, hashc3);
			break;
		}
	}
	for (int i = 0; i <= MAX; i++)//根據獲取的行列信息,確定滿足當前3*3單元格的排列的個數及下標
	{
		bool flag = true;
		for (int j = 0; j < 3; j++)
			if (hashr1[initable[i][j] - '0'])
				flag = false;
		for (int j = 3; j < 6; j++)
			if (hashr2[initable[i][j] - '0'])
				flag = false;
		for (int j = 6; j < 9; j++)
			if (hashr3[initable[i][j] - '0'])
				flag = false;
		for (int j = 0; j < 9; j += 3)
			if (hashc1[initable[i][j] - '0'])
				flag = false;
		for (int j = 1; j < 9; j += 3)
			if (hashc2[initable[i][j] - '0'])
				flag = false;
		for (int j = 2; j < 9; j += 3)
			if (hashc3[initable[i][j] - '0'])
				flag = false;
		if (flag)
			query.push_back(i);
	}
	if (query.size() == 0)
		return -1;
	return query[random(0, query.size() - 1)];
}
void sudo::setcell()//設置單元格
{
	vector<int> cellr;//存放需要查詢的行單元格
	vector<int> cellc;//存放需要查詢的列單元格
	int curorder[11] = { 0,1,2,3,4,7,5,6,8,9 };//排放單元格的順序
	int index = 0;
	int cur = 1;
	while (cur <= 7)
	{
		switch (curorder[cur])
		{
		case 1://排放‘1drawcell(0, 3, 0, 3, random(MIN, MAX));
			cur++;
			break;
		case 2://排放‘2’
			cellr.clear();
			cellc.clear();
			cellr.push_back(1);
			index = Nextcell(cellr, cellc);
			if (index == -1)
				cur--;
			else
			{
				drawcell(0, 3, 3, 6, index); cur++;
			}
			break;
		case 3:
			cellr.clear();
			cellc.clear();
			cellr.push_back(1);
			cellr.push_back(2);
			index = Nextcell(cellr, cellc);
			if (index == -1)
				cur--;
			else
			{
				drawcell(0, 3, 6, 9, index); cur++;
			}
			break;
		case 4:
			cellr.clear();
			cellc.clear();
			cellc.push_back(1);
			index = Nextcell(cellr, cellc);
			if (index == -1)
				cur--;
			else
			{
				drawcell(3, 6, 0, 3, index); cur++;
			}
			break;
		case 5:
			cellr.clear();
			cellc.clear();
			cellr.push_back(4);
			cellc.push_back(2);
			index = Nextcell(cellr, cellc);
			if (index == -1)
				cur--;
			else
			{
				drawcell(3, 6, 3, 6, index); cur++;
			}
			break;
		case 7:
			cellr.clear();
			cellc.clear();
			cellc.push_back(1);
			cellc.push_back(4);
			index = Nextcell(cellr, cellc);
			if (index == -1)
				cur--;
			else
			{
				drawcell(6, 9, 0, 3, index); cur++;
			}
			break;
		default:
			vector<int> query6;//存放單元格6的方案
			vector<int> query8;//存放單元格8的方案
			//查找滿足‘6’位置的單元格
			int hashr1[11] = { 0 }, hashr2[11] = { 0 }, hashr3[11] = { 0 };
			int hashc1[11] = { 0 }, hashc2[11] = { 0 }, hashc3[11] = { 0 };
			getcellr(3, 6, 0, 3, hashr1, hashr2, hashr3);//查找‘4’
			getcellr(3, 6, 3, 6, hashr1, hashr2, hashr3);//查找‘5’
			getcellc(0, 3, 6, 9, hashc1, hashc2, hashc3);//查找‘3’
			for (int i = 0; i <= MAX; i++)
			{
				bool flag = true;
				for (int j = 0; j < 3; j++)
					if (hashr1[initable[i][j] - '0'])
						flag = false;
				for (int j = 3; j < 6; j++)
					if (hashr2[initable[i][j] - '0'])
						flag = false;
				for (int j = 6; j < 9; j++)
					if (hashr3[initable[i][j] - '0'])
						flag = false;
				for (int j = 0; j < 9; j += 3)
					if (hashc1[initable[i][j] - '0'])
						flag = false;
				for (int j = 1; j < 9; j += 3)
					if (hashc2[initable[i][j] - '0'])
						flag = false;
				for (int j = 2; j < 9; j += 3)
					if (hashc3[initable[i][j] - '0'])
						flag = false;
				if (flag)
					query6.push_back(i);
			}
			if (query6.size() == 0)
			{
				cur--;
				break;
			}
			//查找滿足‘8’位置的單元格
			for (int i = 0; i <= 10; i++)
				hashr1[i] = hashr2[i] = hashr3[i] = hashc1[i] = hashc2[i] = hashc3[i] = 0;
			getcellc(0, 3, 3, 6, hashc1, hashc2, hashc3);//查找‘2’
			getcellc(3, 6, 3, 6, hashc1, hashc2, hashc3);//查找‘5’
			getcellr(6, 9, 0, 3, hashr1, hashr2, hashr3);//查找‘7’
			for (int i = 0; i <= MAX; i++)
			{
				bool flag = true;
				for (int j = 0; j < 3; j++)
					if (hashr1[initable[i][j] - '0'])
						flag = false;
				for (int j = 3; j < 6; j++)
					if (hashr2[initable[i][j] - '0'])
						flag = false;
				for (int j = 6; j < 9; j++)
					if (hashr3[initable[i][j] - '0'])
						flag = false;
				for (int j = 0; j < 9; j += 3)
					if (hashc1[initable[i][j] - '0'])
						flag = false;
				for (int j = 1; j < 9; j += 3)
					if (hashc2[initable[i][j] - '0'])
						flag = false;
				for (int j = 2; j < 9; j += 3)
					if (hashc3[initable[i][j] - '0'])
						flag = false;
				if (flag)
					query8.push_back(i);
			}
			if (query8.size() == 0)
			{
				cur--;
				break;
			}
			bool fdfs = false;
			for (size_t i = 0; i < query6.size(); i++)
			{
				drawcell(3, 6, 6, 9, query6[i]);
				for (size_t j = 0; j < query8.size(); j++)
				{
					drawcell(6, 9, 3, 6, query8[j]);
					if (fdfs = dfs(0))//dfs搜索是否存在滿足的地圖
					{
						cur++; break;
					}
				}
				if (fdfs)
					break;
			}
			if (!fdfs)
				cur = 1;
			break;
		}
	}
	return;
}
bool sudo::judge(int x, int y, int k)//判斷(x,y)位置放k是否可行
{
	for (int i = 0; i < 6; i++)
		if (table[i][y] - '0' == k)
			return false;
	for (int i = 0; i < 6; i++)
		if (table[x][i] - '0' == k)
			return false;
	return true;
}
bool sudo::dfs(int cnt)//判斷是否存在答案
{
	static bool used[11] = { false };
	if (cnt == 9)
	{
		return true;
	}
	for (int i = 1; i <= 9; i++)
	{
		if (!used[i])
		{
			used[i] = true;
			if (judge(6 + cnt / 3, 6 + cnt % 3, i))
			{
				table[6 + cnt / 3][6 + cnt % 3] = '0' + i;
				if (dfs(cnt + 1))
				{
					for (int k = 0; k <= 10; k++)//爲了下一次使用,這裏置零
						used[k] = false;
					return true;
				}
			}
			used[i] = false;
		}
	}
	return false;
}

/*
				+---+---+---+---+---+---+---+---+---+       37c
				| 1 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
				+---+---+---+---+---+---+---+---+---+
				| 2 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
				+---+---+---+---+---+---+---+---+---+
				| 3 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
				+---+---+---+---+---+---+---+---+---+
				| 4 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
	21r         +---+---+---+---+---+---+---+---+---+
				| 5 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
				+---+---+---+---+---+---+---+---+---+
				| 6 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
				+---+---+---+---+---+---+---+---+---+
				| 7 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
				+---+---+---+---+---+---+---+---+---+
				| 8 | 2 | 3 | 1 | 2 | 3 | 1 | 2 | 3 |
				+---+---+---+---+---+---+---+---+---+
				|   |   |   |   |   |   |   |   |   |
				+---+---+---+---+---+---+---+---+---+

   A(左)、D(右)、W(上)、S(下)、1~9(數字)、R(重置)、Q(退出)、M(答案)    61c
*/

void sudo::draw()//畫遊戲的圖
{
	setcell();
	clear();
	int y, x;
	getmaxyx(stdscr, y, x);
	int cury = (y - 21) / 2, curx = (x - 37) / 2;
	mvprintw(cury, curx, "+---+---+---+---+---+---+---+---+---+");
	mvprintw(cury + 1, curx, "|   |   |   |   |   |   |   |   |   |");
	mvprintw(cury + 2, curx, "+---+---+---+---+---+---+---+---+---+");
	mvprintw(cury + 3, curx, "|   |   |   |   |   |   |   |   |   |");
	mvprintw(cury + 4, curx, "+---+---+---+---+---+---+---+---+---+");
	mvprintw(cury + 5, curx, "|   |   |   |   |   |   |   |   |   |");
	mvprintw(cury + 6, curx, "+---+---+---+---+---+---+---+---+---+");
	mvprintw(cury + 7, curx, "|   |   |   |   |   |   |   |   |   |");
	mvprintw(cury + 8, curx, "+---+---+---+---+---+---+---+---+---+");
	mvprintw(cury + 9, curx, "|   |   |   |   |   |   |   |   |   |");
	mvprintw(cury + 10, curx, "+---+---+---+---+---+---+---+---+---+");
	mvprintw(cury + 11, curx, "|   |   |   |   |   |   |   |   |   |");
	mvprintw(cury + 12, curx, "+---+---+---+---+---+---+---+---+---+");
	mvprintw(cury + 13, curx, "|   |   |   |   |   |   |   |   |   |");
	mvprintw(cury + 14, curx, "+---+---+---+---+---+---+---+---+---+");
	mvprintw(cury + 15, curx, "|   |   |   |   |   |   |   |   |   |");
	mvprintw(cury + 16, curx, "+---+---+---+---+---+---+---+---+---+");
	mvprintw(cury + 17, curx, "|   |   |   |   |   |   |   |   |   |");
	mvprintw(cury + 18, curx, "+---+---+---+---+---+---+---+---+---+");

	mvprintw(cury + 20, (x - 69) / 2, "A(左)、D(右)、W(上)、S(下)、1~9(數字)、C(清除)、R(重置)、Q(退出)、M(答案)");

	cury = cury + 1;
	curx = curx + 2;
	move(cury, curx);
	int initfill = random(30, 40);
	remind = 81 - initfill;
	for (int i = 0; i < initfill; i++)
	{
		move(cury, curx);
		int getx = -1, gety = -1;
		static default_random_engine e(unsigned(time(0)));
		static uniform_int_distribution<unsigned> u(0, 8);
		getx = u(e);
		gety = u(e);
		move(cury + 2 * gety, curx + 4 * getx);
		while (inch() != ' ')
		{
			getx = u(e);
			gety = u(e);
			move(cury + 2 * gety, curx + 4 * getx);
		}
		curtable[gety][getx] = table[gety][getx];//根據答案地圖更新當前地圖
		addch(table[gety][getx]);
	}

	move(cury, curx);
	refresh();
	return;
}
bool sudo::judgeans(const int& my, const int& mx, char ch)
{
	char ccur = inch();
	if (ccur != ' ')
		return false;
	int y, x;
	getyx(stdscr, y, x);
	int cury = y, curx = mx;
	for (int i = 0; i < 9; i++)
	{
		move(cury, curx);
		char cur = inch();
		if (cur == ch)
			return false;
		curx += 4;
	}
	cury = my, curx = x;
	for (int i = 0; i < 9; i++)
	{
		move(cury, curx);
		char cur = inch();
		if (cur == ch)
			return false;
		cury += 2;
	}
	cury = (y - my) / 2;
	curx = (x - mx) / 4;
	cury = my + cury / 3 * 3 * 2;
	curx = mx + curx / 3 * 3 * 4;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			move(cury + 2 * i, curx + 4 * j);
			char cur = inch();
			if (cur == ch)
				return false;
		}
	}
	return true;
}
bool sudo::judgemove(const int& my, const int& mx, const int& cury, const int& curx)//判斷當前位置是否越界
{
	int y = (cury - my) / 2;
	int x = (curx - mx) / 4;
	if (x >= 0 && x <= 8 && y >= 0 && y <= 8)
		return true;
	return false;
}
void sudo::run()//執行
{
Resetting:

	draw();
	int cy, cx;
	getyx(stdscr, cy, cx);
	int cury = cy, curx = cx;
	char ch;
	while (remind)
	{
		ch = getch();
		if (ch == 'W' || ch == 'w')
		{
			if (judgemove(cy, cx, cury - 2, curx))
			{
				cury -= 2;
				move(cury, curx);
			}
			else
			{
				beep();
			}
			continue;
		}
		else if (ch == 'a' || ch == 'A')
		{
			if (judgemove(cy, cx, cury, curx - 4))
			{
				curx -= 4;
				move(cury, curx);
			}
			else
			{
				beep();
			}
			continue;
		}
		else if (ch == 's' || ch == 'S')
		{
			if (judgemove(cy, cx, cury + 2, curx))
			{
				cury += 2;
				move(cury, curx);
			}
			else
			{
				beep();
			}
			continue;
		}
		else if (ch == 'd' || ch == 'D')
		{
			if (judgemove(cy, cx, cury, curx + 4))
			{
				curx += 4;
				move(cury, curx);
			}
			else
			{
				beep();
			}
			continue;
		}
		else if (ch >= '1' && ch <= '9')
		{
			if (judgeans(cy, cx, ch))
			{
				move(cury, curx);
				addch(ch);
				remind--;
			}
			else
			{
				beep();
			}
			move(cury, curx);
			refresh();
			continue;
		}
		else if (ch == 'c' || ch == 'C')
		{
			char cur = inch();
			if (cur == ' ')
			{
				beep();
			}
			else
			{
				if (curtable[(cury - cy) / 2][(curx - cx) / 4] == ' ')
				{
					addch(' ');
					remind++;
					move(cury, curx);
				}
				else
				{
					beep();
				}
				//在curtable查找
			}
			continue;
		}
		else if (ch == 'r' || ch == 'R')
		{
			for (int ini = 0; ini <= 10; ini++)
				for (int inj = 0; inj <= 10; inj++)
					table[ini][inj] = curtable[ini][inj] = ' ';
			goto Resetting;
		}
		else if (ch == 'q' || ch == 'Q')
		{
			endwin();
			exit(0);
		}
		else if (ch == 'm' || ch == 'M')
		{
			//給出table答案
			cury = cy;
			curx = cx;
			for (int iny = 0; iny < 9; iny++)
			{
				curx = cx;
				for (int inx = 0; inx < 9; inx++)
				{
					move(cury, curx);
					addch(table[(cury - cy) / 2][(curx - cx) / 4]);
					curx += 4;
				}
				cury += 2;
			}
			//打印youlost
			printlost();
			//給出提示輸入
			while (1)
			{
				char ch = getch();
				if (ch == 'r' || ch == 'R')
				{
					goto Resetting;
				}
				if (ch == 'q' || ch == 'Q')
				{
					endwin();
					exit(0);
				}
				else
					beep();
			}
		}
		else
		{
			beep();
		}
	}
	if (remind == 0)
	{
		printwin();
		while (1)
		{
			char ch = getch();
			if (ch == 'r' || ch == 'R')
			{
				goto Resetting;
			}
			if (ch == 'q' || ch == 'Q')
			{
				endwin();
				exit(0);
			}
			else
				beep();
		}
	}
	beep();
	return;
}

/*youwin
				+   +    ++    +  +       +           +   +    + +         +
				 + +    +  +   +  +       +     +     +        +   +       +
				  +     +  +   +  +        +   + +   +    +    +   +       +
				  +     +  +   +  +         + +   + +     +    +   +
				  +      ++     ++           +     +      +    +   +       +
				  按Q退出,按R重新開始,請輸入:
*/
/*youlost
				+   +    ++    +  +       +        ++     ++    + + +      +
				 + +    +  +   +  +       +       +  +   +        +        +
				  +     +  +   +  +       +       +  +    ++      +        +
				  +     +  +   +  +       +       +  +      +     +
				  +      ++     ++        + + +    ++     ++      +        +
				  按Q退出,按R重新開始,請輸入:
*/

void sudo::printwin()//打印youwin
{
	int y, x;
	getmaxyx(stdscr, y, x);
	int cury = (y - 21) / 2, curx = (x - 37) / 2;
	mvprintw(cury + 22, (x - 60) / 2, "+   +    ++    +  +       +           +   +    + +         +");
	mvprintw(cury + 23, (x - 60) / 2, " + +    +  +   +  +       +     +     +        +   +       +");
	mvprintw(cury + 24, (x - 60) / 2, "  +     +  +   +  +        +   + +   +    +    +   +       +");
	mvprintw(cury + 25, (x - 60) / 2, "  +     +  +   +  +         + +   + +     +    +   +        ");
	mvprintw(cury + 26, (x - 60) / 2, "  +      ++     ++           +     +      +    +   +       +");
	mvprintw(cury + 28, (x - 30) / 2, "按Q退出,按R重新開始,請輸入:");

	return;
}
void sudo::printlost()//打印youlost
{

	int y, x;
	getmaxyx(stdscr, y, x);
	int cury = (y - 21) / 2, curx = (x - 37) / 2;
	mvprintw(cury + 22, (x - 60) / 2, "+   +    ++    +  +       +        ++     ++    + + +      +");
	mvprintw(cury + 23, (x - 60) / 2, " + +    +  +   +  +       +       +  +   +        +        +");
	mvprintw(cury + 24, (x - 60) / 2, "  +     +  +   +  +       +       +  +    ++      +        +");
	mvprintw(cury + 25, (x - 60) / 2, "  +     +  +   +  +       +       +  +      +     +         ");
	mvprintw(cury + 26, (x - 60) / 2, "  +      ++     ++        + + +    ++     ++      +        +");
	mvprintw(cury + 28, (x - 30) / 2, "按Q退出,按R重新開始,請輸入:");
	return;
}
sudo::sudo()
{
	initable = new char* [362881];
	for (int i = 0; i <= 362880; i++)
		initable[i] = new char[10];
	table = new char* [11];
	for (int i = 0; i <= 10; i++)
		table[i] = new char[11];
	curtable = new char* [11];
	for (int i = 0; i <= 10; i++)
		curtable[i] = new char[11];
	for (int i = 0; i <= 10; i++)
		for (int j = 0; j <= 10; j++)
			table[i][j] = curtable[i][j] = ' ';
	numbers = 0;
	remind = 0;
}
sudo::~sudo()
{
	for (int i = 0; i <= 362880; i++)
		delete[] initable[i];
	delete[] initable;
	for (int i = 0; i <= 10; i++)
		delete[] table[i];
	delete[] table;
	for (int i = 0; i <= 10; i++)
		delete[] curtable[i];
	delete[] curtable;
	initable = NULL;
	remind = 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章