/*设计原理

①设计格子
 ②让一个方块动起来
 ③让一组方块动起来
 用数组记录每个格子4个点的坐标也就是区域,这样在重画时只用选中数组中的项就可以,关于动,
 使用计时器,根据按的上下左右,来更新一个方块的x或y方块,一组方块动起来,就是去掉一个在另一边加一个
 ④生成随机方块
 ⑤吃子,头部坐标与子坐标相同,吃掉*/

//自定义头文件

#ifndef SNAKE_H
#define SNAKE_H
#include<iostream>
#include<windows.h>
#include<vector>
using namespace std;
const int wall=25;
class Snakeclass
{
 private:
  COORD tailcoord,foodcoord;
  vector<COORD> snake;
  vector<COORD> map2;
  int snakesize,j,i,a;
  int m,mark,speech;
  bool pattern;
 public:
  Snakeclass(){m=wall/2,i=0,j=2,a=0,snakesize=4,mark=0,speech=500;}
  ~Snakeclass(){}
  void showmenu();//菜单
  void showmap1();//经典地图
  void showmap2(int);//街机地图
  void drawsnake();//初始化蛇身坐标
  void snakemove();//蛇移动判断
  void showmark();//显示当前分数
  void food();//食物生成
  void judgedie();//判断死亡
  void customspass();//关卡切换
  void savemark();//记录分数
  void showsavemark();//读取记录分数
  void showface(); //显示表情
  void gotoxy(int x,int y);//控制光标函数
  void HideCursor();//隐藏光标函数
  void color(int a);//控制颜色函数
};
#endif

//函数定义和主程序

#include"snakeclass.h"
#include<iostream>
#include<math.h>
#include<fstream>
#include<iomanip>
#include<windows.h>
#include<ctime>
#include<cstdlib>
#include<conio.h>
#include<vector>
void Snakeclass::gotoxy(int x,int y)//位置函数,输入坐标后,光标会移动到那个位置以便进行输出
{
 COORD pos;
 pos.X=2*x;   //下面输出的图形都占两个位置
 pos.Y=y;
 SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos);//光标控制的位置
}
void Snakeclass::HideCursor()//隐藏光标
{
  CONSOLE_CURSOR_INFO cursor_info = {1, 0};
  SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}
void Snakeclass::color(int a)//颜色函数
{
 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a);//只有一个参数
}
void Snakeclass::showmap1()
{ 
 COORD cod;
 for(int i=0;i<=wall;++i)
 {
     for(int j=0;j<=wall;++j)
  {
         if(i==0||i==wall||j==0||j==wall)
      {
          gotoxy(i ,j);
           color(10);
           cout<<"■";
      }//围墙
       else
    {
         gotoxy(i ,j);
          color(3);
          cout<<"□" ;
    }//可以玩的区域
   }
    }
 for(int i=0;i!=snakesize;++i)
 {
  cod.X=m;
  cod.Y=wall-snakesize+i;
  snake.push_back(cod);
 }
    showface();
}
void Snakeclass::showmap2(int a)
{
 COORD cod;
 switch(a)
 {
  case 1:break;
  case 2:for(int i=m-2;i!=m+3;++i)
   {
    for(int j=m-2;j!=m+3;++j)
    {
     cod.X=i;
     cod.Y=j;
     map2.push_back(cod);
    }
    for(int i=5;i!=10;++i) 
    {
     cod.X=i;
     cod.Y=5;
     map2.push_back(cod);
     cod.X=5;
     cod.Y=i;
     map2.push_back(cod);
     cod.X=10+i;
     cod.Y=5;
     map2.push_back(cod);
     cod.X=19;
     cod.Y=i;
     map2.push_back(cod);
     cod.X=i;
     cod.Y=19;
     map2.push_back(cod);
     cod.X=5;
     cod.Y=10+i;
     map2.push_back(cod);
     cod.X=10+i;
     cod.Y=19;
     map2.push_back(cod);
     cod.X=19;
     cod.Y=10+i;
     map2.push_back(cod);
    }
   }break;
  case 3:for(int i=7;i!=22;++i)
   {
    cod.X=i;
    cod.Y=9;
    map2.push_back(cod);
   }
   for(int j=9;j!=13;++j)
   {
    cod.X=7;
    cod.Y=j;
    map2.push_back(cod);
   }
   for(int j=9;j!=19;++j)
   {
    cod.X=21;
    cod.Y=j;
    map2.push_back(cod);
   }
   for(int i=4;i!=22;++i)
   {
    cod.X=i;
    cod.Y=18;
    map2.push_back(cod);
    cod.X=i;
    cod.Y=6;
    map2.push_back(cod);
   }
   for(int i=4;i!=19;++i)
   {
    cod.X=i;
    cod.Y=15;
    map2.push_back(cod);
   }
   for(int j=12;j!=16;++j)
   {
    cod.X=18;
    cod.Y=j;
    map2.push_back(cod);
   }
   for(int j=6;j!=16;++j)
   {
    cod.X=4;
    cod.Y=j;
    map2.push_back(cod);
   }break;
 }
 for(vector<COORD>::iterator beg=map2.begin();beg!=map2.end();++beg)
 {
  gotoxy(beg->X,beg->Y);
        color(10);
     cout<<"■";
    }
}
void Snakeclass::showmenu()
{
 showmap1();
 a=0;
 COORD cod1,cod2;
 char ch;
 bool well=true,well1;
 gotoxy(m-2,m-2);
 cout<<"●经典模式";
 gotoxy(m-2,m+2);
 cout<<"●街机模式";
 cod1.X=m-4;
 cod1.Y=m-2;
 cod2.X=m-4;
 cod2.Y=m+2;
 while(well)
 {
  well1=true;
  COORD codtemp=cod1;
  gotoxy(codtemp.X,codtemp.Y);
  color(14);
     cout<<"★";
     gotoxy(cod2.X,cod2.Y);
  color(3);
        cout<<"□" ;
  if(kbhit())
  {
   gotoxy(wall,wall);
   ch=getch();
   if(ch!='W'&&ch!='w'&&ch!='D'&&ch!='d'&&ch!='S'&&ch!='s')
   {
    well1=false;
   }
   if(well1)
   {
    switch(ch)
    {
     case 'W':
     case 'w':codtemp=cod1,cod1=cod2,cod2=codtemp;break;
     case 'S':
        case 's':codtemp=cod1,cod1=cod2,cod2=codtemp;break;
        case 'D':
        case 'd':codtemp.X+=2;break;
       }
   }
   
      if(codtemp.X==m-2&&codtemp.Y==m+2)
      {
       pattern=true;
       well=false;
   }
   if(codtemp.X==m-2&&codtemp.Y==m-2)
   {
    pattern=false;
    well=false;
   }
  }
 }
}
void Snakeclass::drawsnake()
{ 
    for(vector<COORD>::iterator beg=snake.begin();beg!=snake.end()-1;++beg)
 {
  gotoxy(beg->X,beg->Y);
        color(14);
        cout<<"★"<<endl;
    }
    showmark();
    gotoxy(wall+2,0);
    cout<<"        《贪吃蛇》";
    gotoxy(wall+2,1);
    cout<<"w,a,s,d控制方向,空格暂停,按住L_SHIFT加速。";
    gotoxy(wall+2,wall);
    color(2);
    cout<<"制作:刁民工作室";
}
void Snakeclass::snakemove()
{ 
 showsavemark();
 int speechtemp1,speechtemp2;
 char ch,sh;
 COORD cd;
 bool well=false,well2=false,well3=true,well4=true;
 while(1)
 { 
  cd.X=snake.begin()->X;
  cd.Y=snake.begin()->Y;
  if(kbhit())
  {
   ch=getch();
   if(well3)
   {
    food();
    well3=false;
   } 
  }
  if(GetAsyncKeyState(VK_LSHIFT) & 0x8000)
  {
   speechtemp2=50;
  }
  else
  {
   speechtemp2=speechtemp1;
  }
  if(((sh=='a'||sh=='A')&&(ch=='D'||ch=='d'))||((sh=='D'||sh=='d')&&(ch=='A'||ch=='a'))||((sh=='W'||sh=='w')&&(ch=='S'||ch=='s'))||((sh=='S'||sh=='s')&&(ch=='W'||ch=='w'))||(ch!='A'&&ch!='a'&&ch!='W'&&ch!='w'&&ch!='D'&&ch!='d'&&ch!='S'&&ch!='s'&&ch!=' '))
       {ch=sh;}
  switch(ch)
  {
   case 'W':
   case 'w':--cd.Y,well=true;break;
   case 'S':
      case 's':++cd.Y,well=true;break;
      case 'A':
      case 'a':--cd.X,well=true;break;
      case 'D':
      case 'd':++cd.X,well=true;break;
      case ' ':well=false;break;
     }
     if(ch!=' ')
  sh=ch;
  if(well)
  {   
   if(snake.begin()->X==foodcoord.X&&snake.begin()->Y==foodcoord.Y)
   {
    well2=true;
    mark+=10;
    if(mark%50==0)
    {
     ++i;
     showface();
     gotoxy(wall+2,m+2);
           color(14);
           cout<<"升级加速!第"<<i<<"阶段";
     speech-=25;
    }
    if(pattern)
    {
     if(mark%100==0)
     {
      if(j==2)
      {
       j=3;
      }
      else
      j=2;
      customspass();
     } 
    }
    snake.begin()->X=foodcoord.X;
    snake.begin()->Y=foodcoord.Y;
    snake.push_back(foodcoord);
    color(14);
    showmark();
   } 
   if(well2)
   {
    food();
    well2=false;
   }
   vector<COORD>::reverse_iterator rbeg=snake.rbegin();
      while(rbeg!=snake.rend()-1)
   {
          rbeg->X=(rbeg+1)->X;
          rbeg->Y=(rbeg+1)->Y;
          ++rbeg;
      }
   snake.begin()->X=cd.X;
    snake.begin()->Y=cd.Y;
    judgedie();
      tailcoord.X=snake.rbegin()->X;
   tailcoord.Y=snake.rbegin()->Y;
         gotoxy(snake.begin()->X,snake.begin()->Y);
         color(14);
         cout<<"★"<<endl;
   gotoxy(tailcoord.X,tailcoord.Y);
   color(3);
         cout<<"□";
  }
  speechtemp1=speech;
  Sleep(speechtemp2);
 }
}
void Snakeclass::customspass()
{
 if(pattern)
 {
  snake.clear();
  map2.clear();
  showmap1();
  showmap2(j);
  drawsnake();
  snakemove();
 }
 else
 {
  snake.clear();
  map2.clear();
  showmap1();
  drawsnake();
  snakemove();
 }
}
void Snakeclass::food()
{
begin:
 srand((unsigned)time(NULL));
    foodcoord.X=rand()%(wall-1)+1;
    foodcoord.Y=rand()%(wall-1)+1;
 for(vector<COORD>::iterator beg=snake.begin();beg!=snake.end();++beg)
 {
  if(foodcoord.X==beg->X&&foodcoord.Y==beg->Y)
  {
   goto begin;
  }
    }
    for(vector<COORD>::iterator beg=map2.begin();beg!=map2.end();++beg)
 {
  if(foodcoord.X==beg->X&&foodcoord.Y==beg->Y)
  {
   goto begin;
  }
    }
 gotoxy(foodcoord.X,foodcoord.Y);
 color(15);
 cout<<"●";
}
void Snakeclass::showmark()
{
 gotoxy(wall+2,m+1);
 cout<<"分数:"<<mark;
}
void Snakeclass::savemark()
{
 ofstream file("贪吃蛇排行榜.txt",ios::out|ios::app);
 file<<mark<<endl;
 file.close();
}
void Snakeclass::showsavemark()
{
 color(14);
 int a,n=0,temp;
 ifstream file("贪吃蛇排行榜.txt",ios::in);
 while(file>>a)
 ++n;
 file.close();
 ifstream file2("贪吃蛇排行榜.txt",ios::in);
 int num[n];
 for(int i=0;i!=n;++i)
 {
  file2>>num[i]; 
 }
 file2.close();
 for(int i=0;i!=n;++i)
 {
  for(int j=i+1;j!=n;++j)
  {
   if(num[i]<num[j])
   {
    temp=num[i];
    num[i]=num[j];
    num[j]=temp;
   }
  }
 }
 gotoxy(wall+2,m+4);
 cout<<"分数排行:"<<endl;
 for(int i=0;i!=n;++i)
 {
  if(i==5)
  break;
  gotoxy(wall+2,m+5+i);
  cout<<"NO."<<i+1<<":"<<num[i]<<endl;
 } 
}
void Snakeclass::judgedie()
{
 if(snake.begin()->X==0||snake.begin()->X==wall||snake.begin()->Y==0||snake.begin()->Y==wall)
    {
        gotoxy(m-3,m);
        color(14);
        cout<<"你把墙撞穿了!";
        savemark();
        showsavemark();
        gotoxy(wall+6,wall);
        exit(0);
 }
 for(vector<COORD>::iterator beg=map2.begin();beg!=map2.end();++beg)
 {
  if(snake.begin()->X==beg->X&&snake.begin()->Y==beg->Y)
  {
   gotoxy(m-3,m);
         color(14);
         cout<<"你把墙撞穿了!";
         savemark();
         showsavemark();
         gotoxy(wall+6,wall);
         exit(0);
  }
    }
 for(vector<COORD>::iterator beg=snake.begin()+1;beg!=snake.end();++beg)
 {
  if(snake.begin()->X==beg->X&&snake.begin()->Y==beg->Y)
  {
   gotoxy(m-3,m);
         color(14);
         cout<<"你把自己吃了!";
         savemark();
         showsavemark();
         gotoxy(wall+6,wall);
         exit(0);
  }
    }
}
void Snakeclass::showface()
{
 if(a==1)
 {
  a=2;
 }
 else
 a=1;
 switch(a)
 {
  case 1:color(15);
    gotoxy(wall+2,3);
    cout<<"                              ";
    gotoxy(wall+2,4);
    cout<<"(”\\( ●—● )";
    gotoxy(wall+2,5);
    cout<<"                              ";
    gotoxy(wall+2,6);
    cout<<"  \\  /       ○ \\ \\        ";
    gotoxy(wall+2,7);
    cout<<"                              ";
    gotoxy(wall+2,8);
    cout<<"   (            )”         ";
    gotoxy(wall+2,9);
    cout<<"                              ";
    gotoxy(wall+2,10);
    cout<<"     \\ __ /\\ __ /           ";
    gotoxy(wall+2,11);
    cout<<"                              ";break;
  case 2:color(14);
    gotoxy(wall+2,3);
    cout<<" へ     /|";
    gotoxy(wall+2,4);
    cout<<" /\7    ∠_/";
    gotoxy(wall+2,5);
    cout<<" / │   / /";
    gotoxy(wall+2,6);
    cout<<"│ Z _,< /   /`ヽ";
    gotoxy(wall+2,7);
    cout<<"│     ヽ   /  〉";
    gotoxy(wall+2,8);
    cout<<"Y     `  /  /     \\";
    gotoxy(wall+2,9);
    cout<<"ィ● 、 ●  ()〈  /";
    gotoxy(wall+2,10);
    cout<<"()  へ    | \〈";
    gotoxy(wall+2,11);
    cout<<" >- 、_  ィ ";break;
 }
}
int main()
{
 Snakeclass csnake;
 csnake.HideCursor();
 csnake.showmenu();
 csnake.customspass();
 return 0;
}