본문 바로가기

언어/C++

명품 c++ 책 open challenge - human eat food

명품 c++ human eat food 하면서, 약간 가상함수의 개념을 살짝 익힌것 같아요 ㅠㅠ

그래도 아직 가상함수를 잘 사용할러면 좀더 이해가 필요할 것 같아요 ㅠㅠ

 

5개의 파일로 분리해서 만들었어요.

Game.hpp, GameController.hpp, Game.cpp, GameController.cpp, main.cpp

 

// Game.hpp 

#ifndef __GAME_HPP__
#define __GAME_HPP__

class GameObject
{
    protected:
        int distance; // 한번 이동 거리
        int x,y; // 현재 위치 x: 왼쪽, 오른쪽 y: 위,아래
    public:
        // 초기 위치와 이동거리 설정
        GameObject(int startX,int startY, int distance)
        : x(startX),y(startY) { this->distance=distance; }
        ~GameObject() {};
        
        // 이동한  후 새로윈 위치로, x,y 변경
        virtual void move()=0;
        // 벽에 충돌 여부를 판단하는 메소드
        virtual bool move_check(int input)=0;
        // 객체의 모양을 아타내는 문자 리턴
        virtual char getShape()=0;

        // x,y값을 리턴하는 함수
        inline int getX() { return x; }
        inline int getY() { return y; }

        // 이 객체가 객체 p와 충돌했으면 true 리턴
        bool collide(GameObject *p);
};

// GameObject 클래스를 상속 받은 Human 클래스
class Human : public GameObject
{
    public:
        // Human 객체는 한번 이동 거리가 1 이므로
        // 다음과 같이 생성자를 만들어줌.
        Human(int startX, int startY) 
        : GameObject(startX,startY,1) {}
        ~Human() {};

        virtual void move();
        virtual bool move_check(int input);
        virtual char getShape();
};

// GameObject 클래스를 상속 받은 Monster 클래스
class Monster : public GameObject
{
    public:
        // Monster 객체는 한번 이동 거리가 2이므로
        // 다음과 같이 생성자를 만들어줌.
        Monster(int startX, int startY) 
        : GameObject(startX,startY,2) {}
        ~Monster() {};

        virtual void move();
        virtual bool move_check(int input);
        virtual char getShape();
};

// GameObject 클래스를 상속 받은 Food 클래스
class Food : public GameObject
{
    private:
        int count1; // 5번중 3번 제자리
        int count2; // 5번중 2번 움직이기
    public:
        // Food 객체는 한번 이동거리가 1이므로
        // 다음과 같이 생성자를 만들어줌.
        Food(int startX, int startY) 
        : GameObject(startX,startY,1), count1(0),count2(0) {}
        ~Food() {};

        virtual void move();
        virtual bool move_check(int input);
        virtual char getShape();
};

#endif

 

// GameController.hpp

#ifndef __Game_Controller_HPP__
#define __Game_Controller_HPP__

#include "Game.hpp"

// 게임의 맵과 Gameobject를 관리하는 handler 클래스 
class GameController
{
    private:
        char map[10][20];
    public:
        // main함수에서 GameObject에 직접적인 접근을 하기 위해서
        // public으로 선언을 해줌.
        Human& h;
        Monster& m;
        Food& f;
    public:
        // Human + Monster + Food 객체
        // 맵을 초기화를 시켜줌.
        GameController(Human& hh,Monster& mm, Food& ff)
        : h(hh), m(mm), f(ff)
        {
            for(int i=0;i<10;i++)
                for(int j=0;j<20;j+=4)
                {
                    map[i][j]='-'; map[i][j+1]='-';
                    map[i][j+2]='-'; map[i][j+3]='-';
                }
        }

        bool Check();   // 게임 시작시 각각의 객체들의 위치 확인
        void Start(); // 게임 시작 알림 
        void ChangeMap(); // 맵을 바꿔줌.
        void DrawMap(); // 맵을 그려줌.
};

#endif

 

// Game.cpp

#include <iostream>
#include "Game.hpp"

using namespace std;

// 맵의 크기를 고려해서
// 벽에 부딪쳤는지 안 부딪쳤는지 확인을 함.
bool Human::move_check(int input)
{
    // tmp 변수를 통해 충돌 유무를 판단후
    // 값을 변조를 시킴.
    int tmp;
    switch (input)
    {
        // 왼쪽
    case 1:
        tmp=this->x-this->distance;
        if (tmp < 0)
        {
            cout << "벽에 부딪쳤습니다. 다시 입력해주세요" << endl;
            return  false;
        }
        this->x-=this->distance;
        break;
        // 아래
    case 2:
        tmp=this->y+this->distance;
        if (tmp > 9)
        {
            cout << "벽에 부딪쳤습니다. 다시 입력해주세요" << endl;
            return false;
        }
        this->y += this->distance;
        break;
        // 위
    case 3:
        tmp=this->y-this->distance;
        if (tmp < 0)
        {
            cout << "벽에 부딪쳤습니다. 다시 입력해주세요" << endl;
            return false;
        }
        this->y -= this->distance;
        break;
        // 오른쪽
    case 4:
        tmp=this->x+this->distance;
        if (tmp > 19)
        {
            cout << "벽에 부딪쳤습니다. 다시 입력해주세요" << endl;
            return false;
        }
        this->x +=this->distance;
        break;
    default:
        cout<<"이상한 값을 입력했씁니다. 다시 입력해주세요"<<endl;
        return false;
        break;
    }
    return true;
}

// 맵의 크기를 고려해서
// 벽에 부딪쳤는지 안 부딪쳤는지 확인을 함.
bool Monster::move_check(int input)
{
    // tmp 변수를 통해 충돌 유무를 판단후
    // 값을 변조를 시킴.
    int tmp;

    switch (input)
    {
        // 왼쪽
    case 1:
        tmp=this->x-this->distance;
        if (tmp < 0)
        {
            // debug 용 프린트
            cout << "몬스터 벽에 부딪침" << endl;
            return  false;
        }
        this->x -= this->distance;
        break;
        // 아래
    case 2:
        tmp=this->y+this->distance;
        if (tmp > 9)
        {
            // debug 용 프린트
            cout << "몬스터 벽에 부딪침" << endl;
            return false;
        }
        this->y += this->distance;
        break;
        // 위
    case 3:
        tmp=this->y-this->distance;
        if (tmp < 0)
        {
            // debug 용 프린트
            cout << "몬스터 벽에 부딪침" << endl;
            return false;
        }
        this->y -= this->distance;
        break;
        // 오른쪽
    case 4:
        tmp=this->x+this->distance;
        if (tmp > 19)
        {
            // debug 용 프린트
            cout << "몬스터 벽에 부딪침" << endl;
            return false;
        }
        this->x +=this->distance;
        break;
    default:
        break;
    }
    return true;
}

// 맵의 크기를 고려해서
// 벽에 부딪쳤는지 안 부딪쳤는지 확인을 함.
bool Food::move_check(int input)
{
    // tmp 변수를 통해 충돌 유무를 판단후
    // 값을 변조를 시킴.
    int tmp;

    switch (input)
    {
        // 왼쪽
    case 1:
        tmp=this->x-this->distance;
        if (tmp < 0)
        {
            // debug용 프린트
            cout << "음식이 벽에 부딪침" << endl;
            return  false;
        }
        this->x -= this->distance;
        break;
        // 아래
    case 2:
        tmp=this->y+this->distance;
        if (tmp > 9)
        {
            // debug용 프린트
            cout << "음식이 벽에 부딪침" << endl;
            return false;
        }
        this->y += this->distance;
        break;
        // 위
    case 3:
        tmp=this->y-this->distance;
        if (tmp < 0)
        {
            // debug용 프린트
            cout << "음식이 벽에 부딪침" << endl;
            return false;
        }
        this->y -= this->distance;
        break;
        // 오른쪽
    case 4:
        tmp=this->x+this->distance;
        if (x > 19)
        {
            // debug용 프린트
            cout << "음식이 벽에 부딪침" << endl;
            return false;
        }
        this->x +=this->distance;
        break;
    default:
        break;
    }
    return true;
}

// 다른 객체와 부딪쳤는지 확인하는 함수.
bool GameObject::collide(GameObject *p)
{
    if (this->x == p->x && this->y == p->y)
        return true;
    else
        return false;
}

// Human 움직임을 구현
void Human::move()
{
    char input;
    int out=0;
    do
    {
        cout << "왼쪽(a), 아래(s), 위(d), 오른쪽(f) >> ";
        cin >> input;
        if(input=='a')
            out=1;
        else if(input=='s')
            out=2;
        else if(input=='d')
            out=3;
        else if(input=='f')
            out=4;
        cin.ignore();
    } while (!move_check(out));
}

// Human의 형태를 리턴함.
char Human::getShape()
{
    return 'H';
}

// Monster 움직임을 구현
void Monster::move()
{
    int ran;
    do {
        ran=rand()%4+1;
    } while(!move_check(ran));
}

// Monster의 형태를 리턴함
char Monster::getShape()
{
    return 'M';
}

// Food 움직임을 구현
void Food::move()
{
    int ran;
    ran=rand()%2;

    // 5번중 3번 제자리 체크
    if(ran==0 && count1<3){
        count1++;
        return ;
    }
    // 5번중 2번 움직임 체크
    else{
        count2++;
        do{
            ran=rand()%4+1;
        } while(!move_check(ran));
    }
    if(count1+count2==5){
        count1=0; count2=0;
    }
}

// Food 형태를 리턴함.
char Food::getShape()
{
    return '@';
}

 

// GameController.cpp

#include <iostream>
#include "GameController.hpp"
using namespace std;

// 게임 시작시 각각의 객체들이 동일한 위치에 생성이 된다면
// 게임을 종료시키는 메소드
bool GameController::Check()
{
    if(h.getX()==m.getX() && h.getY()==m.getY()){
        cout<<"휴먼과 몬스터의 위치가 동일합니다."<<endl;
        cout<<"게임종료"<<endl;
        return false;     
    }
    else if(h.getX()==f.getX() && h.getY()==f.getY()){
        cout<<"휴먼과 음식의 위치가 동일합니다."<<endl;
        cout<<"게임종료"<<endl;
        return false;
    }
    else if(m.getX()==f.getX() && m.getY()==f.getY()){
        cout<<"몬스터와 음식의 위치가 동일합니다."<<endl;
        cout<<"게임종료"<<endl;
        return false;
    }
    return true;
}

// 게임 시작을 알리는 메소드
void GameController::Start()
{
    cout<<"명품 c++ 프로그래밍 책에 있는 Open Challenge 문제입니다"<<endl;
    cout<<"코드 오류 및 수정 사항이 있다면, 777bareman777@gmail.com으로 문의 해주시기 바랍니다."<<endl<<endl;
    cout<<"** Human의 Food 먹기 게임을 시작합니다. **"<<endl;
}

// 각각의 객체들의 위치 정보를 받아서,
// 맵을 바꿔주고 있다.
// loop unrooling을 통해 맵의 정보를 바꾸는 속도를 향상시킴.
void GameController::ChangeMap()
{
    for(int i=0;i<10;i++)
        for(int j=0;j<20;j+=4)
        {
            map[i][j]='-'; map[i][j+1]='-';
            map[i][j+2]='-'; map[i][j+3]='-';
        }
    int x,y; // 행 과 열을 표현할 변수

    // food 위치 설정
    x=f.getX();y=f.getY();
    map[y][x]=f.getShape();

    // human 위치 설정
    x=h.getX(); y=h.getY();
    map[y][x]=h.getShape();

    // monster 위치 설정
    x=m.getX(); y=m.getY();
    map[y][x]=m.getShape();
}

// loop unrooling을 통해 맵을 그리는 속도를 향상시킴.
void GameController::DrawMap()
{
    for(int i=0;i<10;i++)
    {
        for(int j=0;j<20;j+=4)
        {
            cout<<map[i][j]<<map[i][j+1]
            <<map[i][j+2]<<map[i][j+3];
        }
        cout<<endl;
    }
}

 

// main.cpp

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <ctime>
#include "Game.hpp"
#include "GameController.hpp"

using namespace std;

int main()
{
    int randX, randY;
    // Human, Monster, Food의 위치를 항상 랜덤하게 나타나게 만듬.
    srand(time(NULL));
    
    // human 위치 초기화
    randX=rand()%20;randY=rand()%10;
    Human h1(randX,randY);

    // monster 위치 초기화
    randX=rand()%20;randY=rand()%10;
    Monster m1(randX,randY);

    // food 위치 초기화
    randX=rand()%20;randY=rand()%10;
    Food f1(randX,randY);

    // GameController 생성
    GameController gc(h1,m1,f1);

    // 게임 시작 부분
    if(!gc.Check())
        return 0;
    gc.Start();
    while(1){
        // 맵의 정보를 바구고 맵을 그림.
        gc.ChangeMap();
        gc.DrawMap();
        // 게임 오버
        if(gc.h.collide(&gc.m) || gc.m.collide(&gc.f))
        {
            cout<<"Monster is winner!!"<<endl;
            return 0;
        }
        // 게임 승리
        else if (gc.h.collide(&gc.f))
        {
            cout<<"Human is winnder!!"<<endl;
            return 0;
        }
        // 각각 객체들이 human, monster, food 순으로 움직임.
        gc.h.move();
        gc.m.move();
        gc.f.move();
    }
}