zoukankan      html  css  js  c++  java
  • 经典方块游戏一

    贪吃蛇的第一次实现(C++):

    base.hpp

    #ifndef _BASE_H
    #define _BASE_H
    
    #pragma once
    
    #include <time.h>
    #include <stdlib.h>
    
    using namespace std;
    
    enum Block { EMPTY = 0, FILL };
    
    enum Direct { UP = 0, DOWN, LEFT, RIGHT };
    
    enum State { OVER = 0, RUNNING, PAUSE, PASSED };
    
    enum Button { RESET = 0, SOUND, PAUSE_START, OPTIONS, ROTATA_DIRECTION, LEFT_SPEED, RIGHT_SPEED, QUICK_LEVELS, DOWN_LEVELS };
    
    class Point
    {
    public:
        int x, y;
    
        Point(int x = 0, int y = 0) : x(x), y(y) {}
        bool operator==(const Point&point)
        {
            return point.x == x && point.y == y;
        }
    };
    
    /* 基类 */
    class Base
    {
    public:
        const static int WIDTH = 10;
        const static int HEIGHT = 20;
    
    protected:
        int     score;
        State   gameState;
    
    public:
        Block area[WIDTH][HEIGHT];
    
        virtual void refreshArea() = 0;
        int getScore() { return score; }
        Base(int s = 0) : score(s), gameState(RUNNING) {
            srand((unsigned int)time(0));
        }
    
        static void forwardFrom(Point &point, Direct dir);
        static bool checkPoint(const Point &point);
        static int randint(int start, int end);
    };
    
    int Base::randint(int start, int end)
    {
        return (rand() % (end - start)) + start;
    }
    
    void Base::forwardFrom(Point &point, Direct dir)
    {
        switch (dir)
        {
        case UP:
            point.y++;
            break;
        case DOWN:
            point.y--;
            break;
        case LEFT:
            point.x--;
            break;
        case RIGHT:
            point.x++;
            break;
        }
    }
    
    bool Base::checkPoint(const Point &point)
    {
        return point.x >= 0 && point.x < WIDTH && point.y >= 0 && point.y < HEIGHT;
    }
    
    #endif

    snake.hpp

    #ifndef _SNAKE_H
    #define _SNAKE_H
    
    #pragma once
    
    #include "../base/base.hpp"
    #include <iostream>
    #include <List>
    
    using namespace std;
    
    class Snake : public Base
    {
    private:
        const static int FIRST_LEN = 3;
        const static Direct FIRST_DIRECT = RIGHT;
        const static int SCORE_PER_FOOD = 100;
    
    private:
        list<Point> body;       // 0-蛇首
        Direct      direct;
        Point       food;
    
        void clearArea();
        bool addFood();
        void updateScore();
        void turnDirection(Direct dir);
        bool checkBody(Point point);
    
    public:
        void refreshArea();
        void forward();
        void pressButton(Button btn);
        Snake();
        Point const&getFood() { return food; }
    };
    
    void Snake::updateScore()
    {
        score += SCORE_PER_FOOD;
    }
    
    Snake::Snake()
    {
        int startX = (WIDTH - FIRST_LEN) / 2;
        int startY = HEIGHT / 2;
        //body.clear();
        // 初始化 body 和 direct
        for (int loop = 0; loop < FIRST_LEN; loop++)
        {
            body.push_front(Point(startX + loop, startY));
        }
        direct = FIRST_DIRECT;
        // 初始化食物
        Snake::addFood();
        //gameState = State::RUNNING;
        //score = 0;
    }
    
    bool Snake::checkBody(Point point)
    {
        for (list<Point>::iterator i = body.begin(); i != body.end(); i++)
        {
            if ((*i) == point) return false;
        }
        return true;
    }
    
    void Snake::forward()
    {
        if (gameState != RUNNING) return;
    
        Point &lastPoint = body.front();
        Point nextPoint = lastPoint;
        // 获取当前方向下一格的坐标
        Base::forwardFrom(nextPoint, direct);
    
        // 下一步合法(未出界且未碰撞到 body )
        if (checkPoint(nextPoint) && checkBody(nextPoint))
        {
            // 吃到食物,蛇首增加一格
            if (nextPoint == food)
            {
                // 更新分数
                Snake::updateScore();
                body.push_front(nextPoint); // 不能提取出来!
                // 无法生成食物,通关
                if (!Snake::addFood())
                {
                    gameState = PASSED;
                }
            }
            // 未吃到食物,蛇尾最后一格移动到蛇首
            else
            {
                body.pop_back();
                body.push_front(nextPoint);
            }
        }
        // 游戏结束
        else
        {
            gameState = OVER;
        }
    }
    
    bool Snake::addFood()
    {
        int randIdx = Base::randint(0, WIDTH * HEIGHT - body.size());
    
        Snake::refreshArea();
    
        for (int x = 0; x < WIDTH; x++)
        {
            for (int y = 0; y < HEIGHT; y++)
            {
                if (area[x][y] != EMPTY) continue;
                if ((randIdx--) == 0)
                {
                    food.x = x; food.y = y;
                    return true;
                }
            }
        }
        return false;
    }
    
    void Snake::clearArea()
    {
        for (int x = 0; x < WIDTH; x++)
        {
            for (int y = 0; y < HEIGHT; y++)
            {
                area[x][y] = EMPTY;
            }
        }
    }
    
    void Snake::refreshArea()
    {
        Snake::clearArea();
        for (list<Point>::iterator i = body.begin(); i != body.end(); i++)
        {
            area[(*i).x][(*i).y] = FILL;
        }
        //cout<<body.size()<<endl;
    }
    
    void Snake::turnDirection(Direct dir)
    {
        if (direct == dir) return;
    
        list<Point>::iterator i = body.begin();
        Point &p1 = (*i++);
        Point &p2 = (*i++);
    
        if ((dir == LEFT) && (p1.x == p2.x + 1) && (p1.y == p2.y))
            return;
        else if ((dir == DOWN) && (p1.x == p2.x) && (p1.y == p2.y + 1))
            return;
        else if ((dir == RIGHT) && (p1.x == p2.x - 1) && (p1.y == p2.y))
            return;
        else if ((dir == UP) && (p1.x == p2.x) && (p1.y == p2.y - 1))
            return;
        direct = dir;
    }
    
    void Snake::pressButton(Button btn)
    {
        switch (btn)
        {
        case RESET:
            Snake::Snake();
            break;
        case SOUND:
            break;
        case PAUSE_START:
            if (gameState == PAUSE)
                gameState = RUNNING;
            else if (gameState == RUNNING)
                gameState = PAUSE;
            break;
        case OPTIONS:
            break;
        case ROTATA_DIRECTION:
            Snake::forward();
            break;
        case LEFT_SPEED:
            Snake::turnDirection(LEFT);
            break;
        case RIGHT_SPEED:
            Snake::turnDirection(RIGHT);
            break;
        case QUICK_LEVELS:
            Snake::turnDirection(UP);
            break;
        case DOWN_LEVELS:
            Snake::turnDirection(DOWN);
            break;
        }
    }
    
    #endif

    test_snake.cpp

    #include "gtestgtest.h"
    #include "snake.hpp"
    
    /* 0-RESET, 1-SOUND, 2-PAUSE_START, 3-OPTIONS, 4-ROTATA_DIRECTION, 5-LEFT_SPEED, 6-RIGHT_SPEED, 7-QUICK_LEVELS, 8-DOWN_LEVELS  */
    void SnakeOperator(Snake &snake, const char *str)
    {
        for (int i = 0; i < strlen(str); i++)
        {
            snake.pressButton((Button)i);
        }
    }
    
    bool checkSnakeArea(Snake &snake, const Block area[Snake::WIDTH][Snake::HEIGHT])
    {
        snake.refreshArea();
        if (memcmp(snake.area, area, sizeof(area)) == 0) return true;
        return false;
    }
    
    TEST(testSnake, snake_origin)
    {
        Block area[Snake::WIDTH][Snake::HEIGHT] =
        {
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, FILL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, FILL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, FILL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY }
        };
    
        Snake snake;
        ASSERT_TRUE(checkSnakeArea(snake, area));
    }
    
    TEST(testSnake, snake_forward_one_step)
    {
        Block area[Snake::WIDTH][Snake::HEIGHT] =
        {
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, FILL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, FILL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, FILL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY }
        };
        const char *str = "4";
    
        Snake snake;
        ASSERT_TRUE(checkSnakeArea(snake, area));
    }
    
    TEST(testSnake, snake_turn_and_forward)
    {
        Block area[Snake::WIDTH][Snake::HEIGHT] =
        {
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, FILL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, FILL, FILL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY },
            { EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY }
        };
        const char *str = "84";
    
        Snake snake;
        ASSERT_TRUE(checkSnakeArea(snake, area));
    }
    
    #include <stdio.h>
    
    void printArea(Snake &snake)
    {
        snake.refreshArea();
        const Point &food = snake.getFood();
        snake.area[food.x][food.y] = Block::FILL;
        system("cls");
    
        for (int y = 0; y < Base::HEIGHT; y++)
        {
            for (int x = 0; x < Base::WIDTH; x++)
            {
                if (snake.area[x][y] == Block::FILL)
                {
                    printf("%c", '1');
                }
                else
                {
                    printf("..");
                }
            }
            printf("
    ");
        }
    }
    
    void cycle()
    {
        Snake snake;
        int c;
    
        printArea(snake);
    
        while ((c = getchar()) != 'e')
        {
            switch (c)
            {
            case 'w':
                snake.pressButton(Button::QUICK_LEVELS);
                break;
            case 'a':
                snake.pressButton(Button::LEFT_SPEED);
                break;
            case 's':
                snake.pressButton(Button::DOWN_LEVELS);
                break;
            case 'd':
                snake.pressButton(Button::RIGHT_SPEED);
                break;
            case ' ':
                snake.pressButton(Button::PAUSE_START);
                break;
            case 'r':
                snake.pressButton(Button::RESET);
                break;
            case 'u':
                snake.pressButton(Button::ROTATA_DIRECTION);
                break;
    
            }
            
            printArea(snake);
        }
    }
    
    int main(int argc, char **argv)
    {
        int ret = 0;
        //::testing::InitGoogleTest(&argc, argv);
        //ret = RUN_ALL_TESTS();
        cycle();
        return ret;
    }
  • 相关阅读:
    abstract和virtual
    vue中 关于$emit的用法
    babel简介
    vue脚手架的使用
    RAM和ROM
    判断匿名类是否继承父类
    ABP应用层——参数有效性验证
    vue-devtools的安装与使用
    JavaScript中Object.keys用法
    vue中created、mounted、 computed,watch,method 等方法整理
  • 原文地址:https://www.cnblogs.com/rmthy/p/8179137.html
Copyright © 2011-2022 走看看