-
명품 C++ 9장 Open ChallengeC++ 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;elsereturn 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;elsereturn 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;}elsecout << "입력 에러" << 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 이동거리 1Monster *m = new Monster(5, 7, 2); // 몬스터 객체 시작 위치 5,7 이동거리 2Food *f = new Food(8, 10, 1); // 음식 객체 시작 위치 8, 10 이동거리 1public: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