这是我使用ncurses库在C++中使用的蛇版本。我想听听您如何改进这段代码,以及对未来项目的编码和效率的一般建议。我尝试过用纯OOP编写这段代码,也让我知道这一点。
#include<ncurses.h>
#include<unistd.h>
#include<time.h>
#include<stdlib.h>
class snake //to store the x and y coordinates of each snake part
{
int x, y;
char ch;
public:
snake(){ x= y= 0; ch='O';}
snake(int a, int b)
{
x= a; y= b; ch= 'O';
}
snake(const snake &ekans)
{
ch= ekans.ch;
x= ekans.x;
y= ekans.y;
}
void setCh(char x)
{
ch= x;
}
char getCh()
{
return ch;
}
int getX()
{
return x;
}
void setX(int no)
{
x= no;
}
int getY()
{
return y;
}
void setY(int no)
{
y= no;
}
};
class list //to store each snake body
{
node* head;
int length;
public:
list()
{
head= NULL;
length= 0;
}
void add(snake s) //adds at the end
{
node *n= new node;
n->setSnake(s);
n->setNext(head);
head= n;
length++;
}
int listLength()
{
return length;
}
snake get(int n)
{
node *temp =head;
int count= 1;
while(count!= n && temp!= NULL)
{
count++;
temp= temp->getNext();
}
return temp->getSnake();
}
void remove() //removes the first element
{
node *temp= head->getNext();
node *t2= head;
while(temp->getNext()!=NULL)
{
temp=temp->getNext();
t2= t2->getNext();
}
t2->setNext(NULL);
delete temp;
length--;
}
void display()
{
int i= 0;
node *temp= head;
while(temp!= NULL)
{
mvaddch(10,10+i,temp->getSnake().getCh());
mvprintw(20,5,"THIS LOVE");
refresh();
temp= temp->getNext();
}
}
~list()
{
while(head!= NULL)
{
node* n= head;
head= head->getNext();
delete n;
}
length= 0;
}
};
class game
{
int score, max_y, max_x, food_x, food_y, direction;
list l;
public:
game()
{
score= max_y= max_x= food_x= food_y= 0;
direction= 2;
}
void launch();
void play();
void map();
void genFood();
void setSnake();
void moveSnake(int dir);
bool check();
};
void game:: launch()
{
initscr(); //initialize ncurses
cbreak(); //no line buffering
curs_set(FALSE);
keypad(stdscr, TRUE);
noecho();
refresh();
attron(A_BOLD);
mvprintw(LINES/2-2, COLS/2-10, "SNAKES WELCOMES YOU");
mvprintw(LINES/2, COLS/2-12, "PRESS ENTER TO CONTINUE");
int ch;
if((ch= getch())==10)
{
getmaxyx(stdscr, max_y, max_x);
play();
}
else
{
clear();
mvprintw(LINES/2, COLS/2- 16, "YOU DID NOT EVEN GIVE ME A CHANCE......GOODBYE");
refresh();
sleep(2);
}
attroff(A_BOLD);
endwin();
}
void game:: genFood()
{
srand(time(NULL));
food_y= random()%(max_y-6)+4;
food_x= random()%(max_x-4)+2;
}
void game:: map()
{
box(stdscr, 0, 0);
mvprintw(1,1, "SCORE: ");
mvprintw(1,8, "%d",score);
mvprintw(2,1, "Press q to quit");
refresh();
}
void game:: setSnake()
{
clear();
map();
for(int i= 0; i< 8; i++)
{
snake s((COLS/2)-8+i, LINES/2);
l.add(s);
mvprintw(s.getY(),s.getX(),"%c",s.getCh());
}
mvprintw(food_y, food_x, "F");
refresh();
}
void game::play()
{
bool b;
genFood();
setSnake();
mvprintw(8, COLS/2-20, "??????????READY??????????????");
refresh();
sleep(1);
int ch= 0;
timeout(50); //adjust speed of the game
while((ch=getch())!= 'q')
{
switch(ch)
{
case KEY_UP: direction= 1;
break;
case KEY_DOWN: direction= 3;
break;
case KEY_RIGHT: direction= 2;
break;
case KEY_LEFT: direction= 4;
break;
}
clear();
map();
mvprintw(food_y, food_x,"F");
moveSnake(direction);
refresh();
b= check();
if(!b)
{
clear();
mvprintw(max_y/2-2, max_x/2-8, "GAME OVER");
mvprintw(max_y/2, max_x/2-10, "YOUR SCORE %d",score);
refresh();
sleep(2);
break;
}
}
}
bool game:: check()
{
bool b= false;
snake s= l.get(1);
int head_x= s.getX();
int head_y= s.getY();
if(head_x== max_x-1 || head_y== 1 || head_x== 1 || head_y== max_y-1)
return false;
else
{
int len= l.listLength();
for(int i= 4; i< len; i++)
{
s= l.get(i);
if(head_x== s.getX() && head_y== s.getY())
{
b= true;
break;
}
}
if(b)
return false;
else
return true;
}
}
void game:: moveSnake(int dir)
{
snake k;
k= l.get(1);
int x= k.getX(), y= k.getY();
//mvprintw(6,1, "BEFORE x= %d, y= %d, dir=%d",x,y,dir);
if(dir== 1) y--;
else if(dir== 2) x++;
else if(dir== 3) y++;
else x--;
//mvprintw(7,1, "AFTER x=%d, y= %d", x, y);
snake s(x,y);
l.add(s);
if(x==food_x && y==food_y)
{
score++;
genFood();
mvprintw(food_y, food_x, "F");
}
else
l.remove();
int len= l.listLength();
for(int i= 1; i<= len; i++)
{
k= l.get(i);
mvaddch(k.getY(), k.getX(), k.getCh());
refresh();
}
}
int main()
{
game g;
g.launch();
return 0;
} 发布于 2016-02-26 13:52:44
if(b)
return false;
else
return true;使用!运算符,您可以否定一个布尔值。
因此,通过说!b,您可以交换周围的情况:
if(!b)
return true;
else
return false;但是,如果b不为真,则返回true,否则返回false。此时,您最好返回“b是否为真”。
就像这样:
return !b;除此之外,也许b并不是真正合适的名字。collided怎么样?也可能是collisionFound。
bool game:: check()
{
bool collisionFound= false;
snake s= l.get(1);
int head_x= s.getX();
int head_y= s.getY();
if(head_x== max_x-1 || head_y== 1 || head_x== 1 || head_y== max_y-1)
return false;
else
{
int len= l.listLength();
for(int i= 4; i< len; i++)
{
s= l.get(i);
if(head_x== s.getX() && head_y== s.getY())
{
collisionFound = true;
break;
}
}
return !collisionFound;
}
}也许你应该给函数checkCollision贴上标签。但很奇怪你会把底片还给我。让我们看看你在用这个..。
b= check();
if(!b)嗯..。
这里没有必要存储到b,您只需说if(!checkCollision())。但这看起来很奇怪,游戏结束了,如果不是碰撞。这是因为您使check更像一个check if snake is okay函数,但是它确实检查了冲突,然后否定了结果。所以你最好去掉否定:
bool game:: checkForCollision()
{
bool collisionFound= false;
snake s= l.get(1);
int head_x= s.getX();
int head_y= s.getY();
if(head_x== max_x-1 || head_y== 1 || head_x== 1 || head_y== max_y-1)
return true;
else
{
int len= l.listLength();
for(int i= 4; i< len; i++)
{
s= l.get(i);
if(head_x== s.getX() && head_y== s.getY())
{
collisionFound = true;
break;
}
}
return collisionFound;
}
}然后像这样使用:
if(checkForCollision())
{
clear();
mvprintw(max_y/2-2, max_x/2-8, "GAME OVER");
mvprintw(max_y/2, max_x/2-10, "YOUR SCORE %d",score);
refresh();
sleep(2);
break;
}如果您充分使用描述性函数名和变量名,代码最终会读起来像一种奇怪的英语形式。
在这里,您开始检查从第4段开始的蛇段。
int len= l.listLength();
for(int i= 4; i< len; i++)我明白它背后的逻辑:蛇的形状是这样的:
. = not snake
o = snake head
^<>v = snake body
....
.v<.
.o^.
....不可能与索引1、2和3发生冲突,对吗?只有一条头和四节或更长的蛇才能碰撞,那么为什么不只检查4段及以后的碰撞,来节省一些性能呢?
除了..。如果我们把蛇倒过来怎么办?
你会得到一条皱巴巴的蛇。
....
.ô<.
.^..
....可怜的凯康人。
撇开笑话不说,你应该为这个案子想点办法。我玩的一些蛇游戏会给我一个即时的游戏,而我玩的一些蛇游戏不允许我向后移动(因为蛇不能向后移动)。不允许玩家向后移动可能会对玩家更友好,因为如果玩家按错了按钮,他们可能会意外中断。
case KEY_UP: direction= 1;
break;
case KEY_DOWN: direction= 3;
break;
case KEY_RIGHT: direction= 2;
break;
case KEY_LEFT: direction= 4;
break;想象一下你没有KEY_UP,KEY_DOWN,KEY_RIGHT和KEY_LEFT。您的代码将如下所示:
case 38: direction= 1;
break;
case 40: direction= 3;
break;
case 39: direction= 2;
break;
case 37: direction= 4;
break;很难理解,不是吗!
除了..。你对direction也做过同样的事。您应该尝试为方向定义常量。让我们使用一个枚举来完成这个任务。
因此,在代码的顶部定义您的方向:
enum Direction { UP, DOWN, LEFT, RIGHT };声明游戏的direction变量为Direction:
Direction direction;并使用如下方式:
case KEY_UP: direction= UP;
break;
case KEY_DOWN: direction= DOWN;
break;
case KEY_RIGHT: direction= RIGHT;
break;
case KEY_LEFT: direction= LEFT;
break;(如果您将类和枚举保存在不同的文件中,则可能需要使用::访问它,如Direction::LEFT)。
if(dir== UP) y--;
else if(dir== RIGHT) x++;
else if(dir== DOWN) y++;
else x--;发布于 2016-02-28 02:10:06
在" list“类中,您实现了链接列表行为,它为get和add函数提供了O(N)时间复杂度。您可以使用C++容器,例如向量,它为添加/删除/获取函数提供了固定的时间,请参阅push_back、擦除、pop_back...functions。
food_x,food_y
似乎只有蛇的第一部分被移动了。
k= l.get(1);
如果(ch= getch())==10) food_y=随机()%(max_y-6)+4;food_x=随机()%(max_x-4)+2;mvprintw(1,8,"%d",分数);
int head_x= s.getX();int head_y= s.getY();if(head_x== max_x-1 head_y== _x_y-1)
发布于 2016-02-28 16:31:23
这是我的代码的更新版本。使用了@Pimgd给我的很多建议。更改/改进了一些函数和变量名。简化了一些函数。这场比赛有点友好。当你想倒退的时候不会把游戏打印出来。
#include<ncurses.h>
#include<unistd.h>
#include<time.h>
#include<stdlib.h>
enum Direction {Up=1 , Right, Down, Left}; //added to improve understanding of the code
class snake //to store the x and y coordinates of each snake part
{
int x, y;
char ch;
public:
snake(){ x= y= 0; ch='O';}
snake(int a, int b)
{
x= a; y= b; ch= 'O';
}
snake(const snake &ekans)
{
ch= ekans.ch;
x= ekans.x;
y= ekans.y;
}
void setCh(char x)
{
ch= x;
}
char getCh()
{
return ch;
}
int getX()
{
return x;
}
void setX(int no)
{
x= no;
}
int getY()
{
return y;
}
void setY(int no)
{
y= no;
}
};
class node //to make a linked list
{
node* next;
snake s;
public:
snake getSnake()
{
return s;
}
void setSnake(snake ekans)
{
s= ekans;
}
void setNext(node *n)
{
next= n;
}
node* getNext()
{
return next;
}
};
class list //to store each snake body
{
node* head;
int length;
public:
list()
{
head= NULL;
length= 0;
}
void add(snake s) //adds at the end
{
node *n= new node;
n->setSnake(s);
n->setNext(head);
head= n;
length++;
}
int listLength()
{
return length;
}
snake get(int n)
{
node *temp =head;
int count= 1;
while(count!= n && temp!= NULL)
{
count++;
temp= temp->getNext();
}
return temp->getSnake();
}
void remove() //removes the first element
{
node *temp= head->getNext();
node *t2= head;
while(temp->getNext()!=NULL)
{
temp=temp->getNext();
t2= t2->getNext();
}
t2->setNext(NULL);
delete temp;
length--;
}
void display()
{
int i= 0;
node *temp= head;
while(temp!= NULL)
{
mvaddch(10,10+i,temp->getSnake().getCh());
refresh();
temp= temp->getNext();
}
}
~list()
{
while(head!= NULL)
{
node* n= head;
head= head->getNext();
delete n;
}
length= 0;
}
};
class game
{
int score, max_y, max_x, food_x, food_y;// direction, prev_dir;
Direction direction, prev_dir;
list l;
public:
game()
{
score= max_y= max_x= food_x= food_y= 0;
prev_dir= direction= Right;
}
void launch();
void play();
void map();
void genFood();
void setSnake();
void moveSnake(Direction dir);
bool checkForCollision(); //changed
};
void game:: launch()
{
initscr(); //initialize ncurses
cbreak(); //no line buffering
curs_set(FALSE);
keypad(stdscr, TRUE);
noecho();
refresh();
attron(A_BOLD);
mvprintw(LINES/2-2, COLS/2-10, "SNAKES WELCOMES YOU");
mvprintw(LINES/2, COLS/2-12, "PRESS ENTER TO CONTINUE");
int ch;
if((ch= getch())==10)
{
getmaxyx(stdscr, max_y, max_x);
play();
}
else
{
clear();
mvprintw(LINES/2, COLS/2- 16, "YOU DID NOT EVEN GIVE ME A CHANCE......GOODBYE");
refresh();
sleep(2);
}
attroff(A_BOLD);
endwin();
}
void game:: genFood()
{
srand(time(NULL));
food_y= random()%(max_y-6)+4;
food_x= random()%(max_x-4)+2;
}
void game:: map()
{
box(stdscr, 0, 0);
mvprintw(1,1, "SCORE: ");
mvprintw(1,8, "%d",score);
mvprintw(2,1, "Press q to quit");
refresh();
}
void game:: setSnake()
{
clear();
map();
for(int i= 0; i< 8; i++)
{
snake s((COLS/2)-8+i, LINES/2);
l.add(s);
mvprintw(s.getY(),s.getX(),"%c",s.getCh());
}
mvprintw(food_y, food_x, "F");
refresh();
}
void game::play()
{
genFood();
setSnake();
mvprintw(8, COLS/2-20, "??????????READY??????????????");
refresh();
sleep(1);
int ch= 0;
timeout(50); //adjust speed of the game
while((ch=getch())!= 'q')
{
switch(ch)
{
case KEY_UP: direction= Up;
break;
case KEY_DOWN: direction= Down;
break;
case KEY_RIGHT: direction= Right;
break;
case KEY_LEFT: direction= Left;
break;
}
clear();
map();
mvprintw(food_y, food_x,"F");
if(direction+2== prev_dir || prev_dir+2== direction) //added does not allow snake to go backwards
direction= prev_dir;
moveSnake(direction);
refresh();
if(checkForCollision())
{
clear();
mvprintw(max_y/2-2, max_x/2-8, "GAME OVER");
mvprintw(max_y/2, max_x/2-10, "YOUR SCORE %d",score);
refresh();
sleep(2);
break;
}
prev_dir= direction;
}
}
bool game:: checkForCollision()
{
bool collided= false;
snake s= l.get(1);
int head_x= s.getX();
int head_y= s.getY();
if(head_x== max_x-1 || head_y== 1 || head_x== 1 || head_y== max_y-1)
return true;
else
{
int len= l.listLength();
for(int i= 4; i< len; i++)
{
s= l.get(i);
if(head_x== s.getX() && head_y== s.getY())
{
collided= true;
break;
}
}
return collided;
}
}
void game:: moveSnake(Direction dir)
{
snake k;
k= l.get(1);
int x= k.getX(), y= k.getY();
//mvprintw(6,1, "BEFORE x= %d, y= %d, dir=%d",x,y,dir);
//getch();
if(dir== Up) y--;
else if(dir== Left) x--;
else if(dir== Down) y++;
else x++;
//mvprintw(7,1, "AFTER x=%d, y= %d", x, y);
snake s(x,y);
l.add(s);
if(x==food_x && y==food_y)
{
score++;
genFood();
mvprintw(food_y, food_x, "F");
}
else
l.remove();
int len= l.listLength();
for(int i= 1; i<= len; i++)
{
k= l.get(i);
mvaddch(k.getY(), k.getX(), k.getCh());
refresh();
}
}
int main()
{
game g;
g.launch();
return 0;
} https://codereview.stackexchange.com/questions/121192
复制相似问题