정말 오랜만에..... 올리는 사다리타기 만들기 2편입니다.


벌써 반년이 지났네요.. 허미.. ^^;


각설하고, 시작할게요~!



이 포스팅의 제목은 '엑셀 메크로를 사용해 사다리타기 만들기' 이지만..


사실 컴퓨터 언어를 코딩하는데 에 있어 필요한 로직 구상법에 대해 알아보는 포스팅에 가깝습니다.


예전에도 언급한 적이 있는 것 같지만, 엑셀 vba와 같은 정말 기초적인 언어도 여타 언어들과 별반 다르지 않습니다.


로직을 구상하고, 로직을 현실화 시키는 수단인 것은 엑셀 vba나 java나 매한가지입니다.



파일을 받고, 실행시킨 후 따라와주세요~!

지난 게시글에 있는 사다리타기 파일에서 조금 수정되었습니다.


----


1. 그림을 그려보자


먼저 1차원적인 접근부터 시작합니다.


사다리타기에 필요한 요소가 무엇이 있는지, 머리속으로 그림을 그려봅시다.


① 몇 명의 인원이 참여하는지 선택하는 버튼

② 시작 버튼

③ 사다리 위쪽, 참여자 이름이 들어가야 할 공간

④ 사다리 그 자체

⑤ 사다리 아래쪽, 사다리 선택 결과가 들어가야 할 공간




제가 그린 그림은 위와 같습니다.


정답은 없습니다.






2. 기능을 구상하자


사다리타기를 구현하는 데에 필요한 기능을 만들어야 합니다.


쉬운 것부터 차례대로 진행해보겠습니다.


① 1인용 ~7인용 버튼을 누르면 각각 버튼 내용에 맞게 사다리 세로 짝대기가 그려진다. (기존에 있던 내용은 사라진다)

② 시작 버튼을 누르면 랜덤하게 가로 짝대기 (사다리 손으로 잡고 올라가는 부분) 이 그려지며

③ 사다리에 색깔이 입혀지며 자동으로 내려간다.

④ 마지막 결과를 팝업창에 출력한다.


물론 정답은 없습니다.


사다리 만드는 버튼과 사다리 실행 버튼을 따로 만들어도 문제 없고, 결과를 팝업창에 출력하는 대신 아래쪽 칸에 출력시키는 방법도 있습니다.






3. 로직을 구성하자


구상한 기능에 필요한 로직을 구성해야 합니다.


이게 무엇이냐 함은..


컴퓨터도 사람과 비슷합니다.


생각함에 있어 순서가 필요합니다.


자, 사다리타기를 종이에다 대충 그려보고, 손가락으로 짚으며 사다리타기를 진행해보세요.


이때 머리 속에서 이루어지는 사고의 과정을 컴퓨터에게도 동일하게 알려줘야 합니다.


⑴ 사다리를 만들 때 

 

※먼저 세로줄을 인원 수에 맞게 만든다. 


 ① 첫 번째 세로 줄과 두 번째 세로 줄 사이 상단 어딘가에 첫 번째 가로줄을 그린다. 

 ② 우측 칸으로 이동해서 가로줄을 그린다.

 ③ ② 반복

 조건: 가로줄 두개가 연결되어있으면 안된다. (사진 아래쪽 가로줄은 잘못된 예시)

 ④ 우측 끝까지 이동한 경우 한칸 아래로 이동, 및 좌측 첫째 칸을 선택

 ⑤ ③④ 반복

 ⑤ 사다리 세로줄이 더 내려갈 곳이 없을 때 사다리 만들기를 중단한다. (단, 맨 아래칸은 가로줄 생성이 되면 안된다.)

 조건 : 사다리 가로줄은 랜덤으로 듬성듬성 생성해야 한다.

상단: 두 가로줄이 엇갈려있다 OK

하단: 두 가로줄이 연결되있다 NO


위의 로직을 잘 따라갔다면..

 



이렇게 사다리가 완성됩니다.






4. 코딩


이제 코딩이 시작됩니다.


3번에서 구상한 로직들을, 컴퓨터가 알아먹는 말으로 바꿔줘야 합니다.


아래 예시에서는 이해를 위해 변수 선언은 하지 않겠습니다.


※세로줄 만들기


Public Int_PQuantity As Integer '<- Int_PQunantity (플레이하는 인원 수) 변수를 Public으로 선언합니다. 다른 함수에서도 해당 변수를 사용할 수 있습니다.




Sub p_1()

Range("C14:O46").Interior.ColorIndex = xlNone

Range("C15:C46").Interior.Color = black

MsgBox "혼자서는 할 수 없습니다."

End Sub

Sub p_2()

Range("C14:O46").Interior.ColorIndex = xlNone

Range("C15:C46").Interior.Color = black

Range("E15:E46").Interior.Color = black

Int_PQuantity = 2

End Sub

Sub p_3()

Range("C14:O46").Interior.ColorIndex = xlNone

Range("C15:C46").Interior.Color = black

Range("E15:E46").Interior.Color = black

Range("G15:G46").Interior.Color = black

Int_PQuantity = 3

End Sub

Sub p_4()

Range("C14:O46").Interior.ColorIndex = xlNone

Range("C15:C46").Interior.Color = black

Range("E15:E46").Interior.Color = black

Range("G15:G46").Interior.Color = black

Range("I15:I46").Interior.Color = black

Int_PQuantity = 4

End Sub

Sub p_5()

Range("C14:O46").Interior.ColorIndex = xlNone

Range("C15:C46").Interior.Color = black

Range("E15:E46").Interior.Color = black

Range("G15:G46").Interior.Color = black

Range("I15:I46").Interior.Color = black

Range("K15:K46").Interior.Color = black

Int_PQuantity = 5

End Sub

Sub p_6()

Range("C14:O46").Interior.ColorIndex = xlNone

Range("C15:C46").Interior.Color = black

Range("E15:E46").Interior.Color = black

Range("G15:G46").Interior.Color = black

Range("I15:I46").Interior.Color = black

Range("K15:K46").Interior.Color = black

Range("M15:M46").Interior.Color = black

Int_PQuantity = 6

End Sub

Sub p_7()

Range("C14:O46").Interior.ColorIndex = xlNone

Range("C15:C46").Interior.Color = black

Range("E15:E46").Interior.Color = black

Range("G15:G46").Interior.Color = black

Range("I15:I46").Interior.Color = black

Range("K15:K46").Interior.Color = black

Range("M15:M46").Interior.Color = black

Range("O15:O46").Interior.Color = black

Int_PQuantity = 7

End Sub




p_1 ~ p_7 은 1인용~ 7인용 버튼에 해당되는 코드입니다.

Range("x:x").Interior.Color 를 이용해 쉽게 세로줄을 구현할 수 있습니다.

결과는 아래와 같습니다.




 ① 첫 번째 세로 줄과 두 번째 세로 줄 사이 상단 어딘가에 첫 번째 가로줄을 그린다. 

 ② 우측 칸으로 이동해서 가로줄을 그린다.

 ③ ② 반복

 조건: 가로줄 두개가 연결되어있으면 안된다. 

 ④ 우측 끝까지 이동한 경우 한칸 아래로 이동, 및 좌측 첫째 칸을 선택

 ⑤ ③④ 반복

 ⑤ 사다리 세로줄이 더 내려갈 곳이 없을 때 사다리 만들기를 중단한다. (단, 맨 아래칸은 가로줄 생성이 되면 안된다.)

 조건 : 사다리 가로줄은 랜덤으로 듬성듬성 생성해야 한다.



p = 16  

q = 4



Do


    '


    '사다리 가로 선 개수를 조절하기 위한 변수 lotto를 만듭니다. 

    lotto = Int(Rnd * 10) + 1

    

    


    If lotto < 6 Then         'ⓐ


    '여기서 lotto < 6 이 의미하는 것은, 50%의 확률로 가로선이 그어진다는 것입니다. (가로줄 듬성듬성 생성)

    '숫자값을 바꿔서 어떠한 변화가 나타나는지 확인해보세요.


        '바로 위 셀의 색깔이 검정색이 아니라면 (위 아래 가로줄이 겹쳐서 생기는 것을 방지)

        If Not Sheet1.Cells(p, q).Offset(-1, 0).Interior.Color = black Then        'ⓑ

            '좌측 두 번째 셀의 색깔이 검정색이 아니라면 (한 라인에 여러 개 선이 생기는 것을 방지)

            If Not Sheet1.Cells(p, q).Offset(0, -2).Interior.Color = black Then

                '우측 두 번째 셀의 색깔이 검정색이 아니라면 (한 라인에 여러 개 선이 생기는 것을 방지)

                If Not Sheet1.Cells(p, q).Offset(0, 2).Interior.Color = black Then

                    '바로 아래 셀의 색깔이 검정색이 아니라면 (위 아래 가로줄이 겹쳐서 생기는 것을 방지)

                    If Not Sheet1.Cells(p, q).Offset(1, 0).Interior.Color = black Then

                        '해당 셀의 색깔을 검정색으로 바꾼다 (가로선을 생성)

                        Sheet1.Cells(p, q).Interior.Color = black

                    End If

                End If

            End If

         End If

    

    

    End If

    q = q + 2  

    

    If q > Int_PQuantity * 2 Then  'ⓒ

    p = p + 1 'ⓓ

    q = 4 'ⓔ

    End If


 

Loop While p < 46 'ⓓ


lotto=Int(Rnd * 10) + 1 를 통해 lotto의 값을 랜덤하게 추출했습니다.

      아래 볼드체로 작성된 부분은 lotto 값이 6보다 작을 때에만 실행됩니다.

      lotto의 값은 1~10 사이의 숫자가 랜덤으로 지정됩니다.

      따라서, lotto<6은 50% 확률을 의미합니다.


가장 중요한 로직입니다.

3 가지 조건 (좌측에 이미 가로줄이 생성됨, 우측에 이미 가로줄이 생성됨, 바로 위에 이미 가로줄이 생성됨, 바로 아래에 이미 가로줄이 생성됨) 을 피해 가로줄을 생성하는 로직입니다. 일종의 필터와 같은 역할을 하죠.

위 로직을 거치지 않고 랜덤하게 가로줄을 만들었을 경우, 아래와 같이 엉망으로 만들어집니다.





보시다시피 가로줄이 상하좌우 가리지 않고 겹쳐있습니다.


필터를 거치게 되면 아래와 같이 생성됩니다.


아주 이상적인 모양으로 사다리타기가 생성된 모습입니다.


cells(p,q) 에서 p와 q는 각각 선택된 셀의 행값, 열값을 뜻합니다.


p를 1씩 증가시키고, 사다리의 우측 끝에 다다르면,

q를 2씩 증가시켜서 바로 아래 가장 좌측 셀으로 이동합니다.



위 과정이 반복됩니다.




초록색 테두리로 선택된 칸을 cells(p,q)라고 할 때, 위 그림과 같은 순서로 이동합니다.


(p,q) 로직 실행

(p,q+2) 로직 실행

...

맨 오른쪽에 닿으면

(p+1,q) 로직 실행

(p+1,q+2) 로직 실행

... 반복


즉,


①셀이 우측으로 한칸씩 이동하며 50% 확률로 검정색 가로줄을 그리는 로직을 실행시키며,

②로직을 통해 가로줄이 생성되면 안되는 부분에 가로줄이 생성되는 것을 막고,

③맨 오른쪽 칸에 다다르면, 바로 아래 행으로 이동해서 ①부터 다시 시작하는 것입니다.


 If q > Int_PQuantity * 2 Then 


해당 조건문은 셀이 우측 끝에 도달했는지를 확인하는 조건문입니다.


첫 번째 셀(검정색 좁은 셀부터 시작)의 열값을 1이라고 할 때,

가로줄이 들어가야 할 마지막 우측 셀은, 3명 기준으로 4, 4명 기준 6, 5명 기준 8이 됩니다.(인원 수*2 - 2)

따라서 열값 (인원 수*2 - 2)를 넘어갈 때에는 우측으로 더 이상 이동하지 않고, 하단 좌측 끝으로 이동하게 됩니다.


제가 만든 엑셀에서 q는 3부터 시작하기 때문에,

사실 정확한 수식은  If q - 2 > Int_PQuantity * 2 - 2 Then  입니다.

양쪽의 -2 는 생략되었습니다.



행값(p)에 1을 더해 하단의 셀을 선택합니다.


열값(q)를 4로 초기화 하여 좌측 셀부터 시작한다.





이상은 사다리타기 만들기의 첫 번째 과정인 사다리 만들기에 대한 해설이었습니다.


사실, 해설이란게 필요한지는 잘 모르겠습니다.


제 블로그를 정주행하셨다면, 내장되어있는 코드만 조금 연구해보시면 어떻게 사다리가 만들어지는지 충분히 이해하실 수 있으리라 생각합니다.


사용된 문법은 지극히 기초적입니다.


반복문, 조건문이 다입니다.


반복문과 조건문 만으로 정말 다양한 기능을 만들어낼 수 있습니다.


다음 편에서는 자동으로 사다리를 타고 내려오는 기능에 대한 설명을 담아보겠습니다.


Posted by Simon K
:

정말 오랜만에 올리는 포스팅이네요.

 

 시작하기 전에 먼저 코딩의 개념에 관해 짚고 넘어가겠습니다.

컴퓨터인간이 사는 나라가 있다고 가정해봅시다. 컴퓨터인간이 사용하는 언어는 컴퓨터 언어입니다. 컴퓨터 언어는 무엇일까요?

 바로 2진법 숫자입니다. 컴퓨터는 0101100101010.... 이런 방식으로 소통을 하죠.

하지만 사람은 이 숫자의 나열을 이해할 수 없습니다. 컴퓨터인간이 쓰는 언어를 해석하기 위해 여러 회사에서 번역기를 출시하게되죠.

 이 번역기의 종류는 다양합니다. 가장 널리 알려지고 보급된 번역기는 C 입니다.

하지만 사람들은 더욱 간단하고 강력한 번역기를 원하게 됩니다. 예를 들어 '뻐카충' 이라고 입력하면 컴퓨터는 알아서 '버스카드 충전'이라고 이해하는 것 처럼요.

 이게 실현된다면 언어의 효율성은 더 올라가게 되겠죠. 6글자 입력하던걸 3글자만 입력해도 되니까 말이죠.

따라서 회사마다 비슷하지만 다른 방식으로 자신들의 번역기가 이해할 수 있는 줄임말을 만들어내고 간단한 문법들을 만들기 시작합니다.

 SQL JAVA C++ 파이썬 등등이 탄생합니다.

 

 

 각각 번역기마다 특성이 다르고 사용처도 달랐죠. 사람들은 적절한 상황에 필요한 번역기를 사용하게 됩니다.

자연스럽게 낡은 번역기는 도태되고 최신형 번역기가 시장을 장악하게 됩니다. 미래에도 똑같은 일이 벌어질 것이구요.

 자, 그렇다면, 컴퓨터인간과 소통을 잘 하는 사람은 어떤 사람일까요?

① 컴퓨터 언어 번역기 안에 있는 자료를 모두 달달 외운 사람.

② 컴퓨터 언어 번역기의 종류와 구동 방식을 잘 이해하며, 각각의 사용 범위와 번역기의 구동 원리를 이해한 사람.


정답은 2번입니다.

 


 위 비유에서 알 수 있듯이, 프로그래밍 언어를 달달 외우고 있다고 해서 프로그램을 뚝딱 만들어내지 못합니다.

프로그래밍 언어를 '코딩' 이라는 행동을 통해 컴퓨터가 이해할 수 있게 연결할 수 있는 능력이 필요한 것입니다.

사람들은 '나 먹는다 사과' 라고 하면 다 알아들을 수 있지만, 컴퓨터는 '나는 사과를 먹는다' 라고 하지 않는 이상 정확히 이해를 하지 못합니다. (문법이 점점 간략해지고 있기는 합니다)

따라서 프로그래밍 언어가 작동하는 원리와 구조를 아는 것이 중요한 것입니다.

제 첫번째 게시글(http://simon-k.tistory.com/1)에 이미 적어놨지만, 자기 자신을 갓 태어난 아기라고 생각하고 공부를 시작해야 합니다.

 

 아기는 책을 읽을 줄 모릅니다. 단지 이것저것 만져보고 먹어보고 가끔씩 자빠져서 다치기도 하면서 세상을 배우죠.

 코딩 공부도 마찬가지입니다. 코딩은 '말하기'와 비슷합니다. 책만으로는 절대 배울 수 없습니다.

물론 기본적인 프로그래밍 언어 코드는 알고있어야 합니다. 하지만 확실한것은, 서점에서 책 한권을 사서 페이지 1부터 끝까지 볼 필요는 없다는 것입니다.

 프로그래밍 언어의 로직을 이해하려 노력하세요.

 

사다리타기.xlsm <-클릭해서 다운로드하세요.

 

 

 제가 업로드한 사다리타기 엑셀을 열어서 실행해보세요. 실행해보고 도대체 어떤 방식으로 사다리타기를 구현해냈는지 생각해보세요.

 그 구현 방법을 이해하는 것이 중요합니다.


 "아! 사다리타기를 만들 때 이렇게 이렇게 하면 사다리를 랜덤하게 만들어낼 수 있고, 저렇게 저렇게 하면 사다리를 타고 내려가는 모양을 구현해 낼 수 있겠구나!"


위와 같은 생각을 할 수 있도록 학습 방향을 잡아야 합니다.

로직에 대한 이해만 있다면 공부하지 않은 코드는 구글링을 통해 쉽게 알 수 있기 때문입니다.

 

다음 강의에서는 제가 올린 사다리타기 파일의 구체적인 작동 원리에 대해 알아보겠습니다.


Posted by Simon K
:

[엑셀 VBA #18] 엑셀 매크로로 서식 지정하기(테두리, 폰트, 글자크기 등)



이번 엑셀 매크로 강의에서는 엑셀 셀의 서식을 설정하는 방법에 대해 알아보겠습니다.


엑셀 매크로로 셀 테두리, 색깔, 폰트, 글자 크기 등 다양한 서식을 구성할 수 있습니다.


매크로 파일을 받고 따라와주세요.




셀 테두리 만들기

Cells(3, 3).Borders(xlEdgeLeft).LineStyle = xlContinuous    '셀의 왼쪽 테두리 설정

Cells(3, 3).Borders(xlEdgeRight).LineStyle = xlContinuous    '셀의 오른쪽 테두리 설정

Cells(3, 3).Borders(xlEdgeTop).LineStyle = xlContinuous    '셀의 위쪽 테두리 설정

Cells(3, 3).Borders(xlEdgeBottom).LineStyle = xlContinuous    '셀의 아래쪽 테두리 설정


위와 같이 테두리가 생성됩니다.

테두리의 모양을 바꾸고 싶다면 xlContinuous를 다른 값으로 바꿔주면 됩니다.


xlDashDotDot       


xlDash                 


xlSlantDashDot      


xlDouble              



테두리의 굵기를 바꾸고 싶다면 .weight 설정을 하면 됩니다.


Cells(3, 3).Borders(xlEdgeLeft).Weight = xlThin

Cells(3, 3).Borders(xlEdgeRight).Weight = xlThin

Cells(3, 3).Borders(xlEdgeTop).Weight = xlMedium

Cells(3, 3).Borders(xlEdgeBottom).Weight = xlThick






셀 색상 변경하기


Cells(4, 3).Interior.Color = vbRed




색상값은 vbRed, vbBlue등으로 설정할 수 있지만, 다양한 사용자 정의 색상은 RGB로 설정할 수 있습니다.


Cells(4, 3).Interior.Color = RGB(111, 222, 50)







문자 서식 지정하기


Cells(3, 4).Font.Size = 8        '폰트 크기(글자 크기) 설정 

Cells(4, 4).Font.Bold = True        '폰트 볼드체로 바꾸기 True/False

Cells(5, 4).Font.Name = "궁서체"    '폰트 바꾸기

Cells(6, 4).Font.Italic = True        '폰트 이탤릭체(기울임꼴) 바꾸기 True/False

Cells(7, 4).Font.Underline = True        '폰트에 밑줄 긋기 True/False








Posted by Simon K
:

[엑셀 VBA #17] 중복되지 않는 난수 랜덤 추출하기






본 강의에서는 겹치지 않는 난수를 추출하는 방법에 대해 알아보겠습니다.


난수를 추출하는 것은 Rnd 구문으로 쉽게 처리할 수 있지만 난수를 중복되지 않게 처리하려면 일련의 과정을 거쳐야 합니다.






RND 함수


Rnd 함수는 0부터 1 사이의 소수 난수를 생성합니다. (0.00000...1 ~ 0.99999...9)



INT 함수


Int 함수는 인수로 지정된 숫자의 정수부분만을 추출합니다.



원하는 만큼 정수 난수 생성하기


Rnd 함수와 Int 함수를 사용하면 원하는 만큼 정수 난수를 생성할 수 있습니다.


Int(Rnd * 정수 최대값) + 1


예를 들어, Int(Rnd * 50) 는 0에서 49까지의 정수를 반환합니다.


그 값에 1을 더하게 되면 1에서 50까지의 정수를 반환하게 됩니다.





예제 : 로또 번호 추출기 만들기


이번 예제는 7개의 서로 다른 번호(로또)를 추출하는 예제입니다.


Rnd, Int함수와 지난 강의에서 배웠던 배열 오름차순 정렬(버블정렬), 그리고 숫자가 중복되지 않게 하는 방법이 사용됩니다.




Sub example_12()


Dim lotto(1 To 7) As Integer

Dim i As Integer

Dim a As Integer

Dim ii As Integer

Dim n As Integer

Dim m As Integer

Dim sorttemp As Integer


i = 1                


For i = 1 To 7                    '로또 번호가 7개이기 때문에 7번 반복해서 난수 추출


restart:


Randomize                        '난수 재생성

   a = Int(Rnd * 50) + 1        '난수 a 생성(1~50)


lotto(i) = a                        'lotto배열의 각 항에 난수값 입력

            


            For ii = LBound(lotto) To (i - 1)        '첫 난수부터 지금 추출된 난수의 전값(i - 1)까지 반복

                Select Case lotto(ii)             '즉 lotto배열의 마지막 값(지금 추출한 난수)과 이전 난수를 반복 비교

                    Case lotto(i)

                  GoTo restart                    'lotto(ii) 이전 난수값과 lotto(i) 지금 추출한 난수값이 같으면 restart로 이동

                End Select

            Next ii                    '여기까지 중복값 배제하는 코드


Next i



'여기부터 난수 오름차순 정렬(버블정렬) 이해가 안가면 전강의 보세요.

'정렬이 필요가 없다면 아래 For~Next 부분은 전부 삭제해도 무방합니다.

For n = 1 To UBound(lotto) - 1            

    

    For m = 1 To UBound(lotto) - n

        If lotto(m) > lotto(m + 1) Then

            sorttemp = lotto(m + 1)

            lotto(m + 1) = lotto(m)

            lotto(m) = sorttemp

        End If

    

    Next m


Next n                                                '버블정렬 종료


Cells(3, 1).Resize(, UBound(lotto)) = lotto        '세로1 가로7의 배열을 셀에 입력



End Sub



위 코드를 실행하면,




위와 같이 각기 다른 난수를 오름차순으로 추출할 수 있습니다.






저의 강의는 순차적으로 난이도를 높혀가고 있습니다.


강의가 이해가 안된다면 처음 강의부터 차근차근 공부하면 쉽게 이해할 수 있습니다.














Posted by Simon K
:

이전 포스팅 바로가기

배열 관련 포스팅 바로가기


[엑셀 VBA #16] (배열#3)배열 내림차순/오름차순 정렬

(버블 정렬)




이번 포스팅에서는 배열 내의 값을 내림차순/오름차순으로 정렬하는 법에 대해 배워보겠습니다.




엑셀 VBA로 엑셀의 정렬 기능을 구현하는 방법은 여러가지가 있습니다.


그 중 가장 간단한 버블 정렬에 대해 알아보도록 하겠습니다.


예제를 받고 따라와주세요.





버블 정렬이란?


예를 들어 3 , 4 , 6 , 5  이라는 배열이 있다고 쳐봅시다.


버블 정렬을 위 배열에 사용하게 되면 아래와 같은 프로세스가 진행됩니다. (내림차순 정렬으로 설명하겠습니다.)


1. 배열의 첫 항은 두번째 항보다 작은가? 작다면 두 항 위치를 바꾸고, 그렇지 않다면 그냥 내버려 둔다.

배열 변경 : 4 , 3 , 6 , 5


2. 새로운 배열의 두번째 항은 세번째 항보다 작은가? 작다면 위치를 바꿔주고, 그렇지 않다면 내버려 둔다.

배열 변경 : 4 , 6 , 3 , 5


3. 새로운 배열의 세번째 항은 네번째 항보다 작은가? 작다면 위치를 바꾸고, 그렇지 않다면 움직이지 않는다.

배열 변경 : 4 , 6 , 5 , 3

4. 다시 배열의 첫번째 항은 두번째 항보다 작은가? 작다면..... 그렇지 않다면 .....    (생략하겠습니다.)

배열 변경 : 6 , 4 , 5 , 3


5. 배열의 두번째 항은 세번째 항보다 작은가? ........

배열 변경 : 6 , 5 , 4 , 3


6. 다시 배열의 첫번째 항은 두번째 항보다 작은가? ......

배열 변경 : 6 , 5 , 4 , 3 (변화 없음)


7. 내림차순 배열(6 , 5 , 4 , 3) 완성



버블 정렬은 앞 항과 바로 뒤 항의 비교의 반복입니다.


첫 항부터 시작해서, 마지막 항까지의 비교 및 위치 교체가 완료되면 가장 작은 수는 마지막으로 가게 됩니다.


그 다음엔 마지막 항(가장 작은 수)를 배재하고 나머지 숫자들끼리 비교 및 위치 교체를 진행합니다.


그러면 맨 뒤에 가장 작은 수, 뒤에서 두번째에 두번째로 작은 수가 위치하게 됩니다.


이런 프로세스를 항의 개수만큼 진행하면, 마지막에는 내림차순으로 정렬된 배열을 만들 수 있습니다.






이번 예제는 정렬이 안된 성적을 내림차순으로 정렬하는 예제입니다.





Sub example_11()


Dim score()                '점수 배열 선언

Dim sortemp as integer        '바뀌는 대상을 임시로 저장하는 변수   

Dim maxval As Long            '총 항 개수를 구하기 위한 변수

Dim n As Long                   

Dim m As Long


     maxval = Cells(2, 2).End(4).Row - 1        '점수 총 개수를 구함


   ReDim score(1 To maxval)                '점수의 개수에 맞춰서 배열 재선언

    

    score = Application.Transpose(Cells(2, 2).Resize(maxval, 1).Value)        '값을 score 배열에 집어넣음


'Application.Transpose는 열을 행으로(또는 반대로) 바꿔주는 함수. 1차배열은 우로 나열되기 때문에 위치를 바꿔준다


For n = 1 To UBound(score) - 1        '첫번 째 행부터 몇번 반복되야하는지 설정 총 100개라면 99번 반복

    

    

    For m = 1 To UBound(score) - n            '배열의 개수만큼 반복하는 반복문

        If score(m) < score(m + 1) Then        'm번째 항이 m + 1번째 항보다 작다면

            SortTemp = score(m + 1)            '임시저장변수에 m + 1 항의 값을 넣고

            score(m + 1) = score(m)            'm 항의 값을 m + 1 항에 넣는다

            score(m) = SortTemp                'm 항에는 임시저장변수에 저장되있던 m + 1항의 원래값을 넣는다

'(결국 m과 m + 1 항의 값이 바뀜)

        End If

    

    Next m

    

Next n


Cells(2, 3).Resize(maxval, 1) = Application.Transpose(score)            '옆 열에 정렬된 배열을 삽입.



End Sub



※주황색 글자로 쓰인 부분이 버블 정렬의 기본 구조입니다.







Posted by Simon K
:

[엑셀 VBA #15] 셀에 특정 값이 입력될때 실행되는 메크로




지금까지 제가 다뤘던 엑셀 VBA 메크로는 버튼을 눌렀을 때 실행되는 메크로였습니다.


이번 엑셀 VBA 강의에서는 엑셀의 셀에 값을 입력했을 때 실행되는 메크로에 대해 살펴보겠습니다.







어떤 상황에서 사용할 수 있을까?


▶셀에 입력할 수 있는 글자 수를 제한하고 싶을 때(금지어 설정할 때)

▶셀에 값이 입력될 때 폰트, 글자크기, 글자무게(볼드체 여부), 밑줄 등 서식을 바로 지정하고 싶을 때

▶셀에 값을 입력할 때, 함수 없이 연산을 진행하고 싶을 때

▶ ..........



이 외에도 정말 많은 상황에서 사용할 수 있습니다.





사용 방법


Private Sub worksheet_change(ByVal Target As Range)

If Not Intersect(범위, Target) Is Nothing Then

...

...

End If

End Sub


Target은?


Target은 변경되는 대상을 뜻합니다.


ByVal은?


ByVal은 ByRef와 대비됩니다.

코드를 작성할 때 기본값은 ByRef로 되어 있습니다.

ByVal은 상위 프로시져에서 프로시져를 실행 후 같은 값을 유지합니다.

ByRef는 프로시져 실행 도중에 값이 변할 수 있습니다.


따라서, Target 값이 중간에 변동되는 것을 방지하기 위해 ByVal으로 Target을 선언해 줍니다.


Intersect는?

Intersect는 인수의 교집합을 구합니다.

즉, Intersect("A1:B2", Target)의 경우,

변경되는 셀과 "A1:B2" 범위의 교집합이 있을 경우에 교집합 셀/범위를 지정합니다.





▶셀에 입력할 수 있는 글자 수 제한하기




위와 같은 엑셀에서, 생년월일이 입력되는 B2 셀에 입력되는 글자 수를 제한하려고 합니다.


※모듈에서 작성해야 합니다.


Private Sub worksheet_change(ByVal Target As Range)


If Not Intersect(Range("b2"), Target) Is Nothing Then  '변경되는 셀과 B2셀의 교집합. 즉, B2셀에서만 프로시저 발동


        Select Case Len(Target)        '변경되는 셀의 문자 길이값을 조건으로 설정

        

            Case 8, 0                '문자 길이값이 8 혹은 0일때 (8은 정확히 입력된 경우, 0은 아무것도 없을 경우)

            Exit Sub                 '프로시저 종료

            

            Case Else                '8과 0을 제외한 다른 값일 경우

            

            MsgBox "yyyymmdd 형식으로 정확히 입력하세요." 


            Target.Clear            '값 초기화

            

            End Select

            

        

    End If

End Sub


위 프로시저를 작성한 후 B2셀에 글자수가 8이 아닌 문자를 입력할 경우 오류메세지가 출력되며 값이 삭제됩니다.





▶셀에 값이 입력될 때 서식 지정하기




이름이 입력될 때, 글씨체 : 맑은 고딕; 폰트 크기 : 15pt; 폰트 무게 : Bold; 로 설정하고자 합니다.


Private Sub worksheet_change(ByVal Target As Range)


If Not Intersect(Range("b1"), Target) Is Nothing Then

    

    With Target

        .Font.Name = "맑은 고딕"

        .Font.Size = 15

        .Font.Bold = True

    End With

    

End If


End sub



B2셀에 값을 입력과 동시에 글씨체와 폰트 크기, 무게가 바뀐 것을 알 수 있습니다.





▶셀에 값이 입력될 때, 함수 없이 연산하기



위와 같은 시트에서 년도별로 액수를 입력할 경우 보험료 총액이 자동으로 계산되는 코드를 짜보겠습니다.


Private Sub worksheet_change(ByVal Target As Range)


If Not Intersect(Range("B4:B19"), Target) Is Nothing Then

    Sheet13.Cells(3, 2).Value = Application.WorksheetFunction.Sum(Range("B4:B19"))

    End If


    

End Sub








※ Worksheet_change 프로시저는 한 번만 작성할 수 있습니다.


따라서, 시트변경 함수를 여러개 지정하고 싶은 경우, 같은 Worksheet_change 프로시저에 작성해야 합니다.

글머리에 업로드된 예제 파일의 엑셀 VBA 콘솔창을 열어보면 위에 설명한 3가지 코드가 같은 프로시저에 들어가 있는 것을 알 수 있습니다.







Posted by Simon K
:


[엑셀 VBA #14] 문자 나누고 합치기 (split, join)





이번 포스팅에서는 문자를 나누는 split문과 문자를 합치는 join문에 대해 알아보겠습니다.


예제를 받고 따라와주세요.






SPLIT



split문은 일반적으로 텍스트 파일을 엑셀로 불러올 때 많이 쓰이는 문법입니다.


엑셀 VBA 실전예제 카테고리 중 "텍스트 파일 엑셀에 입력하기" 포스팅에서 다뤘었습니다.


예를 들어, 텍스트 문서의 내용이 아래와 같습니다.


김정기 윤주환 정문석 고정우 김진기 정윤환


이 경우 위 텍스트 내용을 엑셀에 붙혀넣으면, 아래와 같이 출력됩니다.



하지만 각 셀에 이름이 하나씩 들어가게 하려면, 이름 문자열을 분리해야 합니다.


이럴 때 사용하는 문법이 split 문입니다.


하지만 split 문을 사용할 때에는 한 가지 조건이 붙습니다.


문자가 나눠지는 부분이 일정한 구분자(공백(space bar), 콤마(,), 슬래시(/)) 등으로 나눠져 있어야 합니다.



Sub example_9()


Dim varName() As String        '배열 varName 선언, 형식 에러가 날 경우 As Variant로 변경

Dim i As Long


i = UBound(Split(Cells(3, 1), " ")) - LBound(Split(Cells(3, 1), " ")) + 1    '문자의 개수 확인



ReDim varName(1 To i)            '문자의 개수만큼 배열 크기 설정


varName = Split(Cells(3, 1), " ")            '공백을 기준으로 문자열 나눔 "vbTab" "," ";" 등 여러가지 사용 가능 



Selection.Resize(, i).Value = varName    '선택한 셀을 기준으로 문자 삽입


End Sub




아래와 같이 출력됩니다. (A4셀 선택 후 실행)






JOIN


JOIN문은 배열 형식으로 저장된 값을 하나로 뭉쳐서 출력해줍니다.


SPLIT과 반대되는 개념고, 엑셀의 concatenate 함수와 비슷합니다.






Sub example_9_2()


Dim varName() As String

Dim i As Long


i = UBound(Split(Cells(3, 1), " ")) - LBound(Split(Cells(3, 1), " ")) + 1



ReDim varName(1 To i)


varName = Split(Cells(3, 1), " ")





Cells(8, 1).Value = Join(varName, "/")



End Sub


위의 코드는 SPLIT 예제에서 출력되는 부분을 빼고, 주황색 부분만 더한 코드입니다.


JOIN문을 사용할때도 구분자의 설정이 필요합니다.


SPLIT과 반대로 값 사이사이에 구분자를 넣어서 출력해줍니다.


아래와 같이 출력됩니다.


마찬가지로 구분자를 바꾸면 다른 형식으로 값을 출력할 수 있습니다.








Posted by Simon K
:


[엑셀 VBA #13] (배열#2) 배열의 크기 확인 Ubound, Lbound






이번 시간에는 엑셀 VBA에서 배열의 크기를 구하기 위해 주로 사용되는 Ubound문과 Lbound문에 대해 알아보겠습니다.


예제를 받고 시작하겠습니다.





Ubound는 배열의 마지막 위치값을, Lbound는 배열의 첫 위치값을 반영합니다.


즉, 


dim varArray(1 to 20)


위와 같이 배열을 선언했을 때,


Ubound(varArray) 값은 20, Lbound(varArray) 값은 1을 반영한다는 것입니다.


"굳이 셀 필요가 있나, 1부터 시작하니까 배열의 크기는 당연히 20이겠지" 라고 생각할 수도 있습니다.


일반적으로 배열을 선언할 때, 시작을 1부터 하는것이 대부분이지만, 엑셀 VBA 기본값은 0부터 시작합니다.


그리고 굳이 1이 아니어도 모든 정수를 배열의 시작 위치값으로 설정할 수 있습니다.


dim varArray(-10 to 20)


위와 같이 배열을 선언했을 때,


Ubound(varArray) 값은 20, Lbound(varArray) 값은 -10이 됩니다.


실질적으로 배열의 크기는 20이 아닌 31이 되는거죠(-10부터 20까지 0을 포함한 모든 정수).


따라서 정확하게 배열의 크기를 구하려면 아래와 같이 코드를 짜야합니다.


UBound(varArray) - LBound(varArray) + 1


위 식의 값이 varArray 배열의 실제 크기가 되는 것이지요.






이제 예제를 살펴보겠습니다.



이번 예제는 첫 번째 행에 입력된 데이터를 배열에 넣고, 배열의 크기를 구하는 예제입니다.


Sub example_8()


Dim varArray()                    '배열 varArray 선언

Dim capacity As Long            '배열 크기 변수 capacity 설정

Dim Col As Long                    '첫 행의 마지막 값의 열 값 Col 변수 설정


Col = Cells(1, 1).End(2).Column            '첫 행의 마지막 값의 위치를 찾고 열 값을 설정


ReDim varArray(1 To Col)                        '배열 동적선언


varArray = Cells(1, 1).Resize(, Col).Value            '값을 배열에 저장

capacity = UBound(varArray) - LBound(varArray) + 1        '배열의 크기 구하기



MsgBox "배열의 크기는 " & capacity & "입니다."



End Sub










Posted by Simon K
:



[엑셀 VBA #12] (배열응용) 특정 셀 영역 그대로 복사/ 


동하기




이번 엑셀 VBA 강의에서는 특정 셀을 기준으로 원하는 영역을 그대로 복사 및 이동하는 법에 대해서 배워보겠습니다.


예제를 받고 따라와 주세요.









이번 예제에는 두 가지 내용이 들어가 있습니다.


먼저 2차원 배열으로 구성된 셀 영역을 복사/이동하는 엑셀 VBA 코드를 알아보겠습니다.



좌측 상단 모서리에 있는 셀을 기준으로 값이 있는 모든 영역을 파란색 셀을 기준으로 이동하는 코드입니다.


예제 상에는 4x3의 배열으로 정해져 있지만, 사용자가 임의로 배열의 크기를 조정해도 문제 없도록 동적배열을 선언합니다.


Option Explicit            '변수가 선언 없이 사용되는걸 방지


Sub example_7()


Dim varArray                'varArray 배열 선언

Const n = 1                '기준으로할 셀의 행값 n 설정

Const m = 1                '기준으로할 셀의 열값 m 설정


Dim i As Integer

Dim p As Integer


i = Cells(n, m).End(2).Column - m + 1        '배열의 가로 크기 구하기

p = Cells(n, m).End(4).Row - n + 1            '배열의 세로 크기 구하기


ReDim varArray(1 To p, 1 To i)                '위에서 구한 배열의 크기로 배열 재선언


varArray = Cells(n, m).Resize(p, i)                '배열의 크기대로 셀(n,m)을 기준으로 배열 저장

Cells(5, 5).Resize(p, i) = varArray                '셀(5,5)에 저장된 배열 불러오기



End Sub



※Resize문과 End속성이 이해가 되지 않으면 관련 내용이 이전 엑셀 강의에 수록되어 있으니 확인하시고 진행하기 바랍니다.


위 코드를 실행시키면 아래와 같이 출력됩니다.





배열의 크기를 바꾸면 어떻게 출력될까요?





변화한 배열의 크기에 맞춰서 배열이 재선언되고, 크기에 맞춰서 정상적으로 복사됩니다.






이제 방금 배운 배열 응용법으로 간단한 회원관리 시스템을 만들어 보겠습니다.





위와 같은 회원관리 시스템에서 회원이 탈퇴했을 경우, 회원의 이름을 선택하고 매크로를 실행하면 아래 과거회원 시트로 해당된 회원 정보를 이동시키는 엑셀 VBA 매크로입니다.


option explicit

Sub example_7_2()


Dim varArray()                    '배열 varArray 선언

Dim n As Long                    '회원 이름이 포함된 셀의 행 n 선언

Dim m As Long                     '회원 이름이 포함된 셀의 열 m 선언

Dim i As Long                        '행의 길이(이동해야 할 셀의 양) 변수 선언



n = Selection.Row                '선택한 셀의 행을 n에 입력

m = Selection.Column                '선택한 셀의 열을 m에 입력


    If m <> 1 Then                    'm의 값이 1이 아닐 경우, 즉 선택한 셀이 이름이 포함된 열이 아닐경우

    MsgBox "회원 이름을 선택해야 합니다."           

    Exit Sub                            '종료

    Else

    End If

    

i = Sheet9.Cells(n, m).End(2).Column                    '이동해야 할 셀의 양 설정


ReDim varArray(1 To i)                            '이동해야 할 셀의 양에 맞춰서 배열 크기 조절




varArray = Sheet9.Cells(n, m).Resize(, i).Value                    '배열에 복사해야 할 값 지정

Sheet10.Cells(Rows.Count, 1).End(3)(2).Resize(, i) = varArray          '데이터가 들어가야 하는 위치를 찾고 배열을 입력 


Selection.EntireRow.Delete                    '과거로 이동한 인원 자료 현재회원에서 제거


End Sub



※만약 Resize 부분과 End(3)(2) 부분이 이해가 되지 않는다면 제가 이전에 올린 Resize와 End속성의 강의를 찾아보세요!





눈치가 빠르신 분은 눈치채셨을 수도 있습니다.


사실 위의 두 예제는 배열 선언이 필요 없습니다!


회원관리시스템 예제의 보라색 부분을 배열을 사용하지 않고 아래와 같이 바꿔도 똑같은 결과가 출력됩니다.


Sheet10.Cells(Rows.Count, 1).End(3)(2).Resize(, i) = Sheet9.Cells(n, m).Resize(, i).Value


그렇다면 굳이 배열을 사용하는 이유는 뭘까요?


먼저, 출력되는 값은 같지만, 두 가지 코드는 분명히 다릅니다.


첫 번째 코드는 배열을 선언 후, 복사해야 할 값을 배열(메모리)에 저장한 후 뿌려주었습니다.

두 번째 코드는 단순히 같은 값을 다른 셀에 똑같이 넣었습니다.


배열을 선언해서 메모리에 저장하게 되면, 셀의 값은 이제 배열의 값으로 복제가 되고, 복사하려는 셀이 사라지거나 수정이 되어도 그 값은 그대로 남아있게 됩니다.


반면에, 두 번째 코드처럼 메모리에 값을 저장하는 과정을 건너뛰게 되면 복사하고자 하는 셀의 값이 사라지거나 수정되는 경우 출력에 오류가 생기게 됩니다.


간단하게 예를 들어보겠습니다.


회원관리 예제의 초록색으로 표시된 부분을 보라색 코드 사이에 넣어보겠습니다.


varArray = Sheet9.Cells(n, m).Resize(, i).Value                

Selection.EntireRow.Delete 

Sheet10.Cells(Rows.Count, 1).End(3)(2).Resize(, i) = varArray  


과거 학생 시트로 값이 입력되기 전에 복사하고자 하는 값들을 엑셀 시트에서 삭제했음에도 불구하고, 출력되는 결과는 이전과 동일합니다. 이미 메모리에 배열이 저장되었기 때문에, 엑셀 시트상의 값이 사라진다고 해도 메모리에 저장된 값에는 변동이 없기 때문입니다.


또한 메모리를 사용하는 작업이기 때문에 대량 작업의 경우 작업의 속도가 현저하게 빨라집니다.


따라서 배열을 선언하는 습관을 갖고 있는 것은 정말 중요합니다.









Posted by Simon K
:

[엑셀 VBA #11] (배열#1) 배열 이해하기. 배열의 차원과 

정적, 동적배열




이번 시간부터는 엑셀 VBA를 배울 때 가장 까다로운 개념 중 하나인 배열에 대해 알아보겠습니다.


한 포스팅에 담기에는 벅찰 것 같아서 나눠서 진행하도록 하겠습니다.




배열은 확실히 까다로운 개념이 맞습니다.


하지만 정말 중요한 개념이고 많이 쓰이기 때문에 꼭 이해해야 하는 개념이기도 합니다.


엑셀 VBA의 배열은 수학적 개념의 배열과 동일합니다.


변수 i에 한 가지의 수, 문자를 저장할 수 있다면, 배열 i에는 한꺼번에 여러 개의 수와 문자를 저장할 수 있습니다.


하지만 안타깝게도 배열이 이렇게 단순하지만은 않습니다...


엑셀 VBA는 배열을 1차원부터 60차원까지 허용하고 있습니다.


이는 무엇을 의미하고 있는 것일까요?





N차 배열의 의미


1. 1차 배열


1차 배열은 직선형의 단순한 배열을 의미합니다.



배열 속에 있는 각각 개체들이 앞, 뒤 순서로만 배치되어 있습니다.


엑셀의 한 에 위치한 값들의 배열이라고 생각할 수 있습니다.





2. 2차 배열


2차 배열은 직사각형(정사각형) 의 배열을 의미합니다.



배열 속의 개체들이 상하좌우로 나뉘어서 배치되어 있습니다.


엑셀의 한 시트 안에 있는 값들의 배열이라고 생각할 수 있습니다. 배열이 (i, p)와 같은 좌표로 구성이 됩니다.




3. 3차 배열


3차 배열은 직육면체(정육면체) 의 배열을 의미합니다.




배열 속의 개체들이 상하좌우 및 위 아래로 배치되어 있습니다.


여러 시트(sheet1, sheet2, sheet3.....)로 구성된 엑셀 파일에 있는 값들의 배열이라고 생각할 수 있습니다. 배열이 (i, p, o)와 같은 좌표로 구성됩니다.





4. 4차 이상 배열


사실 4차 이상 배열은 잘 사용되지 않습니다. 엑셀의 범위를 넘어가기 때문이지요..


4차 배열의 경우 여러 엑셀 파일을 담고있는 폴더, 5차 배열의 경우 여러 폴더를 담고있는 하드드라이브, 6차 배열의 경우 여러 하드드라이브를 담고있는 컴퓨터, 7차 배열의 경우 여러 컴퓨터들을 담고있는 PC방에 비유할 수 있겠네요.


계속 차원을 넓혀가면 우주까지 다다를 수 있습니다. 


억지스런 비유이긴 하지만, 엑셀 VBA에 이런 고차원적인 요소는 필요 없기에,일반적으로 3차 배열까지만 사용되고 있습니다.


물론 4, 5, 6차 배열도 분명 사용할 수 있고 사용되고 있습니다. 하지만 일반적인 엑셀에는 그 만큼 넓은 배열이 필요하지 않습니다. 







자, 이해가 되시나요? 아직 좀 아리송할겁니다.


더 간단하게 비유해보겠습니다.


배열을 엑셀에 비유했을 때, 엑셀이라는 것이 점점 진화를 한다고 생각해 보겠습니다.


엑셀의 가장 작은 기본 단위는 "셀"입니다.


그렇다면 태초의 엑셀은 아래와 같다고 가정할 수 있습니다.


이 때의 엑셀에는 배열의 개념이 필요 없습니다.


셀이 하나밖에 없기 때문이죠.


하지만 엑셀이 한단계 진화한다면 말은 달라집니다.



엑셀이 한 단계 진화해서 한 개의 행을 이루었습니다.


이 때부터 배열의 개념이 필요하게 됩니다.


배열(0), 배열(1), 배열(2), ... , 배열(n)으로 구성된 1차 배열이 등장하게 됩니다.




엑셀이 한 단계 더 진화해서 시트를 구성했습니다.


배열(0, 0) 배열(0, 1) 배열(0, 2)..... 배열(n, m)으로 구성된 2차 배열이 등장하게 됩니다.




엑셀이 한 단계 더 발전해서 엑셀 파일을 구성했습니다.


배열(0, 0, sheet1) 배열(0, 0, sheet2) ..... 배열(n, m, sheetx)로 구성된 3차 배열이 등장하게 됩니다.






정적배열과 동적배열


정적배열과 동적배열의 개념은 간단합니다.


정적배열은 이미 배열의 용량을 정해준 배열이고, 동적배열은 배열의 용량을 정해주지 않은 배열입니다.


동적배열은 배열이 차지하는 크기가 확실하지 않을 때 사용합니다.


굳이 동적배열을 선언하지 않고 정적배열로 배열을 최대한 크게 만들어도 이론상으로는 상관 없습니다.


하지만 배열은 상당히 많은 메모리를 차지합니다.


배열을 불필요하게 크게 선언한다면 메모리 부족 현상이 나타나기 쉽습니다.


따라서 배열을 동적으로 선언하여 불필요한 메모리 차지를 방지해야 합니다.




정적배열의 선언


1차 정적배열


Dim varArray(1 to 10)


2차 정적배열


Dim varArray(1 to 10, 1 to 20)    '행은 10, 열은 20인 직사각형 배열


동적배열의 선언



1차 동적배열


Dim varArray()

...

...                '배열에 필요한 크기 n을 구함

Redim varArray(n)            'varArray() 배열을 크기 n의 정적배열으로 다시 선언



2차 동적배열


Dim varArray()

...

...                '배열에 필요한 행 크기 n, 열 크기 m을 구함

Redim varArray(1 to n, 1 to m)                'varArray() 배열을 행 크기 n, 열 크기 m의 정적배열으로 다시 선언






이번 포스팅에선 배열의 기본 개념과 배열의 차원, 그리고 정적, 동적 배열에 대해 알아봤습니다.


다음 포스팅은 배열에 대한 좀 더 심화된 내용으로 찾아오겠습니다.



Posted by Simon K
: