ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [자바(JAVA)] Random() 함수, Array과 ArrayList의 차이점, contain() 함수
    JAVA 2023. 6. 12. 20:16
    728x90

     

     

    문제:
    0~9까지 중복되지 않는 랜덤한 숫자 3개를 선택 후 사용자가 총 3개의 숫자를 입력한다.
    🔻아래 상황에 맞춰서 메세지를 출력한다.
    1) 숫자와 값의 위치가 모두 일치하면 S
    2) 숫자값은 일치하나 위치가 다른 경우 B
    3) 사용자가 맞출때까지 시도는 무제한으로 진행한다.

    ex) 랜덤숫자: [1, 2, 3]
    입력값: [2, 3, 4]
    👉출력값: 0S2B

    4) 출력형태는 아래와 같이 진행한다.
    1번째 시도: 987
    0B0S
    2번째 시도: 654
    0B1S
    3번째 시도: 123
    3S
    3번만에 맞히셨습니다.

     

     


    🔎 풀이

    ⭐ 고려한 상황
    1) 랜덤숫자 선택시 중복여부를 검증 후 중복일 경우 랜덤값을 다시 뽑기
    2) 랜덤값을 받을 참조형 변수의 종류 고려하기
    3) S와 B을 체크할때 중복으로 체크되지 않도록 하기

     

     

    🔽 전체코드(더보기 펼치기)

    더보기

    import java.util.ArrayList;
    import java.util.Random;
    import java.util.Scanner;

    public class Chapter1 {
        public static void main(String[] args) {
            // 입력부
            Random random = new Random();
            ArrayList<Integer> comNum = new ArrayList<>();     // 컴퓨터 랜덤값 받을 배열
            int[] guess = new int[3];                    // 사용자 입력값 받을 배열
            int count = 1;                                     // S, B, 시도횟수 기록

            // 랜덤값 중복없이 선택
            while(comNum.size() < 3) {                         // arrayList의 길이가 3이 될때까지 반복
                int randomNum = random.nextInt(10);
                if (!comNum.contains(randomNum)) {     // 랜덤넘버가 컴퓨터 문제넘버 내부에 없을 경우에만 저장
                    comNum.add(randomNum);
                }
            }
            // System.out.println("컴퓨터 랜덤값: " + comNum);  컴퓨터에 랜덤값이 정상입력 됐는지 확인용

            // 사용자 입력값

            System.out.println("컴퓨터가 숫자를 생성하였습니다. 답을 맞춰보세요!");
            Scanner sc = new Scanner(System.in);
            
            while (true) {
                System.out.print(count + "번째 시도 : ");
                for (int i = 0; i < guess.length; i++) {
                guess[i] = sc.nextInt();
                }        
                int Snum = 0, Bnum = 0;                     // 입력 후 상태확인에 사용되어 지역변수로 선언

                for (int i = 0; i < comNum.size(); i++) {
                    if (comNum.get(i) == guess[i]) {
                        Snum++;
                    } else {
                        for (int j = 0; j < comNum.size(); j++) {
                           if (comNum.get(i) == guess[j]) {
                                Bnum++;
                            }
                       }
                   }
               }
                if (Snum < 3 && Bnum < 3) {

                    System.out.println(Bnum + "B" + Snum + "S" );
                    count++;

                }
                else if (Bnum == 3) {
                    System.out.println(Bnum + "B" );
                    count++;
              }
               else if (Snum == 3){
                    System.out.println(Snum + "S" );
                    System.out.println(count
                    + "번만에 맞히셨습니다."
                    + "\n"
                    + "게임을 종료합니다.");
                    break;

                }
            }
        }
    }

     

     

     


    🔸 1. 랜덤값 출력하기

    - Random()을 이용한다.

     

    `Random` 클래스는 자바에서 난수를 생성하는 데 사용되는 클래스이다. 
    생성자에 전달하는 매개변수는 생성되는 난수의 범위를 지정한다. 
    Random() 함수는 사용시 import java.util.Random를 해야한다.

     

    Random() 사용방법

    1.import java.util.Random; 

    import java.util.Random;

     

    2. 범위값 정하기

    Random random = new Random();
    int randomNum = random.nextInt(10);

    선언 후 원하는 타입에 맞게 범위를 지정한다.

    random.nextInt(10); ()의 숫자는 0부터 10미만의 숫자를 범위로 가진다.

    random()의 정확한 범위값 설정은 아래와 같다.

     

    // 1 이상 10 이하의 범위에서 난수 생성
    int min = 1;
    int max = 10;
    int randomInRange = min + (int) ((max - min + 1) * random.nextInt());

     

    `Random(10)`에서 괄호 안에 숫자 10을 넣는 것은 `Random` 클래스의 생성자에 전달되는 매개변수이며, 이 값은 난수 생성의 범위를 지정하는 데 사용된다.

     

     

    💬 예시1) 랜덤값의 범위가 0~15인 경우
    int randomNum = random.nextInt(16);

    💬 예시2) 랜덤값의 범위가 15~20인 경우
    int randomNum = random.nextInt(6)+15;
    👉 random.nextInt(6) = 0~5까지의 값을 가짐
    👉 시작점이 15부터니까 +15를 진행함
    정확한 코드기준은 아래를 참고

     

    Random random = new Random();
    int minValue = 15;
    int maxValue = 21; // 범위는 15부터 20까지이므로 maxValue 21

    int randomNumber = random.nextInt(maxValue - minValue) + minValue;

     

    Random()의 경우 반환값을 직접 정할 수 있다.

    int형: int randomNumber random.nextInt

    Double 형: double randomNumber = random.nextDouble();

    👉 Double형은 0이상 1미만의 수가 반환된다.

     

     

     


     

     

    🔸 2. 랜덤값을 저장할 참조형 변수 고르기

     

     

    ✔ (1) 입력받을 사용자값은 int[]로 지정했다.

    📄 사용자 입력값을 Array로 저장한 이유
    - 사용자가 입력할 값은 총 3개로 고정되었다.
    - Array는 고정 크기를 갖기 때문에 크기를 동적으로 변경할 필요가 없는 상황에서는 Array가 더 효율적이다.
    - ArrayList는 동적 배열로 구현되어 있어 요소의 추가, 삭제, 삽입 등의 연산에서 배열의 재할당과 복사가 필요하지만, int 배열은 고정 크기이므로 배열의 크기 조정이 필요하지 않아서 요소에 접근하는 속도가 빠를 수 있다.
    따라서, guess 배열을 사용하는 것이 ArrayList 보다 메모리 사용과 접근 속도 측면에서 더 효율적이라고 판단했다.
    참조) https://imcodiiing.tistory.com/122  中
    4. Array를 사용했을 때 성능면에서 더 효율적인 이유

     


     

    ✔ (2) 랜덤값을 저장할 참조형 변수 결정하기

     

     

     

    https://imcodiiing.tistory.com/122

     

    [자바(JAVA)] 컬렉션 ArrayList, LinkedList, Stack, Queue, Set , Map

    🔷 Java 컬렉션 - Java 프로그래밍 언어에서 데이터를 저장하고 조작하기 위한 자료 구조의 집합이다. - 배열을 더 고도화 시킨 것으로 다수의 참조형 데이터를 더 쉽고 효과적으로 추가, 검색, 수

    imcodiiing.tistory.com

     

     

    : 배웠던 java 컬렉션 중에 중복값을 허용하지 않는 참조형 변수가 기억났다.

    • Set : 순서가 없는 데이터의 집합 (데이터 중복 허용 안함) - 순서없고 중복없는 배열
    • Map : 순서가 없는 (Key,Value) 쌍으로 이루어진 데이터의 집합 (Key값 중복 허용 안함)

     

    Map의 경우 Key값만 중복허용 불가고 value는 중복이 가능하기 때문에

    Set을 사용해보기로 했다.

     

     

     

    ❌ Set() 구현 실패 ❌

    🤔 의도: 애초에 데이터의 중복이 없다면 중복체크를 진행하는 코드를 줄일 수 있지 않을까?
    👉 Set을 사용하려 했으나 오류를 해결 못함(순서비교 오류)

    🤷‍♀풀이: Set은 값의 중복은 방지해서 랜덤값은 정상적으로 저장되나,
    순서가 없는 배열이기 때문에 추후 자리를 비교하여 "S" 혹은 "B"값의 카운딩에서 문제가 발생했다.
    S와 B값은 컴퓨터가 저장한 값을 순차적으로 불러와서 자리와 값이 맞는지, 자리는 다르나 값은 맞는지 여부를 판단해야되나 Set에 저장된 값을 순서대로 비교하는 부분에서 막혔다.
    해결방법이 있을것 같은데 코드를 아무리 바꿔봐도 원하는대로 진행되지 않아 
    결국 "순서가 있는 참조형 변수+중복값 유효성 검사"
    로 방향을 바꾸었다.

     

     


    ❌Array()로 구현하기 실패❌

     

    🤔 의도: 랜덤값도 숫자 3개로 크기가 고정되었다면 ArrayList보다 빠른 처리가 가능한 Array를 사용하자!
    👉 Array로 진행시 초기화 [0, 0, 0]으로 만들어져서 중복값 체크, 반복횟수 지정에서 오류가 발생한다.

    🤷‍♀풀이: int[] comNum = new int[3]; 을 진행하면 
    comNum의 현재값은 {0, 0, 0} 이다.
    comNum에 값을 add할 때 반복문을 사용하는데
    반복문의 조건을 for(int i=0; i < 3; i++) or   for(int i=0; i < comNum.length; i++) 로 설정해도 이미 초기화되어 값이 0으로 들어간 배열이기 때문에 length는 3이 나온다.
    즉, 중복여부와 관계없이 반복문은 3번 돌아간다.

    여기서 컴퓨터가 정한 값이 "0"일 경우 오류가 발생한다.
    랜덤값이 아래처럼 0,2,2로 선택되었다고 치자

    <컴퓨터의 랜덤값>
    comNum[1].add(0);
    comNum[1].add(2);
    comNum[1].add(2);

    * comNum() => 0,0,0 인 상태일 때 중복값 저장 불가의 로직을 따라 아래와 같이 진행된다.

    comNum[1].add(0);  (저장됨)
    comNum[1].add(2);  (저장됨)
    comNum[1].add(2);  (저장안됨_중복)

    의도대로라면 입력된 값이 2개니까 한번 더 반복하여 값을 저장해야 된다.
    그러나 위와 같이 진행했을 때의 실제값은
    comNum() = {0, 2, 0} 이 된다.
    기존에 초기화로 이미 입력된 0이 있기 때문에 중복체크를 했음에도 중복값이 남게 되어 구현에 오류가 발생한다.


    결국 랜덤값을 받는 변수는
    "초기화가 필요없는 ArrayList()"
    로 방향을 바꾸었다.

     

     

     

    ⭕ArrayList()로 저장하기 ⭕

     

    🤔 의도: 초기화할 필요없는 ArrayList로 비어있는 변수에 값을 채우고 중복값은 저장하지 않게 설정한다.
    채워진 값의 크기가 3일때 반복을 종료한다.
    👉 구현 성공

     

    풀이

     

    Random random = new Random();
    ArrayList<Integer> comNum = new ArrayList<>(); // 컴퓨터 랜덤값 받을 배열
    int[] guess = new int[3]; // 사용자 입력값 받을 배열
    int dupliNum = -1; // 컴퓨터 압력값 중복검사
    int count = 1; // S, B, 시도횟수 기록

    // 랜덤값 중복없이 선택
    while(comNum.size() < 3) { // arrayList의 길이가 3이 될때까지 반복
    int randomNum = random.nextInt(10);
    if (!comNum.contains(randomNum)) { // 랜덤넘버가 컴퓨터 문제넘버 내부에 없을 경우에만 저장
    comNum.add(randomNum);
    }
    }

    while문에서 ArrayList의 길이가 3이 될때까지 반복한다.

    단, randomNum이 기존 comNum에 포함되어 있지 않다는 조건을 걸어준다

    = 정상동작 확인함


    🖐 contain() 함수란?

    contains 메서드는 Collection 인터페이스에 정의된 메서드로, 주어진 객체가 컬렉션에 포함되어 있는지 여부를 확인하는 데 사용된다.
    boolean contains (Object o)   // true or false

    contains 메서드는 매개변수로 전달된 객체(o)가 컬렉션에 존재하면 true를 반환하고, 그렇지 않으면 false를 반환하는데, 이를 통해 특정 객체가 컬렉션에 포함되어 있는지 검사할 수 있다.

    contains 메서드는 Collection 인터페이스를 구현하는 모든 클래스에서 사용할 수 있으며,
    주로 List, Set, Queue 등과 같은 컬렉션 클래스에서 활용된다.

    Collection 인터페이스는 Java 컬렉션 프레임워크의 기본 인터페이스로, 다양한 컬렉션을 다룰 수 있는 공통 동작을 정의한다.

     


    `Collection` 인터페이스를 구현하는 대표적인 클래스의 예시

    1. `List`: `ArrayList`, `LinkedList`, `Vector` , ...
    2. `Set`: `HashSet`, `LinkedHashSet`, `TreeSet` , ...
    3. `Queue`: `LinkedList`, `PriorityQueue`, ...

    따라서 위의 클래스들을 사용하면 `contain` 메서드를 호출하여 특정 요소가 컬렉션에 포함되어 있는지 확인할 수 있다. 

     

     

    ✅ contain() 사용예시

    List<String> list = new ArrayList<>();
    list.add("apple");
    list.add("banana");
    list.add("orange");
    
    if (list.contains("apple")) {
        System.out.println("리스트에 apple이 포함되어 있습니다.");
    }

    위의 코드는 `List` 인터페이스를 구현한 `ArrayList` 클래스를 사용하였고,

    `contain` 메서드를 사용하여 "apple"이 리스트에 포함되어 있는지 여부를 확인할 수 있다.

    포함여부는 논리값으로 반환된다.

     


     

    🔸 2. S와 B을 체크할때 중복으로 체크되지 않도록 하기

     

    순서
    1순위 체크: 위치와 값이 일치하는 경우
    2순위 체크: 위치는 다르나 값이 일치하는 경우

    if, else if로 경우를 나눠줌
    출력문 역시 3S와 3B을 나눈다

     

     // 사용자 입력값
            Scanner sc = new Scanner(System.in);
            System.out.println("컴퓨터가 숫자를 생성하였습니다. 답을 맞춰보세요!");
    
            while (true) {
                System.out.print(count + "번째 시도 : ");
                for (int i = 0; i < guess.length; i++) {
                    guess[i] = sc.nextInt();
                }
                int Snum = 0, Bnum = 0;         // 입력 후 상태확인에 사용되어 지역변수로 선언
    
                for (int i = 0; i < comNum.size(); i++) {
                    if (comNum.get(i) == guess[i]) {
                        Snum++;
                    } else {
                        for (int j = 0; j < comNum.size(); j++) {
                            if (comNum.get(i) == guess[j]) {
                                Bnum++;
                            }
                        }
                    }
                }
    
                if (Snum < 3 && Bnum < 3) {
                    System.out.println(Bnum + "B" + Snum + "S" );
                    count++;
                }
                else if (Bnum == 3) {
                    System.out.println(Bnum + "B" );
                    count++;
                }
                else if (Snum == 3){
                    System.out.println(Snum + "S" );
                    System.out.println(count
                            + "번만에 맞히셨습니다."
                            + "\n"
                            + "게임을 종료합니다.");
                    break;
                }
            }
        }
    }

     

     

    ✅ 풀이

     

    입력값을 순서대로 int[]에 저장하고 for 반복문을 통해 값을 비교한다.

    S와 B는 반복문 내에서만 사용되어 지역변수로 설정,

    시도횟수는 1부터 기록되어야 하며, while 내부에 지역변수로 입력할 경우 계속 1로 설정되기 때문에  전역변수로 설정했다.

    3B일때는 "3B0S"가 아닌 "3B"만 출력되어야 하고

    3일때는 "3S"만 출력 + 정답안내 출력문 + 반복문 종료가 필요하기 때문에 if 조건문을 걸어서 코드를 작성했다.

     

     

    위의 코드로 실행한 결과는....

    💯

    728x90
Designed by Tistory.