Nie doczytałeś mojego postu (lub nie zrozumiałeś).
Uważam że:
Cell *tmp=NextHeadCeil(Dir d);
// Gdzie
Ceil *NextHeadCeil(Dir d) { unsigned pos=head-Tb; return Tb+(pos/Width+DIR[d].dy)*Width+pos%Width+DIR[d].dx; }
jest czytelniejsze od:
get_cell(get_point(cell) + dir2vec(d));
// Gdzie
struct Point { unsigned y, x; };
struct Vector2d { int dy, dx;};
Point operator+(const Point& p, const Vector2d& v) { return {p.y + v.dy, p.x + v.dx}; }
const Vector2d& dir2vec(Dir d) {
static const Vector2d DIR[] = {{0,-1}, {0,1}, {-1,0}, {1,0}};
return DIR[static_cast(d)];
}
Cell& get_cell(const Point& p) { return board.at(p.y*size.width + p.x); }
Point get_point(const Cell& cell) {
unsigned pos = &cell - board.data();
board.at(pos);
return {pos/size.width, pos%size.width};
}
Oraz:
PopTail();
jest czytelniejsze od:
body.pop_back();
EDIT: Twoim problemem (i niestety nie tylko twoim) jak widzisz coś niezbyt zrozumiałego natychmiast zaczynasz jeszcze bardziej komplikować, zapominając o:
Więc uprościłem nieco, przy okazji dodając absolutnie minimalistyczny nie przenośny i prymitywny, windowsowy, konsolowy TUI:
#include
#include
#include
#include
#include
typedef enum
{
wEmpty, wApple, wSnake,
wBorderUp, wBorderDn, wBorderLf, wBorderRt,
wBorderUpLf, wBorderDnLf, wBorderUpRt, wBorderDnRt
} What;
typedef enum { drUp, drDn, drLf, drRt } Dir;
class Screen;
class Map
{
public:
struct Cell
{
private:
Cell *prev;
What what;
public:
Cell():prev(0),what(wEmpty) {}
operator What()const { return what; }
bool SetWhat(What w) { if(what==wEmpty) what=w; return what==w; }
bool SetApple() { return SetWhat(wApple); }
friend class Map;
};
private:
unsigned Size,Width,Grow,Apples;
Cell *Tb,*head,*tail;
public:
Map(unsigned Height,unsigned Width,unsigned SnakeY,unsigned SnakeX):
Size(Height*Width),Width(Width),Grow(0),Apples(0),
Tb(new Cell[Size]),head(Tb+SnakeY*Width+SnakeX),tail(head)
{
}
~Map() { delete[] Tb; }
Cell *NextHeadCeil(Dir d) { static int DIR[]={-Width,+Width,-1,+1}; return head+DIR[d]; } //ale można zamienić poniższym
/* {
if(d==drUp) return head-Width;
if(d==drDn) return head+Width;
if(d==drLf) return head-1;
if(d==drRt) return head+1;
throw "■■■";
}*/
void PushHead(Cell *newhead) { (head=head->prev=newhead)->what=wSnake; }
void PopTail() { tail->what=wEmpty; tail=tail->prev; }
bool Move(Dir d)
{
Cell *newhead=NextHeadCeil(d);
if((Tb>head)||(head>=Tb+Size)) return false; // na wypadek gdyby nie było przewidzianych krawędzi
if(newhead->what==wApple)
{
--Apples;
Grow+=1+std::rand()%4;
}
else if(newhead->what!=wEmpty) return false;
PushHead(newhead);
if(Grow) --Grow;
else PopTail();
return true;
}
void RandApples(unsigned n) { while(Apples
Cell *operator[](unsigned y) { return Tb+y*Width; }
};
const unsigned MapHeight=24,MapWidth=70;
class Screen
{
Map map;
Dir dir;
public:
Screen():map(MapHeight,MapWidth,MapHeight>>1,MapWidth>>1),dir(drLf) {}
void Draw()
{
for(unsigned y=0;y
}
void MakeBorder()
{
unsigned h=MapHeight-1,w=MapWidth-1;
map[0][0].SetWhat(wBorderUpLf);
map[h][0].SetWhat(wBorderDnLf);
map[0][w].SetWhat(wBorderUpRt);
map[h][w].SetWhat(wBorderDnRt);
for(unsigned y=1;y
{
map[y][0].SetWhat(wBorderLf);
map[y][w].SetWhat(wBorderRt);
}
for(unsigned x=1;x
{
map[0][x].SetWhat(wBorderUp);
map[h][x].SetWhat(wBorderDn);
}
}
void Draw(unsigned y,unsigned x,What w)
{
if(y&&!x) std::cout<
static char TB[]=" @*--||++++";
std::cout<
}
void NextFrame(int ticks)
{
long whait=clock()+ticks;
while(whait>clock())
{
if((kbhit())&&(getch()==224))
{
switch(getch())
{
case 72: dir=drUp; break;
case 80: dir=drDn; break;
case 77: dir=drRt; break;
case 75: dir=drLf; break;
}
}
}
}
void run(unsigned apples,unsigned ticks)
{
HANDLE hStdOut=GetStdHandle(STD_OUTPUT_HANDLE);
COORD coord={0,0};
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(hStdOut,&csbi);
MakeBorder();
while(map.Move(dir))
{
map.RandApples(apples);
SetConsoleCursorPosition(hStdOut,coord);
Draw();
NextFrame(ticks);
}
}
};
int main()
{
Screen S;
S.run(3,6);
std::cout<
for(unsigned i=0;i<20;++i)
{
static char GameOver[]="Game Over";
std::cout<<'\r'<
Sleep(300);
}
return 0;
}