c++实现贪吃蛇

```
#include<iostream>
#include<utility>
#include<set>
#include<deque>
#include<Windows.h>
#include <ctime>
#include <stdexcept>
#include<string>
#include<conio.h>
WORD SQUARE_COLOR[7] = { FOREGROUND_RED | FOREGROUND_INTENSITY,
FOREGROUND_GREEN | FOREGROUND_INTENSITY,
FOREGROUND_BLUE | FOREGROUND_INTENSITY,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY,
FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY
};义方向

#define KEY_UP      72
#define KEY_DOWN    80
#define KEY_LEFT    75
#define KEY_RIGHT   77
#define KEY_ESC     27
//边框属性
#define MAPW 30
#define MAPH 20
#define OFFSET_L 2
#define OFFSET_U 2

using namespace std;
class Bitmap;
class Feed;
class Snake;

//获取句柄函数
HANDLE initiate() {
    HANDLE hOutput;
    hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    return hOutput;
}
//控制台输出函数
bool textout(HANDLE hOutput, int x, int y, LPTSTR lpszCtring,WORD wColors[], int nColors) {
    DWORD cWritten;
    BOOL fSuccess;
    COORD coord;
    coord.X = x;
    coord.Y = y;
    fSuccess = WriteConsoleOutputCharacter(
        hOutput,
        lpszCtring,
        lstrlen(lpszCtring),
        coord,
        &cWritten
    );

    for (;fSuccess && coord.X < lstrlen(lpszCtring) + x;coord.X += nColors) {
        fSuccess = WriteConsoleOutputAttribute(
            hOutput,
            wColors,
            nColors,
            coord,
            &cWritten
        );
    }
    if (!fSuccess)
        cout << "error:WriteConsoleOutputCharacter" << endl;
    return 0;
}//end

bool textout1(HANDLE hOutput,int x,int y,LPTSTR lpszCtring) {
    DWORD cWritten;
    BOOL fSuccess;
    COORD coord;
    coord.X = x;
    coord.Y = y;
    fSuccess = WriteConsoleOutputCharacter(
        hOutput,
        lpszCtring,
        lstrlen(lpszCtring),
        coord,
        &cWritten
    );
    if (!fSuccess)
        cout << "error:WriteConsoleOutputCharacter" << endl;
    return 0;
}

enum type {
    bitmap_type,
    feed_type,
    snake_type,
    none_type,
};

extern HANDLE handle;

//打印游戏界面
template<typename T> void print(T &t, enum type ty) {
    LPTSTR lpszText = TEXT("◆") ;
    switch (ty) {
    case bitmap_type:
        lpszText = TEXT("◆");
        break;
    case feed_type:
        lpszText = TEXT("●");
        break;
    case snake_type:
        lpszText = TEXT("■");
        break;
    case none_type:
        lpszText = TEXT(" ");
        break;
    default:
        runtime_error("无效的背景框!");
        break;
    }
    for (T::iterator it = t.begin();it != t.end();++it)
        textout(handle, OFFSET_L + 2 * it->coord.first, OFFSET_U + it->coord.second, lpszText, SQUARE_COLOR+it->color,1);
}

//Node
struct Node {
    pair<int, int> coord;
    int color;
    Node(int x,int y,int c):coord(x,y),color(c){}
    friend inline bool operator<(const Node &lhs, const Node &rhs);
};

//比较两个节点是否相同的函数
bool equalNode(Node node1, Node node2) {
    if (node1.coord.first == node2.coord.first && node1.coord.second == node2.coord.second)
        return true;
    else
        return false;
}

//运算符重载(因为set需要排序)
inline bool operator<(const Node &lhs, const Node &rhs)
{
    if (lhs.coord.second < rhs.coord.second)
    {
        return true;
    }
    else if (lhs.coord.second == rhs.coord.second)
    {
        return lhs.coord.first < rhs.coord.first;
    }
    else
    {
        return false;
    }
}

//Bitmap 类
class Bitmap{
public:
    friend class Feed;
    friend class Snake;
    Bitmap(int map_x,int map_y,int map_w,int map_h,int map_c):x(map_x),y(map_y),w(map_w),h(map_h),c(map_c){}
    void printBitmap();
    void Insert(pair<int, int> edge);
private:
    int x, y, w, h, c;
    set<Node> bm;
};

void Bitmap::Insert(pair<int, int> edge) {
    if (edge.first >= x && edge.first <= x + w - 1 && edge.second >= y && edge.second <= y + h - 1)
        bm.insert(Node(edge.first, edge.second,c));
    else
        throw runtime_error("无效的背景框!");
}

void Bitmap::printBitmap() {
    print(bm, bitmap_type);
}

//feed类
class Feed {
public:
    friend class Snake;
    void PrintFeed();
private:
    set<Node> fd;
};

void Feed::PrintFeed() {
    print(fd, feed_type);
}

class Snake {
public:
    friend class Feed;
    enum direction {
        up,
        down,
        left,
        right
    };
    Snake(pair<int, int> head, pair<int, int> tail);
    void PrintSnake();
    void EraseSnake();
    void MoveFront(pair<int,int> t);
    bool NextStep(direction d,Bitmap &b,Feed &fd,bool &eat);
    void Snake::AddNewFeed(Bitmap &b, Feed &f);
    direction GetDir() {
        return this->dir;
    }
    bool ChangeDirection(direction d, Bitmap &b, Feed &f,  bool &eat);                 //判断方向改变是否合法
private:
    deque<Node> sn;
    direction dir;
    void AddFrontNode(Node n, Feed &f);
};

Snake::Snake(pair<int, int> head, pair<int, int> tail) {
    srand(static_cast<unsigned int>(time(NULL)));
    if (head.first == tail.first) {
        if (head.second < tail.second) {
            dir = up;
            for (int i = head.second;i <= tail.second;++i)
                sn.push_back(Node(head.first, i,rand()%7));
        }
        else if (head.second > tail.second) {
            dir = down;
            for (int i = head.second;i >= tail.second;--i)
                sn.push_back(Node(head.first, i, rand() % 7));
        }
        else
            throw runtime_error("无法绘蛇");
    }
    else if (head.second == tail.second) {
        if (head.first > tail.first) {
            dir = right;
            for (int i = head.first;i >= tail.first;--i)
                sn.push_back(Node(head.second, i, rand() % 7));
        }
        else if (head.first < tail.first) {
            dir = left;
            for (int i = head.first;i <= tail.first;++i)
                sn.push_back(Node(head.second, i, rand() % 7));
        }
    }
    else
        throw runtime_error("无法绘蛇");
}
void Snake::PrintSnake() {
    print(sn, snake_type);
}

void Snake::EraseSnake() {
    print(sn, none_type);
}


void Snake::AddFrontNode(Node n, Feed &f) {
    sn.push_front(n);
    f.fd.erase(n);
}

void Snake::MoveFront(pair<int,int> t) {
    for (deque<Node>::reverse_iterator it = sn.rbegin();it != sn.rend();it++) {
        if (it != sn.rend() - 1) {
            it->coord.first = (it + 1)->coord.first;
            it->coord.second = (it + 1)->coord.second;
        }
        else {
            it->coord.first = t.first;
            it->coord.second = t.second;
        }
    }
}

bool Snake::NextStep(direction d, Bitmap &b, Feed &f, bool &eat) {
    pair<int, int> temp;      //存放头节点
    switch (d)
    {
    case up:
        temp.first = sn[0].coord.first;
        temp.second = sn[0].coord.second - 1;
        break;
    case down:
        temp.first = sn[0].coord.first;
        temp.second = sn[0].coord.second + 1;
        break;
    case left:
        temp.first = sn[0].coord.first - 1;
        temp.second = sn[0].coord.second;
        break;
    case right:
        temp.first = sn[0].coord.first + 1;
        temp.second = sn[0].coord.second;
        break;
    default:
        throw runtime_error("反向无效");
        break;
    }
    dir = d;
    for (set<Node>::iterator it = b.bm.cbegin();it != b.bm.cend();it++) 
        if (equalNode(*it, Node(temp.first, temp.second,6))) 
            return false;

    for (deque<Node>::iterator it = sn.begin();it != sn.end() - 1;it++) 
        if (equalNode(*it, Node(temp.first, temp.second,6)))
            return false;

    for (set<Node>::iterator it = f.fd.begin();it != f.fd.end();it++) {
        if (equalNode(*it, Node(temp.first, temp.second,6))) {
            eat = true;
            AddFrontNode(*it, f);
            AddNewFeed(b, f);
            f.PrintFeed();
            EraseSnake();
            PrintSnake();
            return true;
        }
    }
    EraseSnake();
    MoveFront(temp);
    PrintSnake();
    return true;
}

bool Snake::ChangeDirection(direction d, Bitmap &b, Feed &f, bool &eat) {
    if (d == dir)  return true;         //不执行操作,但继续执行下面的代码

    if (dir == up && d == down ||
        dir == down && d == up ||
        dir == left && d == right ||
        dir == right && d == left)
        return true;
    return NextStep(d, b, f, eat);
}

void Snake::AddNewFeed(Bitmap &b, Feed &f) {
    pair<int, int> temp;
    bool ok = false;
    set<Node>::iterator it;

    srand(static_cast<unsigned int>(time(NULL)));
    while (1) {
        temp.first = rand() % b.w + b.x;
        temp.second = rand() % b.h + b.y;
        Node node(temp.first, temp.second,6);
        for (it = b.bm.begin();it != b.bm.end(); it++) {
            if (equalNode(*it, node)) {
                ok = false;
                break;
            }
            ok = true;
        }
        if (!ok) continue;

        for (it = f.fd.begin();it != f.fd.end(); it++) {
            if (equalNode(*it, node)) {
                ok = false;
                break;
            }
            ok = true;
        }
        if (!ok) continue;

        deque<Node>::iterator dit;
        for (dit = sn.begin();dit != sn.end();dit++) {
            if (equalNode(*dit, node)) {
                ok = false;
                break;
            }
            ok = true;
        }
        if (!ok) continue;

        f.fd.insert(Node(temp.first, temp.second,rand()%7));
        break;
    }
}



HANDLE handle;

void init(Bitmap &b,Feed &feed,Snake &s){
    handle = initiate();
    for (int i = 0; i < MAPW; i++)
    {
        b.Insert(make_pair(i, 0));
        b.Insert(make_pair(i, MAPH - 1));
    }
    for (int j = 1; j < MAPH - 1; j++)
    {
        b.Insert(make_pair(0, j));
        b.Insert(make_pair(MAPW - 1, j));
    }
    b.printBitmap();
    for (int i = 0;i < 3;++i)
        s.AddNewFeed(b, feed);
    feed.PrintFeed();
    s.PrintSnake();
    LPTSTR Text1 = TEXT("SCORE:");
    LPTSTR Text2 = TEXT("LEVEL:");
    LPTSTR Text = TEXT("❤按任意键开始!❤");
    textout1(handle, 1, 1, Text);
    textout1(handle, OFFSET_L + 2*MAPW , OFFSET_U, Text1);
    textout1(handle, OFFSET_L + 2 * MAPW, OFFSET_U + 5, Text2);
    char c = _getch();
}

int main() {
    srand(static_cast<unsigned int>(time(NULL)));
    Bitmap myBitmap(0, 0, MAPW, MAPH,rand()%7);
    Snake mySnake(make_pair(10, 10), make_pair(10, 12));
    Feed myFeed;
    init(myBitmap,myFeed,mySnake);

    int score = 0, level = 0, max_delay = 70 - 10 * level, uplevel = 5, speed = 6, minspeed = 4;
    bool ret = true, eat = false;
    while (1)
    {
        //textout(handle, OFFSET_L + 2 * MAPW + 2, 4, string);
        /*_itoa_s(level, string, 10);
        textout(handle, OFFSET_L + 2 * MAPW + 2, 15, string);*/

        int delay = 0;
        max_delay = 35 - 5 * level;
        while (delay < max_delay)
        {
            if (_kbhit())
            {
                int key = _getch();
                switch (key)
                {
                case KEY_UP:
                    ret = mySnake.ChangeDirection(Snake::up, myBitmap, myFeed, eat);
                    break;
                case KEY_DOWN:
                    ret = mySnake.ChangeDirection(Snake::down, myBitmap, myFeed, eat);
                    break;
                case KEY_LEFT:
                    ret = mySnake.ChangeDirection(Snake::left, myBitmap, myFeed, eat);
                    break;
                case KEY_RIGHT:
                    ret = mySnake.ChangeDirection(Snake::right, myBitmap, myFeed, eat);
                    break;
                case KEY_ESC:
                    exit(EXIT_SUCCESS);
                }
                if (!ret) {
                    textout1(handle, OFFSET_L + MAPW / 2, OFFSET_U + MAPH / 2, TEXT("游戏结束"));
                    char c = _getch();
                    exit(EXIT_SUCCESS);
                }
                if (eat) {
                    eat = false;
                    score++;
                    if (score%uplevel == 0) {
                        level++;
                        uplevel += 3;
                        --speed;
                        speed = ((speed == minspeed) ? minspeed : speed);
                    }
                }
            }
            Sleep(speed);
            delay++;
        } //while (delay < max_delay)
        ret = mySnake.NextStep(mySnake.GetDir(), myBitmap, myFeed, eat);
        if (!ret) {
            textout1(handle, OFFSET_L + MAPW / 2, OFFSET_U + MAPH / 2, TEXT("游戏结束"));
            char c = _getch();
            exit(EXIT_SUCCESS);
        }
        if (eat) {
            eat = false;
            score++;
            if (score%uplevel == 0) {
                level++;
                uplevel += 3;
                --speed;
                speed = ((speed == minspeed) ? minspeed : speed);
            }
        }
    }//while(1)
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
#include <stdio.h> #include <iostream.h> #include <windows.h> #include <stdlib.h> #include <winuser.h> const int size=13,gameSpeed=500; class node { private: int x; int y; node *next; public: node(); void changeX(int X); void changeY(int Y); void changeNext(node *N); int getX(); int getY(); node *getNext(); }; node::node() { x=0; y=0; next=NULL; } int node::getX() { return x; } int node::getY() { return y; } void node::changeX(int X) { x=X; } void node::changeY(int Y) { y=Y; } void node::changeNext(node *N) { next=N; } node *node::getNext() { return next; } class linkList { protected: node *head; public: linkList();//制造一个有头结点的线性表 int getLength(); node *getNode(int i);//i:0-n int getIndex(node *e);//i:1-n,没有返回0 node *getPriorNode(node *e); node *getNextNode(node *e); void insert(int i,node *e);//i:1-(n+1) void Delete(int i); }; linkList::linkList() { head=new node; head->changeNext(NULL); } int linkList::getLength() { node *p=head->getNext(); int i=0; while(p) { i++; p=p->getNext(); } return i; } node *linkList::getNode(int i) { node *p=head; int j=0; while(p&&j<i)//!记住这句 { p=p->getNext(); j++; } return p; } int linkList::getIndex(node *e) { node *p=head->getNext(); int i=1; while(p) { if(p->getX()==e->getX()&&p->getY()==e->getY()) { return i; } i++; p=p->getNext(); } return 0; } node *linkList::getPriorNode(node *e) { node *p=NULL; int i=getIndex(e); if(i!=0) { p=getNode(i-1); } return p; } node *linkList::getNextNode(node *e) { node *p=NULL; int i=getIndex(e); if(i!=0) { p=getNode(i+1); } return p; } void linkList::insert(int i,node *e) { node *p=getNode(i-1); e->changeNext(p->getNext()); p->changeNext(e); } void linkList::Delete(int i) { node *p=getNode(i-1),*q=p->getNext(); p->changeNext(p->getNext()->getNext()); delete q; } class snake:public linkList { private: char direction; node *lastTail; public: snake(); char getDirection(); void go(); void changeDirection(char D); node *getLastTail(); }; node *snake::getLastTail() { return lastTail; } void snake::changeDirection(char D) { direction=D; } void snake::go() { node *e=new node; e->changeNext(NULL); switch(direction) { case 'w': e->changeX(head->getNext()->getX()-1); e->changeY(head->getNext()->getY()); insert(1,e); break; case 's': e->changeX(head->getNext()->getX()+1); e->changeY(head->getNext()->getY()); insert(1,e); break; case 'a': e->changeX(head->getNext()->getX()); e->changeY(head->getNext()->getY()-1); insert(1,e); break; case 'd': e->changeX(head->getNext()->getX()); e->changeY(head->getNext()->getY()+1); insert(1,e); break; } lastTail=new node; lastTail->changeX(getNode(getLength())->getX()); lastTail->changeY(getNode(getLength())->getY()); lastTail->changeNext(NULL); Delete(getLength()); } char snake::getDirection() { return direction; } snake::snake():linkList() { direction='d'; head=new node; head->changeNext(new node); head->getNext()->changeNext(new node); head->getNext()->getNext()->changeNext(new node); head->getNext()->getNext()->getNext()->changeNext(NULL); head->changeX(0); head->changeY(0); head->getNext()->changeX(size/2); head->getNext()->changeY(size/2); head->getNext()->getNext()->changeX(size/2); head->getNext()->getNext()->changeY(size/2-1); head->getNext()->getNext()->getNext()->changeX(size/2); head->getNext()->getNext()->getNext()->changeY(size/2-2); lastTail=NULL; } class food:public linkList { public: food(); }; food::food():linkList() { head=new node; head->changeNext(new node); head->getNext()->changeNext(new node); head->getNext()->getNext()->changeNext(NULL); head->changeX(0); head->changeY(0); do{ head->getNext()->changeX(rand()%(size-1)+1); head->getNext()->changeY(rand()%(size-1)+1); }while(0);//*** do{ head->getNext()->getNext()->changeX(rand()%(size-1)+1); head->getNext()->getNext()->changeY(rand()%(size-1)+1); }while(0); } class border:public linkList { public: border(); }; border::border():linkList() { head=new node; head->changeX(0); head->changeY(0); node *p=head; for(int i=0;i<size+2;i++) { p->changeNext(new node); p=p->getNext(); p->changeX(0); p->changeY(i); } for(i=1;i<size+2;i++) { p->changeNext(new node); p=p->getNext(); p->changeX(i); p->changeY(size+1); } for(i=size;i>=0;i--) { p->changeNext(new node); p=p->getNext(); p->changeX(size+1); p->changeY(i); } for(i=size;i>0;i--) { p->changeNext(new node); p=p->getNext(); p->changeX(i); p->changeY(0); } p->changeNext(NULL); } class map { private: int m[size+2][size+2]; public: map(); void refresh(); void display(snake *S,food *F,border *B,float score); bool detectCollision(linkList *S,linkList *O); }; void map::refresh() { for(int i=0;i<size+2;i++) { for(int j=0;j<size+2;j++) { m[i][j]=0; } } } map::map() { for(int i=0;i<size+2;i++) { for(int j=0;j<size+2;j++) { m[i][j]=0; } } } bool map::detectCollision(linkList *S,linkList *O) { node *p=S->getNode(1); if(O->getIndex(p)!=0) { return 1; } else { return 0; } } void map::display(snake *S,food *F,border *B,float score) { system("cls"); for(int i=1;i<=S->getLength();i++) { m[S->getNode(i)->getX()][S->getNode(i)->getY()]=1; } for(i=1;i<=F->getLength();i++) { m[F->getNode(i)->getX()][F->getNode(i)->getY()]=2; } for(i=1;i<=B->getLength();i++) { m[B->getNode(i)->getX()][B->getNode(i)->getY()]=4; } cout<<"score="<<score*10<<endl; for(i=0;i<size+2;i++) { for(int j=0;j<size+2;j++) { if(m[i][j]==0) { cout<<" "; } else if(m[i][j]==1) { cout<<"* "; } else if(m[i][j]==2) { cout<<"o "; } else if(m[i][j]==4) { cout<<"+ "; } } cout<<endl; } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值