/*
请开启 c++11 
请注意关闭大写锁定,输入法调整至英文!
打开控制台后,请右键标题栏,给插入模式打勾并关闭其他选项 
请控制台运行完之后再操作! 
*/
#include <bits/stdc++.h>
#include <windows.h>
#include <unistd.h>
#include <conio.h> 
using namespace std;
// definations
#define KEY_DOWN(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
#define ll long long
#define elif else if
#define cls system("cls")
// tools
void Say(string s,int slpt = 25){
	for(int i=0;i<s.length();i++) cout<<s[i],Sleep(slpt);
	return;
}
void ReTitle(string s){
	cls;
	cout<<s<<endl;
	cout<<"————————————————————————————————————————"<<endl;
}
mt19937 RandEn(time(0));
int Rand(int l, int r){
	return uniform_int_distribution<int>(l, r)(RandEn);
}
// value
enum Rule{
	Normal = 1,
	Always_2,
	Fibonacci,
	Threes,
	Merge_Any,
	Tile_0,
	Negative,
	Gravity
}rule = Normal;
enum Autoplay{
	Stop = 1,
	Corner,
	Swing,
	Swirl,
	Random
}ap = Stop;
int sz = 4;
unsigned char upc = 'w', dnc = 's', lec = 'a', ric = 'd';
unsigned char upcc = 72, dncc = 80, lecc = 75, ricc = 77;
bool f[10][10];
long long p[10][10];
long long score = 0, max_score = 0;
long long fib[50];
bool tag = true;
string ver = "1.1.2";
// pre-func
void Init();
void Pre();
void hide();
string decode();//加密 
bool encode();//解密 
void Main();
void Start();
bool mergable(long long x, long long y);
int cnt_empty();
bool checklr();
bool check();
void save(int type = 0);
void read();
int spawn_();
void spawn();
string changesl();
void change_Rule();
void change_Autoplay();
void outp();
void sup();
void sdn();
void sle();
void sri();
void Startinit();
void Setting();
void Setting_Merge();
void Setting_Auto();
void Setting_Size();
void Setting_Button();
void Show_Rule();
// button
struct Button{
	int x, y;
	string name;
	int len;
};
Button Create(int x, int y, string name){
	Button t;
	t.x = x;
	t.y = y;
	t.name = name;
	t.len = name.size();
	return t;
}
void getpos(POINT &pt){
    HWND hwnd = GetForegroundWindow();
    GetCursorPos(&pt);
    ScreenToClient(hwnd,&pt);
    pt.y = pt.y / 16;
    pt.x = pt.x / 16;
}
void gotoxy(int x,int y){
	COORD pos;
	pos.X = y * 2;
	pos.Y = x;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);
} 
bool click(Button button){
	gotoxy(button.x, button.y);
	cout << button.name << endl;
	POINT pt;
	getpos(pt);
	if(pt.y == button.x && (pt.x >= button.y && pt.x <= button.y + button.len/2)){
		gotoxy(button.x, button.y);
		cout << button.name;
		if(KEY_DOWN(MOUSE_MOVED)){
			return true; 
		}
	}
	return false;
}
// func
string its(int num){
	if (!num) return "0";
	string res = "";
	while (num)
	{
		res = (char)(num % 10 + 48) + res;
		num /= 10;
	}
	return res;
}
string decode(){
	string s = "";
	for(int i = 1;i <= sz; i++)
	{
		for(int j = 1;j <= sz; j++)
		{
			s += its(p[i][j]);
		}
	}
	return s;
}
bool encode(string stmp){
	string sans = decode();
	if(sans == stmp)return true;
	else return false; 
}
void Init(){
	fib[0] = fib[1] = 1;
	for (int i = 2;i <= 40;++i)
		fib[i] = fib[i-2] + fib[i-1];
}
void Pre(){
	ReTitle("前言");
	Say("2048 小游戏 - c++ 控制台\n");
	Say("作者:看什么看 & cjk\n");
	Say("版本:1.1.2 CN\n");
	Say("第一次游玩前请务必查看规则\n");
	Say("感谢游玩!\n");
	Sleep(1500);
} 
void change_Rule(int num){
	if(num == 1)rule = Normal;
	if(num == 2)rule = Always_2;
	if(num == 3)rule = Fibonacci;
	if(num == 4)rule = Threes;
	if(num == 5)rule = Merge_Any;
	if(num == 6)rule = Tile_0;
	if(num == 7)rule = Negative;
	if(num == 8)rule = Gravity;
}
void change_Autoplay(int num){
	if(num == 1)ap = Stop;
	if(num == 2)ap = Corner;
	if(num == 3)ap = Swing;
	if(num == 4)ap = Swirl;
	if(num == 5)ap = Random;
}
void hide(){
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(handle, &CursorInfo);
    CursorInfo.bVisible = 0; 
    SetConsoleCursorInfo(handle, &CursorInfo);
}
void Main(){
	hide();
	Init();
	Pre();
	if(score||max_score) exit(-1);
	while(1)
	{
		ReTitle("主页面");
		Button Exit, Startgame, Set, Game_Rule, Save_Game, Read_Game, New_Game;
		Exit = Create(2, 0, "0 退出游戏"); 
		Startgame = Create(3, 0, "1 开始游戏"); 
		Set = Create(4, 0, "2 设置"); 
		Game_Rule = Create(5, 0, "3 游戏规则"); 
		Save_Game = Create(6, 0, "4 保存游戏"); 
		Read_Game = Create(7, 0, "5 读取存档"); 
		New_Game = Create(8, 0, "6 新开游戏"); 
		if(click(Exit))exit(0);
		if(click(Startgame))Start();
		if(click(Set))Setting();
		if(click(Game_Rule))Show_Rule();
		if(click(Save_Game))save();
		if(click(Read_Game))read();
		if(click(New_Game)){Startinit();max_score = 0;rule = Normal;ap = Stop;}
	}
}
void Startinit(){
	memset(f, 0, sizeof(f));
	memset(p, 0, sizeof(p));
	score = 0;
}
void Start(){
	//Startinit();
	bool flag = false;//是否操作 
	long long step = 0;
	while (1){
		++step;
		if (score > max_score) max_score = score;
		
		ReTitle("游戏");
		printf ("当前分数:%d    最高分数:%d\n", score, max_score);
		if (!check()){
			outp();
			Say("G a m e   o v e r");
			Startinit();
			Sleep(3000);
			return ;
		}
		printf ("如果不想玩了,按 esc 键退出哦\n");
		if(flag != false || cnt_empty() == sz * sz)spawn();
		//Sleep(100);
		outp();
		
		if (rule == Gravity) {
			Sleep(300);
			ReTitle("游戏");
			printf ("当前分数:%d    最高分数:%d\n", score, max_score);
			printf ("如果不想玩了,按 esc 键退出哦\n"); 
			sdn();
			outp();
		} 
		
		if (ap == Stop){
			char ch = getch();
			while (ch != upc && ch != dnc && ch != lec && ch != ric && ch != 27 && ch != upcc && ch != dncc && ch != lecc && ch != ricc) ch = getch();
			if (ch == upc || ch == upcc) sup();
			elif (ch == dnc || ch == dncc) sdn();
			elif (ch == lec || ch == lecc) sle();
			elif (ch == ric || ch == ricc) sri();
			else {
				printf ("正在退出……");
				Sleep(1000);
				return ;
			}
		}
		else {
			char ch = getch();
			while (ch != 27 && ch != 32) ch = getch();
			if (ch == 27){
				printf ("正在退出……");
				Sleep(1000);
				return ;
			}
			else {
				switch(ap){
					case 2 : (step & 1) ? sdn() : sle(); break;
					case 3 : checklr() ? ((step & 1) ? sle() : sri()) : sup(); break;
					case 4 : 
						switch (step & 3){
							case 0 : sup(); break;
							case 1 : sle(); break;
							case 2 : sdn(); break;
							case 3 : sri(); break;
						}
						break;
					case 5 :
						switch (Rand(0, 3)){
							case 0 : sup(); break;
							case 1 : sle(); break;
							case 2 : sdn(); break;
							case 3 : sri(); break;
						}
						break;
				}
			}
		}
		flag = true;
	}	
}
bool mergable(long long x, long long y){
	int px, py;
	switch(rule){
		case Normal : return x == y;
		case Always_2 : return x == y;
		case Fibonacci : 
			if (x == 1 && y == 1) return 1;
			px = lower_bound(fib + 1, fib + 41, x) - fib;
			py = lower_bound(fib + 1, fib + 41, y) - fib;
			return abs(px - py) == 1;
		case Threes : return x + y == 3 || (x > 2 && y > 2 && x == y);
		case Merge_Any : return 1;
		case Tile_0 : return x == y;
		case Negative : return x == y || x + y == 0;
		case Gravity : return x == y;
	}
}
int cnt_empty(){
	int res = 0;
	for (int i = 1;i <= sz;++i)
		for (int j = 1;j <= sz;++j)
			res += !f[i][j];
	return res;
}
bool check(){
	if (cnt_empty()) return 1;
	for (int i = 1;i <= sz;++i)
		for (int j = 1;j < sz;++j)
			if (f[i][j] && abs(p[i][j]) >= 1e9){
				p[i][j] = f[i][j] = 0;
			}
	for (int i = 1;i <= sz;++i)
		for (int j = 1;j < sz;++j)
			if (mergable(p[i][j], p[i][j+1]))
				return 1;
	for (int i = 1;i < sz;++i)
		for (int j = 1;j <= sz;++j)
			if (mergable(p[i][j], p[i+1][j]))
				return 1;
	return 0;
}
bool checklr(){
	for (int i = 1;i <= sz;++i)
		for (int j = 1;j < sz;++j)
			if (mergable(p[i][j], p[i][j+1]))
				return 1;
	return 0;
}
void light_color(int a){
/*亮白*/    if(a==0) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
/*蓝色*/    if(a==1) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_BLUE);
/*绿色*/    if(a==2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN);
/*紫色*/    if(a==3) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_BLUE);
/*红色*/    if(a==4) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED);
/*黄色*/    if(a==5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN);
/*深蓝色*/    if(a==6) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_BLUE);
/*土黄色or金黄色*/    if(a==7) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN);
/*灰色接近白*/    if(a==8) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
/*青色*/  if(a == 9) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_GREEN|FOREGROUND_BLUE);
/*粉色*/  if(a == 10) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|FOREGROUND_RED|FOREGROUND_BLUE);
/*原色*/  if(a == 11) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY);
/*亮白*/    if(a==12) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_INTENSITY|BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE);
/*蓝色*/    if(a==13) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_INTENSITY|BACKGROUND_GREEN|BACKGROUND_BLUE);
/*绿色*/    if(a==14) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_INTENSITY|BACKGROUND_GREEN);
/*紫色*/    if(a==15) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_INTENSITY|BACKGROUND_RED|BACKGROUND_BLUE);
/*红色*/    if(a==16) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_INTENSITY|BACKGROUND_RED);
/*黄色*/    if(a==17) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_INTENSITY|BACKGROUND_RED|BACKGROUND_GREEN);
/*深蓝色*/    if(a==18) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_INTENSITY|BACKGROUND_BLUE);
/*土黄色or金黄色*/    if(a==19) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|BACKGROUND_RED|BACKGROUND_GREEN);
/*灰色接近白*/    if(a==20) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY|BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE);
/*青色*/  if(a == 21) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_INTENSITY|BACKGROUND_GREEN|BACKGROUND_BLUE);
/*粉色*/  if(a == 22) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_INTENSITY|BACKGROUND_RED|BACKGROUND_BLUE);
/*原色*/  if(a == 23) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_INTENSITY);
}
void dark_color(int a){
/*亮白*/    if(a==0) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
/*蓝色*/    if(a==1) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN|FOREGROUND_BLUE);
/*绿色*/    if(a==2) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN);
/*紫色*/    if(a==3) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_BLUE);
/*红色*/    if(a==4) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED);
/*黄色*/    if(a==5) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN);
/*深蓝色*/  if(a==6) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_BLUE);
/*金黄色*/  if(a==7) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN);
/*灰色*/    if(a==8) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE);
/*青色*/    if(a==9) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_GREEN|FOREGROUND_BLUE);
/*粉色*/    if(a==10) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED|FOREGROUND_BLUE);
/*原色*/    if(a == 11) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_INTENSITY);
/*亮白*/    if(a==12) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE);
/*蓝色*/    if(a==13) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_GREEN|BACKGROUND_BLUE);
/*绿色*/    if(a==14) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_GREEN);
/*紫色*/    if(a==15) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_RED|BACKGROUND_BLUE);
/*红色*/    if(a==16) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_RED);
/*黄色*/    if(a==17) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_RED|BACKGROUND_GREEN);
/*深蓝色*/  if(a==18) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_BLUE);
/*金黄色*/  if(a==19) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_RED|BACKGROUND_GREEN);
/*灰色   */ if(a==20) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BLUE);
/*青色*/    if(a==21) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_GREEN|BACKGROUND_BLUE);
/*粉色*/    if(a==22) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),BACKGROUND_RED|BACKGROUND_BLUE);
}
namespace rnothing{
#define white 0
#define blue 1
#define green 2
#define purple 3
#define red 4
#define yellow 5
#define Blue 6
#define gold 7
#define grey 8
#define qing 9
#define pink 10
#define nothing 11
#define BG_white 12 
#define BG_blue 13
#define BG_green 14
#define BG_purple 15
#define BG_red 16
#define BG_yellow 17
#define BG_Blue 18
#define BG_gold 19
#define BG_grey 20
#define BG_qing 21
#define BG_pink 22
#define BG_first 23
}
using namespace rnothing;
void setcolor(Rule num,int op){
	if(num == Negative)
	{
		op = -op;
		light_color(log2(op));
	}
	if(num == Tile_0)
	{
		if(op == 0)op = 1;
		light_color(log2(op));
	}
	if(num == Normal || num == Gravity || num == Always_2)
	{
		light_color(log2(op));
	}
	if(num == Merge_Any)
	{
		light_color(Rand(0, 10));
	}
	if(num == Threes)
	{
		if(op == 1)light_color(0);
		if(op == 2)light_color(1);
		if(op == 3)light_color(2);
		else
		{
			op /= 3;
			light_color(log2(op) + 3);
		}
	}
	if(num == Fibonacci)
	{
		for(int i = 0;i <= 60; i++)
		{
			if(fib[i] == op) light_color(i % 10 + 1);
		}
	}
}
string changesl(int num)
{
	if(num == Normal)return "Normal";
	if(num == Always_2)return "Always_2";
	if(num == Fibonacci)return "Fibonacci";
	if(num == Threes)return "Threes";
	if(num == Merge_Any)return "Merge_Any";
	if(num == Tile_0)return "Tile_0";
	if(num == Negative)return "Negative";
	if(num == Gravity)return "Gravity";
}
void save(int type){	
	string file = "你的2048存档" + changesl(rule) + ".txt"; 
	ofstream outfile(file.c_str(),std::ios::trunc|ios::binary|ios::in|ios::out);
	//outfile to output
	outfile << ver << endl;
	outfile << sz << endl;
	for(int i = 1;i <= sz; i++)
	{
		for(int j = 1;j <= sz; j++)
		{
			outfile << p[i][j] << ' ';
		}
		outfile << endl;
	}
	for(int i = 1;i <= sz; i++)
	{
		for(int j = 1;j <= sz; j++)
		{
			outfile << f[i][j] << ' ';
		}
		outfile << endl;
	}
	outfile << score << ' ' << max_score << endl;
	outfile << rule << ' ' << ap << endl;
	outfile << decode() << endl << tag << endl;
    outfile.close();
    cls;
    if(type == 0)cout << "已成功保存为 “你的2048存档.txt”" << endl; 
    if(type == 0)Sleep(2000);
    return ;
}
void read(){
	string files;
	for(int i = 1;i <= 8; i++)
	{
		files = "你的2048存档" + changesl(i) + ".txt"; 
		if(access(files.c_str(), F_OK) == -1)
		{
			cls;
			light_color(red);
			cout << "目前还没有找到存档!\n";
			dark_color(white);
			Sleep(2000);
			return ;
		}
	}
	ifstream fin(files.c_str());
	string version;
	fin >> version;
	if(ver != version)
	{
		cls;
		dark_color(yellow);
		cout<<"警告";
		dark_color(white);
		cout<<"      你正在读取"<<version<<"的存档!\n当前版本为"<<ver<<",可能会出现漏洞,后果自负!"<<endl;
        cout<<"0,返回  1,爷知道爷在做什么"<<endl;
        int choose;
        cin>>choose;
        if(choose==1){
            cout<<"祝你好运..."<<endl;
            Sleep(1000);
        }
		else{return ;}
	}
	fin >> sz;
	for(int i = 1;i <= sz; i++)
	{
		for(int j = 1;j <= sz; j++)
		{
			fin >> p[i][j];
		}
	}
	for(int i = 1;i <= sz; i++)
	{
		for(int j = 1;j <= sz; j++)
		{
			fin >> f[i][j];
		}
	}
	fin >> score >> max_score;
	int rulep, app;
	fin >> rulep >> app;
	change_Rule(rulep);
	change_Autoplay(app); 
	string stmp;
	fin >> stmp >> tag;
	if(encode(stmp) == false)
	{
		if(tag > 0)
		{
			light_color(red);
			cout << "你触发了反作弊机制,私自改动了存档,现在给予警告";
			tag = 0;
			Sleep(2000); 
			save(1);//马上保存 
			dark_color(white);
			return ;
		}
		else
		{
			dark_color(red);
			cout << "您的信誉已不足,请新开存档!";
			dark_color(white);
			Startinit();max_score = 0;rule = Normal;ap = Stop;
			Sleep(2000);
			save(1);//马上保存 
			return ;
		}
	}
	cls;
	cout<<"成功读取存档!"<<endl;
	Sleep(2000);
	return ;
}
int spawn_(){
	switch(rule){
		case Normal : return Rand(1, 2) * 2;
		case Fibonacci : return 1;
		case Threes : return Rand(1, 3);
		case Merge_Any : return Rand(1, 2);
		case Tile_0 : return Rand(0, 2) * 2;
		case Negative : return Rand(0, 1) * 2 - 1;
		case Gravity : return Rand(1, 2) * 2;
	}
}
void spawn(){
	vector<pair<int,int> >vec;
	for (int i = 1;i <= sz;++i)
		for (int j = 1;j <= sz;++j)
			if (!f[i][j])
				vec.emplace_back(i, j);
	int x, y = -1;
	if (!cnt_empty()) return ;
	elif (cnt_empty() * 2 <= sz * sz)
		x = Rand(0, vec.size()-1);
	else {
		x = Rand(0, vec.size()-1), y = Rand(0, vec.size()-2);
		if (x <= y) ++y;
	}
	p[vec[x].first][vec[x].second] = spawn_(), f[vec[x].first][vec[x].second] = 1;
	if (~y) p[vec[y].first][vec[y].second] = spawn_(), f[vec[y].first][vec[y].second] = 1;
}
void outp(){
	for (int i = 1;i <= sz;++i){
		for (int j = 1;j <= sz;++j){
			if (i == 1){
				if (j == 1) printf("┌");
				else printf ("┬");
			}
			else {
				if (j == 1) printf("├");
				else printf ("┼");
			}
			printf ("──────────");
		}
		if (i == 1) printf ("┐\n");
		else printf ("┤\n");
		for (int j = 1;j <= sz;++j)
			if (f[i][j]) 
			{
				printf ("│"); 
				setcolor(rule, p[i][j]);
				printf ("%10lld", p[i][j]);
				dark_color(white);
			}
			else printf ("│          ");
		printf ("│\n");
	} 
	for (int j = 1;j <= sz;++j){
		if (j == 1) printf ("└");
		else printf ("┴");
		printf ("──────────");
	}
	printf ("┘\n");
}
void sup(){
	for (int i = 1;i <= sz;++i){
		vector<long long> v1, v2;
		for (int j = 1;j <= sz;++j)
			if (f[j][i])
				v1.push_back(p[j][i]);
		while (!v1.empty()){
			if (v1.size() == 1){
				v2.push_back(v1[0]);
				v1.erase(v1.begin());
			}
			elif (!mergable(v1[0], v1[1])){
				v2.push_back(v1[0]);
				v1.erase(v1.begin());
			}
			else {
				v2.push_back(v1[0] + v1[1]);
				score += v1[0] + v1[1];
				v1.erase(v1.begin());
				v1.erase(v1.begin());
			}
		}
		for (int j = 1, k = 0;j <= sz;++j, ++k){
			if (k < v2.size()) p[j][i] = v2[k], f[j][i] = 1;
			else p[j][i] = f[j][i] = 0;
		}
	}
}
void sdn(){
	for (int i = 1;i <= sz;++i){
		vector<long long> v1, v2;
		for (int j = sz;j;--j)
			if (f[j][i])
				v1.push_back(p[j][i]);
		while (!v1.empty()){
			if (v1.size() == 1){
				v2.push_back(v1[0]);
				v1.erase(v1.begin());
			}
			elif (!mergable(v1[0], v1[1])){
				v2.push_back(v1[0]);
				v1.erase(v1.begin());
			}
			else {
				v2.push_back(v1[0] + v1[1]);
				score += v1[0] + v1[1];
				v1.erase(v1.begin());
				v1.erase(v1.begin());
			}
		}
		for (int j = sz, k = 0;j;--j, ++k){
			if (k < v2.size()) p[j][i] = v2[k], f[j][i] = 1;
			else p[j][i] = f[j][i] = 0;
		}
	}
}
void sle(){
	for (int i = 1;i <= sz;++i){
		vector<long long> v1, v2;
		for (int j = 1;j <= sz;++j)
			if (f[i][j])
				v1.push_back(p[i][j]);
		while (!v1.empty()){
			if (v1.size() == 1){
				v2.push_back(v1[0]);
				v1.erase(v1.begin());
			}
			elif (!mergable(v1[0], v1[1])){
				v2.push_back(v1[0]);
				v1.erase(v1.begin());
			}
			else {
				v2.push_back(v1[0] + v1[1]);
				score += v1[0] + v1[1];
				v1.erase(v1.begin());
				v1.erase(v1.begin());
			}
		}
		for (int j = 1, k = 0;j <= sz;++j, ++k){
			if (k < v2.size()) p[i][j] = v2[k], f[i][j] = 1;
			else p[i][j] = f[i][j] = 0;
		}
	}
}
void sri(){
	for (int i = 1;i <= sz;++i){
		vector<long long> v1, v2;
		for (int j = sz;j;--j)
			if (f[i][j])
				v1.push_back(p[i][j]);
		while (!v1.empty()){
			if (v1.size() == 1){
				v2.push_back(v1[0]);
				v1.erase(v1.begin());
			}
			elif (!mergable(v1[0], v1[1])){
				v2.push_back(v1[0]);
				v1.erase(v1.begin());
			}
			else {
				v2.push_back(v1[0] + v1[1]);
				score += v1[0] + v1[1];
				v1.erase(v1.begin());
				v1.erase(v1.begin());
			}
		}
		for (int j = sz, k = 0;j;--j, ++k){
			if (k < v2.size()) p[i][j] = v2[k], f[i][j] = 1;
			else p[i][j] = f[i][j] = 0;
		}
	}
}
void Setting(){
	ReTitle("设置");
	printf("请按下对应数字键\n\n");
	printf("0 退出\n");
	printf("1 合并规则\n");
	printf("2 自动游玩\n");
	printf("3 棋盘大小\n");
	printf("4 按键设置\n");
	char ch = getch();
	while (ch < '0' || '4' < ch) ch = getch();
	switch(ch){
		case '0' : return ;
		case '1' : Setting_Merge(); break;
		case '2' : Setting_Auto(); break;
		case '3' : Setting_Size(); break;
		case '4' : Setting_Button(); break;
	}
	Setting();
}
void Setting_Merge(){
	ReTitle("设置 >> 合并设置");
	printf("请按下对应数字键(当前设置:%d)\n\n", rule); 
	printf("0 退出\n");
	printf("1 Normal\n");
	printf("2 Always_2\n");
	printf("3 Fibonacci\n");
	printf("4 Threes\n"); 
	printf("5 Merge_Any\n"); 
	printf("6 Tile_0\n"); 
	printf("7 Negative\n"); 
	printf("8 Gravity\n");
	char ch = getch();
	while (ch < '0' || '8' < ch) ch = getch();
	switch(ch){
		case '0' : return ;
		case '1' : rule = Normal; break;
		case '2' : rule = Always_2; break;
		case '3' : rule = Fibonacci; break;
		case '4' : rule = Threes; break;
		case '5' : rule = Merge_Any; break;
		case '6' : rule = Tile_0; break;
		case '7' : rule = Negative; break;
		case '8' : rule = Gravity; break;
	}
	save(1);
	Setting_Merge();
}
void Setting_Auto(){
	ReTitle("设置 >> 自动游玩");
	printf("请按下对应数字键(当前设置:%d)\n\n", ap); 
	printf("0 退出\n");
	printf("1 Stop\n");
	printf("2 Corner\n");
	printf("3 Swing\n");
	printf("4 Swirl\n"); 
	printf("5 Random\n"); 
	char ch = getch();
	while (ch < '0' || '5' < ch) ch = getch();
	switch(ch){
		case '0' : return ;
		case '1' : ap = Stop; break;
		case '2' : ap = Corner; break;
		case '3' : ap = Swing; break;
		case '4' : ap = Swirl; break;
		case '5' : ap = Random; break;
	}
	Setting_Auto();
}
void Setting_Size(){
	while(1)
	{
		Sleep(75);
		ReTitle("设置 >> 棋盘大小");
		Button plus, minus, Break;
		plus = Create(2, 4, "+");
		minus = Create(2, 0, "-");
		Break = Create(3, 0, "退出设置");
		if(click(minus))sz--;
		if (sz < 2) sz = 2;
		gotoxy(2, 2);
		cout << sz;
		if(click(plus))sz++;
		if (sz > 8) sz = 8;
		if(click(Break))break;
	}
//	printf("请输入棋盘大小(当前大小:%d):", sz);
//	scanf ("%d", &sz);
	Setting();
} 
void Setting_Button(){
	ReTitle("设置 >> 按键设置");
	printf("请按下对应键(当前设置:%c)\n\n", upc);
	printf("0 退出\n");
	printf("1 下一个\n");
	printf("小写字母 设置按键\n");
	char ch = getch();
	while (!islower(ch) && (ch < '0' || ch > '1')) ch = getch();
	switch(ch){
		case '0' : return ;
		case '1' : break;
		default : upc = ch;
	}
	ReTitle("设置 >> 按键设置");
	printf("请按下对应键(当前设置:%c)\n\n", dnc);
	printf("0 退出\n");
	printf("1 下一个\n");
	printf("小写字母 设置按键\n");
	ch = getch();
	while (!islower(ch) && (ch < '0' || ch > '1')) ch = getch();
	switch(ch){
		case '0' : return ;
		case '1' : break;
		default : dnc = ch;
	}
	ReTitle("设置 >> 按键设置");
	printf("请按下对应键(当前设置:%c)\n\n", lec);
	printf("0 退出\n");
	printf("1 下一个\n");
	printf("小写字母 设置按键\n");
	ch = getch();
	while (!islower(ch) && (ch < '0' || ch > '1')) ch = getch();
	switch(ch){
		case '0' : return ;
		case '1' : break;
		default : lec = ch;
	}
	ReTitle("设置 >> 按键设置");
	printf("请按下对应键(当前设置:%c)\n\n", ric);
	printf("0 退出\n");
	printf("1 下一个\n");
	printf("小写字母 设置按键\n");
	ch = getch();
	while (!islower(ch) && (ch < '0' || ch > '1')) ch = getch();
	switch(ch){
		case '0' : return ;
		case '1' : break;
		default : ric = ch;
	}
	Setting_Button();
}
void Show_Rule(){
	ReTitle("游戏规则");
	Say("首先是合并规则\n\n");
	Sleep(1500);
	printf("规则:Normal\n");
	printf("\t正常的 2048(只会生成数字 2,4)\n\n");
	printf("规则:Always_2\n");
	printf("\t只会生成数字 2\n\n");
	printf("规则:Fibonacci\n");
	printf("\t只会生成数字 1\n");
	printf("\t只能合并两个相邻的斐波那契数\n\n");
	printf("规则:Threes\n");
	printf("\t只会生成数字 1, 2, 3\n");
	printf("\t只能合并 1,2 或者 x,x(x>2)\n\n");
	printf("规则:Merge_Any\n");
	printf("\t只会生成数字 1, 2\n");
	printf("\t可以合并任何数!冲冲冲!\n\n");
	printf("规则:Tile_0\n");
	printf("\t有可能生成数字 0\n");
	printf("\t0 只能和 0 合并\n\n");
	printf("规则:Negative\n");
	printf("\t只生成数字 -1, 1\n");
	printf("\t只能合并 x,x 或者 x,-x\n\n");
	printf("规则:Gravity\n");
	printf("\t在重力环境下运行的2048!\n\n");
	Sleep(1500);
	Say("按任意键继续……");
	char ch = getch();
	ReTitle("游戏规则");
	Say("其次是自动游玩规则\n\n");
	Say("自动游玩需要您长按空格\n\n");
	Sleep(1500);
	printf("规则:Corner\n");
	printf("\t往一个角移动\n\n");
	printf("规则:Swing\n");
	printf("\t左右左右,让我们一起摇摆\n\n");
	printf("规则:Swirl\n");
	printf("\t上下左右上下左右……\n\n");
	printf("规则:Random\n");
	printf("\t随机,看rp\n\n");	
	printf("规则:Stop\n");
	printf("\t不开启自动游玩\n\n");
	Sleep(1500);
	Say("按任意键继续……");
	ch = getch();
	ReTitle("游戏规则");
	Say("你可以修改这些设置,还有一些其他的设置哦\n\n");
	Sleep(1500);
	Say("按任意键退出");
	ch = getch();
	return ;
}
int main(){ Main(); }