본 강의부터 본격적으로 미로만들기 알고리즘인 Hun And Kill을 구현해 봅시다.

 

이전 강의까지의 코드입니다.

Sub MakeMaze()
	worksheets("Sheet2").Select
	Dim map_size As Integer
	Dim maze() As Boolean '동적배열 선언
	
	map_size = worksheets("Sheet1").Cells(8,2).value
	ReDim maze(map_size+2, map_size+2) '배열 크기 선언
	
	'배열값 초기화
	For i=1 To map_size+2
		For j=1 To map_size+2
			If i = 1 Or j = 1 Or i = map_size+2 Or j = map_size+2 Then
				maze(i,j) = True
			Else
				maze(i,j) = False
			End If
		Next j
	Next i
	
	'셀을 정사각형으로 만들기
	Range("A1:XFD1048576").ColumnWidth = 1.00 
	Range("A1:XFD1048576").RowHeight = 10.00
    
	'조이스틱을 위한 셀 만들기
	Range(Cells(1,1), Cells(3,3)).ColumnWidth = 0.1 
	Range(Cells(1,1), Cells(3,3)).RowHeight = 1.0
    
	'필요없는 셀은 숨기기
	Rows(map_size+6 & ":" & Rows.Count).EntireRow.Hidden = True
	Range(Cells(4,map_size+6), Cells(map_size+5,Columns.Count)).EntireColumn.Hidden = True
	
	'미로 테두리 그리기
	Range(Cells(3+1, 3+1), Cells(3+map_size+2, 3+map_size+2)).Interior.ColorIndex = 3
	Range(Cells(3+2, 3+2), Cells(3+map_size+1, 3+map_size+1)).Interior.ColorIndex = 0
	
	Range(Cells(3+1, 3+1), Cells(3+map_size+2, 3+map_size+2)).Borders.Weight = xlThick
End Sub

 

Hunt And Kill이 알고리즘은 아래의 링크에 자세히 설명되어 있습니다.

2020/02/26 - [엑셀 vba 게임] - 엑셀 vba 미로만들기(1) - Hunt And Kill 알고리즘 설명

 

엑셀 vba 미로만들기(1) - Hunt And Kill 알고리즘 설명

본 강의에서는 엑셀 vba를 이용해 미로를 만들어 보겠습니다. 우선 미로를 만드는 알고리즘에는 여러가지가 있지만 저희가 쓸 알고리즘은 Hunt And Kill 알고리즘 입니다. 1. 미로가 아닌 칸을 랜덤으로 선택합니..

comgonghakdo.tistory.com

먼저 알고리즘의 첫번째인 임의의 칸을 설정해 봅시다

 

먼저 난수를 생성해 봅시다. 난수 생성 방법도 아래의 링크에서 자세한 설명을 찾아보실 수 있습니다.

2020/02/21 - [엑셀 vba 기초] - 엑셀 vba 랜덤한 수 생성하는 법

 

엑셀 vba 랜덤한 수 생성하는 법

본 강의에서는 랜덤한 수를 생성하는 법을 알아보겠습니다. 랜덤한 수를 생성할 때는 기본적으로 Rnd가 이용됩니다. Sub CreateRandomNumber() Dim randomNumber As Integer randomNumber = Rnd End Sub 하지만 위..

comgonghakdo.tistory.com

Sub MakeMaze()
	Randomize '난수 Seed값 초기화
	Dim row, col  As Integer
    
	''' 이전 강의의 코드(생략) '''
	
	row = Int(Rnd * map_size) + 2
	col = Int(Rnd * map_size) + 2
	maze(row,col) = True
	Cells(3+row, 3+col).Interior.ColorIndex = 6
End Sub

row와 col의 변수를 새로 생성하고 각 변수에 테두리를 제외한 셀에 해당하는 행과 열을 넣어야 합니다.

 

난수 생성의 범위 크기는 map_size이고 시작값은 테두리를 제외해야 하므로 1이 아닌 2를 사용해야 합니다.

 

만약 map_size가 5라면 2~6까지의 난수를, map_size가 10이라면 2~12까지의 난수를 생성해야 하기 때문입니다.

 

그 후에 랜덤으로 선택된 셀에서 부터 미로를 만들어 갈 것이므로 maze(row,col)의 값을 True로 설정해 줍니다.

 

또한 어떤 셀이 선택되었는지 알아보기 위해서 선택된 셀의 배경색을 노란색으로 바꿔줍니다

 

여기서 유의해야 할 점은 셀을 선택할 때에는 테두리 안의 미로를 선택해야 하므로 조이스틱크기인 3을 더한  Cells(3+row, 3+col)과 같이 표현해 줍니다.

row=9, col=5의 셀이 선택된 모습

이젠 노란색 셀을 움직여 봅시다.

 

Hunt And Kill의 첫번째 로직은 미로가 아닌 칸이 미로를 만들면서 나아갈 수 있을 때까지 나아가는 것입니다.

 

이를 코드로 구현해 봅시다.

 

Sub MakeMaze()
	Randomize '난수 Seed값 초기화
	Dim row, col  As Integer
    
	Dim move As Integer
    
	''' 이전 강의의 코드(생략) '''
	
	row = Int(Rnd * map_size) + 2
	col = Int(Rnd * map_size) + 2
	maze(row,col) = True
	Cells(3+row, 3+col).Interior.ColorIndex = 6
    
	Do Until maze(row-1, col) And maze(row+1, col) And maze(row, col-1) And maze(row, col+1)
		''' 코드 작성 중...'''
	Loop
End Sub

우선 움직일 방향을 정하는 move 변수를 생성해 줍니다.

 

그리고 Do Until Loop 반복문을 사용합니다.

 

maze(row-1, col)은 현재 선택된 미로의 위쪽 셀

maze(row+1,col)은 현재 선택된 미로의 아래쪽 셀

maze(row,col-1)은 현재 선택된 미로의 왼쪽 셀

maze(row,col+1)은 현재 선택된 미로의 오른쪽 셀

 

입니다.

 

그리고 maze()의 배열값이 True라면 그 칸은 이미 미로가 생성되었다는 뜻입니다.

 

따라서 Do Until Loop 반복문에 사용된 조건문은 현재 선택된 미로에서 더이상 나아갈 곳이 없다는 걸 의미합니다.

 

그럼 계속해서 코드를 작성해 봅시다.

 

코드가 길어지면 보기 어려우니 아래의 예제에서는 Do Until Loop 반복문의 안쪽 코드만 작성하겠습니다.

 

Do Until maze(row-1, col) And maze(row+1, col) And maze(row, col-1) And maze(row, col+1)
	move = Int(Rnd * 4) + 1
	Select Case move
		Case 1 '위쪽으로 이동할 때
			If maze(row-1, col) = False Then
				Cells(3+row - 1, 3+col).Borders(xlEdgeBottom).LineStyle = xlNone
				row = row - 1
			End If
		Case 2 '오른족으로 이동할 때
			If maze(row, col+1) = False Then
				Cells(3+row, 3+col + 1).Borders(xlEdgeLeft).LineStyle = xlNone
				col = col + 1
			End If
		Case 3 '왼쪽으로 이동할 때
			If maze(row, col-1) = False Then
				cells(3+row, 3+col - 1).Borders(xlEdgeRight).LineStyle = xlNone
				col = col - 1
			End If
		Case 4 '아래쪽으로 이동할 때
			If maze(row+1, col) = False Then
				Cells(3+row + 1, 3+col).Borders(xlEdgeTop).LineStyle = xlNone
				row = row + 1
			End If
	End Select
	maze(row,col) = True
	Cells(3+row, 3+col).interior.ColorIndex = 6
Loop

move 변수에 1부터 4까지 중 난수를 입력해 줍니다. 그 후에 Select Case 문으로 move의 각 값에 맞는 코드를 실행해 줍니다.

 

move = 1 일 때를 보면,

 

move = 1 은 위쪽으로 이동을 뜻하므로 If maze(row-1, col) = False 를 통해 위쪽 셀이 미로인지 확인합니다.

maze()의 값이 False라면 미로가 아니라는 뜻이므로 우선 Cells().Borders(xlEdgeBottom).LineStyle = xlNone을 이용해 위쪽 셀의 아래쪽 테두리를 지워줍니다.

 

그 후에 row 값에서 1을 빼고 Select Case 문을 빠져나옵니다.

 

Select Case 문 밖에 있는 남은 코드를 실행함으로써 이동한 셀도 미로로 선택이 되고 셀 배경색도 노란색으로 바뀌게 됩니다.

 

매크로 실행 사진

위의 사진과 같이 미로의 생성 과정을 딜레이를 통해 보고싶다면 시간 지연을 이용하시면 됩니다.

 

시간 지연에 대한 자세한 설명은 아래 링크에 있습니다.

2020/02/22 - [엑셀 vba 기초] - 엑셀 vba 시간 지연(딜레이) 넣는 법

 

엑셀 vba 시간 지연(딜레이) 넣는 법

Sleep(x) 시간 지연은 반복문 실행시 너무 빠르게 지나가 진행 과정을 볼 수 없거나, 엑셀을 통한 시각적 효과(게임 등)를 만들 때 사용합니다. 여러가지 방법이 있지만 필자는 가장 편한 Sleep(x) 함수를 사용합..

comgonghakdo.tistory.com

지금까지의 코드를 올리면서 이번 강의를 마치겠습니다.

 

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) '시간지연 코드

Sub MakeMaze()
	Randomize
	worksheets("Sheet2").Select
	Dim map_size As Integer
	Dim maze() As Boolean '동적배열 선언
	Dim row, col As Integer
	
	map_size = worksheets("Sheet1").Cells(8,2).value
	ReDim maze(map_size+2, map_size+2) '배열 크기 선언
	
	'배열값 초기화
	For i=1 To map_size+2
		For j=1 To map_size+2
			If i = 1 Or j = 1 Or i = map_size+2 Or j = map_size+2 Then
				maze(i,j) = True
			Else
				maze(i,j) = False
			End If
		Next j
	Next i
	
	'셀을 정사각형으로 만들기
	Range("A1:XFD1048576").ColumnWidth = 1.00 
	Range("A1:XFD1048576").RowHeight = 10.00
    
	'조이스틱을 위한 셀 만들기
	Range(Cells(1,1), Cells(3,3)).ColumnWidth = 0.1 
	Range(Cells(1,1), Cells(3,3)).RowHeight = 1.0
    
	'필요없는 셀은 숨기기
	Rows(map_size+6 & ":" & Rows.Count).EntireRow.Hidden = True
	Range(Cells(4,map_size+6), Cells(map_size+5,Columns.Count)).EntireColumn.Hidden = True
	
	'미로 테두리 그리기
	Range(Cells(3+1, 3+1), Cells(3+map_size+2, 3+map_size+2)).Interior.ColorIndex = 3
	Range(Cells(3+2, 3+2), Cells(3+map_size+1, 3+map_size+1)).Interior.ColorIndex = 0
	
	Range(Cells(3+1, 3+1), Cells(3+map_size+2, 3+map_size+2)).Borders.Weight = xlThick
	
	row = Int(Rnd * map_size) + 2
	col = Int(Rnd * map_size) + 2
	maze(row,col) = True
	Cells(3+row, 3+col).Interior.ColorIndex = 6
	
	Do Until maze(row-1, col) And maze(row+1, col) And maze(row, col-1) And maze(row, col+1)
		move = Int(Rnd * 4) + 1
		Select Case move
			Case 1 '위쪽으로 이동할 때
				If maze(row-1, col) = False Then
					Cells(3+row - 1, 3+col).Borders(xlEdgeBottom).LineStyle = xlNone
					row = row - 1
				End If
			Case 2 '오른족으로 이동할 때
				If maze(row, col+1) = False Then
					Cells(3+row, 3+col + 1).Borders(xlEdgeLeft).LineStyle = xlNone
					col = col + 1
				End If
			Case 3 '왼쪽으로 이동할 때
				If maze(row, col-1) = False Then
					cells(3+row, 3+col - 1).Borders(xlEdgeRight).LineStyle = xlNone
					col = col - 1
				End If
			Case 4 '아래쪽으로 이동할 때
				If maze(row+1, col) = False Then
					Cells(3+row + 1, 3+col).Borders(xlEdgeTop).LineStyle = xlNone
					row = row + 1
				End If
			End Select
		maze(row,col) = True
		Cells(3+row, 3+col).interior.ColorIndex = 6
		Sleep(50) '시간지연 코드
	Loop
End Sub

 


WRITTEN BY
컴공학도

,

본 강의에서는 엑셀 vba에서 셀을 오름차순 또는 내림차순으로 정렬하는 법을 다루겠습니다.

 

일단 기본적으로 Sort라는 함수를 사용합니다.

 

Sort의 인자로는 기본적으로 Key와 Order가 있습니다.

 

Key는 말 그대로 정렬의 기준을 정하는 것이고 값은 Cell 또는 Range 등이 들어갈 수 있습니다.

 

Order는 오름차순 또는 내림차순을 정할 수 있습니다. 오름차순은 "xlAscending", 내림차순은 "xlDescending" 입니다.

 

아래 예제를 통해 더 자세히 알아보겠습니다.

 

Sub Macro()
	Range("A1:A9").Sort Key1:=Cells(1,1), Order1:=xlAscending
End Sub

Key1값을 1행1열로 하였고 정렬은 오름차순인 xlAscending으로 설정하여 실행한 결과입니다.

 

Cells(1,1)이 아니라 Range("A1")으로 하여도 무방합니다.

 

여기서 Key의 변수 이름이 Key1로 뒤에 숫자가 붙는 이유는 Key값과 Order의 값은 3개까지 가능하며 Key1, Key2, Key3 로 사용할 수 있습니다. Order도 동일합니다.

 

아래 예제를 통해 여러개의 키의 값으로 정렬한걸 보여드리겠습니다.

 

Sub macro2()
	Range("A1:B20").Sort Key1:=Range("B1"), Order1:=xlAscending, Key2:=Range("A1"), Order2:=xlDescending
End Sub

우선 Range("A1:B20")으로 두개의 열을 포함시켜 줍니다. 이럴경우 한 개의 열을 기준으로 정렬하면 다른 열의 값들도 따라오게 됩니다.

 

첫번째 정렬기준은 알파벳 오름차순이고, 두번째 기준을 숫자의 내림차순입니다.

 

먼저 첫번째 기준대로 알파벳 오름차순이 된 후에, 같은 알파벳을 가진 범위안에서 숫자 내림차순이 됩니다.

 

이렇듯 여러개의 기준으로 정렬을 할 수 있습니다.

 

이것으로 Sort함수 사용법을 마치겠습니다.


WRITTEN BY
컴공학도

,

Sleep(x)

 

시간 지연은 반복문 실행시 너무 빠르게 지나가 진행 과정을 볼 수 없거나,

엑셀을 통한 시각적 효과(게임 등)를 만들 때 사용합니다.

 

여러가지 방법이 있지만 필자는 가장 편한 Sleep(x) 함수를 사용합니다. (x는 1000분의 1초)

 

Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Sub Macro()
      For i=5 To 0 Step -1
            Cells(1,1).value = i
            Sleep(1000)
      Next i
End Sub

위의 예제는 3초의 시간을 재는 매크로입니다.

 

첫번째 줄의 Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 은 Sleep함수를 쓰기위해 필요한 코드입니다.

 

Sleep()함수는 Cells()나 Range()같은 vba의 기본 내장함수가 아닙니다.

 

따라서 내가 Sleep함수를 쓰겠다~ 하고 선언을 해 주어야 쓸 수 있습니다. 

 

구체적으로는 살펴보면 "kernel32"라는 라이브러리(Lib)에서 Sleep이라는 함수를 Private형식(다른 모듈에서는 사용할 수 없는 선언방법)으로 선언한다는 것입니다. ByVal dwMilliseconds As Long은 Sleep함수를 쓰기 위해 넘겨주어야 하는 dwMilliseconds라는 이름의 인자입니다. 위의 코드에서는 1000이 됩니다.

 

일반적인 사무용도의 엑셀 매크로를 만들겠다고 하시는 분들은 Sleep함수가 그닥 필요가 없을 수 있습니다.

하지만 엑셀 매크로로 사무용도 이외의 알고리즘 구현 연습을 할 때에는 알고리즘의 작동 과정을 눈으로 볼 수 있고, 간단한 미니게임을 만들 때에는 게임화면에 시각적 효과를 줄 수 있습니다.

 

아래에는 필자가 만든 미로만들기 알고리즘에서 미로가 만들어지는 과정을 자세히 보기위해 Sleep함수를 사용한 예입니다.

Sleep함수를 쓰지 않았을 때

Sleep함수를 쓰지 않아 컴퓨터의 빠른 연산속도 때문에 미로가 만들어지는 과정을 볼 수가 없습니다.

Sleep함수를 썼을 때

하지만 Sleep함수를 쓴다면 미로가 만들어지는 과정을 볼 수 있어서 알고리즘에 오류가 있을 경우 찾기 쉽습니다.

 

이것으로 엑셀 vba시간지연(딜레이)넣는 법을 마치겠습니다.


WRITTEN BY
컴공학도

,

본 강의에서는 셀의 배경색에 대해 바꾸는 법을 알아보겠습니다.

 

엑셀에서는 기본적으로 위와 같은 방법으로 셀의 배경색을 바꿉니다.

 

하지만 vba 매크로를 활용해서도 바꿀 수 있습니다.

 

Sub Macro()
      Range("A1:E11").Interior.ColorIndex = 3
End Sub

 

Range.Interior.ColorIndex 의 값을 변경함으로써 셀의 배경색을 바꿀 수 있습니다. (3은 빨간색)

 

Sub Macro()
      Dim colorIndex As Integer
      colorIndex = 1
      For i=1 To 10
            For j=1 To 5
                  Cells(i,j).value = colorIndex
                  Cells(i,j).Interior.ColorIndex = colorIndex
                  colorIndex = colorIndex + 1
            Next j
      Next i
End Sub

*과정을 보기 위해 반복문에 시간지연을 넣었습니다.

위의 코드처럼 ColorIndex값마다 정해진 배경색이 있습니다.

 

ColorIndex 색상표

좀더 다채로운 색을 넣고 싶다면

Interior.ColorIndex가 아니라 Interior.Color = RGB(x,y,z) 를 통해 rgb값을 지정할 수 있습니다.

(ex. Cells(1,1).Interior.Color = RGB(50, 23, 34)


WRITTEN BY
컴공학도

,