Hunt And Kill 알고리즘 구현의 두번째 시간입니다.
이전 강의까지 우리는 미로 안의 랜덤한 셀을 하나 선택에 더이상 갈 곳이 없을 때까지 미로를 만들며 나아가는 로직을 구현했습니다.
아래의 코드가 이전까지 작성한 코드입니다.
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
MsgBox map_size+1 & " " & row+3 & " " & col+3
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
이번엔 Hunt And Kill이라는 이름처럼 미로가 아닌 곳 중에서 미로와 맞닿아 있는 곳을 찾아서(Hunt) 미로로 만들어 주면(Kill) 됩니다.
그럼 미로가 아닌 곳 중에서 왼쪽에서 오른쪽으로, 위쪽에서 아래쪽으로 미로와 맞닿아 있는 셀을 찾아봅시다.
우리가 미로와 맞닿아 있는지 알아보려면 확인해야 하는 것이 두가지 있습니다.
1. 상하좌우에 maze 배열의 값이 True인가
2. 상하좌우에 maze 배열의 값이 True인 곳이 미로의 테두리인가
두번째 조건을 확인하는 이유는 앞서 우리가 maze 배열에서 테두리에 해당하는 부분을 True로 설정하였기 때문입니다.
두번째 조건을 확인하지 않는다면 분명 maze(2,2)를 확인할 때 maze(1,2)가 테두리임에도 불구하고 미로와 맞닿아 있다고 판단할 것이므로 예방해주어야 합니다.
이를 코드로 구현해 봅시다.
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) '시간지연 코드
Sub MakeMaze()
''' 이전 강의의 코드 '''
For i=2 To map_size+1
For j=2 To map_size+1
If maze(i,j) = False Then
If maze(i+1,j) = True And Cells(3+i+1, 3+j).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
ElseIf maze(i-1,j) = True And Cells(3+i-1, 3+j).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
ElseIf maze(i,j+1) = True And Cells(3+i, 3+j+1).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
ElseIf maze(i,j-1) = True And Cells(3+i, 3+j-1).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
End If
End If
Next j
Next i
End Sub
i는 행을, j는 열을 뜻하는 변수로 이중 For문을 이용해서 왼쪽에서 오른쪽으로, 위쪽에서 아래쪽으로 훑어줍니다.
여기서 i와 j가 2부터 시작하는 이유는 굳이 미로의 테두리까지 확인할 필요가 없기 때문이고 이는 map_size+2가 아닌 map_size+1까지만 확인하는 이유이기도 합니다.
maze(i,j)의 값이 False라면 미로가 아닌 셀이고 여기서 If ElseIf 조건문을 통해 미로와 맞닿아 있는지 확인합니다. 조건은 위에서 설명한 것과 같습니다.
아래의 사진은 코드 실행 결과입니다.(맵의 크기는 10입니다.)
실행 결과에서 들어나는 문제점은 미로와 맞닿아있는 모든 셀이 노란색이 되어버리는 것입니다.
우리가 원하는 건 왼쪽에서 오른쪽으로, 위쪽에서 아래로의 순서로 확인했을 때 가장 먼저 찾는 셀만을 미로로 만드는 것입니다.
따라서 우리가 원하는 셀을 찾으면 이중 For문을 빠져나가는 코드를 추가해 줍시다.
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
Dim found As Boolean
''' 중략 '''
For i=2 To map_size+1
For j=2 To map_size+1
If maze(i,j) = False Then
If maze(i+1,j) = True And Cells(3+i+1, 3+j).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
found = True
ElseIf maze(i-1,j) = True And Cells(3+i-1, 3+j).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
found = True
ElseIf maze(i,j+1) = True And Cells(3+i, 3+j+1).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
found = True
ElseIf maze(i,j-1) = True And Cells(3+i, 3+j-1).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
found = True
End If
End If
If found Then
Exit For
End If
Next j
If found Then
Exit For
End If
Next i
End Sub
Boolean형의 found 변수를 활용해 셀을 찾는다면 Exit를 이용해서 For문을 빠져나오도록 했습니다.
이것으로 Hunt And Kill 알고리즘의 두번째인 미로와 맞닿아 있는 부분을 찾는 것을 구현해 보았습니다.
아래의 코드는 지금까지의 코드입니다.
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
Dim found 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
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
found = False
For i=2 To map_size+1
For j=2 To map_size+1
If maze(i,j) = False Then
If maze(i+1,j) = True And Cells(3+i+1, 3+j).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
found = True
ElseIf maze(i-1,j) = True And Cells(3+i-1, 3+j).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
found = True
ElseIf maze(i,j+1) = True And Cells(3+i, 3+j+1).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
found = True
ElseIf maze(i,j-1) = True And Cells(3+i, 3+j-1).Interior.ColorIndex <> 3 Then
Cells(3+i, 3+j).Interior.ColorIndex = 6
found = True
End If
End If
If found Then
Exit For
End If
Next j
If found Then
Exit For
End If
Next i
End Sub
고생하셨습니다~
'엑셀 vba 게임' 카테고리의 다른 글
엑셀 vba 미로만들기(9) - 직접 플레이하기 (1) | 2020.03.10 |
---|---|
엑셀 vba 미로만들기(8) - Hunt And Kill 알고리즘 구현3 (1) | 2020.03.09 |
엑셀 vba 미로만들기(6) - Hunt And Kill 알고리즘 구현1 (0) | 2020.03.05 |
엑셀 vba 미로만들기(5) - 미로 테두리 설정 (0) | 2020.02.29 |
엑셀 vba 미로만들기(4) - 배열 (0) | 2020.02.29 |
WRITTEN BY