get_prime 메소드는 매개변수도 없고 출력값(리턴하는 값)도 없는 메소드인데, prime이라는 배열은 어디서 가져왔나?
get_prime() 메소드 위에다가 먼저 prime이라는 정적 boolean 타입의 필드를 선언해 주었다. 이렇게!
public static boolean[] prime; // main 메소드 밖에서 선언
나는 정적 필드를 선언할 생각은 못 했는데, 생각해 보니 정적 필드를 선언하고 그 필드를 정적 메소드에 언급하면 굳이 로컬변수나 객체를 생성하지 않아도 되겠다.
이렇게 위에서 정적 필드를 선언하고, 나중에 main함수 안에서 prime 배열의 길이만 선언해 주면 된다.
N+1의 길이로 설정해서 0부터 N까지의 소수값 여부를 저장할 수 있는 배열을 만들어 준다.
(정적 필드 prime배열을 N+1의 길이로 설정한 것도, 그냥 0부터 N까지의 수들 중 소수를 다 구해버리고 나중에 M에서 N 사이에 있는 소수 값만 추출하기 위해서인 것 같다. prime배열을 M부터 N까지 선언한다면 기존 에라토스테네스의 체 알고리즘을 일부 변형해야 되서 번거로운 점도 있을 듯.)
prime = new boolean[(N+1)]; // main 메소드 안에서 설정
에라토스테네스의 체 알고리즘은 2개의 중첩 for문으로 구성된다.
1. 여기선 true이면 소수가 아니고 false면 소수라고 간주한다.
2. 이는 어떤 수의 배수는 모두 소수에서 제외한다는 원리를 이용한다.
첫 번째 for문에서의 i는 어떤 수의 역할을 한다.
두 번째 for문에서의 j는 어떤 수의 배수 역할을 한다.
좀 더 구체적으로 보면,
1. 0과 1은 소수가 아니고 2는 소수라서, i=2부터 시작한다.
2. j는 i*i이다. i*i는 i라는 약수를 갖기 때문에 소수에서 제외된다.
3. 이 j에다가 i씩 더한다. 즉 i*i, i*(i+1), i*(i+2), ... 이렇게 해서 i를 약수로 갖는 모든 값들을 제외시킨다.
4. 그 다음은 i=3, 위의 과정을 반복한다. 그런데 만약 i=4처럼 소수가 아닌 값이 i 자리에 와도 이미 i=2일 때 j의 값에 해당되어서 제외되었기 때문에 상관 없다.
5. 이렇게 N까지 반복하는 것이 아니라, N에 루트 씌운 값까지만 반복한다. 그 이후의 값은 검사할 필요가 없다.
+) 5번의 이유:
어떤 자연수 N은 1과 자신이 아닌 다른 두 수 A와 B의 곱으로 나타낼 수 있다고 해 보자. (즉 N은 소수가 아니다.)
A * B = N이다.
그런데 만약 A가 N의 제곱근보다 크다면, 나머지 B는 반드시 N의 제곱근보다 작아야 한다. 안 그러면 A*B는 N보다 큰 값을 갖게 되어서 식이 성립하지 않는다.
=> 즉 N이 소수가 아니라고 가정할 때, N의 제곱근까지만 검사하면 합성수 N을 이루는 두 수 A, B중 작은 수(여기서는 B)까지는 검사할 수 있고, 만약 여기까지 검사했을 때 N의 약수가 나오지 않는다면?
=> B가 없는 것이므로 A*B = N 이라는 가정이 깨지게 된다. 고로 이때 N은 소수가 아니라고 볼 수 있다.
=> N의 제곱근까지만 검사하면 N이 소수인지 아닌지를 알 수 있다!
아무튼 그래서 get_prime() 정적 메소드를 선언해서 N까지의 수 중에서 소수인 값만 찾아 준다.
그 다음에는 main함수에서 해결하면 되는데,
1. if문에서 최솟값인 M이 최댓값인 N보다 큰 예외 상황 및 M, N이 0과 10000 사이가 아닌 예외 경우를 따로 처리한다.
2. 초기 sum 값은 0, min값은 int 타입이 가질 수 있는 가장 큰 값으로 설정하고, 바꿔 나간다.
** 왜 min 값을 0이 아니라 최댓값으로 설정하는지는 잘 모르겠다...!
int sum = 0;
int min = Integer.MAX_VALUE;
// Integer 클래스 안에 MAX_VALUE라는 final static 필드가 선언되어 있어서 이렇게 불러올 수 있나보다.
그리고 정적 필드 prime의 각 원소를 for문을 사용해서 하나씩 해당 값이 false인지(=소수인지) 비교하는데, 만약 false라면 sum 값에다 더해 주고, min 값으로 할당해 준다.
for(int i=M; i<=N; i++) {
if(prime[i]==false) {
sum += i;
if(min==Integer.MAX_VALUE) {
min = i;
}
}
}
이때, prime의 해당 원소의 값이 false일 때 min의 값을 i로 할당해 줘야 한다.
이렇게 조건을 주면, min값이 초기에 설정한 Integer.MAX_VALUE일 때만 min 값을 i로 할당하는데,
그러면 min값은 한 번만 할당되고 여러 번 변경되지 않는다.
마지막으로, 만약 M부터 N까지의 범위에 소수가 없었을 때, 즉 sum == 0일 때의 조건만 지정해 준다.
1. 입력을 받아야 하므로 Scanner(BufferedReader를 쓰지 않아도 시간 초과가 안 되었다.)
2. N의 약수에 해당하는 수를 저장할 ArrayList. 소인수가 몇 개일지 몰라서 배열 말고 ArrayList를 사용했다.
2. 정적 필드
9-2를 풀면서 정적 필드, 메소드를 잘 활용하면 객체 생성이나 로컬변수 처리 문제를 안 겪어도 된다는 생각에 정적 필드와 메소드를 선언했다.
public static int N;
public static ArrayList<Integer> number = new ArrayList<Integer>();
public static int i = 2;
1. N : scanner로 입력받을 N을 다른 메소드에서 다시 정의하기 귀찮아서 정적 필드로 선언.
2. ArrayList도 위에서 import만 해 주면 static field로 선언할 수 있었다...!
3. i는 while문에서 하나씩 증가시키고 해당 조건에 맞으면 소인수로 ArrayList에 추가시킬 수인데, 로컬 변수로 선언했다가 괜히 처리하기 까다로워질 것 같아서 정적 필드로 선언했다.
3. 정적 메소드 선언
자연수 N이 주어지면 해당 자연수를 소인수분해하는 isDivisor() 메소드를 선언하였다.
public static void isDivisor(int N) {
if(N==1) { // 예외1 : N=1일 때
System.out.println("");
}else if(N<0 | N>10000000) { // 예외2 : N이 범위를 벗어날 때
System.out.println("Error");
}else {
while(true) {
if(N==i) { // case 1
number.add(i);
break;
}else if(N % i != 0) { // case 2
i++;
}else if(N % i == 0) { // case 3
N = N/i;
number.add(i);
}
}
for(int k=0; k<number.size(); k++) {
System.out.println(number.get(k));
}
}
}
case 1:
소인수분해가 다 완료되고 더 이상 인수(혹은 약수)가 없으면 나눠지고 남은 수인 N과 나눌 수인 i가 서로 같아진다. 이 경우에만 while문을 break하도록 했다.
case 2:
N이 i로 나눠지지 않을 때 = i가 N의 소인수가 아닐 때.
i+1을 해서 값만 변화시켰다.
case 3:
N이 i로 나눠질 때 = i가 N의 소인수일 때.
우선 N을 i로 나눠서 N 값을 변화시키고, 해당 i값을 ArrayList에 추가했다.
i값을 증가시키지 않았으므로, 만약 N이 i로 여러 번 나눠지는 수였다면 그만큼 i가 추가로 ArrayList에 추가되도록 했다.
그리고 이렇게 만들어진 number이라는 ArrayList를 0번부터 끝까지(ArrayList의 size -1까지) 출력시켰다.
4. main 메소드
앞에서 메소드와 필드로 모든 과정을 선언해서 main메소드는 짧게 작성할 수 있었다.
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
N = sc.nextInt();
isDivisor(N); // 3번에서 작성한 isDivisor 정적 메소드 사용
sc.close(); // scanner 꼭 닫아주기!
}
Step 9-4. 소수 구하기(1929번)
이 문제도 혼자 풀었다.
<접근>
Step 9-2의 에라토스테네스의 체의 원리를 그대로 활용했다.
다만 아까는 int타입의 sum 변수를 사용한 대신, 지금은 에라토스테네스의 체로 0부터 N까지의 소수를 구한 뒤, M부터 N까지의 소수만 출력하는 방식을 사용하였다.
import java.util.Scanner;
public class Main {
// 정적 필드 선언
public static int M;
public static int N;
public static boolean[] prime;
public static void main(String[] args) {
// 정적 메소드에 사용할 값 할당하기
Scanner sc = new Scanner(System.in);
M = sc.nextInt();
N = sc.nextInt();
prime = new boolean[(N+1)];
if(M>=1 && N>=M && N<=1000000) {
get_prime(); // 정적 메소드 사용
// 정적 메소드에서는 1~N의 소수를 구했으나, M~N의 소수만 출력
for(int i=M; i<prime.length; i++) {
if(prime[i]==false) {
System.out.println(i);
}
}
}else { // 예외처리 : M과 N의 범위가 잘못되었을 때
System.out.println("ERROR");
}
sc.close();
}
// 정적 메소드 선언
public static void get_prime() {
prime[0] = true;
prime[1] = true;
for(int i=2 ; i<=Math.sqrt(N) ; i++) {
for(int j=(i*i); j<prime.length; j += i) {
prime[j] = true;
}
}
}
}
Step 9-5(4948번)
이것도 혼자 풀었다! 사실 에라토스테네스의 체 원리만 알면 쉽게 풀 수 있는 문제인 것 같다.
<원리>
9-2, 9-4와 마찬가지로 에라토스테네스의 체 알고리즘은 정적 메소드로 선언해 놓은 상태에서 시작하면 편하다.
다만 여기는 여러 개의 test case가 주어지고, 각각 한 줄씩 주어지며, 몇 개가 주어질지 모른다는 점에서 주의해야 한다.
1. N의 입력 여러 개 받기
이때 N은 몇 개가 나올지 모르고 한 줄씩 나오므로, StringTokenizer 등을 사용하지 않아도 분리가 되었다. 나는 원래 분리된 걸 분리하려고 하느라 애를 먹었는데, 원래 스캐너는 입력을 하면 한 줄 단위로 처리하는 거였다.
다만 여러 줄을 입력하고 언제 끝날지 모른다는 점에서 for문보다는 while문이 사용하기 적합했다.
-> 그래서 main메소드 영역을 이렇게 작성했다.
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(true) {
N = Integer.parseInt(sc.nextLine().trim());
if(N==0) {
break;
}
if(N<1 | N>123456) {
System.out.println("ERROR");
break;
}else {
prime = new boolean[((2*N)+1)];
get_prime();
}
}
sc.close();
}
입력의 마지막에 0이 주어진다는 말은, 0이 입력으로 주어지면 프로그램을 종료시키라는 말과 같다.
그래서 while문을 두고 break하는 조건을 N==0일 때로 지정했다.
+ 또한 N은 sc.nextLine()으로 입력을 한 줄씩 받아서 처리하도록 했다.
+ N 뒤에는 trim() 메소드를 써서, 혹시나 공백과 섞인 문자열이 들어갔을 때 숫자만 추출할 수 있도록 했다.
2. 에라토스테네스의 체 원리를 이용 + 문제에 맞게 get_prime 정적메소드 다시 정의
우선 정적 메소드에서 사용할 정적 필드를 먼저 정의했다.
public static int N; // main 메소드에서 입력 받을 때 사용
public static boolean[] prime; // 많은 숫자들 각각이 소수인지 아닌지를 저장하기 위한 배열
public static int count = 0; // 특정 범위에서 소수의 숫자를 세기 위한 int 타입 필드
public static void get_prime() {
count = 0; // N이 새로 바뀌어서 메소드가 새로 호출될 때마다 count를 0으로 초기화한다.
prime[0] = true;
prime[1] = true;
if(N==1) { // N=1이면 i=2로 시작해서 소수를 셀 수 없으므로 예외로 처리했다.
System.out.println(1);
}else if(N==0) {
System.out.println("");
}else { // 에라토스테네스의 체 알고리즘 그대로 사용
for(int i=2 ; i<=Math.sqrt((2*N)) ; i++) {
for(int j=(i*i); j<prime.length; j += i) {
prime[j] = true;
}
}
//N보다 크고 2N보다 작은 소수들만 출력
for(int i=(N+1) ; i<=(2*N) ; i++) {
if(prime[i]==false) {
count ++; // 소수 하나 나올 때마다 count + 1
}
}
System.out.println(count);
}
}
최종 코드는 이렇다.
package ml.app2;
import java.util.Scanner;
public class Main {
public static int N;
public static boolean[] prime;
public static int count = 0;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(true) {
N = Integer.parseInt(sc.nextLine().trim());
if(N==0) {
break;
}
if(N<1 | N>123456) {
System.out.println("ERROR");
break;
}else {
prime = new boolean[((2*N)+1)];
get_prime();
}
}
sc.close();
}
public static void get_prime() {
count = 0;
prime[0] = true;
prime[1] = true;
if(N==1) {
System.out.println(1);
}else if(N==0) {
System.out.println("");
}else {
for(int i=2 ; i<=Math.sqrt((2*N)) ; i++) {
for(int j=(i*i); j<prime.length; j += i) {
prime[j] = true;
}
}
for(int i=(N+1) ; i<=(2*N) ; i++) {
if(prime[i]==false) {
count ++;
}
}
System.out.println(count);
}
}
}
에라토스테네스의 체 알고리즘을 알고 있었으나, 여기서는 주어진 짝수를 소수의 합으로 나타내되, '두 소수의 차가 가장 적은 쌍으로 나타내라'는 조건이 추가적으로 붙어서 그 점이 어려웠던 것 같다. 그래도 내가 생각한 범위에서의 예제 데이터는 처리할 수 있었는데, 왜 오류가 난 것인지는 잘 모르겠다ㅠㅠ
* IndexOutOfBoundsException 예외가 특히 많이 나왔는데, 어디서 나왔는지를 모르겠다...!
일단 풀이 시작>>
<보완할 점>
블로그 글을 보면서 이해하니, 내 코드가 생각보다 많이 복잡했음을 알 수 있었다.
나는 주어진 짝수가 여러 소수의 합으로 나타낼 수 있고, 그게 총 몇 쌍일지를 모르므로 ArrayList 구조를 사용해야 한다고 생각했지만, while문 하나로도 간단하게 코드를 짤 수 있는 문제였다.
<기존 나의 풀이의 개선점>
: 사용하지 않아도 될 변수 + 자료구조가 꽤 많고, 코드가 복잡했다!
import java.io.*;
import java.util.ArrayList; // 사용할 필요가 없었다
public class Main {
public static boolean[] prime = new boolean[10001];
public static int n;
public static ArrayList<Integer> goldberg; // 사용할 필요가 없었다
public static int sub_index; // 사용할 필요가 없었다
public static void main(String[] args) throws IOException {
try { // 사용할 필요가 없었다
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int T = Integer.parseInt(br.readLine().trim());
get_prime();
for (int i = 0; i < T; i++) {
n = Integer.parseInt(br.readLine().trim());
goldberg = new ArrayList<Integer>(); // 사용할 필요가 없었다
if (n > 10000 | n < 4) {
bw.write("ERROR");
break;
} else {
get_goldberg();
}
}
bw.close();
}catch(IndexOutOfBoundsException e) {
System.out.println(e);
}
}
public static void get_prime() {
prime[0] = true;
prime[1] = true;
for (int i = 2; i <= Math.sqrt(10000); i++) {
for (int j = (i * i); j < prime.length; j += i) {
prime[j] = true;
}
}
}
public static void get_goldberg() throws IOException { // 사용할 필요가 없었음. 이 긴 걸!
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
for (int i=3; i<=(n/2); i+=2) {
if( prime[i]==false && prime[(n-i)]==false) {
goldberg.add(i);
goldberg.add((n-i));
}else if(prime[i]==false && (2*i)==n) {
goldberg.add(i);
goldberg.add(i);
}
}
int min = Integer.MAX_VALUE;
int sub_index = 0;
for (int i = 0; i < goldberg.size(); i += 2) {
int sub = Math.abs(goldberg.get(i) - goldberg.get(i + 1));
if (sub < min) {
sub_index = i;
}
}
bw.write(String.valueOf(goldberg.get(sub_index)) + " ");
bw.write(String.valueOf(goldberg.get(sub_index + 1)) + "\n");
bw.flush();
}
}
<핵심>
1. 한 수의 합이 되는 두 수의 쌍 중 가장 차가 적은 것을 선택하려면, (블로그 글 보면서 배운점)
: 짝수 2N의 경우 N+N에서부터 시작하여, (N-1)+(N+1) 이런 식으로 첫 번째 수는 하나씩 감소, 두 번째 수는 하나씩 증가시킨다. 그러면 두 수의 차가 커지면서 두 수의 합은 그대로 유지된다. 이런 식으로 while문을 전개시키고, 두 수가 모두 소수가 되는 시점에 while문을 break하면 다른 변수를 생성하지 않아도 된다.
2. 주어진 짝수의 범위는 어차피 제한되어 있으니, 처음에 크기가 10001(10000+1)인 boolean 타입의 배열을 만들고 그 범위의 소수를 다 구하는 것이 매번 새로 배열을 만들고 소수를 새로 구하는 것 보다 빠르다. (당연하지만...!)
<코드 다시 작성>
import java.io.*;
public class Main {
public static boolean[] prime = new boolean[10001];
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
int T = Integer.parseInt(br.readLine().trim());
get_prime();
while(T>0) {
int n = Integer.parseInt(br.readLine().trim());
int firstNum = n/2;
int secondNum = n/2;
while(true) {
if(prime[firstNum]==false && prime[secondNum]==false) {
System.out.println(firstNum + " " + secondNum);
break;
}
firstNum--;
secondNum++;
}
T--;
}
bw.close();
}
public static void get_prime() {
prime[0] = true;
prime[1] = true;
for (int i = 2; i <= Math.sqrt(10000); i++) {
for (int j = (i * i); j < prime.length; j += i) {
prime[j] = true;
}
}
}
}
public static void main(String[] args) {
int sum = 0;
for(int i=1; i<=100; i++) {
sum += i;
}
System.out.println(sum);
}
* for문은 연속하는 수의 합을 구할 때도 많이 사용한다.
=> 이럴 때는 += 등의 증감연산자를 사용할 수 있다.
2. for문 안에서 정의된 변수는 로컬 변수(local variable)로, for문 밖으로 값을 갖고 나올 수 없다.
오류 예시!
public static void main(String[] args) {
for(int i=1; i<=100; i++) {
sum += i;
}
System.out.println(sum);
}
* 이 코드는 실행시키면 오류가 난다.
: b/c sum 변수는 for문 안에서 정의되었는데, for문 바깥에서 사용하려고 하면 sum변수 값을 불러올 수 없다.
=> sum변수를 for문 밖에서도 사용하고 싶다면, for문이 시작하기 이전에, 즉 for문 밖에서 정의를 먼저 해 주면 된다.
3. for문 : 초기화식, 조건식, 증감식에 각각 두 개 이상의 변수 넣기
public static void main(String[] args) {
int sum = 0;
for(int i=1, j=100; i<=100 && j>=50 ; i++, j--) {
sum = sum + i * j;
}
System.out.println(sum);
}
1) 해당 조건에 대한 실행할 실행문이 하나라면 {}를 생략해도 좋지만, 그 이외에는 다 {}를 넣어야 한다.
public static void main(String[] args) {
int score = 91;
if (score >=90) {
System.out.println("You are Level A.");
System.out.println("Congratulations!");
}
if (score <80)
System.out.println("You are Level B."); System.out.println("Keep up the good work");
System.out.println("Try a little harder!");
}
이렇게 if문 바로 아래 줄에, 같은 줄에 실행문을 두 개 이상 적는다고 해도, {}가 없으면 if문은 맨 앞의 실행문만 if문에 적용시킨다.
2) IF문으로 성적이 나오는 프로세스를 비슷하게 따라 해 보았다.
import java.util.Scanner;
public class chapter_4 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("What's your midterm score?");
int midterm = scanner.nextInt();
System.out.println("What's your assignment score?");
int assignment = scanner.nextInt();
System.out.println("What's your team project score?");
int team_project = scanner.nextInt();
System.out.println("What's your final exam score?");
int final_exam = scanner.nextInt();
double score = midterm*0.3 + assignment + team_project*0.3 + final_exam*0.3;
System.out.println("Your entire score is " + score);
if (score >=90) {
String grade = "A";
System.out.println("Your grade is " + grade);
}else if (score >=80){
String grade = "B";
System.out.println("Your grade is " + grade);
}else if (score >=70) {
String grade = "C";
System.out.println("Your grade is " + grade);
}else if (score >=60) {
String grade = "D";
System.out.println("Your grade is " + grade);
}else {
String grade = "F";
System.out.println("Your grade is " + grade);
}
scanner.close();
}
}
* 갑자기 생각나서 써봄
: printf()에서 여러 개의 형식과 여러 출력을 한꺼번에 지정할 때는 버전 오류가 난다!
Java se 11 이전 버전에서는 잘 작동하는지 궁금했지만 Oracle 회원가입을 해서 깔아야 한다니 참으로 귀찮은 일이 아닐 수 없다.
그래서 printf 함수는 사용을 안 하기로 했다. 어차피 백준에서는 Java se 11에 맞게 코드가 잘 작동된다고 한다.
3) 아쉽지만 printf 대신 println으로 로또번호 출력기를 만들어 봄
public static void main(String[] args) {
int num1 = (int) (Math.random()*45 +1);
int num2 = (int) (Math.random()*45 +1);
int num3 = (int) (Math.random()*45 +1);
int num4 = (int) (Math.random()*45 +1);
int num5 = (int) (Math.random()*45 +1);
int num6 = (int) (Math.random()*45 +1);
System.out.println(num1);
System.out.println(num2);
System.out.println(num3);
System.out.println(num4);
System.out.println(num5);
System.out.println(num6);
}
}
: Math.random() <- 대문자 필수!
얘는 double 타입의 0부터 1 사이에 있는 난수를 발생시키는데, *45를 하고 1을 더해준 다음 강제로 int 타입으로 변환시킨다. 그러면 1부터 45사이에 값을 갖는 로또 번호 랜덤 생성기가 된다.
4) 치밀하게 설계하면 주사위 게임도 가능한 듯.
public static void main(String[] args) {
int dice = (int)(Math.random()*6 +1);
if(dice == 1) {
System.out.println("1칸 전진하시오.");
}else if(dice == 2) {
System.out.println("무인도입니다. 한 턴 쉬어가세요.");
}else if(dice == 3) {
System.out.println("상대편의 말을 잡았습니다. 한번 더 굴리세요.");
}else if(dice == 4) {
System.out.println("통행료로 100,000원을 제출하세요.");
}else if(dice == 5) {
System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
}else{
System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
}
}
1-2. Switch문
똑같은 주사위 게임을 Switch문을 이용해서 만들 수 있다.
public static void main(String[] args) {
int dice = (int)(Math.random()*6 +1);
switch(dice) {
case 1:
System.out.println("1칸 전진하시오.");
break;
case 2:
System.out.println("무인도입니다. 한 턴 쉬어가세요.");
break;
case 3:
System.out.println("상대편의 말을 잡았습니다. 한 턴 더 굴리세요.");
break;
case 4:
System.out.println("통행료로 100,000원을 제출하세요.");
break;
case 5:
System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
break;
default:
System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
break;
}
}
오히려 Switch문은 숫자 형태의 값을 갖는 변수를 사용하므로, 코드가 더 간단하게 작성될 수 있다.
+ 복잡하게 실행하면 진짜 주사위 게임도 가능할 듯.
+ 미연시 게임?처럼 대답에 따라서 스토리가 달라지는 게임도 가능할 듯.
Switch문의 대상인 변수의 값에 따라 출력되는 결과를 다르게 하고 싶다면,
반드시 각 case마다 break; 문을 작성해야 한다!!
그렇지 않으면 이렇게 된다. ↓
public static void main(String[] args) {
int dice = 2;
switch(dice) {
case 1:
System.out.println("1칸 전진하시오.");
case 2:
System.out.println("무인도입니다. 한 턴 쉬어가세요.");
case 3:
System.out.println("상대편의 말을 잡았습니다. 한 턴 더 굴리세요.");
case 4:
System.out.println("통행료로 100,000원을 제출하세요.");
case 5:
System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
default:
System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
}
}
: switch문의 변수인 dice는 2이다. 그런데 switch문의 case 사이마다 변수가 없어서, 각 case가 구분되지 않고 위에서부터 아래로 차례대로 코드가 실행되어서 이처럼 여러 경우에 해당하는 결과들이 다 같이 나오고 있다.
1) switch문의 변수 : char 타입의 입력 받기
import java.util.Scanner;
Scanner scanner = new Scanner(System.in);
char alphabet = alphabet.next().charAt(0);
+ char타입은 nextInt 등의 기능이 없다. 그래서 next() 다음에 charAt()을 입력한다.
+ 그런데 charAt(0) 에서 0의 의미가 무엇인지는 잘 모르겠다.
import java.util.Scanner;
public class chapter_4 {
public static void main(String[] args) {
System.out.println("What's your code?");
Scanner scanner = new Scanner(System.in);
char alphabet = scanner.next().charAt(0);
switch(alphabet) {
case 'a':
System.out.println("1칸 전진하시오.");
break;
case 'b':
System.out.println("무인도입니다. 한 턴 쉬어가세요.");
break;
case 'c':
System.out.println("상대편의 말을 잡았습니다. 한 턴 더 굴리세요.");
break;
case 'd':
System.out.println("통행료로 100,000원을 제출하세요.");
break;
case 'e':
System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
break;
default:
System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
}
}
}
2) Switch문의 변수 : String 타입의 입력 받기
import java.util.Scanner;
Scanner scanner = new Scanner(System.in);
String str = scanner.nextLine();
+ 그런데 nextLine 코드를 사용할 때, 공백을 인식/인식하지 못해서 생기는 불편함에 대해서는 나중에 알아보자.
import java.util.Scanner;
public class chapter_4 {
public static void main(String[] args) {
System.out.println("What's your code?");
Scanner scanner = new Scanner(System.in);
String code = scanner.nextLine();
switch(code) {
case "Apple":
System.out.println("1칸 전진하시오.");
break;
case "Banana":
System.out.println("무인도입니다. 한 턴 쉬어가세요.");
break;
case "Carrot":
System.out.println("상대편의 말을 잡았습니다. 한 턴 더 굴리세요.");
break;
case "Daisy":
System.out.println("통행료로 100,000원을 제출하세요.");
break;
case "Egg":
System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
break;
default:
System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
}
}
}
공백을 잘 인식하는지를 보기 위해서, String 변수의 각 case값을 2어절 이상의 단어로 설정했다.
import java.util.Scanner;
public class chapter_4 {
public static void main(String[] args) {
System.out.println("What's your code?");
Scanner scanner = new Scanner(System.in);
String code = scanner.nextLine();
switch(code) {
case "Apple Juice":
System.out.println("1칸 전진하시오.");
break;
case "Banana Smoothie":
System.out.println("무인도입니다. 한 턴 쉬어가세요.");
break;
case "Carrot Cake":
System.out.println("상대편의 말을 잡았습니다. 한 턴 더 굴리세요.");
break;
case "Daisy Tea":
System.out.println("통행료로 100,000원을 제출하세요.");
break;
case "Egg Tart":
System.out.println("해당 영토의 건물을 살 수 있습니다. 구매하시겠습니까?");
break;
default:
System.out.println("결승점에 도착했습니다. 게임이 끝납니다.");
}
}
}
공백은 잘 인식하는 것 같다. 그리고 String 타입의 경우 정확한 string을 입력해야 한다! 대소문자도 구분한다!
ex) 'Egg Tart'를 대소문자 구분, 정확히 입력해야지만 해당 결과가 나온다
-> egg tart (X) , Egg Tart (O)
+ Scanner에는 여러 method가 있다.
ex) int 타입 변수 입력 시에는 nextInt 를 쓰는 것처럼!
=> String 타입 변수 입력시에는 .next 또는 .nextLine 를 사용하는데, 둘 사이에 차이가 있다.
1) scanner.next();
띄어쓰기 이후의 입력은 받아들이지 않는다.
각 입력의 구분 단위가 \n처럼 띄어쓰기인 것 같다.
import java.util.Scanner;
public class chapter_4 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String data = input.next();
System.out.println(data);
input.close();
}
}