none
[VB6][TIP] 1 부터 10 까지의 수를 '중복 없이' 랜덤하게 6개 뽑기 문제에 대한 TIP RRS feed

  • 질문

  • [VB6][TIP] 1 부터 10 까지의 수를 '중복 없이' 랜덤하게 6개 뽑기 문제에 대한 TIP
    • 편집됨 devlife 2012년 6월 29일 금요일 오전 10:56
    2012년 6월 29일 금요일 오전 10:56

답변

  • 우선, 다들 아시다시피 랜덤하게 수를 뽑는 방법은 아래와 같이 구현할 수 있답니다. :)

     

    Dim randomNum As Integer
    Randomize
    randomNum = Int(Rnd * 10) + 1

     

    그런데, 저 소스 코드가 어떤 원리로 동작하는지 모르시는 분들을 위해 Rnd() 함수를 설명하겠습니다. :)

    Rnd() 함수는 아래 조건을 만족하는 'X' 값을 무작위로 반환하는 함수입니다.
    0 ≤ X < 1

    사실 Rnd도 내부적으론 '난수 계열'이라는 표 비슷한 것을 사용합니다.
    이것을 랜덤하게 초기화 시켜주는 녀석이 Randomize() 함수입니다.
    이 함수는 아래와 같은 용법으로 사용할 수 있습니다. (과거 큐 베이직때는 다른 용법으로 사용했습니다.)

    Randomize
    따라서, Rnd () 함수로 1부터 10까지 뽑아오려면 아래와 같이 해야합니다.

    Rnd () =
    0.00001 … ~ 0.99999 …

    Rnd () * 10 =
    0.00001 … ~ 9.99999 …

    Int(Rnd () * 10) =
    0 ~ 9

    Int(Rnd () * 10) + 1 =
    1 ~ 10

    위와 같은 방법으로 구할 수 있습니다.
    (Int() 함수는 버그가 존재하므로, CInt/CLng나 Fix를 쓰는 것을 추천합니다.)

    그런데, 위와 같은 방법으로 구할 때, 겹치지 않고 6개를 뽑을 수 있을까요?
    위와 같은 방법으로 뽑으면 같은 수가 2번 이상 나오지 않는다는 보장도 없을테고….

    간단한 방법은, 배열 (Array)을 이용하는 방법이 있습니다.
    배열에 1부터 10까지 저장한 뒤, 하나씩 빼는 알고리즘을 이용하면 됩니다.

    아래는 그런 방법으로 구현한, 1~10 중 6개를 랜덤하게 중복없이 뽑는 방법을 보여주는 예제입니다.

     

    Sub Main()
        Dim arrCol As Integer, arrIndex As Integer, strChosen As String, lngCount As Long
        Dim arrNumbers() As Integer   ' 1 ~ 10을 저장하는 동적 배열
        ReDim arrNumbers(9)           ' 10개의 배열 첨자 동적 생성
        Randomize                     ' 난수 초기화
       
        For arrCol = 0 To 9           ' 배열의 값을 설정합니다.
            arrNumbers(arrCol) = arrCol + 1
        Next
        
        Do While lngCount < 6         ' 총 6회 반복
            arrIndex = Int(Rnd * (UBound(arrNumbers) + 1))
            ' 무작위로 랜덤한 하나의 첨자를 구함
           
            If strChosen = "" Then
                strChosen = CStr(arrNumbers(arrIndex))
            Else
                strChosen = strChosen & ", " & CStr(arrNumbers(arrIndex))
            End If
            ' 결과에 더함
           
            arrNumbers(arrIndex) = arrNumbers(UBound(arrNumbers))
            ' 현재 구한 배열의 첨자에 맨 끝 첨자의 값을 대입함.
            ReDim Preserve arrNumbers(UBound(arrNumbers) - 1)
            ' 맨 끝 첨자를 제거함.
            lngCount = lngCount + 1
            ' 카운트 변수 증가
        Loop
       
        Erase arrNumbers ' 배열을 메모리상에서 제거
        MsgBox strChosen ' 결과 출력
    End Sub

    • 답변으로 표시됨 devlife 2012년 6월 29일 금요일 오전 10:57
    2012년 6월 29일 금요일 오전 10:56

모든 응답

  • 우선, 다들 아시다시피 랜덤하게 수를 뽑는 방법은 아래와 같이 구현할 수 있답니다. :)

     

    Dim randomNum As Integer
    Randomize
    randomNum = Int(Rnd * 10) + 1

     

    그런데, 저 소스 코드가 어떤 원리로 동작하는지 모르시는 분들을 위해 Rnd() 함수를 설명하겠습니다. :)

    Rnd() 함수는 아래 조건을 만족하는 'X' 값을 무작위로 반환하는 함수입니다.
    0 ≤ X < 1

    사실 Rnd도 내부적으론 '난수 계열'이라는 표 비슷한 것을 사용합니다.
    이것을 랜덤하게 초기화 시켜주는 녀석이 Randomize() 함수입니다.
    이 함수는 아래와 같은 용법으로 사용할 수 있습니다. (과거 큐 베이직때는 다른 용법으로 사용했습니다.)

    Randomize
    따라서, Rnd () 함수로 1부터 10까지 뽑아오려면 아래와 같이 해야합니다.

    Rnd () =
    0.00001 … ~ 0.99999 …

    Rnd () * 10 =
    0.00001 … ~ 9.99999 …

    Int(Rnd () * 10) =
    0 ~ 9

    Int(Rnd () * 10) + 1 =
    1 ~ 10

    위와 같은 방법으로 구할 수 있습니다.
    (Int() 함수는 버그가 존재하므로, CInt/CLng나 Fix를 쓰는 것을 추천합니다.)

    그런데, 위와 같은 방법으로 구할 때, 겹치지 않고 6개를 뽑을 수 있을까요?
    위와 같은 방법으로 뽑으면 같은 수가 2번 이상 나오지 않는다는 보장도 없을테고….

    간단한 방법은, 배열 (Array)을 이용하는 방법이 있습니다.
    배열에 1부터 10까지 저장한 뒤, 하나씩 빼는 알고리즘을 이용하면 됩니다.

    아래는 그런 방법으로 구현한, 1~10 중 6개를 랜덤하게 중복없이 뽑는 방법을 보여주는 예제입니다.

     

    Sub Main()
        Dim arrCol As Integer, arrIndex As Integer, strChosen As String, lngCount As Long
        Dim arrNumbers() As Integer   ' 1 ~ 10을 저장하는 동적 배열
        ReDim arrNumbers(9)           ' 10개의 배열 첨자 동적 생성
        Randomize                     ' 난수 초기화
       
        For arrCol = 0 To 9           ' 배열의 값을 설정합니다.
            arrNumbers(arrCol) = arrCol + 1
        Next
        
        Do While lngCount < 6         ' 총 6회 반복
            arrIndex = Int(Rnd * (UBound(arrNumbers) + 1))
            ' 무작위로 랜덤한 하나의 첨자를 구함
           
            If strChosen = "" Then
                strChosen = CStr(arrNumbers(arrIndex))
            Else
                strChosen = strChosen & ", " & CStr(arrNumbers(arrIndex))
            End If
            ' 결과에 더함
           
            arrNumbers(arrIndex) = arrNumbers(UBound(arrNumbers))
            ' 현재 구한 배열의 첨자에 맨 끝 첨자의 값을 대입함.
            ReDim Preserve arrNumbers(UBound(arrNumbers) - 1)
            ' 맨 끝 첨자를 제거함.
            lngCount = lngCount + 1
            ' 카운트 변수 증가
        Loop
       
        Erase arrNumbers ' 배열을 메모리상에서 제거
        MsgBox strChosen ' 결과 출력
    End Sub

    • 답변으로 표시됨 devlife 2012년 6월 29일 금요일 오전 10:57
    2012년 6월 29일 금요일 오전 10:56
  • goto문이나 재귀함수 쓰지 않고도 뽑아낼 수 있는 좋은 방법이네요!

    특히 현재 구한 배열의 첨자에 맨끝 첨자의 값을 대입하고 마지막 배열 첨자를 제거해버리는 게 멋진 한 수네요.

    • 편집됨 konahn 2016년 5월 31일 화요일 오전 3:43
    2016년 5월 31일 화요일 오전 3:19