abstract: 자바에서 추상 클래스나 추상 메서드를 정의할 때 사용한다.
추상 클래스 : 객체를 직접 생성할 수 없고, 공통적인 속성과 동작을 정의하여 상속을 통해 구체화되도록 설계된 클래스이다.
추상 메서드 : 자식 클래스에서 반드시 오버라이딩(재정의)해야 한다.
-> 객체지향 프로그래밍에서 다형성과 설계 유연성을 높일 수 있다.
package lesson05;
abstract class Ex01_Animal {
String name;
public Ex01_Animal(String name){
this.name = name;
}
abstract void sound();
void sleep(){
System.out.println(name + "이(가) 잠을 잡니다.");
}
}
class Dog extends Ex01_Animal {
public Dog(String name){
super(name);
}
@Override
void sound() {
System.out.println(name + "이(가) 멍멍 짖습니다.");
}
void eat(){
System.out.println(name +"이(가) 먹습니다.");
}
}
public class Ex01_Main {
public static void main(String[] args) {
// Animal animal = new animal("동물"); // ❌ 추상 클래스는 객체 생성 불가
Dog dog = new Dog("루시");
dog.sound();
dog.sleep();
dog.eat();
Ex01_Animal dog2 = new Dog("루시");
dog2.sound();
dog2.sleep();
// dog2.eat();
}
}
루시이(가) 멍멍 짖습니다.
루시이(가) 잠을 잡니다.
루시이(가) 먹습니다.
루시이(가) 멍멍 짖습니다.
루시이(가) 잠을 잡니다.
package lesson05;
abstract class Shape{
abstract double getArea(); // 추상 메서드: 면적 계산
}
class Circle extends Shape{
double radius;
Circle(double radius){
this.radius = radius;
}
@Override
double getArea() {
return radius * radius * Math.PI;
}
}
class Rectangle extends Shape{
double width, height;
Rectangle(double width, double height){
this.width = width;
this.height = height;
}
@Override
double getArea() {
return width * height;
}
}
public class Ex02_Main {
public static void main(String[] args) {
Shape s1 = new Circle(5);
System.out.println("원 면적: " + s1.getArea());
Shape s2 = new Rectangle(4, 5);
System.out.println("사각형 면적: " + s2.getArea());
}
}
원 면적: 78.53981633974483
사각형 면적: 20.0
import java.util.Random;
import java.util.Scanner;
abstract class Animal {
String name;
int maxHp;
int hp;
int power;
int maxSkillCount;
int skillCount;
public Animal(String name, int power, int maxHp, int maxSkillCount) {
this.name = name;
this.power = power;
this.maxHp = maxHp;
this.hp = maxHp;
this.maxSkillCount = maxSkillCount;
this.skillCount = maxSkillCount;
}
abstract void attack();
abstract int getAttackPower();
abstract String getSkillName();
abstract void useSkill(Animal enemy);
boolean isAlive() {
return hp > 0;
}
boolean canUseSkill() {
return skillCount > 0;
}
void takeDamage(int damage) {
hp -= damage;
if (hp < 0) hp = 0;
}
void printStatus() {
System.out.println(name + " 체력: " + hp + "/" + maxHp + " | 스킬 남은 횟수: " + skillCount + "/" + maxSkillCount);
}
}
class Dragon extends Animal {
public Dragon() {
super("드래곤", 30, 180, 3); // 체력 상향, 스킬 3회
}
@Override
void attack() {
System.out.println("🔥 드래곤이 불을 내뿜는다!");
}
@Override
int getAttackPower() {
return power + new Random().nextInt(20); // 30~49
}
@Override
String getSkillName() {
return "파이어 브레스";
}
@Override
void useSkill(Animal enemy) {
if (canUseSkill()) {
skillCount--;
int damage = 40 + new Random().nextInt(20); // 40~59
System.out.println("🔥 드래곤의 스킬! 파이어 브레스!! (불꽃 데미지 " + damage + ")");
enemy.takeDamage(damage);
} else {
System.out.println("❌ 드래곤은 더 이상 스킬을 사용할 수 없습니다!");
}
}
}
class Wolf extends Animal {
public Wolf() {
super("늑대", 25, 160, 2); // 체력 상향, 스킬 2회
}
@Override
void attack() {
System.out.println("🌕 늑대가 어둠 속에서 덮친다!");
}
@Override
int getAttackPower() {
return power + new Random().nextInt(15); // 25~39
}
@Override
String getSkillName() {
return "달빛 송곳니";
}
@Override
void useSkill(Animal enemy) {
if (canUseSkill()) {
skillCount--;
int damage = 35 + new Random().nextInt(15); // 35~49
System.out.println("🌙 늑대의 스킬! 달빛 송곳니!! (강력 데미지 " + damage + ")");
enemy.takeDamage(damage);
} else {
System.out.println("❌ 늑대는 더 이상 스킬을 사용할 수 없습니다!");
}
}
}
class Bear extends Animal {
public Bear() {
super("곰", 20, 200, 1);
}
@Override
void attack() {
System.out.println("🐻 곰이 앞발로 내려친다!");
}
@Override
int getAttackPower() {
return power + new Random().nextInt(10); // 20~29
}
@Override
String getSkillName() {
return "대지 강타";
}
@Override
void useSkill(Animal enemy) {
if (canUseSkill()) {
skillCount--;
int damage = (int)(enemy.hp * 0.3);
if (damage < 25) damage = 25;
System.out.println("🌍 곰의 스킬! 대지 강타!! (적 체력의 30% 데미지: " + damage + ")");
enemy.takeDamage(damage);
} else {
System.out.println("❌ 곰은 더 이상 스킬을 사용할 수 없습니다!");
}
}
}
// === 메인 게임 ===
public class AnimalBattleGame {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Animal[] allAnimals = { new Dragon(), new Wolf(), new Bear() };
Animal[] playerTeam = new Animal[2];
Animal[] enemyTeam = new Animal[2];
Random rand = new Random();
System.out.println("🧙 전설의 포켓동물 배틀에 오신 걸 환영합니다!");
System.out.println("두 마리의 포켓동물을 선택하세요:");
for (int i = 0; i < 2; i++) {
System.out.println("1. 드래곤 🐉\n2. 늑대 🐺\n3. 곰 🐻");
System.out.print((i + 1) + "번째 동물 선택: ");
int choice = sc.nextInt();
playerTeam[i] = copyAnimal(allAnimals[choice - 1]);
}
// 적 팀 랜덤 구성
for (int i = 0; i < 2; i++) {
while (true) {
Animal enemy = copyAnimal(allAnimals[rand.nextInt(3)]);
boolean exists = false;
for (int j = 0; j < i; j++) {
if (enemy.name.equals(enemyTeam[j].name)) {
exists = true;
break;
}
}
if (!exists) {
enemyTeam[i] = enemy;
break;
}
}
}
int playerIdx = 0;
int enemyIdx = 0;
while (true) {
Animal player = playerTeam[playerIdx];
Animal enemy = enemyTeam[enemyIdx];
System.out.println("\n====================================");
System.out.println("👊 현재 전투 중인 포켓동물");
player.printStatus();
enemy.printStatus();
// 플레이어 턴
System.out.println("\n[당신의 턴]");
System.out.println("1. 일반 공격");
System.out.println("2. 스킬 사용 (" + player.getSkillName() + ")");
System.out.println("3. 동물 교체");
System.out.print("선택 >> ");
int action = sc.nextInt();
if (action == 1) {
player.attack();
int damage = player.getAttackPower();
System.out.println("💥 공격력: " + damage);
enemy.takeDamage(damage);
} else if (action == 2) {
player.useSkill(enemy);
} else if (action == 3) {
int otherIdx = 1 - playerIdx;
if (!playerTeam[otherIdx].isAlive()) {
System.out.println("⚠️ 다른 동물이 전투불능입니다!");
continue;
}
playerIdx = otherIdx;
System.out.println("🔁 포켓동물 교체!");
continue;
}
if (!enemy.isAlive()) {
System.out.println("✅ 적 " + enemy.name + "이(가) 쓰러졌습니다!");
enemyIdx++;
if (enemyIdx >= 2) {
System.out.println("🎉 당신이 승리했습니다!!");
break;
}
}
// 적 턴
Animal currEnemy = enemyTeam[enemyIdx];
Animal currPlayer = playerTeam[playerIdx];
System.out.println("\n[👾 적의 턴: " + currEnemy.name + "]");
int enemyChoice;
if (currEnemy.hp < 60 && currEnemy.canUseSkill() && rand.nextInt(100) < 70) {
enemyChoice = 1;
} else {
enemyChoice = 0;
}
if (enemyChoice == 0) {
System.out.println("👾 적이 일반 공격을 선택합니다!");
currEnemy.attack();
int damage = currEnemy.getAttackPower();
System.out.println("💥 공격력: " + damage);
currPlayer.takeDamage(damage);
} else {
System.out.println("👾 적이 스킬 '" + currEnemy.getSkillName() + "'을(를) 사용합니다!");
currEnemy.useSkill(currPlayer);
}
if (!currPlayer.isAlive()) {
System.out.println("☠️ 당신의 " + currPlayer.name + "이(가) 쓰러졌습니다!");
if (!playerTeam[1 - playerIdx].isAlive()) {
System.out.println("💀 모든 포켓동물이 쓰러졌습니다. 패배...");
break;
} else {
playerIdx = 1 - playerIdx;
System.out.println("🔁 자동으로 다른 포켓동물로 교체합니다!");
}
}
}
sc.close();
}
public static Animal copyAnimal(Animal original) {
if (original.name.equals("드래곤")) return new Dragon();
else if (original.name.equals("늑대")) return new Wolf();
else return new Bear();
}
}