编译器需要支持C++11
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include <unistd.h>
#include <cstdio>
#include <fcntl.h>
#include <pthread.h>
#include <termios.h>
using namespace std;
class Posi{
private:
int y;
int x;
char c;
public:
int getY(void)const{return y;}
int getX(void)const{return x;}
char getC(void)const{return c;}
void setY(int Y){y = Y;}
void setX(int X){x = X;}
void setC(char C){c = C;}
Posi():y(0),x(0),c('H'){}
Posi(int Y,int X,char C):y(Y),x(X),c(C){}
//Posi(Posi& a):y(a.getY()),x(a.getX()),c(getC()){}
~Posi(){}
bool operator==(const Posi& a)const{
return (y==a.getY() && x==a.getX());
}
friend ostream& operator<<(ostream& out,const Posi& a);
};
ostream& operator<<(ostream& out,const Posi& a){
out<< "\033["<<to_string(a.getY())<<";"
<<to_string(a.getX())<<"H"<<a.c;
return out;
}
class Snake{
private:
vector<Posi> body;
int direction; //0:up 1:down 2:left 3:right
bool crash;
public:
Snake():direction(1),crash(false){}
Snake(char head):direction(1),crash(false){
body.push_back(Posi{0,0,head});
}
Snake(Posi p):direction(1),crash(false){
body.push_back(p);
}
int length(void)const{
return body.size();
}
Posi getHead(void)const{
return body[0];
}
void setDir(int dir){
direction = dir;
}
bool isOver(void)const{
return crash;
}
bool findP(Posi& a)const{
return (find(body.begin(),body.end(),a)!=body.end());
}
void extendBody(Posi a){
body.push_back(a);
}
void move(void){
if(length()!=0){
for(int i=body.size()-1,j = 0;i>0;--i){
j = i-1;
body[i].setY(body[j].getY());
body[i].setX(body[j].getX());
}
if(direction==0 && body[0].getY()>1){
body[0].setY(body[0].getY()-1);
body[0].setX(body[0].getX());
}else if(direction==1 && body[0].getY()<20){
body[0].setY(body[0].getY()+1);
body[0].setX(body[0].getX());
}else if(direction==2 && body[0].getX()>1){
body[0].setY(body[0].getY());
body[0].setX(body[0].getX()-1);
}else if(direction==3 && body[0].getX()<20){
body[0].setY(body[0].getY());
body[0].setX(body[0].getX()+1);
}else{
crash = true;
}
if(find(body.begin()+1,body.end(),body[0])!=body.end())
crash = true;
}
}
friend ostream& operator<<(ostream&,Snake&);
~Snake(){}
};
ostream& operator<<(ostream& out,Snake& a){
out<< "\033[2J";
if(a.crash==false){
for(vector<Posi>::iterator it=(a.body).begin();it!=(a.body).end();++it)
out<< *it;
}else{
out << "GameOver" << endl;
}
return out;
}
class TermScreen{
private:
Snake& snake;
Posi& food;
public:
TermScreen(Snake& s,Posi& p):snake(s),food(p){}
void feed(void){
food.setX(5);
food.setY(5);
while(snake.findP(food)){
food.setX((food.getX()+11)%20);
food.setY((food.getY()+13)%20);
}
food.setC('a'+(food.getX()+food.getY())%26);
}
void eat(void){
if(snake.getHead()==food){
snake.extendBody(food);
feed();
}
snake.move();
}
friend ostream& operator <<(ostream& out,TermScreen& t);
~TermScreen(){}
};
ostream& operator<<(ostream& out,TermScreen& t){
out<< t.snake;
out<< t.food;
}
void setStdoutNoBuff(ostream& out){
out.setf(ios::unitbuf);
}
void setTerm(void){
struct termios option;
tcgetattr(0,&option);
option.c_lflag &=~(ICANON|ECHO|ECHOE);
tcsetattr(0,TCSANOW,&option);
}
void recoverTerm(void){
struct termios option;
tcgetattr(0,&option);
option.c_lflag |=(ICANON|ECHO|ECHOE);
tcsetattr(0,TCSANOW,&option);
}
/*
void setStdoutNoEcho(ostream& out){
}
void setStdinNoBuff(istream& in){
in.setf(ios::unitbuf);
}
void setStdinNonBlock(void){
int flags;
flags = fcntl(STDIN_FILENO,F_GETFL);
flags |=O_NONBLOCK;
if(fcntl(STDIN_FILENO,F_SETFL,flags)<0){
perror("fcntl");
exit(EXIT_FAILURE);
}
}*/
void *getDirection(Snake* s){
char buf[10];
while(1){
int r = read(STDIN_FILENO,buf,1);
if(r>0){
if(buf[0]=='a')
s->setDir(2);
else if(buf[0]=='w')
s->setDir(0);
else if(buf[0]=='s')
s->setDir(1);
else if(buf[0]=='d')
s->setDir(3);
}
if(s->isOver()){
break;
}
}
pthread_exit(NULL);
}
int main(void){
setStdoutNoBuff(cout);
setTerm();
// setStdinNonBlock();
Snake s;
s.extendBody(Posi(5,6,'c'));
s.extendBody(Posi(5,5,'d'));
s.extendBody(Posi(5,4,'a'));
s.extendBody(Posi(4,4,'t'));
Posi food(4,9,'f');
TermScreen t(s,food);
cout << t;
pthread_t thread_id;
pthread_create(&thread_id,NULL,(void*(*)(void*))getDirection,&s);
while(1){
t.eat();
cout << t;
if(s.isOver()){
break;
}
sleep(1);
}
pthread_join(thread_id,NULL);
recoverTerm();
return 0;
}