1. main.cpp 수정 부분
//step3.
int hpPotion = 0;
int mpPotion = 0;
bool isGameStart = false;
//포인터를 사용해서 변수의 메모리 주소를 넘겨줘야 해당 주소로 직접 찾아가서 조작할 수 있음.
setPotion(5, &hpPotion, &mpPotion); //변수의 메모리 주소를 넘기기 위해 & 연산자를 사용하였음
cout << "\n* HP 포션 5개, MP 포션 5개가 기본 지급되었습니다." << endl;
system("pause > nul");
while (!isGameStart) {
system("cls");
...
포인터를 활용한 포션 개수 초기화 함수 추가
main 함수 위쪽에 메모리 주소를 받아 포션 개수를 설정해 주는 setPotion 함수를 새로 추가. 이에 따라 기존에는 int hpPotion = 5; 처럼 바로 숫자를 넣어서 초기화했지만, 이제는 0으로 초기화한 뒤 setPotion(5, &hpPotion, &mpPotion);을 호출해서 포인터의 주소값을 통해 값을 변경하도록 수정.
cin >> MenuChoice;
switch (MenuChoice) {
//던전에 입장하면 랜덤 몬스터(MonsterSpawn)가 소환되고, 전투 루프가 시작 + 루프가 끝나면 인벤토리에 아이템 더하기
case 1: {
//물약을 먹은 후 던전 입장하면 버프가 1 차감 되어야 함. Player.h에 정의해놓음.
player->consumeBuff();
//MonsterSpawn 클래스의 정적함수인 RandomNormalMonster()를 호출
Monster currentMonster = MonsterSpawn::RandomNormalMonster();
//Battle 클래스의 startBattle함수 실행. 전투가 끝난 후 droppedItem 변수에 아이템 정보 받음.
Item droppedItem = Battle::startBattle(player, currentMonster);
//전투루프 종료 후 플레이어가 살아있다면 경험치를 획득하게
if (player->getHP() > 0) {
player->earnExp(currentMonster.getExpReward());
}
//인벤토리에 이미 같은 아이템이 있는지 확인
if (droppedItem.name != "") {
bool isInventoryFound = false;
//같은 아이템이 있는 경우
//inventory는 vector를 사용하기에 auto& 으로 처음부터 끝까지 스캔.
for (auto& item : inventory) {
if (item.name == droppedItem.name) {
item.count += droppedItem.count; //아이템 카운트를 1 늘림.
isInventoryFound = true;
break;
}
}
//같은 아이템이 없는 경우
if (!isInventoryFound) {
if (inventory.size() < inventory_MAX) {
inventory.push_back(droppedItem); //인벤토리에 새 칸을 추가하기 위해 push_back 사용.
}
else {
cout << " -> 인벤토리가 가득 차서 [" << droppedItem.name << "]을(를) 버렸습니다." << endl;
}
}
}
break;
}
던전 입장 시 버프 턴 차감 로직 추가
메인 메뉴에서 1번 던전 입장을 선택했을 때, 몬스터가 소환되기 직전에 player->consumeBuff(); 코드 추가. 주석에 적어둔 것처럼, 포션 제작소에서 만든 포션을 사용하고 버프를 얻은 상태로 던전에 입장하면 버프 지속 횟수를 1씩 차감하기 위한 기능. (아직 포션 사용 기능은 만들지 않았음)
전투 종료 후 몬스터 경험치 획득 로직 추가
던전에서 전투(Battle::startBattle)가 끝난 직후에 플레이어가 살아있는지(player->getHP() > 0) 확인하는 조건. 플레이어가 전투에서 생존했다면 player->earnExp(currentMonster.getExpReward()); 코드가 실행되면서 잡은 몬스터의 경험치를 보상으로 획득하도록 로직을 업데이트.
2-1. Player.h 변경 부분
#ifndef PLAYER_H_
#define PLAYER_H_
#include <iostream>
#include <string>
using namespace std;
class Monster; //Monster 클래스 전방 선언
class Player {
protected:
string name;
string job;
int level;
int hp, mp, power, defence;
int exp;
int maxExp;
int maxHp;
int maxMp;
int staminaBuffTurnsLeft = 0;
int powBuffTurnsLeft = 0;
public:
Player(string name, int hp, int mp, int power, int defence);
virtual ~Player() {} //상속 목적의 부모 클래스의 가상 소멸자
//virtual void attack() = 0; 기존의 순수 가상 함수
virtual void attack(Monster* monster) = 0; //-> 각 직업별 함수 오버라이드(몬스터 클래스 전방 선언 이후 변경)
void printPlayerStatus(); //전직 이후의 상태창
//경험치 획득 및 레벨업
void earnExp(int amount);
void levelUp();
//포션 사용 함수
void useHpPotion();
void useMpPotion();
//void useStaminaPotion();
//void useStrengthPotion();
//getter와 setter 함수. name, job, hp, mp, power, defence
string getName() { return name; }
string getJob() { return job; }
int getHP() { return hp; } //hp값을 반환해줘야 하니까 int.
void setHP(int value) { hp = value; } //반환할 필요는 없으니까 void. value는 공간을 만들어놓음.
int getMP() { return mp; }
void setMP(int value) { mp = value; }
int getPower() { return power; }
int getDefence() { return defence; }
//경험치 관련 getter setter
int getExp() { return exp; }
int getMaxExp() { return maxExp; }
//던전 3회 동안 공격력 2배 -> 버프 상태, 남은 횟수, 공격력에서 조건 추가
int getBuffPower() { return (powBuffTurnsLeft > 0) ? power * 2 : power; }
void useStaminaPotion() { staminaBuffTurnsLeft = 3; }
void useStrengthPotion() { powBuffTurnsLeft = 3; }
void consumeBuff() {
if (staminaBuffTurnsLeft > 0) {
staminaBuffTurnsLeft--;
}
if (powBuffTurnsLeft > 0) {
powBuffTurnsLeft--;
}
}
};
#endif
몬스터 클래스 전방 선언 추가
파일 위쪽에 class Monster;라는 전방 선언 추가. Player 클래스 안에서 Monster 객체를 사용할 떄, 서로 헤더 파일을 참조하면서 생길 수 있는 꼬임 현상을 방지하기 위해 미리 알려주는 역할.
새로운 상태와 버프 관련 멤버 변수 추가
protected 영역에 캐릭터의 성장을 위한 경험치 관련 변수(exp, maxExp)와 최대 체력/마나를 기억할 변수(maxHp, maxMp)추가. 그리고 포션 제작소와 연동될 버프 지속 턴 수를 계산하기 위해 staminaBuffTurnsLeft와 powBuffTurnsLeft 변수를 0으로 초기화된 상태로 추가.
공격(attack) 함수 구조 변경
원래는 virtual void attack() = 0;으로 허공에 공격하는 형태였다면, 업데이트 후 virtual void attack(Monster* monster) = 0;으로 바꿈. 전방선언을 한 이유가 이 포인터를 쓰기 위함이었음. 플레이어가 특정 몬스터를 타겟으로 지정해서 공격할 수 있도록 몬스터 매개변수를 받게 됨.
경험치 및 레벨업 관련 함수 추가
메인 코드에서 전투가 끝난 뒤 경험치를 얻던 로직을 처리할 수 있게 void earnExp(int amount);와 void levelUp(); 함수가 선언되었고, 이 값을 외부에서 확인할 수 있도록 하단에 getExp()와 getMaxExp() 함수도 함께 추가.
포션 및 버프 시스템 관련 함수 대거 추가
기본 포션을 사용하기 위한 useHpPotion(), useMpPotion() 선언을 추가. 특정 포션을 먹으면 남은 턴 수를 3으로 늘려주는 useStaminaPotion()과 useStrengthPotion(), 던전에 입장할 때마다 버프 턴을 1씩 깎는 consumeBuff(), 그리고 공격력 버프가 남아있을 때 실시간으로 공격력을 2배로 뻥튀기해서 반환해 주는 getBuffPower()추가.(버프 시스템 때문에 선언한 함수가 많아졌음)
2-2. Player.cpp 변경 부분
#include "Player.h"
//Player:: Player클래스 안에 있는,
//Player(...) 생성자. 캐릭터가 생성될 때 한번 생성.
// : name(), hp()~ 멤버 초기화 리스트. 생성자 생성한 후에 외부에서 받아온 매개변수로 초기화해라.
Player::Player(string name, int hp, int mp, int power, int defence)
: name(name), hp(hp), mp(mp), maxHp(hp), maxMp(mp), power(power), defence(defence), level(1), job("초보자"), exp(0), maxExp(100) {
}
//경험치 획득
void Player::earnExp(int amount) {
//던전 3회 동안 경험치 2배 -> 버프 상태, 남은 횟수, 경험치 로직에 조건 추가. 물약 상태면 amount를 2배로 세팅.
if (staminaBuffTurnsLeft > 0) {
amount *= 2;
}
exp += amount;
cout << "★ 전투 승리!" << endl;
cout << " -> 경험치 +" << amount << " 획득! (현재 경험치: " << exp << "/" << maxExp << ")" << endl << endl;
if (staminaBuffTurnsLeft > 0) {
cout << "현재 스태미나포션의 효과로 경험치를 2배 획득했습니다. (" << staminaBuffTurnsLeft << ")회 남음" << endl;
}
//if대신 while을 써서 조건값이 true면 반복되도록 했음.
while (exp >= maxExp) {
levelUp();
}
//수정 이전. 레벨이 1씩밖에 오르지 않았음. 레벨 1 오르면 exp = 0 으로 초기화.
//if (exp >= maxExp) {
// levelUp();
//}
}
//레벨업 + 경험치 초기화
void Player::levelUp() {
int previousLevel = level;
level++;
maxHp += 10;
maxMp += 5;
power += 5;
hp = maxHp;
mp = maxMp;
//레벨업 했을 때 경험치를 0으로 초기화하는 게 아니라 레벨업 요구치만큼 차감하면 됨.
exp -= maxExp;
//exp = 0; (이전 버전)
maxExp += 50; //요구 경험치 50씩 증가.
cout << "★ 레벨 업! Lv." << previousLevel << " -> Lv." << level << endl;
cout << " -> HP + 10, MP +5, 공격력 +5 증가!" << endl << endl;
system("pause");
}
//exp, lecel 추가해서 새롭게 상태창 함수 작성
void Player::printPlayerStatus() {
cout << "------------------------------------" << endl;
cout << "닉네임: " << name << " | 직업: " << job << " | Lv." << level << " (" << exp << " / " << maxExp << ")" << endl;
cout << "HP: " << hp << " / " << maxHp << " | MP: " << mp << " / " << maxMp << " | 공격력: " << power << " | 방어력: " << defence << endl;
cout << "------------------------------------" << endl;
}
//포션때문에 useHp, Mp 포션 만들어야 했음
void Player::useHpPotion() {
hp += 20;
if (hp > maxHp) {
hp = maxHp;
}
}
void Player::useMpPotion() {
mp += 20;
if (mp > maxMp) {
mp = maxMp;
}
}
생성자 초기화 리스트 확장
캐릭터가 처음 만들어질 때 실행되는 생성자의 초기화 리스트에 항목들을 추가. 기존의 기본 스탯뿐만 아니라 최대 체력maxHp, maxMp, exp = 0(초기 경험치), maxExp = 100 를 한 번에 세팅하도록 업데이트.
경험치 획득 및 버프 연동 로직 구현
earnExp 함수를 추가. 전투 승리 시 경험치를 올려주도록 간단하게 작성할 수 있으나, 스태미나 버프(staminaBuffTurnsLeft > 0)가 켜져 있으면 추가 경험치를 획득하는 로직까지 포함하였음. 또한 레벨업 판정을 if문 대신 while문으로 변경해서 한 번에 많은 양의 경험치를 받았는데도 레벨업이 하나만 되지 않도록, 연속으로 레벨업할 수 있도록 변경.
레벨업 능력치 상승 및 잔여 경험치 이월
levelUp 함수의 경우. 레벨이 오르면 최대 체력이 10, 최대 마나가 5, 공격력이 5 상승하고, 현재 체력과 마나를 최대치까지 채워주는 기능을 포함. 레벨업 시 경험치를 0으로 초기화하지 않고 exp -= maxExp;를 사용해서 레벨업에 쓰인 만큼만 차감하고 남은 경험치는 이월시키도록 변경.
상태창 출력 정보 디테일 추가
printPlayerStatus 함수의 변경. 레벨 옆에 현재 경험치와 요구 경험치 비율을 띄워주고, 체력과 마나도 현재 수치와 최대 수치를 슬래시(/)로 구분하였음.
포션 사용 시 최대치 초과 방지 기능
마지막으로 useHpPotion과 useMpPotion 함수를 추가. 체력과 마나를 20씩 올려주고, 만약 포션을 먹고 회복된 수치가 최대치(maxHp, maxMp)를 넘어가게 되면 최대치까지만 맞춰지도록 제한하였음.
3. MonsterSpawn.cpp
//MonsterSpawn.cpp
//Monster(string name, int hp, int power, int defence, string item, int price, int expReward)
case 0:
return Monster("슬라임", 30, 20, 10, "슬라임의 끈적한 젤리", 30, 20);
경험치 획득 로직이 추가되어서, 몬스터에게 각각 경험치를 부여했다. (expReward. Monster.h에 생성자가 존재)
4. Monster.h
class Monster {
private:
string name;
int hp, power, defence;
int expReward;
private 영역에 int expReward; 변수를 추가 정의. 몬스터가 가지고 있는 경험치 보상 수치를 저장할 목적.
public: //생성자
Monster(string name, int hp, int power, int defence, string item, int price, int expReward)
: name(name), hp(hp), power(power), defence(defence), dropItemName(item), dropItemPrice(price), expReward(expReward) {
}
새로운 변수가 추가됨에 따라 생성자의 매개변수를 하나 늘렸음. 마지막 인자로 int expReward를 받으며, 초기화 리스트를 통해 멤버 변수를 초기화하도록 수정. 따라서 MonsterSpawn에서 경험치 값을 추가로 입력했음.
//몬스터가 가지고 있는 expReward getter함수
int getExpReward() { return expReward; }
getter함수를 추가해서 몬스터의 경험치 보상 값을 가져올 수 있도록 했음.
5. Battle.cpp
#include "Battle.h"
#include "Item.h"
#include <iostream>
using namespace std;
Item Battle::startBattle(Player* player, Monster& monster) {
cout << "\n===========================================" << endl;
cout << "[ 전투 시작! ] " << player->getName() << "(" << player->getJob() << ") vs " << monster.getName() << endl;
cout << "===========================================" << endl;
while (player->getHP() > 0 && monster.getHP() > 0) { //둘다 살아있을 때 전투루프
cout << "\n--- 플레이어 턴 ---" << endl; //플레이어 턴, 플레이어 공격
player->attack(&monster);
//몬스터가 사망했을 경우 문자열을 추가로 출력 -> Win 방향으로
if (monster.getHP() <= 0) {
cout << " (사망)" << endl;
break; //몬스터가 사망했으므로 전투루프 종료
}
//몬스터의 공격
cout << "\n--- 몬스터 턴 ---" << endl;
monster.attack(player);
cout << player->getName() << " HP: " << player->getHP() << endl;
//플레이어가 패배했을 경우 문자열을 추가로 출력 -> Lose 방향으로
if (player->getHP() <= 0) {
cout << "\n[ 패배 ] " << player->getName() << "님은 패배했습니다." << endl;
break;
}
}
//이제 전투 루프 탈출했으니까 승리 or 패배 텍스트 출력
if (monster.getHP() <= 0) {
cout << "\n★ 전투 승리!" << endl;
cout << " -> " << monster.getDropItemName() << " 획득!" << endl;
cout << " -> 인벤토리에 저장되었습니다." << endl;
cout << "\n계속하려면 아무 키나 누르세요." << endl;
system("pause > nul");
return Item(monster.getDropItemName(), 50, 1); //생성자를 활용해서 가독성을 높였음.
}
if (player->getHP() < 0) {
cout << "..전투에서 패배하였습니다.." << endl;
cout << "..메인 메뉴로 돌아가세요.." << endl;
system("pause > nul");
return Item(); //함수를 종료하고 startBattle 시작 전으로 돌아감.
}
}
가장 큰 변화는 책임 분산, 그리고 코드가 하나의 클래스에 집중되는 것을 막고자 했음.
데미지 계산 및 HP 갱신 로직의 이동
원래는 Battle::startBattle 함수 내부에서 직접 플레이어의 공격력과 몬스터의 방어력을 계산하고, setHP를 통해 몬스터의 체력을 깎았으나, player->attack(&monster); 으로 대체. 공격 시 발생하는 데미지 계산과 상대방의 HP 감소 처리를 Player 클래스의 attack 메서드가 전담하도록 변경하였음.
함수 인자 전달 방식의 변화
이전에는 player->attack()을 인자 없이 호출했으나, player->attack(&monster)와 같이 공격 대상인 monster의 주소값을 인자로 넘기게 변경. 플레이어가 누구를 공격하는지 확인하고 대상 객체에 직접 접근해서 상태를 변화시킬 수 있게 하기 위함.
코드의 간결성 및 가독성
불필요한 지역 변수(playerDamage, beforeMonsterHP) 선언과 조건문(데미지가 0 이하일 때 1로 고정하는 로직 등)을 제거했음. startBattle 함수의 가독성을 올리기 위함이었음.
텍스트 출력의 변화
이전 버전에서는 monster.getHP() 변화 과정을 "HP: 100 -> 80"과 같이 Battle 클래스에서 직접 출력했지만, 변경 이후에는 상세한 전투 수치 출력을 Player::attack 메서드 내부로 옮겼음.
6. 직업 헤더파일, 소스 파일(ex)Thief.h, Thief.cpp)
1) Thief.h
#ifndef THIEF_H_
#define THIEF_H_
#include "Player.h"
//전방 선언은 Monster가 있다는 것만 알리기(Player.h가 있으니까)
class Monster;
//자식 클래스 Thief가 부모 클래스 Player(public만)를 상속하도록 만듬.
class Thief : public Player {
public:
Thief(string name, int hp, int mp, int power, int defence);
void attack(Monster* monster) override;
};
#endif
선언과 구현의 분리
생성자(Thief(...))와 attack() 함수의 구체적인 동작이 헤더 파일(.h) 안에 모두 포함되어 있는 인라인(Inline) 형태였었으나, 이제는 헤더에 함수를 선언만 함.
Monster 클래스와의 상호작용 추가
attack(Monster* monster)와 같이 Monster 객체의 포인터를 인자로 받아서 도적(플레이어)이 단순히 공격 모션을 취하는 것을 넘어 특정 몬스터에게 대미지를 입히는 등의 직접적인 상호작용을 가능하게 했음.
전방 선언(Forward Declaration) 활용
class Monster;라는 전방 선언이 추가되었고, 이를 통해 헤더 간의 상호 참조 문제를 방지했음.
함수 시그니처 변경 (오버라이딩 조건)
부모 클래스인 Player의 attack 함수도 Monster*를 인자로 받도록 함께 업데이트하였음.
2) Thief.cpp
#include "Thief.h"
#include "Monster.h"
#include <iostream>
using namespace std;
Thief::Thief(string name, int hp, int mp, int power, int defence) : Player(name, hp, mp, power, defence) {
job = "도적"; //직업명
power += 10; //직업 특화 스탯
}
void Thief::attack(Monster* monster) {
int damage = (getPower() - monster->getDefence()) / 5;
if (damage <= 0) {
damage = 1;
}
int beforeMonsterHP = monster->getHP();
for (int i = 0; i < 5; i++) {
monster->setHP(monster->getHP() - damage);
}
cout << "[도적] 단검을 찌른다! -> " << monster->getName() << "에게 " << damage << " 데미지! (x5)" << endl; //직업 특수 문자열 출력
cout << monster->getName() << " HP: " << beforeMonsterHP << " -> " << monster->getHP();
}
범위 지정 연산자(::) 사용: Thief::Thief나 Thief::attack처럼 함수 이름 앞에 Thief::를 붙여, 이 함수들이 Thief 클래스에 소속된 것임을 명시.
생성자(Constructor)의 역할 수행
Thief.h에서 선언했던 생성자를 실제로 구현하며 초기화를 진행. 부모 클래스(Player)의 생성자를 먼저 호출한 뒤, 내부에서 job = "도적"이나 power += 10과 같이 도적 클래스만의 고유 스탯을 설정하는 로직을 실행하도록 했음.
attack(Monster* monster) 내부의 상세한 전투 공식 작성
monster->getDefence()를 통해 상대의 방어력을 가져와 대미지를 계산하고,
for문을 사용하여 "단검으로 여러 번 공격한다"는 도적의 컨셉을 monster->setHP()를 5회 반복 호출하는 방식을 구현했음. 궁수의 경우에는 같은 방식으로 3번 공격하도록 변경. power에서 defence를 먼저 빼고 그 뒤에 횟수로 나눠줘야 함. 그렇지 않으면 공격력이 5분의 1이 되어버려서 몬스터의 방어구를 뚫지 못하는 망한 캐릭터가 되어버리기 때문.
이후에는 공격 전후의 HP 변화를 계산하여 정보를 출력하도록 포인터를 활용해서 변경하였음.
*오늘의 코드카타*
정수 n을 입력받아 n의 약수를 모두 더한 값을 리턴하는 함수, solution을 완성해주세요.
n은 0 이상 3,000이하인 정수입니다.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
int solution(int n) {
int answer = 0;
for (int i = 1; i * i <= n; ++i) {
if ( n % i == 0 ) {
answer += i;
if ( i * i != n ) {
answer += ( n / i );
}
}
}
return answer;
}
핵심 아이디어는, 모든 정수 n을 a * b 꼴로 나타낼 수 있다는 것.
그리고 a가 결정되면 자동적으로 b가 결정된다는 것이다.
엄청 큰 수가 아니라면 a를 찾기는 쉽다. 이 경우에는 i = 1부터 n의 제곱근까지만 스캔하면서 a를 찾고 자동으로 b가 찾아지게 한다. 다만, 예를 들어 16의 약수를 찾는 과정에서 16 = 4*4 같은 경우에 4가 중복되므로 이를 피하기 위해 두 숫자가 다를 때만 더하라는 조건을 추가한다.
n의 제곱근보다 큰 수를 스캔할 필요가 없는게, 이미 n제곱근보다 작거나 같은 수 범주에서 스캔하면서 짝꿍을 다 찾았기 때문에
굳이 중복해서 찾을 필요가 없는 것이다.
그래서 만약 n % i == 0 이라면, 적절한 수로 잘 나누어서 약수를 찾아낸 것이므로 그 수 i를 더한다. 그리고, i^2 이 n보다 작거나 같은 수일 때까지 i를 증가시키면서 조건을 충족하는 i 값을 찾는다.
그러면 같은 조건에서 약수의 개수를 세는 방법은?
간단하다. 이미 작성한 코드에 if 조건문을 넣기만 하면 된다.
프로그래밍적으로는 반복문을 이용해서 숫자를 세는 것이다.
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
int solution(int n) {
int count = 0; //개수 세기
for (int i = 1; i * i <= n; ++i) {
if ( n % i == 0 ) {
if ( i * i == n ) { count += 1; }
else { count += 2; }
}
}
return count;
}
아까와 같은 논리로 i * i = n 형태가 나오면 i가 중복되므로 개수를 셀 때 하나만 세도록 한다. n 제곱근보다 작거나 같은 경우는 자동적으로 짝꿍이 정해지므로 2개를 세도록 한다.
수학적으로 생각해보면 소인수분해를 활용해야 한다.
가장 작은 소수인 2부터 시작해서 숫자를 나누고 특정 소수로 더 이상 나누어지지 않을 때까지 계속 나누면서 그 숫자로 몇번 나누었는지 누적하면서 센다.
그리고 (지수 + 1) 값 끼리 곱해주면 된다.
예를 들어서 12 = 2^2 * 3 이니까, (2+1) * (1+1) = 6개가 약수의 개수가 된다. 반복문을 활용하는 것과 비교해보자면, 12의 제곱근이 대략 3과 4 사이의 값이므로, i = 1, 2, 3 일 때 갯수를 셀 것이고 짝꿍도 덩달아서 정해지니까 6개의 값이 출력 될 것이다.
그러면 소인수분해를 어떻게 코드로 구현할까?
n이 0보다 큰 정수라는 조건에서의 소인수분해 코드는 다음과 같다. 핵심 아이디어는 가장 작은 소수인 2부터 n의 제곱근까지 i로 나누기 시작하고, 나누어 떨어지는 i값을 찾으면 지수를 카운트하는 식이다.
#include <iostream>
long long count(int n) {
if ( n == 1 ) return 1;
long long totalCount = 1;
int tempN = n;
for (int i = 2; i * i <= tempN; ++i) {
if (tempN % i == 0) {
int exponent = 0;
while (tempN % i == 0) {
exponent++;
tempN /= i;
}
totalCount *= (exponent + 1);
}
}
if (tempN > 1) {
totalcount *= 2;
}
return totalCount;
}
롱롱은 엄청 큰 수까지 감안해서 써보자.
n값으로 직접 나누기보다 tempN을 선언해서 계속 나눌 수를 임시로 만들어 주는 게 좋다. 그리고 tempN을 i로 나눈 값을 다시 tempN으로 만들어서 while문으로 계속 나누면서 나머지 값이 0 이 될때마다 exponent에 숫자를 하나씩 더한다.
이렇게 되면 소인수분해처럼 지수의 개수를 누적해서 셀 수가 있다.
결론적으로 (지수 + 1) 값들을 곱한 값이 totalCount가 되어 약수의 개수를 셀 수가 있다.
주의할 점은, 루프가 끝난 후에 tempN이 1보다 크다면 남은 수는 소수이기 때문에, 소수의 지수는 1이므로 1+1인 2를 추가로 곱해줘야한다.
