자바 개발자 일기 16일차 (Scanner)

Shy·2024년 1월 19일

아이티윌

목록 보기
16/22

Scanner

Scanner 클래스는 Java의 java.util 패키지에 포함되어 있는 클래스로, 다양한 종류의 입력을 쉽게 읽을 수 있게 해주는 도구이다. 주로 텍스트 입력을 구문 분석하고, 특정 타입의 값을 (예: int, double, String 등) 읽어오는 데 사용된다. 다음은 Scanner 클래스의 주요 특징과 사용 방법에 대한 설명이다.

  1. 입력 소스: Scanner는 다양한 입력 소스로부터 데이터를 읽을 수 있다. 이는 파일, 문자열, InputStream (예: System.in) 등이 될 수 있다.

  2. 생성자: Scanner 객체를 생성할 때 입력 소스를 지정한다. 예를 들어, 키보드 입력을 읽기 위해서는 System.in을 사용한다.

Scanner scanner = new Scanner(System.in);
  1. 데이터 읽기: Scanner는 다양한 메소드를 제공하여 문자열, 정수, 실수 등 다양한 형태의 데이터를 읽을 수 있다. 예를 들어 nextInt(), nextDouble(), nextLine() 등이 있다.

  2. 문자열 토큰화: 기본적으로 Scanner는 공백(스페이스, 탭, 줄바꿈 등)을 사용하여 입력을 토큰으로 분리한다. next() 메소드는 다음 토큰을 문자열로 반환한다.

  3. 형 변환: Scanner는 문자열 입력을 다른 데이터 타입으로 쉽게 변환할 수 있게 해준다. 예를 들어, nextInt()는 입력된 문자열을 정수로 변환한다.

  4. 자원 관리: Scanner 사용이 끝나면 close() 메소드를 호출하여 연결된 리소스를 해제하는 것이 좋다. 이는 파일이나 네트워크 리소스와 같이 제한된 시스템 리소스를 사용하는 경우 특히 중요하다.

예시 코드

import java.util.Scanner;

public class ScannerExample {
    public static void main(String[] args) {
        // Scanner 객체 생성, System.in은 표준 입력(키보드)을 의미한다.
        Scanner scanner = new Scanner(System.in);

        System.out.print("문자열을 입력하세요: ");
        String str = scanner.nextLine();  // 문자열 입력 받기
        System.out.println("입력된 문자열: " + str);

        System.out.print("정수를 입력하세요: ");
        int number = scanner.nextInt();  // 정수 입력 받기
        System.out.println("입력된 정수: " + number);

        // nextInt() 이후 nextLine()을 바로 사용할 경우를 대비하여 추가적인 nextLine() 호출
        scanner.nextLine();

        System.out.print("실수를 입력하세요: ");
        double decimal = scanner.nextDouble();  // 실수 입력 받기
        System.out.println("입력된 실수: " + decimal);

        // Scanner 객체 닫기
        scanner.close();
    }
}

이 코드를 실행하면 사용자에게 문자열, 정수, 실수를 차례대로 입력하도록 요청하고, 입력된 각 값은 화면에 출력된다. 주의해야 할 점은 nextInt() 또는 nextDouble() 같은 메소드를 사용한 후 nextLine()을 사용하려면, nextInt() 또는 nextDouble()이 읽지 않은 줄바꿈 문자를 처리하기 위해 추가적인 nextLine() 호출이 필요하다는 것이다. 이렇게 하지 않으면 nextLine()은 남아 있는 줄바꿈 문자를 새로운 라인으로 인식하고 빈 문자열을 반환할 수 있다.

예제코드

package com.mystudey.scanner1;

import java.util.Scanner;

public class Scanner_Exam {

    public static void main(String[] args) {
        // Scanner 객체를 생성하여 콘솔로부터 데이터를 읽어온다.
        Scanner scan = new Scanner(System.in);
        
        // 사용자에게 문자열 입력을 요청하고 입력받은 문자열을 출력한다.
        System.out.print("문자열 입력1 : ");
        String str1 = scan.nextLine(); // 첫 번째 문자열을 입력받는다.
        System.out.println(">>>" + str1); // 입력받은 문자열을 출력한다.
        
        System.out.println("-----------");
        
        // 사용자에게 또 다른 문자열 입력을 요청하고 입력받은 문자열을 출력한다.
        System.out.print("문자열 입력2 : ");
        String str2 = scan.nextLine(); // 두 번째 문자열을 입력받는다.
        System.out.println(">>>" + str2); // 입력받은 문자열을 출력한다.
        
        System.out.println("========================");
        // nextInt() 사용 후 nextLine()을 호출할 때의 주의점을 설명하는 주석
        System.out.println("정수값을 2개를 입력하면 합계 출력");
        
        int sum = 0;
        
        // 첫 번째 정수 입력
        System.out.print("숫자입력1 : ");
        int num1 = scan.nextInt(); // 첫 번째 정수를 입력받는다.
        scan.nextLine(); // nextInt() 후 남은 줄바꿈 문자를 처리한다.

        // 두 번째 정수 입력
        System.out.print("숫자입력2 : ");
        int num2 = Integer.parseInt(scan.nextLine()); // 문자열로 입력받은 후 정수로 변환한다.
        
        // 두 정수의 합을 계산하고 출력한다.
        sum = num1 + num2;
        System.out.println("합계 : " + sum);
        
        // 사용자로부터 이름 입력을 요청하고 출력한다.
        System.out.print("이름 : ");
        String name = scan.nextLine(); // 이름을 문자열로 입력받는다.
        System.out.println("입력된 이름 : " + name); // 입력받은 이름을 출력한다.
        
        System.out.println("===========================");
    }
}
문자열 입력1 : ㅇㅇㅈㅂ
>>>ㅇㅇㅈㅂ
-----------
문자열 입력2 : ㅈㅂㅇㅂㅈ저ㅐ
>>>ㅈㅂㅇㅂㅈ저ㅐ
========================
정수값을 2개를 입력하면 합계 출력
숫자입력1 : 22
숫자입력2 : 33
합계 : 55
이름 : ㅏㅏㅏㅏㅏ
입력된 이름 : ㅏㅏㅏㅏㅏ
===========================
:: 정수 숫자 3개 연속 작성 : 
11
22
33
---------
>> 11
>> 22
>> 33

실습코드

package com.mystudey.scanner1;

import java.util.Scanner;

public class Scanner_Exam3_while {

	public static void main(String[] args) {
		// 성적처리 - Scanner 사용
		// 입력 : 성명, 국어, 영어, 수학 점수를 입력받아
		// 처리 : 총점, 평균 계산한다.
		// 출력 : 결과 화면 출력
		// ------------------------------------
		// 설명 : 홍길동
		// 국어 : 100
		// 영어 : 90
		// 수학 : 81
		// ------------------------------------
		// 총점 : 271
		// 평균 : 90.33
		// ------------------------------------
		boolean con = true;
		while (con) {
			Scanner scan = new Scanner(System.in);
			System.out.print("이름을 입력해주세요. : ");
			String name = scan.nextLine();
			System.out.print("국어점수를 입력해주세요. : ");
			int kor = scan.nextInt();
			System.out.print("영어점수를 입력해주세요. : ");
			int eng = scan.nextInt();
			System.out.print("수학점수를 입력해주세요. : ");
			int math = scan.nextInt();
			scan.nextLine();
			int sum = kor + eng + math;
			double avg = Math.round(((double) sum / 3) * 100) / 100.0;
			
			System.out.println("이름 : " + name + "\t 국어 : " + kor + "\t 영어 : " + eng + "\t 수학 : " + math + "\t 총점 : " + sum + "\t 평균 : " + avg);
			
			System.out.print("계속 하시겠습니까? no를 입력하면 종료됩니다. : ");
			String contype = scan.nextLine();
			if (contype.equalsIgnoreCase("no")) {
				con = false;
			}
		}
		
	}
	
}
이름을 입력해주세요. : ㅇㅇㅇ
국어점수를 입력해주세요. : 22
영어점수를 입력해주세요. : 33
수학점수를 입력해주세요. : 11
이름 : ㅇㅇㅇ	 국어 : 22	 영어 : 33	 수학 : 11	 총점 : 66	 평균 : 22.0
계속 하시겠습니까? no를 입력하면 종료됩니다. : yes
이름을 입력해주세요. : aslf
국어점수를 입력해주세요. : 99
영어점수를 입력해주세요. : 88
수학점수를 입력해주세요. : 92
이름 : aslf	 국어 : 99	 영어 : 88	 수학 : 92	 총점 : 279	 평균 : 93.0
계속 하시겠습니까? no를 입력하면 종료됩니다. : yes
이름을 입력해주세요. : 77
국어점수를 입력해주세요. : 1
영어점수를 입력해주세요. : 1
수학점수를 입력해주세요. : 2
이름 : 77	 국어 : 1	 영어 : 1	 수학 : 2	 총점 : 4	 평균 : 1.33
계속 하시겠습니까? no를 입력하면 종료됩니다. : no

실습코드1 (Cafe)

package com.mystudy.scanner3_cafe;

import java.util.Scanner;

public class Scanner_Exam_cafe {
    private static final int PRICE_AMERICANO = 3000;
    private static final int PRICE_LATTE = 3500;
    private static final int PRICE_MOCHA = 4000;
    private static final int PRICE_JUICE = 5000;

	public static void main(String[] args) {
		/*
		 * 음료의 종류
		 * 1. 아메리카노(3000)  2. 카페라떼(3500)  3. 카페모카(4000)  4. 과일주스(5000)
		 * -------------------------------------------------------------------
		 * 입력값 : 메뉴번호, 주문수량, 입금액(고객이 낸 돈)
		 * 출력값 : 입금액, 판매액(단가 * 수량), 잔돈(입금액 - 판매액)
		 * -------------------------------------------------------------------
		 * 
		 * 1. 아메리카노  2. 카페라떼  3. 카페모카  4. 과일주스  0. 종료
		 * > 메뉴를 선택하세요(1~4) : 1
		 * > 주문수량 : 3
		 * > 입금액 : 10000
		 * ---------------------------
		 * 입금액 : 10000
		 * 판매액 : 9000
		 * 잔액 : 1000
		 */
		boolean con = true;
		while(con) {
			int beverage = choiceBeverage();
			int price = numberOfDrinks(beverage);
			change(price);
		}

	}
	
	public static int choiceBeverage() {
		int beverage = -1;
		while (true) {
			Scanner scan = new Scanner(System.in);
			System.out.println("1. 아메리카노  2. 카페라떼  3. 카페모카  4. 과일주스  0. 종료");
			beverage = scan.nextInt();
			scan.nextLine();
	        if (beverage >= 1 && beverage <= 4) {
	        	break;
	        } else if (beverage == 0) {
	        	break;
	        } else {
	        	System.out.println("잘못된 메뉴 선택입니다. 1~4 사이의 번호를 입력해주세요.");
	        }
		}
		return beverage;
	}
	
	
	public static int numberOfDrinks(int beverage) {
		Scanner scan = new Scanner(System.in);
		System.out.print("> 주문수량을 입력하세요. : ");
		int numberDrinks = scan.nextInt();
		scan.nextLine();
		int price = 0;
		if (beverage == 1) {
			price = PRICE_AMERICANO * numberDrinks;
		} else if (beverage == 2) {
			price = PRICE_LATTE * numberDrinks;
		} else if (beverage == 3) {
			price = PRICE_MOCHA * numberDrinks;
		} else if (beverage == 4) {
			price = PRICE_JUICE * numberDrinks;
		}
		
		return price;
	}
	
	public static void change(int price) {
		Scanner scan = new Scanner(System.in);
		System.out.println("입금액 : ");
		int money = scan.nextInt();
		scan.nextLine();
		if (money > price) {
			int change = money - price;
			System.out.println("입금액 : " + money);
			System.out.println("판매액 : " + price);
			System.out.println("잔액 : " + change);
		} else {
			System.out.println("금액이 부족합니다. 다시 주문해주세요.");
		}
		System.out.println();
	}

}
1. 아메리카노  2. 카페라떼  3. 카페모카  4. 과일주스  0. 종료
100
잘못된 메뉴 선택입니다. 1~4 사이의 번호를 입력해주세요.
1. 아메리카노  2. 카페라떼  3. 카페모카  4. 과일주스  0. 종료
5
잘못된 메뉴 선택입니다. 1~4 사이의 번호를 입력해주세요.
1. 아메리카노  2. 카페라떼  3. 카페모카  4. 과일주스  0. 종료
1
> 주문수량을 입력하세요. : 100
입금액 : 
1000000
입금액 : 1000000
판매액 : 300000
잔액 : 700000

1. 아메리카노  2. 카페라떼  3. 카페모카  4. 과일주스  0. 종료
0

refactoring

  1. Scanner 객체 재사용
    • 현재 choiceBeverage(), numberOfDrinks(), change() 각 메소드에서 별도로 Scanner 객체를 생성하고 있다. 하나의 Scanner 객체를 메인 메소드에서 생성하고 이를 필요한 메소드로 전달하는 방식으로 변경하는 것이 좋다.
  2. 메소드 분리와 명확성 향상
    • 각 메소드의 역할을 더 명확히 하고, 하나의 메소드가 너무 많은 일을 하지 않도록 분리할 수 있다. 예를 들어, numberOfDrinks() 메소드는 주문 수량을 받아 가격을 계산하는 두 가지 작업을 수행하고 있는데, 이를 두 개의 메소드로 분리할 수 있다.
  3. 상수 활용
    • 음료의 가격과 같이 변경되지 않는 값을 상수로 정의하면 코드의 가독성과 유지보수성을 향상시킬 수 있다.
  4. 불필요한 scan.nextLine() 제거
    • nextInt() 후에 nextLine()을 사용하지 않는 경우, scan.nextLine() 호출이 불필요하다. 이러한 부분을 제거한다.
  5. 종료 조건 간소화
    • quit() 메소드는 불필요하게 복잡하다. 이 메소드 없이도 종료 조건을 간단하게 처리할 수 있다.
package com.mystudy.scanner3_cafe;

import java.util.Scanner;

public class Scanner_Exam_cafe_refactoring {
    private static final int PRICE_AMERICANO = 3000;
    private static final int PRICE_LATTE = 3500;
    private static final int PRICE_MOCHA = 4000;
    private static final int PRICE_JUICE = 5000;

    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        boolean continueOrder = true;

        while (continueOrder) {
            int beverage = choiceBeverage(scan);
            if (beverage == 0) {
                break;
            }

            int numberOfDrinks = getNumberOfDrinks(scan);
            int price = calculatePrice(beverage, numberOfDrinks);
            processPayment(scan, price);
        }

        scan.close();
    }

    public static int choiceBeverage(Scanner scan) {
    	int beverage = -1;
    	while(true) {
    		System.out.println("1. 아메리카노  2. 카페라떼  3. 카페모카  4. 과일주스  0. 종료");
			beverage = scan.nextInt();
			scan.nextLine();
	        if (beverage >= 1 && beverage <= 4) {
	        	break;
	        } else if (beverage == 0) {
	        	break;
	        } else {
	        	System.out.println("잘못된 메뉴 선택입니다. 1~4 사이의 번호를 입력해주세요.");
	        }
    	}
        return beverage;
    }

    public static int getNumberOfDrinks(Scanner scan) {
        int numberOfDrinks = -1;
        while (numberOfDrinks < 1) {
            System.out.print("> 주문수량을 입력하세요. : ");
            numberOfDrinks = scan.nextInt();
            scan.nextLine();

            if (numberOfDrinks < 1) {
                System.out.println("주문수량은 1 이상이어야 합니다. 다시 입력해주세요.");
            }
        }
        return numberOfDrinks;
    }

    public static int calculatePrice(int beverage, int numberDrinks) {
        switch (beverage) {
            case 1: return PRICE_AMERICANO * numberDrinks;
            case 2: return PRICE_LATTE * numberDrinks;
            case 3: return PRICE_MOCHA * numberDrinks;
            case 4: return PRICE_JUICE * numberDrinks;
            default: return 0;
        }
    }

    public static void processPayment(Scanner scan, int price) {
        System.out.print("입금액 : ");
        int money = scan.nextInt();

        if (money >= price) {
            int change = money - price;
            System.out.println("입금액 : " + money);
            System.out.println("판매액 : " + price);
            System.out.println("잔액 : " + change);
        } else {
            System.out.println("금액이 부족합니다. 다시 주문해주세요.");
        }
        System.out.println();
    }
}

실습2 (Rock, Sccisor, Papper)

import java.util.Scanner;

public class aiRSP {
	/*
	 * 가위바위보에 관한 파라미터로
	 * 바위 = 1, 가위 = 2, 보 = 3 종료 = 0
	 * 으로 둡니다.
	 */
	/*
	 * 승패에 관해서는 -1, 2 면 컴퓨터의 승리
	 * 1, -2 이면 플레이어의 승리
	 * 0이면 무승부로 처리합니다.
	 */
	private static final int EXIT = 0;
	private static final int DRAW = 0;
	private static final int[] COMPUTER_WIN = {-1, 2};
	private static final int[] PLAYER_WIN = {1, -2};
	
	
	public void start() {
		Scanner scan = new Scanner(System.in);
		while(true) {
			int computer_choice = computer_choice();
			int player_choice = player_choice(scan);
			
			if (player_choice == EXIT) {
				System.out.println("게임을 종료합니다.");
				break;
			}
			
			
			judge(computer_choice, player_choice);
			
			System.out.println();
			
		}
	}
	
	public int computer_choice() {
		int computer_choice = (int) Math.ceil(Math.random() * 3);
		return computer_choice;
	}
	
	public int player_choice(Scanner scan) {
		System.out.println("1. 바위 2. 가위 3. 보 0. 종료");
		int player_choice = scan.nextInt();
		switch (player_choice) {
			case 1:
				System.out.println("바위를 내셨습니다.");
				return player_choice;
			case 2:
				System.out.println("가위를 내셨습니다.");
				return player_choice;
			case 3:
				System.out.println("보를 내셨습니다.");
				return player_choice;
			case 0:
				System.out.println("종료를 선택하셨습니다.");
				return player_choice;
			default :
				System.out.println("잘못된 값을 호출하셨습니다.");
				return EXIT;
		}
	}
	
	public void judge(int computer_choice, int player_choice) {
		int difference = computer_choice - player_choice;
		print_computer_choice(computer_choice);
		if (difference == DRAW) {
			System.out.println("무승무 입니다.");
		} else if (difference == -1 || difference == 2) {
			System.out.println("컴퓨터 승리");
		} else if (difference == 1 || difference == -2) {
			System.out.println("플레이어 승리");
		} else {
			System.out.println("예외상황 발생!!");
		}
	}
	
	public void print_computer_choice(int computer_choice) {
		switch (computer_choice) {
			case 1: 
				System.out.println("컴퓨터는 주먹을 냈습니다.");
				break;
			case 2: 
				System.out.println("컴퓨터는 가위를 냈습니다.");
				break;
			case 3: 
				System.out.println("컴퓨터는 보자기를 냈습니다.");
				break;
		}
	}
	
}

public class Scanner_Exam4_scissors {

	public static void main(String[] args) {
		/*
		 * 컴퓨터와 함께하는 가위, 바위, 보
		 * 0. 컴퓨터가 가위(1), 바위(2), 보(3) 선택(Math.random())
		 * 1. - 1. 가위 2. 바위 3. 보 0. 종료 (함수 만들다가 이 조건을 수정함)
		 * 2. 선택값 입력
		 * 3. 결과 비교 후 승자, 패자 결정
		 * (반복) 게임 반복 진행 - 0(종료) 선택시 까지
		 */
		new aiRSP().start();
	}

}

refactoring

  1. 컴퓨터 선택 메서드 개선
    • computer_choice 메서드에서 Math.ceil(Math.random() * 3) 대신 Math.random()Math.floor()를 사용하여 1부터 3까지의 정수를 생성하는 방식을 개선할 수 있다. 이는 Math.ceil()이 0을 반환할 수 있는 문제를 해결해 준다.
  2. 코드의 가독성 향상
    • 메서드와 변수 이름은 모두 소문자로 시작하는 것이 일반적인 자바 컨벤션이다. 예를 들어, computer_choice 대신 computerChoice를 사용하는 것이 좋다.
  3. 예외 처리 개선
    • player_choice 메서드에서 잘못된 입력을 받았을 때 게임을 종료하기보다 사용자에게 다시 입력하도록 요청하는 것이 사용자 경험을 개선할 수 있다.
import java.util.InputMismatchException;
import java.util.Scanner;

public class AiRSP_refactoring {
	private static final int EXIT = 0;
	private static final int DRAW = 0;
	private static final int[] COMPUTER_WIN = {-1, 2};
	private static final int[] PLAYER_WIN = {1, -2};

	public void start() {
		Scanner scan = new Scanner(System.in);
		while (true) {
			int computerChoice = generateComputerChoice();
			int playerChoice = getPlayerChoice(scan);

			if (playerChoice == EXIT) {
				System.out.println("게임을 종료합니다.");
				break;
			}

			judge(computerChoice, playerChoice);
			System.out.println();
		}
	}

	private int generateComputerChoice() {
		return (int) (Math.random() * 3) + 1;
	}

	private int getPlayerChoice(Scanner scan) {
	    // 플레이어의 선택을 저장할 변수
	    int playerChoice = 0;
	    try {
	    	
		    // do-while 루프를 사용하여 유효한 입력을 받을 때까지 반복
		    do {
		        // 사용자에게 바위(1), 가위(2), 보(3), 종료(0) 중 하나를 선택하도록 요청
		        System.out.println("1. 바위 2. 가위 3. 보 0. 종료");
	
		        // Scanner 객체를 사용하여 사용자로부터 정수 입력을 받음
		        playerChoice = scan.nextInt();
	
		        // 사용자의 입력에 따라 다른 작업을 수행
		        switch (playerChoice) {
		            case 1: // 사용자가 1(바위)을 선택한 경우
		                System.out.println("바위를 내셨습니다.");
		                break;
		            case 2: // 사용자가 2(가위)를 선택한 경우
		                System.out.println("가위를 내셨습니다.");
		                break;
		            case 3: // 사용자가 3(보)를 선택한 경우
		                System.out.println("보를 내셨습니다.");
		                break;
		            case 0: // 사용자가 0(종료)을 선택한 경우
		                System.out.println("종료를 선택하셨습니다.");
		                return playerChoice; // 메서드 종료 및 playerChoice 반환
		            default: // 유효하지 않은 값이 입력된 경우
		                System.out.println("잘못된 값을 입력하셨습니다. 다시 입력하세요.");
		        }
		    } while (playerChoice < 0 || playerChoice > 3); // 유효한 값(0~3)이 입력될 때까지 반복
		    
		    // 유효한 입력을 받으면 playerChoice 반환
		    return playerChoice;
	    	
	    } catch (InputMismatchException e) {
	    	System.out.println("숫자가 아닌 값이 입력되었습니다.");
	    }
		return playerChoice;
	}

	private void judge(int computerChoice, int playerChoice) {
		int difference = computerChoice - playerChoice;
		printComputerChoice(computerChoice);

		if (difference == DRAW) {
			System.out.println("무승부입니다.");
		} else if (contains(COMPUTER_WIN, difference)) {
			System.out.println("컴퓨터 승리");
		} else if (contains(PLAYER_WIN, difference)) {
			System.out.println("플레이어 승리");
		} else {
			System.out.println("예외상황 발생!!");
		}
	}

	private boolean contains(int[] array, int value) {
		for (int i : array) {
			if (i == value) {
				return true;
			}
		}
		return false;
	}

	private void printComputerChoice(int computerChoice) {
		switch (computerChoice) {
			case 1: System.out.println("컴퓨터는 바위를 냈습니다."); break;
			case 2: System.out.println("컴퓨터는 가위를 냈습니다."); break;
			case 3: System.out.println("컴퓨터는 보를 냈습니다."); break;
		}
	}
}

public class Scanner_Exam4_scissors {

	public static void main(String[] args) {
		/*
		 * 컴퓨터와 함께하는 가위, 바위, 보
		 * 0. 컴퓨터가 가위(1), 바위(2), 보(3) 선택(Math.random())
		 * 1. - 1. 가위 2. 바위 3. 보 0. 종료
		 * 2. 선택값 입력
		 * 3. 결과 비교 후 승자, 패자 결정
		 * (반복) 게임 반복 진행 - 0(종료) 선택시 까지
		 */
		// new aiRSP().start();
		new AiRSP_refactoring().start();
	}

}
1. 바위 2. 가위 3. 보 0. 종료
1
바위를 내셨습니다.
컴퓨터는 가위를 냈습니다.
플레이어 승리

1. 바위 2. 가위 3. 보 0. 종료
3
보를 내셨습니다.
컴퓨터는 바위를 냈습니다.
플레이어 승리

1. 바위 2. 가위 3. 보 0. 종료
2
가위를 내셨습니다.
컴퓨터는 보를 냈습니다.
플레이어 승리

1. 바위 2. 가위 3. 보 0. 종료
w
숫자가 아닌 값이 입력되었습니다.
게임을 종료합니다.

실습3(GuessNumber)

import java.util.InputMismatchException;
import java.util.Scanner;

/*
 * 컴퓨터가 1~100 까지 숫자 중 하나를 정한다.
 * 선택의 기회 5회
 */


/*
 * 업그레이드 : try catch 를 사용하여 오류를 다뤘다.
 * 범위 밖의 숫자를 입력받으면 다시 입력하도록 제작
 * 숫자가 아닌 문자를 입력할 경우 오류를 띄우고 종료시키는 것이 아니라, 다시 입력을 받아올 수 있게 만들었다.
 */

class GuessNumber {
    private static final int MAX_LIFE = 5;
    private static final int MAX_NUMBER = 100;
    private static final int MIN_NUMBER = 1;
    private static final int CONTINUE_GAME = 1;
    private static final int END_GAME = 0;
	
	public void start() {
		
		Scanner scan = new Scanner(System.in);
		boolean game_continue = true;
		
		while (game_continue) {
			int life = MAX_LIFE;
			boolean isCorrectGuess = false;
			int answer = (int) Math.floor(Math.random() * MAX_NUMBER + MIN_NUMBER);
			
			while (life > 0 && !isCorrectGuess) {
				System.out.println("1부터 100사이의 숫자 중 하나를 정하세요.");
				int selectedNumber = selectNumber(scan);
				isCorrectGuess = checkGuess(selectedNumber, answer);
				if (!isCorrectGuess) {
					life = lifeManagement(life, answer);
					System.out.println();
				} else {
					System.out.println("성공!! 당신은 " + (MAX_LIFE - life) + "번 만에 정답을 맞추셨습니다.");
				}
				
			}
			
			game_continue = askToContinue(scan);
			
		}
		

		
	}
	
	/*
	 * 플레이어의 정답을 확인하는 메서드
	 * 플레이어의 추측 값이 높거나 낮은지, 혹은 정답인지 판단한다.
	 */
	private static boolean checkGuess(int selectedNumber, int answerNumber) {
		if (selectedNumber > answerNumber) {
			System.out.println("::: Down! :::");
			return false;
		} else if (selectedNumber < answerNumber) {
			System.out.println("::: Up! :::");
			return false;
		} else {
			System.out.println("::: Correct! :::");
			return true;
		}
		
	}
	
	/*
	 * 플레이어로부터 숫자를 입력받는 메서드
	 * 숫자가 아닌 값을 입력 받으면 예외처리를 한다.
	 */
	private static int selectNumber(Scanner scan) {
	    int number = 0;

	    while (true) {
	        try {
	            System.out.println("범위에 맞는 숫자를 입력해 주세요(1~100)");
	            number = scan.nextInt();

	            if (number > 0 && number < 101) {
	                return number;
	            } else {
	                System.out.println("범위를 벗어난 숫자입니다. 다시 입력해 주세요.");
	            }
	        } catch (InputMismatchException e) {
	            System.out.println("숫자가 아닌 값이 입력되었습니다. 숫자를 입력해 주세요.");
	            scan.nextLine(); // 스캐너의 현재 라인을 비워 입력 버퍼를 정리
	        }
	    }
	}
	
	/*
	 * 사용자의 생명을 관리하는 메서드
	 * 생명을 하나 감소시키고 남은 횟수를 출력한다.
	 * 생명이 0일 경우, 답을 알려준다.
	 */
	private static int lifeManagement(int life, int answerNumber) {
		life--;
		if (life == 0) {
			System.out.println("당신의 남은 기회가 없습니다.");
			System.out.println("정답은 " + answerNumber + "입니다.");
		} else {
			System.out.println("당신의 남은 기회는 " + life + "회 입니다.");
		}
		return life;
	}
	
	/*
	 * 게임이 모두 끝나고, 계속 할 지 묻는 메서드
	 * 사용자가 게임을 계속할지 종료할지 결정한다.
	 */
	private static boolean askToContinue(Scanner scan) {
		System.out.println("계속 하시겠습니까? ::: (종료:0 , 계속:1) :::");
		int select_continue = 0;
		
		System.out.println();
		
		while (true) {
			try {
				do {
					select_continue = scan.nextInt();
					switch(select_continue) {
						case END_GAME:
							System.out.println("게임을 종료합니다.");
							System.out.println();
							return false;
						case CONTINUE_GAME:
							System.out.println("게임을 계속합니다.");
							System.out.println();
							return true;
						default:
							System.out.println("0이나 1을 입력해 주십시오.");
							System.out.println();
					}
				} while (select_continue < 0 || select_continue > 1);
				
			} catch (InputMismatchException e) {
		    	System.out.println("숫자가 아닌 값이 입력되었습니다. 숫자를 입력해 주세요.");
		    	scan.nextLine();
		    }
		}
		

	}
}

public class GuessNumberGame {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new GuessNumber().start();
	}

}
1부터 100사이의 숫자 중 하나를 정하세요.
범위에 맞는 숫자를 입력해 주세요(1~100)
1
::: Up! :::
당신의 남은 기회는 4회 입니다.

1부터 100사이의 숫자 중 하나를 정하세요.
범위에 맞는 숫자를 입력해 주세요(1~100)
99
::: Down! :::
당신의 남은 기회는 3회 입니다.

1부터 100사이의 숫자 중 하나를 정하세요.
범위에 맞는 숫자를 입력해 주세요(1~100)
38
::: Up! :::
당신의 남은 기회는 2회 입니다.

1부터 100사이의 숫자 중 하나를 정하세요.
범위에 맞는 숫자를 입력해 주세요(1~100)
94
::: Down! :::
당신의 남은 기회는 1회 입니다.

1부터 100사이의 숫자 중 하나를 정하세요.
범위에 맞는 숫자를 입력해 주세요(1~100)
45
::: Down! :::
당신의 남은 기회가 없습니다.
정답은 43입니다.

계속 하시겠습니까? ::: (종료:0 , 계속:1) :::

w
숫자가 아닌 값이 입력되었습니다. 숫자를 입력해 주세요.
e
숫자가 아닌 값이 입력되었습니다. 숫자를 입력해 주세요.
1
게임을 계속합니다.

1부터 100사이의 숫자 중 하나를 정하세요.
범위에 맞는 숫자를 입력해 주세요(1~100)
99
::: Down! :::
당신의 남은 기회는 4회 입니다.

1부터 100사이의 숫자 중 하나를 정하세요.
범위에 맞는 숫자를 입력해 주세요(1~100)
66
::: Down! :::
당신의 남은 기회는 3회 입니다.

1부터 100사이의 숫자 중 하나를 정하세요.
범위에 맞는 숫자를 입력해 주세요(1~100)
33
::: Up! :::
당신의 남은 기회는 2회 입니다.

1부터 100사이의 숫자 중 하나를 정하세요.
범위에 맞는 숫자를 입력해 주세요(1~100)
44
::: Up! :::
당신의 남은 기회는 1회 입니다.

1부터 100사이의 숫자 중 하나를 정하세요.
범위에 맞는 숫자를 입력해 주세요(1~100)
47
::: Up! :::
당신의 남은 기회가 없습니다.
정답은 50입니다.

계속 하시겠습니까? ::: (종료:0 , 계속:1) :::

0
게임을 종료합니다.

(주의) next(), nextInt(), ..... + nextLine() 사용시 오동작 가능성 있다.

Scanner 클래스에서 next(), nextInt(), nextDouble() 등의 메소드는 입력된 값 다음에 오는 줄바꿈 문자(엔터 키)를 소비하지 않는다. 즉, 사용자가 숫자를 입력하고 엔터를 치면 숫자는 nextInt()에 의해 읽히지만, 엔터 키로 인한 줄바꿈 문자는 그대로 입력 스트림에 남아 있게 된다.

이후 nextLine() 메소드가 호출되면, 이 줄바꿈 문자를 새로운 라인의 시작으로 간주하고, 그 즉시 빈 문자열을 반환하게 된다. 결과적으로 nextLine()은 사용자가 의도한 입력을 받기 전에 반환되는 것처럼 보이게 된다.

이 문제를 해결하기 위한 일반적인 방법은 두 가지이다.

  1. nextInt()nextLine() 호출
    • nextInt() (또는 다른 nextXxx() 메소드) 이후에 nextLine()을 호출하기 전에 추가적인 nextLine()을 호출하여 남아 있는 줄바꿈 문자를 소비한다. 이 방법은 코드에서 "해결 1"로 표시된 부분에서 사용되었다.
int num1 = scan.nextInt();
scan.nextLine(); // 빈 문자열 읽어서 버리기
  1. 입력을 문자열로 받은 후 변환
    • 모든 입력을 nextLine()을 통해 문자열로 받은 다음, 필요한 타입으로 변환한다. 이 방법은 "해결방법 2"로 표시된 부분에서 사용되었으며, Integer.parseInt()를 사용하여 문자열을 정수로 변환한다.
int num2 = Integer.parseInt(scan.nextLine());
profile
신입사원...

0개의 댓글