ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 명품 C++ 9장 Open Challenge
    C++ 2018. 11. 7. 23:53

    Human의 Food 먹기 게임


    게임에는 Human, Monster, Food의 세 객체가 등장하며, 이들은 10x20 격자판에서 각각 정해진 규칙에 의해 움직인다. Human 객체는 사용자의 키에 의해 왼족(a 키), 아래(s 키), 위(d 키), 오른쪽(f 키)으로 한 칸씩 움직이고, Monster는 한 번에 2칸씩, 왼쪽, 아래, 위, 오른쪽 방향으로 랜덤하게 움직인다. Food는 5번 중에 3번은 제자리에 있고, 나머지 2번은 4가지 방향 중 랜덤하게 한 칸씩 움직인다.

    게임은 Human이 Monster를 피해 Food를 먹으면(Food의 위치로 이동) 성공으로 끝나고, Monster가 Food를 먹거나 Human이 Monster에게 잡히면 실패로 끝난다. 

    다음은 각 객체의 이동을 정의하는 move()와 각 객체의 모양을 정의하는 getShape() 함수를 순수 가상 함수로 가진 추상 클래스 GameObject이다. GameObject를 상속받아 Human, Monster, Food 클래스를 작성하라. 그리고 전체적인 게임을 진행하는 Game 클래스와 main() 함수를 작성하고 프로그램을 완성하라.


    class GameObject { // 추상 클래스
    protected:
        int distance; // 한 번 이동 거리
        int x, y; // 현재 위치
    public:
        GameObject(int startX, int startY, int distance) { // 초기 위치와 이동거리 설정
            this->x = startX; this->y = startY;
            this->distance = distance;
        }
        virtual ~GameObject() {}; // 가상 소멸자
        virtual void move() = 0; // 이동한 후 새로운 위치로 x, y 변경
        virtual char getShape() = 0; // 객체의 모양을 나타내는 문자 리턴
        int getX() { return x; }
        int getY() { return y; }
        bool collide(GameObject *p) { // 이 객체가 객체 p와 충돌했으면 true 리턴
            if (this->x == p->getX() && this->y == p->getY())
                return true;
            else
                return false;
        }
    };


    키가 입력될 때마다 Human, Monster, Food 객체의 move()를 순서대로 호출한다. 게임이 진행되는 과정은 다음 그림과 같으며, 게임의 종료 조건에 일치하면 게임을 종료한다.


    소스코드


    #include <iostream>
    #include <string>
    #include <ctime>
    #include <cstdlib>
    using namespace std;
    class GameObject { // 추상 클래스
    protected:
        int distance; // 한 번 이동 거리
        int x, y; // 현재 위치
    public:
        GameObject(int startX, int startY, int distance) { // 초기 위치와 이동거리 설정
            this->x = startX; this->y = startY;
            this->distance = distance;
        }
        virtual ~GameObject() {}; // 가상 소멸자
        virtual void move() = 0; // 이동한 후 새로운 위치로 x, y 변경
        virtual char getShape() = 0; // 객체의 모양을 나타내는 문자 리턴
        int getX() { return x; }
        int getY() { return y; }
        bool collide(GameObject *p) { // 이 객체가 객체 p와 충돌했으면 true 리턴
            if (this->x == p->getX() && this->y == p->getY())
                return true;
            else
                return false;
        }
    };
    class Human : public GameObject { // 휴먼 클래스
    public:
        Human(int x, int y, int dis) :GameObject(x, y, dis){} // 처음 위치와 이동거리를 기본 클래스에 넘겨줌
        void move();
        char getShape() { return 'H'; }
    };
    void Human::move() {
        string key;
        for (;;) {
            cout << "왼쪽(a), 아래(s), 위(d), 오른쪽(f) >> ";
            cin >> key;
            if (key == "a") { // 왼쪽으로 이동
                if (y != 0) {
                    y -= distance;
                    break;
                }
                else cout << "이동불가" << endl;
            }
            else if (key == "s") { // 아래로 이동
                if (x != 9) {
                    x += distance;
                    break;
                }
                else cout << "이동불가" << endl;
            }
            else if (key == "d") { // 위로 이동
                if (x != 0) {
                    x -= distance;
                    break;
                }
                else cout << "이동불가" << endl;
            }
            else if (key == "f") { // 오른쪽으로 이동
                if (y != 19) {
                    y += distance;
                    break;
                }
                else cout << "이동불가" << endl;
            }
            else
                cout << "입력 에러" << endl;
        }
    }
    class Monster : public GameObject {
    public:
        Monster(int x, int y, int dis) :GameObject(x, y, dis) { srand((unsigned)time(0)); } // 랜덤하게 이동하기때문에
        void move();
        char getShape() { return 'M'; }
    };
    void Monster::move() {
        for (;;) {
            int n = rand() % 4; // 4가지의 랜덤한 경우
            if (n == 0) { // 왼쪽으로 이동
                if (y > 1) {
                    y -= distance;
                    break;
                }
            }
            else if (n == 1) { // 아래쪽으로 이동
                if (x < 8) {
                    x += distance;
                    break;
                }
            }
            else if (n == 2) { // 위쪽으로 이동
                if (x > 1) {
                    x -= distance;
                    break;
                }
            }
            else {
                if (y < 18) { // 오른쪽으로 이동
                    y += distance;
                    break;
                }
            }
        }
    }
    class Food : public GameObject {
    public:
        Food(int x, int y, int dis) :GameObject(x, y, dis) {}
        void move();
        char getShape() { return '@'; }
    };
    void Food::move() {
        for (;;) {
            int n = rand() % 4;
            if (n == 0) { // 왼쪽으로 이동
                if (y != 0) {
                    y -= distance;
                    break;
                }
            }
            else if (n == 1) { // 아래로 이동
                if (x != 9) {
                    x += distance;
                    break;
                }
            }
            else if (n == 2) { // 위로 이동
                if (x != 0) {
                    x -= distance;
                    break;
                }
            }
            else {
                if (y != 19) { // 오른쪽으로 이동
                    y += distance;
                    break;
                }
            }
        }
    }
    class Game {
        string board[10][20]; // 10x20 격자판
        Human *h = new Human(0, 0, 1); // 휴먼 객체 시작 위치 0,0 이동거리 1
        Monster *m = new Monster(5, 7, 2); // 몬스터 객체 시작 위치 5,7 이동거리 2
        Food *f = new Food(8, 10, 1); // 음식 객체 시작 위치 8, 10 이동거리 1
    public:
        Game() {
            srand((unsigned)time(0));
            cout << "** Human의 Food 먹기 게임을 시작합니다. **" << endl << endl;
            for (int i = 0; i < 10; ++i) { // 격자판 배열 초기화
                for (int j = 0; j < 20; ++j)
                    board[i][j] = "-";
            }
        }
        ~Game() { delete h; delete m; delete f; }
        void game(); // 게임 진행 함수
        void clr1() {
            board[h->getX()][h->getY()] = "-";
            board[m->getX()][m->getY()] = "-";
        }
        void clr2() { // food 객체의 이동은 5번중 2번 만이기 때문에 따로 만듬
            board[f->getX()][f->getY()] = "-";
        }
        void setXY() {
            board[h->getX()][h->getY()] = h->getShape();
            board[m->getX()][m->getY()] = m->getShape();
            board[f->getX()][f->getY()] = f->getShape();
        }
        void show() {
            for (int i = 0; i < 10; ++i) {
                for (int j = 0; j < 20; ++j)
                    cout << board[i][j];
                cout << endl;
            }
        }
    };
    void Game::game() {
        int count = 0, gamecount = 0;
        for (;;) {
            setXY();
            show();
            clr1();
            h->move(); m->move();
            int n = rand();
            cout << endl;
            if (n % 2 == 0 && count<2 && gamecount<=3) { // 5번중 처음 세번에 랜덤하게 food 이동
                clr2();
                f->move();
                ++count;
            }
            if (gamecount > 3 && count < 2) { // 3번을 돌았는데 2번을 다 못 돌았다면 남은 두 번 다 움직여야한다
                clr2();
                f->move();
                ++count;
            }
            if (f->collide(h)) { // 휴먼이 food를 먹으면
                setXY();
                board[f->getX()][f->getY()] = "H";
                show();
                cout << "Human is Winner!!" << endl;
                break;
            }
            else if (h->collide(m)) { // 몬스터가 사람을 먹으면
                setXY();
                board[f->getX()][f->getY()] = "M";
                show();
                cout << "Monster is Winner!!" << endl;
                break;
            }
            else if (f->collide(m)) { // 몬스터가 food 를 먹으면
                setXY();
                board[f->getX()][f->getY()] = "M";
                show();
                cout << "Monster is Winner!!" << endl;
                break;
            }
            ++gamecount;
            if ((gamecount % 5) == 0) { // food가 5번중 2번움직이게끔 하는것을 만들기위해
                count = 0;
                gamecount = 0;
            }
        }
    }
    int main() {
        Game *g=new Game;
        g->game();
        delete g;
    }


    실행결과



    실행 결과의 중간 과정은 생략되었습니다.

    프로그램 설명은 주석으로 추가하였습니다.

    food 는 5번중에 2번만 움직입니다.

    5번중에 3번동안 랜덤하게 돌고 

    2번을 채우지 못 했다면, 남은 2번에서 2번을 채우도록 합니다.



    순수 가상 함수을 사용하여 오버라이딩하여 기본 클래스에서 함수를 정의하고

    파생 클래스에서 기능을 구현하여 클래스마다 이름은 같지만 다른 기능을 하는 함수를 사용합니다.


    'C++' 카테고리의 다른 글

    명품 C++ 10장 2번  (0) 2018.11.16
    명품 C++ 10장 1번  (0) 2018.11.16
    명품 C++ 9장 10번  (0) 2018.11.07
    명품 C++ 9장 9번  (0) 2018.11.07
    명품 C++ 9장 7번 8번  (0) 2018.11.06

    댓글

© 2018 TISTORY. All rights reserved.