[Baekjoon,3190]뱀

1 분 소요

Vue

해결

이 문제는 위와 같은 이미지의 게임을 구현하면 되는 문제이다. 구현해야 할 부분은 아래와 같다.

  • 뱀을 객체로 표현
    • 변수: 현재 상태
      • 위치
      • 방향
      • 꼬리의 위치
    • 함수: 다음으로 한 칸 움직임
      • 벽 또는 몸에 부딪힘, 사과를 먹는 행위 표현
    • 함수: 방향 전환

코드의 간결화를 위해 +=, == 연산자를 오버로딩 하였으며 움직임 정보가 순서대로 주어지기 때문에 queue에 저장했다. 또한 방향을 전환하는 행위를 상수 배열을 이용하였고 각 방향에 대해 1을 더하거나 빼면 방향 전환을 할 수 있도록 했다. move 함수는 다음 움직임이 실패로 돌아가는 경우 false를 반환하였다.

사과를 먹는 것은 queue를 이용하여 쉽게 표현했다. 사과를 못 먹으면 새로운 위치의 큐를 추가하고 꼬리의 큐를 pop하는 식이다.

구현

구현 할 때 주의사항은 사과의 좌표가 [1,1]을 기준으로 주어지는 것을 유념해야 한다는 것이다.

#include <iostream>
#include <vector>
#include <queue>
using namespace std;

enum{ UP=0, RIGHT, DOWN, LEFT }; 

const int dx[4]={0,1,0,-1};
const int dy[4]={-1,0,1,0};

int N,COUNT=0;

class Pos
{
private:
    int y,x;
public:
    Pos(int _y=0, int _x=0) : y(_y), x(_x) {}
    bool operator==(const Pos& a) const
    {
        return (a.x==x) && (a.y==y);
    }
    Pos& operator+=(const Pos& a)
    {
        y+=a.y;
        x+=a.x;
        return *this;
    }
    bool inRange()
    {
        return 0<=x && x<N && 0<=y && y<N;
    }
};

// <사과 위치, 존재 여부>
vector<pair<Pos,bool> > applesPos;

class Snake
{
private:
    Pos pos;
    int dir;
    queue<Pos> tail;
public:
    Snake() : pos(), dir(RIGHT) 
    {
        tail.push(Pos());
    }
    // 방향을 바꾼다. 
    void turn(char ch)
    {
        // 왼쪽으로 회전 
        if(ch=='L')
        {
            if(--dir==-1)
                dir=LEFT;
        }
        else if(ch=='D')
        {
            if(++dir==4)
                dir=UP;
        }
    }
    // 현재 방향으로 이동하는 데 범위를 벗어나거나 몸에 부딪힌 경우 false를 반환한다. 
    bool move()
    {
        ++COUNT;
        Pos nextPos(dy[dir],dx[dir]);
        nextPos+=pos;
        if(!nextPos.inRange())
            return false;

        // 몸에 부딪히는 지 확인
        bool isHited=false;
        int size=tail.size();
        while(size--)
        {
            Pos slicePos=tail.front();
            tail.pop();
            if(nextPos==slicePos)
                isHited=true;
            tail.push(slicePos);
        }
        if(isHited)
            return false;

        bool canEat=false;
        // 사과를 먹은 경우 확인한다. 
        for(int i=0;i<applesPos.size();++i)
            if(applesPos[i].second && applesPos[i].first==nextPos)
            {
                applesPos[i].second=false;
                canEat=true;
                break;
            }

        tail.push(nextPos);
        // 사과를 못 먹은 경우
        if(!canEat)
            tail.pop();
        
        pos+=Pos(dy[dir],dx[dir]);
        return true;
    }
};

int main()
{
    int appleNum;
    cin>>N>>appleNum;
    for(int i=0;i<appleNum;++i)
    {
        int y,x;
        cin>>y>>x;
        applesPos.push_back(make_pair(Pos(y-1,x-1),true));
    }
    
    // 움직임 정보 
    queue<pair<int,char> > moveInfo;
    int moveNum;
    cin>>moveNum;
    for(int i=0;i<moveNum;++i)
    {
        int at;
        char dir;
        cin>>at>>dir;
        moveInfo.push(make_pair(at,dir));
    }
    
    // 시뮬레이션을 돌린다.
    Snake snake;
    while(snake.move())
        if(moveInfo.front().first==COUNT)
        {
            snake.turn(moveInfo.front().second);
            moveInfo.pop();
        }
    
    cout<<COUNT<<endl;
    return 0;
}

댓글남기기