## 과제 : 제네릭 이진 트리 구현 목표 : 제네릭을 사용하여 다양한 데이터 타입을 저장할 수 있는 이진 트리를 구현한다. 요구사항 : 다음 코드를 참고하여, 제네릭을 사용하여 다양한 데이터 타입을 저장할 수 있는 이진 트리를 구현한다. ```java public class MyBinaryTree { public static class Node { int data; Node left; Node right; public Node(int data) { this.data = data; } } private Node root; public void insert(int value) { root = insert(root, value); } private Node insert(Node node, int value) { if (node == null) { return new Node(value); } if (value < node.data) { node.left = insert(node.left, value); } else if (value > node.data) { node.right = insert(node.right, value); } return node; } public boolean contains(int value) { return contains(root, value); } private boolean contains(Node node, int value) { if (node == null) { return false; } if (value < node.data) { return contains(node.left, value); } else if (value > node.data) { return contains(node.right, value); } else { return true; } } public void delete(int value) { root = delete(root, value); } private Node delete(Node node, int value) { if (node == null) { return null; } if (value < node.data) { node.left = delete(node.left, value); } else if (value > node.data) { node.right = delete(node.right, value); } else { if (node.left == null) { return node.right; } else if (node.right == null) { return node.left; } node.data = findMin(node.right).data; node.right = delete(node.right, node.data); } return node; } private Node findMin(Node node) { while (node.left != null) { node = node.left; } return node; } } ``` ### 과제를 수행하기 전에 Comparable 인터페이스에 대해서 알아보자 Comparable 인터페이스란? - Comparable 인터페이스는 객체를 비교하는데 사용되는 인터페이스이다. 이를 통해 객체들을 정렬할 때 기준을 제공한다 - 객체들의 자연 순서를 정의하기 위해 사용된다. - Comparable 인터페이스를 구현한 클래스의 인스턴스는 서로 비교가 가능하며, 이를 통해 정렬이나 순서를 관리하는 작업을 수행할 수 있다. - Comparable 인터페이스는 같은 자료형의 다른 객체 하나를 인자로 받아와 비교하는 compareTo 함수를 사용한다. - public int compareTo(T o); - 현재 객체가 매개변수 객체보다 작을 경우: 음수 값을 반환. - 현재 객체와 매개변수 객체가 같을 경우: 0을 반환. - 현재 객체가 매개변수 객체보다 클 경우: 양수 값을 반환. #### Comparable 인터페이스 구현 예 ```java public class Person implements Comparable<Person> { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public int compareTo(Person other) { return this.age - other.age; // 나이를 기준으로 비교 } } ``` ## 과제: 블랙잭 게임 구현 **목표: 콘솔 인터페이스에서 블랙잭 게임을 구현한다.** 블랙잭은 카드 게임으로, 플레이어와 딜러가 카드를 받아 21에 가까운 숫자를 만드는 게임이다. 플레이어와 딜러는 각각 2장의 카드를 받고, 플레이어는 카드를 더 받을지(‘Hit’) 그만 받을지(‘Stand’)를 선택할 수 있다. 플레이어는 카드를 더 받을 때마다 카드의 숫자를 합계하여 21에 가까워지도록 해야 하며, 21을 초과하면 패배한다. 이 때 `A`는 1 또는 11로 계산할 수 있으며, `J`, `Q`, `K`는 각각 10으로 계산한다. 딜러는 카드를 더 받을지 여부를 선택할 수 없으며, 딜러는 16 이하일 때는 무조건 카드를 더 받고, 17 이상일 때는 카드를 받지 않는다. **요구사항:** 1. **게임 준비** - 52장의 카드 덱을 생성하고 섞는다. - 플레이어와 딜러에게 각각 2장의 카드를 나눠준다. - 딜러의 첫 번째 카드만 공개하고, 두 번째 카드는 가린다. 2. **플레이어 턴** - 플레이어의 카드 합계를 보여준다. - 플레이어에게 'Hit' 또는 'Stand'를 입력받는다. - 'Hit'를 선택하면 플레이어에게 한 장의 카드를 더 나눠준다. - 'Stand'를 선택하면 플레이어의 턴이 종료된다. - 플레이어의 카드 합계가 21을 초과하면 자동으로 'Bust'되어 게임에서 진다. 3. **딜러 턴** - 딜러의 두 번째 카드를 공개한다. - 딜러의 카드 합계가 16 이하이면 계속해서 카드를 받는다. - 딜러의 카드 합계가 17 이상이면 'Stand'한다. 4. **게임 결과** - 플레이어와 딜러의 카드 합계를 비교한다. - 21에 가까운 쪽이 이기거나, 상대방이 'Bust'되면 이긴다. - 비기면 무승부가 된다. - 게임 결과를 출력한다. 5. **다시 플레이** - 게임이 종료된 후, 플레이어에게 다시 플레이할지 여부를 묻는다. ## 과제 : 제네릭 이진 트리 구현 모범 답안 ```java public class MyBinaryTree<T extends Comparable<T>> { public static class Node<T> { T data; Node<T> left; Node<T> right; public Node(T data) { this.data = data; } } private Node<T> root; public void insert(T value) { root = insert(root, value); } private Node<T> insert(Node<T> node, T value) { if (node == null) { return new Node<>(value); } int cmp = value.compareTo(node.data); if (cmp < 0) { node.left = insert(node.left, value); } else if (cmp > 0) { node.right = insert(node.right, value); } return node; } public boolean contains(T value) { return contains(root, value); } private boolean contains(Node<T> node, T value) { if (node == null) { return false; } int cmp = value.compareTo(node.data); if (cmp < 0) { return contains(node.left, value); } else if (cmp > 0) { return contains(node.right, value); } else { return true; } } public void delete(T value) { root = delete(root, value); } private Node<T> delete(Node<T> node, T value) { if (node == null) { return null; } int cmp = value.compareTo(node.data); if (cmp < 0) { node.left = delete(node.left, value); } else if (cmp > 0) { node.right = delete(node.right, value); } else { if (node.left == null) { return node.right; } else if (node.right == null) { return node.left; } node.data = findMin(node.right).data; node.right = delete(node.right, node.data); } return node; } private Node<T> findMin(Node<T> node) { while (node.left != null) { node = node.left; } return node; } } ``` ## 과제 : 블랙잭 게임 구현 모범 답안 ```java package test; import java.util.*; public class BlackjackGame { private static final int BLACKJACK = 21; private static final String[] SUITS = {"♥", "♦", "♣", "♠"}; private static final String[] RANKS = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"}; private final static List<String> deck = new ArrayList<>(); private final static List<String> playerHand = new ArrayList<>(); private final static List<String> dealerHand = new ArrayList<>(); private final static Scanner scanner = new Scanner(System.in); public static void main(String[] args) { initializeDeck(); playGame(); } private static void initializeDeck() { for (String suit : SUITS) { for (String rank : RANKS) { deck.add(rank + suit); } } shuffle(deck); } public static void shuffle(List<String> list) { Random random = new Random(); for (int i = list.size() - 1; i > 0; i--) { int j = random.nextInt(i + 1); list.set(i, list.set(j, list.get(i))); } } private static void playGame() { do { playerHand.clear(); dealerHand.clear(); dealInitialCards(); printGameState(true); playerTurn(); if (!playerBusted()) { dealerTurn(); } printFinalGameState(); determineWinner(); } while (playAgain()); } private static void dealInitialCards() { playerHand.add(deck.remove(0)); dealerHand.add(deck.remove(0)); playerHand.add(deck.remove(0)); dealerHand.add(deck.remove(0)); } private static void printGameState(boolean hideSecondDealerCard) { System.out.println("플레이어 카드: " + playerHand); System.out.print("딜러 카드: " + dealerHand.get(0)); if (hideSecondDealerCard) { System.out.println(" ?"); } else { System.out.println(" " + dealerHand.get(1)); } } private static void playerTurn() { while (true) { System.out.print("히트하시겠습니까? (y/n): "); String choice = scanner.nextLine().trim().toLowerCase(); if (choice.equals("y")) { playerHand.add(deck.remove(0)); printGameState(true); if (getHandValue(playerHand) > BLACKJACK) { System.out.println("플레이어 버스트!"); return; } } else if (choice.equals("n")) { break; } else { System.out.println("올바른 입력이 아닙니다. 다시 입력해주세요."); } } } private static boolean playerBusted() { return getHandValue(playerHand) > BLACKJACK; } private static void dealerTurn() { System.out.println("딜러 턴 시작"); printGameState(false); while (getHandValue(dealerHand) < 17) { dealerHand.add(deck.remove(0)); System.out.println("딜러가 카드를 받았습니다."); printGameState(false); } if (getHandValue(dealerHand) > BLACKJACK) { System.out.println("딜러 버스트!"); } } private static void printFinalGameState() { System.out.println("\n최종 게임 상태"); System.out.println("플레이어 카드: " + playerHand + " (합계: " + getHandValue(playerHand) + ")"); System.out.println("딜러 카드: " + dealerHand + " (합계: " + getHandValue(dealerHand) + ")"); } private static void determineWinner() { int playerValue = getHandValue(playerHand); int dealerValue = getHandValue(dealerHand); if (playerBusted()) { System.out.println("플레이어 패배!"); } else if (dealerValue > BLACKJACK) { System.out.println("플레이어 승리!"); } else if (playerValue > dealerValue) { System.out.println("플레이어 승리!"); } else if (playerValue < dealerValue) { System.out.println("플레이어 패배!"); } else { System.out.println("무승부!"); } } private static boolean playAgain() { System.out.print("\n다시 플레이하시겠습니까? (y/n): "); String choice = scanner.nextLine().trim().toLowerCase(); return choice.equals("y"); } private static int getHandValue(List<String> hand) { int value = 0; int aceCount = 0; for (String card : hand) { String rank = card.substring(0, card.length() - 1); if (rank.equals("A")) { aceCount++; } else if (rank.equals("J") || rank.equals("Q") || rank.equals("K")) { value += 10; } else { value += Integer.parseInt(rank); } } while (aceCount > 0) { if (value + 11 <= BLACKJACK) { value += 11; } else { value += 1; } aceCount--; } return value; } } ```