Notice
Recent Posts
Recent Comments
Link
«   2025/12   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

rabbit97 님의 블로그

23일 일지 본문

개발 일지

23일 일지

rabbit97 2024. 8. 23. 20:28

오늘은 일어나서 알고리즘 2문제 풀고 바로 개인 과제! 

그래도 확실히 기본기가 늘고 있다고 느낀게 처음엔 알고리즘 문제에서 다음 문제 넘어갈때마다 뭘 써야하지 한참 고민하면서 풀었는데

양의 정수 x가 하샤드 수이려면 x의 자릿수의 합으로 x가 나누어져야 합니다. 예를 들어 18의 자릿수 합은 1+8=9이고, 18은 9로 나누어 떨어지므로 18은 하샤드 수입니다. 자연수 x를 입력받아 x가 하샤드 수인지 아닌지 검사하는 함수, solution을 완성해주세요.

 

function solution(x) {
let a = 0;
let b = x.toString();
for (let i = 0; i < b.length; i++) {
a += Number(b[i]);
}
return x % a === 0;
}



두 정수 a, b가 주어졌을 때 a와 b 사이에 속한 모든 정수의 합을 리턴하는 함수, solution을 완성하세요.
예를 들어 a = 3, b = 5인 경우, 3 + 4 + 5 = 12이므로 12를 리턴합니다.

 

function solution(a, b) {
let x = 0;
if (a <= b) {
for (let i = a; i <= b; i++) {
x += i;
}
} else {
for (let i = b; i <= a; i++) {
x += i;
}
}

return x;
}

쓸대없이 reduce나 for of 처럼 코드를 간편하고 효율적인 코드를 내가 못만드니 검색하면서 풀었던 전보단

오직 for 만을 이용해서 풀었다. 저번 주말부터 특훈이였던 기본기 다지기에 성공했나보다!! (뿌듯)

 

물론 이 간단한 걸 만들면서도 오류가 너무 많이 났었지만

푸는 거에 집중해서 검색해서 구현도 못하는거 가져다 쓴 것 보단 내 능력 안에서 스스로 풀었다는 거에 만족

 

그리고 개인 과제 근황

import chalk from 'chalk';
import readlineSync from 'readline-sync';

class Skill {
constructor(name, probability, effect) {
this.name = name;
this.probability = probability;
this.effect = effect;
}
}
const combo = new Skill('연속 공격', 0.3, (player, monster, logs) => {
for (let i = 0; i < 3; i++) {
player.attack(monster, logs);
}
logs.push(chalk.green(`연속 공격을 성공!`));
});

class Player {
constructor(player) {
this.name = '';
this.hp = 100;
this.attacks = 10;
this.defense = 5;
this.speed = 8;
this.inventory = [];
}

equip(item) {
this.inventory.push(item);
this.applyEquipmentStats();
}

unequip(item) {
const index = this.inventory.indexOf(item);
if (index !== -1) {
this.inventory.splice(index, 1);
this.applyEquipmentStats();
}
}

applyEquipmentStats() {
this.attacks = 10;
this.defense = 5;
this.inventory.forEach((item) => {
this.attacks += item.attackBonus;
this.defense += item.defenseBonus;
});
}

attack(monster, logs) {
if (Math.random() < combo.probability) {
combo.effect(this, monster, logs);
return;
}
const critical = 0.1;
const Cri = Math.random() < critical;
const inidamage = this.attacks - monster.defense;
const random = Math.random() * 20 - 10;
const damage = Math.max(1, Math.round(inidamage + random));
const finalDamage = Cri ? damage * 2 : damage;

monster.hp -= finalDamage > 0 ? finalDamage : 1;

logs.push(chalk.green(`${this.name}${finalDamage}${Cri ? ' (크리티컬!)' : ''} 공격!`));
}
}

function increaseStats(player, stage) {
const increase = 30;
player.attacks += Math.floor(Math.random() * increase) + 10;
player.defense += Math.floor(Math.random() * increase);
player.speed += 1;

console.log(
chalk.green(`공격력: ${player.attacks}, 방어력: ${player.defense}, 스피드: ${player.speed}`),
);
}

class Equipment {
constructor(name, attackBonus, defenseBonus) {
this.name = name;
this.attackBonus = attackBonus;
this.defenseBonus = defenseBonus;
}
}

class Monster {
constructor(stage) {
this.hp = stage * 100;
this.attacks = stage * 20;
this.defense = stage * 6;
this.speed = stage * 5;
this.name = `몬스터${stage}`;
}
attack(player) {
const inidamage = this.attacks - player.defense;
const random = Math.random() * 20 - 10;
const damage = Math.max(1, Math.round(inidamage + random));
player.hp -= damage > 0 ? damage : 10;
console.log(`${this.name}${damage} 공격!`);
return damage;
}
}

function displayStatus(stage, player, monster) {
console.log(chalk.magentaBright(`\n=== Current Status ===\n`));
console.log(
chalk.cyanBright(`\n | Stage: ${stage} \n`) +
chalk.blueBright(
`\n | 플레이어 정보 | 체력 ${player.hp} | 공격력 ${player.attacks} | 방어력 ${player.defense} | 스피드 ${player.speed} | 장비 ${player.inventory} \n`,
) +
chalk.redBright(
`\n | 몬스터 정보 | 체력 ${monster.hp} | 공격력 ${monster.attacks} | 방어력 ${monster.defense} | 스피드 ${monster.speed} \n`,
),
);
console.log(chalk.magentaBright(`\n=====================\n`));
}

function Turn(player, monster) {
const speedy = player.speed - monster.speed;
const probability = 0.5 + speedy * 0.1;

return Math.random() < probability ? 'player' : 'monster';
}

const battle = async (stage, player, monster) => {
let logs = [];
let turn = 0;

while (player.hp > 0 && monster.hp > 0) {
console.clear();
displayStatus(stage, player, monster);

logs.forEach((log) => console.log(log));

const turns = Turn(player, monster);

if (turn === 0) {
console.log(chalk.green(`\n1. 공격한다 2. 장비 장착 - 몬스터가 때림.`));
const choice = readlineSync.question(chalk.bgGray('선택 > '));

logs.push(chalk.green(`**** ${choice}를 선택 ****`));

switch (choice) {
case '1':
player.attack(monster, logs);
if (monster.hp <= 0) {
console.log(`${monster.name} 처치!! 다음 스테이지!`);
player.hp += 50;
console.log(` 체력이 50 증가 !! 현재 체력 : ${player.hp} `);
logs.push(chalk.green(`${player.name}${player.attacks} 공격!`));
increaseStats(player, stage);
const dropRate = 0.3;
if (Math.random() < dropRate) {
const newEquipment = new Equipment('검', 10, 5);
player.inventory.push(newEquipment);
logs.push(chalk.green('검을 주웠다!'));
}
break;
} else {
turn = 1;
break;
}

case '2':
console.log('현재 장비 목록:');
player.inventory.forEach((item, index) => {
console.log(
`${index + 1}. ${item.name} (공격력 +${item.attackBonus}, 방어력 +${item.defenseBonus})`,
);
});
const equipChoice = readlineSync.question('장비를 선택하세요 (0: 취소): ');
if (equipChoice > 0 && equipChoice <= player.inventory.length) {
const selectedItem = player.inventory[equipChoice - 1];
player.equip(selectedItem);
logs.push(chalk.green(`${selectedItem.name} 장착!`));
}
break;
}
} else {
console.log(chalk.red(`${monster.name}의 턴.`));
const damage = monster.attack(player);
logs.push(chalk.red(`${monster.name} ${damage} 공격!`));

if (monster.hp > 0) {
logs.push(chalk.red(` 몬스터 공격 후 플레이어 체력 : ${player.hp}`));
} else {
console.log('몬스터의 체력이 0 이하입니다.');
}
if (player.hp <= 0) {
console.log(`으악`);
break;
}
}
turn = (turn + 1) % 2;
}
};

export async function startGame() {
const player = new Player();
let stage = 1;

while (stage <= 10) {
const monster = new Monster(stage);
await battle(stage, player, monster);

stage++;
}
}

 

어제는 새벽부터 그 날 저녁까지 로그 때문에 시간을 너무 오래 잡아먹었는데 오늘은 뭔가 술술 풀리는거 같더니 점심쯤 구현이 끝나 기록 중

 

스킬과 장비를 구현하긴 했는데 스킬은 2, 3번을 통해서 하는게 아니라 1번을 눌러 공격을 하면 일정확률로 나가게끔 구현을 했다.

 

장비도 구현을 했는데 몬스터를 잡으면 일정 확률로 드랍이 되고 2번을 통해 장비를 교체하게끔 했다.

 

크리티컬 확률이나 장비 획득은 차차 다 만들고 조절하면 되고


그래서 3번부터는 뭘 넣지 고민중이긴 한데 아마 물약으로 체력 올리는거 아니면 그냥 마을로 돌아가기 하면서 메뉴화면으로 나가게끔 해야겠다.

 

그리고 마지막으로 스테이지마다 몬스터랑 캐릭터가 능력치가 올라가게 했는데 몬스터는 올라가는 스텟 수치가 고정이고 플레이어는 변동이다.

 

데미지도 플레이어랑 몬스터 둘 다 변동으로 바꿨다 이것도 다 만들고 나서 수치를 조정 할 예정

 

장착한 장비마다 다른 스킬이 나가게끔 하고싶긴 하지만 일단 문제부터 해결하고....

일단 큰 문제는 스피드에 따른 선공이 이상하다.

선공 결정하는 방법이 플레이어 속도에서 몬스터 속도를 뺀 값에 확률을 넣은건데 몬스터 스탯이 높게 올라가다보니 음수 값이 된 것 같다.

 

함수 턴을 만들때 스피드 수치도 고려를 미리 했어야하는데.. 경험이 아직 부족하다보니 일단 넣고 오류뜨면 분석을 하게 된다.


아무튼 이 턴 문제만 해결하고 로그를 좀 더 손 본 다음에 제출을 해도 되지만 시간이 좀 남아서 장비마다 다른 스킬이 나가게끔 할 예정이다.

 

기본기가 더 있었다면 검색을 안하면서 차근차근 하나씩 만들었을텐데 검색을 위주로 다른 사람들이 한걸 참고하면서 하다보니 도대체 어디가 문제인지 알 수가 없네 특히 로그 출력..........

그래도 안그래도 필요했던 코드의 구조를 학습한다는 생각으로 결과보단 과정에 집중 해야겠다.

 

----------------------------------------------------------------------------------------------------------------------

오후 추가 수정

import chalk from 'chalk';
import readlineSync from 'readline-sync';

class Skill {
constructor(name, probability, effect) {
this.name = name;
this.probability = probability;
this.effect = effect;
}
}
const combo = new Skill('연속 공격', 0.3, (player, monster, logs) => {
for (let i = 0; i < 3; i++) {
player.attack(monster, logs);
}
logs.push(chalk.green(`연속 공격을 성공!`));
});

class Player {
constructor(player) {
this.name = '';
this.hp = 100;
this.attacks = 10;
this.defense = 5;
this.speed = 12;
this.inventory = [];
}

equip(item) {
this.inventory.push(item);
this.applyEquipmentStats();
}

unequip(item) {
const index = this.inventory.indexOf(item);
if (index !== -1) {
this.inventory.splice(index, 1);
this.applyEquipmentStats();
}
}

applyEquipmentStats() {
this.attacks = 10;
this.defense = 5;
this.inventory.forEach((item) => {
this.attacks += item.attackBonus;
this.defense += item.defenseBonus;
});
}

attack(monster, logs) {
const critical = 0.1;
const Cri = Math.random() < critical;
const inidamage = this.attacks - monster.defense;
const random = Math.random() * 20 - 1;
const damage = Math.max(1, Math.round(inidamage + random));
const finalDamage = Cri ? damage * 2 : damage;
monster.hp -= finalDamage > 0 ? finalDamage : 1;

logs.push(chalk.green(`${this.name}${finalDamage}${Cri ? ' (크리티컬!)' : ''} 공격!`));

if (Math.random() < combo.probability) {
combo.effect(this, monster, logs);
return;
}
}
}

function increaseStats(player, stage) {
const increase = 30;
player.attacks += Math.floor(Math.random() * increase) + 10;
player.defense += Math.floor(Math.random() * increase);

console.log(
chalk.green(`공격력: ${player.attacks}, 방어력: ${player.defense}, 스피드: ${player.speed}`),
);
}

class Equipment {
constructor(name, attackBonus, defenseBonus) {
this.name = name;
this.attackBonus = attackBonus;
this.defenseBonus = defenseBonus;
}
}

class Monster {
constructor(stage) {
this.hp = stage * 100;
this.attacks = stage * 20;
this.defense = stage * 6;
this.speed = stage * 1;
this.name = `몬스터${stage}`;
}
attack(player) {
const inidamage = this.attacks - player.defense;
const random = Math.random() * 20 - 10;
const damage = Math.max(1, Math.round(inidamage + random));
player.hp -= damage;
console.log(`${this.name}${damage} 공격!`);
return damage;
}
}

function displayStatus(stage, player, monster) {
console.log(chalk.magentaBright(`\n=== Current Status ===\n`));
console.log(
chalk.cyanBright(`\n | Stage: ${stage} \n`) +
chalk.blueBright(
`\n | 플레이어 정보 | 체력 ${player.hp} | 공격력 ${player.attacks} | 방어력 ${player.defense} | 스피드 ${player.speed} | \n | 장비 ${player.inventory}| \n`,
) +
chalk.redBright(
`\n | 몬스터 정보 | 체력 ${monster.hp} | 공격력 ${monster.attacks} | 방어력 ${monster.defense} | 스피드 ${monster.speed} | \n`,
),
);
console.log(chalk.magentaBright(`\n=====================\n`));
}

function Turn(player, monster) {
const speedy = player.speed - monster.speed;
if (speedy < 0) {
speedy = 0;
}
const probability = 0.7 + speedy * 0.01;
return Math.random() < probability ? 'player' : 'monster';
}

const battle = async (stage, player, monster) => {
let logs = [];
let turns = Turn(player, monster);

while (player.hp > 0 && monster.hp > 0) {
console.clear();
displayStatus(stage, player, monster);

logs.forEach((log) => console.log(log));

turns = Turn(player, monster);

if (turns === 'player') {
console.log(chalk.green(`\n플레이어의 턴입니다.`));
console.log(chalk.green(`\n1. 공격한다 2. 장비 장착 - 몬스터가 때림.`));
const choice = readlineSync.question(chalk.bgGray('선택 > '));

logs.push(chalk.green(`**** ${choice}를 선택 ****`));

switch (choice) {
case '1':
player.attack(monster, logs);
if (monster.hp <= 0) {
console.log(`${monster.name} 처치!! 다음 스테이지!`);
player.hp += 50;
console.log(` 체력이 50 증가 !! 현재 체력 : ${player.hp} `);
logs.push(chalk.green(`${player.name}${player.attacks} 공격!`));
increaseStats(player, stage);
const dropRate = 0.3;
if (Math.random() < dropRate) {
const newEquipment = new Equipment('검', 10, 5);
player.inventory.push(newEquipment);
logs.push(chalk.green('검을 주웠다!'));
}
}
break;
case '2':
console.log('현재 장비 목록:');
player.inventory.forEach((item, index) => {
console.log(
`${index + 1}. ${item.name} (공격력 +${item.attackBonus}, 방어력 +${item.defenseBonus})`,
);
});
const equipChoice = readlineSync.question('장비를 선택하세요 (0: 취소 (턴 소모)): ');
if (equipChoice > 0 && equipChoice <= player.inventory.length) {
const selectedItem = player.inventory[equipChoice - 1];
player.equip(selectedItem);
logs.push(chalk.green(`${selectedItem.name} 장착!`));
}
break;
}
} else {
const damage = monster.attack(player);
logs.push(chalk.red(`${monster.name} ${damage} 공격!`));
}

if (monster.hp > 0) {
logs.push(chalk.red(` 몬스터 공격 후 플레이어 체력 : ${player.hp}`));
} else {
console.log('몬스터의 체력이 0 이하입니다.');
}
if (player.hp <= 0) {
console.log(`으악`);
break;
}
}
};

export async function startGame() {
const player = new Player();
let stage = 1;

while (stage <= 10) {
const monster = new Monster(stage);
await battle(stage, player, monster);

stage++;
}
}

 

턴제는 구조상 불가능했다. 왜냐하면 처음부터 턴이 플레이어일때 스위치가 돌고 아니면 바로 몬스터의 공격이 나가는건데 이걸 결정하는건 함수 Turn에서 플레이어 스피드와 몬스터의 스피드를 뺀 값에서 확률로 결정하는거라 배틀의 if 플레이어 턴이 아닐 경우에는 무조건 몬스터에게 턴이 넘어가 내 턴이 오지 않기 때문

 

하지만 그냥 이걸 이용해서 몬스터의 스피드는 1부터 시작해서 스테이지++당 1씩 올라가는걸로 하고 플레이어 스피드는 12로 고정해서 스테이지가 올라갈 수록 몬스터의 연속 공격 확률이 올라가는걸로 하기로 했다. 최종 스테이지에서는 플레이어 스피드는 12 몬스터는10 - 프로바빌리티 값이 1에 가까울 수록 플레이어턴이 결정되는데 확률이 1퍼씩 낮아져 플레이어 선공 확률이 처음엔 81퍼센트에서 시작해 10스테이지에서는 72퍼센트로 낮아진다. 플레이어 선공 확률이 기본적으로 높은 이유는 스위치를 돌면 몬스터는 플레이어를 한대씩 때리기 때문

 

로그도 잘 나오고 있고 거의 마무리가 다 되어가니 뿌듯하다. 구현하고 싶은건 모두 하고 싶었지만 하루 12시간 넘게 과제만 집중하는 것보단 적당히 알고리즘과 강의를 병행하면서 하는게 좋다고 생각해 너무 시간 투자를 안 할 생각이다. 어차피 목적은 코드의 구조를 이해하면서 하나씩 구현해나가는거였기 때문

 

일주일이 정말 알찼다. 2주일 전까지만 해도 막막했던 이번 달이 좀 널널해진 것 같다. 다행이도 코딩은 아직까지 재미있었고 학습 적응도 빠르게 하는거 같다.

 

--------------------------------------------------------------------------------------------------------------------

오늘의 학습 요약

 

과제도 슬슬 윤곽이 잡혀가고 있다. 확실히 놀란게 저번 일주일에는 이제 막 자바스크립트 들어갈때 기본기가 너무 부족하다는 생각이 많았는데 오늘 느낀게 어제보다는 모르겠지만 일주일 전보다는 많이 늘었다. 주마다 목표를 세우면 참 좋을 것 같은데.. 일단 주말에 과제를 다 끝내고 월요일부터 node 강의를 들을 예정이다. 다음주 까지도 열심히하자!

'개발 일지' 카테고리의 다른 글

25일 일지  (0) 2024.08.25
24일 일지  (0) 2024.08.25
22일 일지  (0) 2024.08.22
21일 일지  (0) 2024.08.21
20일 일지  (0) 2024.08.20