BOJ::17081 RPG Extreme

시사점

이해(x)

설계, 손 코딩(x)

시간 복잡도

공간 복잡도

손 코딩 후 문제 리뷰(x)

구현(x)

함수 List

void PRINT(); : 게임 종료시, 맵을 출력합니다.
void PRINT3(int idx, int who, int exitreason); : 게임 종료시, 주인공의 상태  사유를 출력합니다.

void input(); : 모든 입력을 받습니다.
 - void input_mp();  : 맵의 상태를 입력받습니다.
 - void input_move();  : 시뮬레이션 돌릴 이동방향을 입력받습니다.
 - void input_mons();  : 몬스터의 신상을 입력받습니다.
 - void input_items(); : 아이템 관련 사항을 입력받습니다.
void init(); : 주인공의 상태를 초기화합니다.
bool over(int x, int y); 
void getItem(int x, int y); : 이동  아이템이 있는 칸으로  경우, 처리해주는 함수
void getMonster(int x, int y); : 이동  몬스터를 만난 경우, 처리해주는 함수
void process(); 전반적으로 모든 시뮬레이션 과정을 담고 있습니다.

업데이트 되는 변수

실제 구현

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<b;i++)
const int MAXNM = 100, SCRACH = 5;
const char DIR[]={'U','R','D','L'};
const int dx[]={-1, 0, 1, 0}, dy[]={0, 1, 0, -1};
enum ac {HR = 0, RE, CO, EX, DX, HU, CU};
std::string seq[]={"HR", "RE", "CO", "EX", "DX", "HU", "CU"};
struct mon{int atk; int shield; int mxHp; int curHp; int giveExp;std::string ss;};
struct itms{char T; int addup;};
struct hero{int x; int y; int atk; int sword; int shield; int cover; int mxHp; int curHp; int curExp; int mxExp; int Lvl; int cntAccs; bool accs[7];};
using namespace std;

int n, m, sx, sy;
int cntmons, cntitems;
char mp[MAXNM][MAXNM];
int mp_item[MAXNM][MAXNM];
int mp_mons[MAXNM][MAXNM];
vector<int> moves;

hero me;
vector<mon> monsters;
vector<itms> items;
void PRINT();
void PRINT3(int idx, int who, int exitreason);
void input(); void input_mp(); void input_move(); void input_mons(); void input_items();
void init();
bool over(int x, int y);
void getItem(int x, int y);
void getMonster(int x, int y);
// mp[x][y] = {'.', '#', 'B', '^', '&', 'M'}
// 종료 조건 = { me.curHP <= 0(monster와 싸워서), me.curHP <= 0(트랩 밟아서), M잡은 경우, moves다 돈 경우, }
void process(){
    int idx = 0, who  = 0, exitreason = 3;
    input();
    init();
    rep(i, 0, moves.size()){
        idx = i;
        int nx = me.x + dx[moves[i]], ny = me.y + dy[moves[i]];
        if(over(nx, ny) || mp[nx][ny] == '#'){
			nx = me.x, ny = me.y;
            if(mp[me.x][me.y] == '^') me.curHp -= SCRACH/(me.accs[DX]?5:1);
            goto here;
        }
        else if(mp[nx][ny] == '^') me.curHp -= SCRACH/(me.accs[DX]?5:1);
        else if(mp[nx][ny] == '.') ;
        else if(mp[nx][ny] == 'B'){
            getItem(nx, ny);
            mp[nx][ny] = '.';
        }else if(mp[nx][ny] == '&' || mp[nx][ny] == 'M'){
            getMonster(nx, ny);
            if(me.curHp > 0){
                if(mp[nx][ny] == 'M'){
                    mp[nx][ny] = '.';
                    me.x = nx, me.y = ny;
                    exitreason = 2;
                    break;
                }
                mp[nx][ny] = '.';
            }
            else{
                who = mp_mons[nx][ny];
            }
        }else { /* Do nothing */ }
        me.x = nx, me.y = ny;
    here:;
        if(me.curHp <= 0 && me.accs[RE]) me.x = sx, me.y = sy, me.curHp = me.mxHp, me.accs[RE] = false;
        // 끝에서 체력확인
        if(me.curHp <= 0){
            if(mp[nx][ny] == '^' || over(nx, ny))exitreason = 1;
            else exitreason = 0;
            break;
        }
    }
    PRINT();
    PRINT3(idx, who, exitreason);
}
int main(){
#ifdef DEBUG
    freopen("input.txt", "r", stdin);
#endif
    ios_base::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    process();
    return 0;
}
void getMonster(int x, int y){
    // before fight
    struct mon curMon = monsters[mp_mons[x][y]];
    if(mp[x][y] == 'M' && me.accs[HU]) me.curHp = me.mxHp;
	int rnd = 0;
	while(true){
		int me_atk = me.atk + me.sword;
        if(rnd == 0 && me.accs[CO]) me_atk *= (2+ me.accs[DX]);
        int me_shield = me.shield + me.cover;
        // me -> monster
        curMon.curHp -= max(1, me_atk - curMon.shield);
        if(curMon.curHp <= 0) break;

        // me <- monster
        if(rnd == 0 && mp[x][y] == 'M' && me.accs[HU]) ;
        else me.curHp -= max(1, curMon.atk - me_shield);
        if(me.curHp <= 0) break;
		rnd++;
	}
    // after fight
    if(me.curHp > 0){
        if(me.accs[HR]) me.curHp = min(me.curHp +3, me.mxHp);
        me.curExp += (double)curMon.giveExp * ((double)1 +(double)(me.accs[EX]?0.2:0) );
        if(me.curExp >= me.mxExp){
            ++me.Lvl, me.curExp = 0, me.mxExp = me.Lvl * 5;
            me.mxHp += 5, me.atk += 2, me.shield += 2;
            me.curHp = me.mxHp;
        }
    }else{

    }
}
void getItem(int x, int y){
    struct itms curItm = items[mp_item[x][y]];
    if(curItm.T == 'W') me.sword = curItm.addup;
    else if(curItm.T == 'A') me.cover = curItm.addup;
    else{
        if(me.cntAccs < 4 && !me.accs[curItm.addup]){
            me.accs[curItm.addup] = true;
            me.cntAccs++;
        }
    }
}
bool over(int x, int y){ return (x<0 || y<0 || x>=n || y>=m);}
void init(){
    // hero
    me.x = sx, me.y = sy;
    me.atk = 2, me.shield = 2, me.curHp = 20, me.mxHp = 20, me.Lvl = 1;
    me.curExp = 0, me.mxExp = me.Lvl * 5;
}
void input_mp(){
    cin >> n >> m;
    rep(i, 0, n){
        rep(j, 0, m){
            cin >> mp[i][j];
            if(mp[i][j] == '@'){
                mp[i][j] = '.';
                sx = i, sy = j;
            }else if(mp[i][j] == '&' || mp[i][j] == 'M'){
                mp_mons[i][j] = cntmons++;
            }else if(mp[i][j] == 'B'){
                mp_item[i][j] = cntitems++;
            }
        }
    }
}
void input_move(){
    string s; cin >> s;
    rep(i, 0, s.size()){
        rep(k, 0, 4) if(DIR[k] == s[i]){
            moves.push_back(k);
            break;
        }
    }
}
void input_mons(){
    monsters = vector<mon> (cntmons);
    rep(i, 0, cntmons){
        int r, c; string name; int atk, shield, mxHp, giveExp;
        cin >> r >> c >> name >> atk >> shield >> mxHp >> giveExp;
        monsters[mp_mons[r-1][c-1]] = {atk, shield, mxHp, mxHp, giveExp, name};
    }
}
void input_items(){
    items = vector<itms> (cntitems);
    rep(i, 0, cntitems){
        int r, c; char T; int si= -1; string ss;
        cin >> r >> c >> T;
        if(T == 'O'){
            cin >> ss;
            rep(k, 0, 7) if(strcmp(seq[k].c_str(), ss.c_str()) == 0){
                si = k;
                break;
            }
        }
        else cin >> si;
        items[mp_item[r-1][c-1]] = {T, si};
    }
}
void input(){
    input_mp();
    input_move();
    input_mons();
    input_items();
}
void PRINT(){
    rep(i, 0, n){
        rep(j, 0, m){
            if(i == me.x && j == me.y && me.curHp > 0) cout << '@';
            else cout << mp[i][j];
        }cout << endl;
    }
}
// 종료 조건 = { me.curHP <= 0(monster와 싸워서), me.curHP <= 0(트랩 밟아서), M잡은 경우, moves다 돈 경우, }
void PRINT3(int idx, int who, int reason){
    cout << "Passed Turns : " << idx+1 << endl;
    cout << "LV : " << me.Lvl << endl;
    cout << "HP : " << max(0, me.curHp) << "/" << me.mxHp << endl;
    cout << "ATT : " << me.atk<< "+"<<me.sword << endl;
    cout << "DEF : " << me.shield <<"+"<<me.cover << endl;
    cout << "EXP : " << me.curExp <<"/" << me.mxExp << endl;
    if(reason == 0){
        cout << "YOU HAVE BEEN KILLED BY " << monsters[who].ss <<".." << endl;
    }else if(reason == 1){
        cout << "YOU HAVE BEEN KILLED BY SPIKE TRAP.." << endl;
    }else if(reason == 2){
        cout << "YOU WIN!" << endl;
    }else{
        cout << "Press any key to continue." << endl;
    }
}

구현 후 코드리뷰 + 예제 돌려보기(x)

디버깅(x)

좋은 코드

최적화