9*9数独游戏C++开发

  • Post author:
  • Post category:其他

前言

  这一段时间学了不少东西,想找个项目历练一下,就去牛客上翻了翻,看到这个我小时候经常玩的游戏,就想开发一下试试。因为第一次做项目,不知道如何做,就去牛客此项目下的评论区看了下别人的作品,发现算法有错,不能正常玩,决定自己开发一个能玩的游戏。

游戏介绍

  数独是源自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;
}


版权声明:本文为weixin_43855330原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。