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;
}

总结:①函数WriteConsoleOutputCharacter(…)和函数WriteConsoleOutputAtrribute(…)结合使用控制在控制台上指定的输出内容和输出属性。
②HANDLE initiate() {
HANDLE hOutput;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
return hOutput;
}使用GetStdHandle()返回标准的输入、输出或错误的设备的句柄.
③关于程序中的运算符重载:
因为set容器是有序容器。对于有序容器-map、multimap、set以及multiset,关键字类型必须定义元素比较的方法。默认情况下,标准库使用关键字类型的<运算符来比较两个关键字。
④Sleep();
功 能: 执行挂起一段时间
⑤利用 srand()和rand()函数产生随机数。srand函数是随机数发生器的初始化函数。原型:void srand(unsigned int seed);
⑥游戏思路:将每个食物看成一个节点,蛇看作许多节点的集合。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值