⚠ 이 강좌는 오토핫키 v1을 다룹니다
지금 보시는 강좌는 구버전 오토핫키(v1.1)를 다루고 있습니다. 따라서 본 강좌의 내용은 현재 최신 오토핫키 버전 (v2.0)과 호환되지 않습니다. 구버전의 정보가 필요한 것이 아니라면, 가능한 한 새로운 사이트에 작성한 v2 강좌(https://ahkv2.pnal.dev)를 봐주시길 바랍니다.
[프날 오토핫키] 배열 #7: 프로그래밍 문제
지금까지 배운 배열을 이용하여 아래 문제를 풀어봅시다. 난이도는 쉬운 것부터 어려운 것까지 골고루 준비해보았는데, 못 풀겠으면 최소 1시간은 해결 방법을 고민해보도록 합시다. 바로 정답을 보면 실력이 늘지 않습니다. 강좌를 다시 보면 정답이 전부 있으니, 이해하셨다면 큰 문제는 없을 것입니다.
정답은 압축 파일 하나에 묶어서 최하단에 업로드해두었습니다.
1. 단순 배열 시각화하기
일차원 단순 배열을 MsgBox로 시각화하는 함수를 만들어봅시다.
이 함수는 매개변수로 입력받은 배열을 공백 두 칸으로 각 요소를 쪼개서 보여줍니다.
[출력 예시]
ExampleArr의 요소: 1 3 5 7
[제약 요건]
- 함수의 이름은 ShowArr()로 할 것.
- 함수의 매개변수로 ①[배열]과 ②[배열의 이름]을 받을 것. (각 매개변수의 이름은 무관)
- 함수의 반환값은 없음. (return만 사용해도 좋고, 반환값이 없기 때문에 return을 생략해도 좋습니다.)
- 배열의 크기와 상관없이 모든 요소를 출력 가능하게 설계할 것.
- 함수 내에서 MsgBox를 이용하여 출력할 것. (MsgBox는 한 번만 나와야함)
- Array.Push() 혹은 Array.Pop() 메서드를 사용하지 말 것.
2. 단순 배열에 값 추가하기
A_Sec은 현재 초(00~59)가 담겨있는 내장 변수입니다. F1키를 누를 때마다 단순 일차원 배열의 요소에 현재 초를 추가해봅시다.
[제약 요건]
- ESC를 눌러 프로그램을 종료할 수 있도록 할 것
- 단순 일차원 배열의 이름은 SecArr로 할 것
- SecArr에 요소를 추가할 때마다 1번 문제에서 만든 ShowArr() 함수를 이용하여 현재 배열의 요소를 출력할 것
- 요소의 개수가 5개가 되면 자동으로 프로그램이 종료되게 할 것.
3. 단순 배열에 값 거꾸로 추가하기
2번 문제에서 만든 프로그램은 최근에 추가한 초가 맨 뒤에 추가됩니다. 이번엔 반대로, 최근에 추가한 초가 1번 인덱스로 삽입되도록 프로그램을 수정해봅시다.
[제약 요건] (2번 문제와 같음)
- ESC를 눌러 프로그램을 종료할 수 있도록 할 것
- 단순 일차원 배열의 이름은 SecArr로 할 것
- SecArr에 요소를 추가할 때마다 1번 문제에서 만든 ShowArr() 함수를 이용하여 현재 배열의 요소를 출력할 것
- 요소의 개수가 5개가 되면 자동으로 프로그램이 종료되게 할 것.
4. 이차원 배열 시각화하기
1번 문제에서 만든 ShowArr() 함수와 마찬가지로, 2차원 배열도 시각화 해봅시다.
이번 함수는 각 열 간 요소는 탭(`t), 행 간 요소는 개행 한 칸(`n)으로 띄어씁니다(출력 예시 사진 참고).
[출력 예시(이차원 배열의 요소가 1~12인 3x4 배열 경우의 예시)]
ExampleDim의 요소
1 2 3 4
5 6 7 8
9 10 11 12
[제약 요건]
- 함수의 이름은 ShowDim()로 할 것.
- 함수의 매개변수로 ①[배열]과 ②[배열의 세로 크기], ③[배열의 가로 크기], ④[배열의 이름]을 받을 것.
- 각 매개변수의 이름은 무관함.
- 함수의 반환값은 없음. (return만 사용하거나, return 자체를 생략)
- 함수 내에서 MsgBox를 이용하여 출력할 것. (MsgBox는 한 번만 나와야함)
- Array.Push() 혹은 Array.Pop() 메서드를 사용하지 말 것.
- 자신이 만든 테스트용 배열의 모습에 따라 정답과 출력 예시는 다를 수 있습니다. 배열의 모습이 정상적으로 시각화되었다면 성공입니다. (ShowDim() 함수를 만드는 것이 문제의 목적)
5. 달팽이 배열
반복문을 사용하여 아래와 같이 달팽이 배열을 만들어봅시다. 달팽이 배열이란, 왼쪽 위(1행 1열)부터 시작하여 시계 방향으로 돌아가며 1씩 증가하는 숫자가 담긴 배열을 의미합니다. 아래의 출력 예시를 참고하세요.
[출력 예시] - 위에서 만든 ShowDim() 사용
ExampleSnail의 요소
1 2 3 4
12 13 14 5
11 16 15 6
10 9 8 7
[제약 조건]
- 4x4 달팽이 배열, 8x8 달팽이 배열을 한 번씩(총 두 번) 출력할 것.
- 달팽이 배열을 만들어주는 함수 MakeSnail()을 만들 것.
- MakeSnail()의 매개변수로 ①배열 한 변의 크기(4x4일 경우 '4')를 받을 것.
- MakeSnail()의 반환값은 만들어진 이차원 배열(달팽이 배열)일 것.
- 만들어진 배열을 위에서 만든 ShowDim() 함수로 출력할 것.
- 주어진 매개변수에 맞는 크기의 달팽이 배열을 생성하는 MakeSnail() 함수를 만드는 것이 목적인 문제입니다.
달팽이 배열 문제는 수많은 컴퓨터 공학부 신입생들을 좌절에 빠뜨릴정도로 상당한 수준의 컴퓨팅 사고 능력이 필요합니다. 알고리즘이 한 번에 생각나는게 오히려 이상할정도로 처음 접하면 어려운 문제이므로, 하루정도 넉넉히 해결 방법을 생각해보시면 좋겠습니다. 여러 방법이 있으니 정답과 달라도 결과만 똑같으면 정답이라고 생각하세요. 배열 문제보다는 알고리즘 문제에 가깝습니다.
6. 독서실 관리 프로그램
독서실 관리 프로그램이라고 하기엔 애매하지만, 학생들의 이름을 입력하면 이름, 입실 시간, 퇴실 시간을 배열로 저장하는 프로그램을 만들어봅시다. 입실 시간은 현재 초(00~59)로 하며, 퇴실 시간은 30초 뒤입니다. (실제론 독서실을 30초만 이용할리가 없지만, 테스트를 위해 매 초마다 바뀌는 값을 사용하였습니다.)
[출력 예시]
아래 움직이는 사진 참고
[제약 요건]
- 정해진 GUI 모양을 따를 것. | 사진 참고 및 예제코드 지급
- 버튼을 누르면 Edit에 입력된 학생 이름을 ListBox로 이동시킨 후, 추후 ListBox에서 해당 이름을 누르면 두 개의 Edit에 각각 입실 시간과 퇴실 시간을 표시할 것 (퇴실 시간은 입실 시간의 30초 뒤) | 사진 참고
- 배열의 이름은 무관하나, 각 행마다 이름(name), 입실시간(enterTime), 퇴실시간(exitTime)을 저장함. 행 번호는 1, 2, 3, ... 처럼 1씩 증가함. 즉, 이름과 관계없이 1번 학생, 2번 학생등으로 취급할 것
위와 같은 GUI는 지급해드리니, 아래 GUI 스크립트에 살을 붙이는 방식으로 제작해보세요.
강좌 본편에 나온 것만으로도 풀 수 있지만, 딱 하나 강좌에 소개되지 않은 부분이 있습니다.
위와 같이 ListBox에 AltSubmit 옵션이 붙어있을 경우, ListBox의 v레이블 값은 선택한 리스트 항목의 '텍스트'가 아닌 '순번'을 가집니다. 즉, 위 출력 예시 사진에서 세 항목을 각각 선택했을 때 v레이블 값은 "홍길동", "김철수", "김영희"가 아니라 1, 2, 3을 가진다는 것이죠. 이를 참고해서 문제를 다 푸신 후, ListBox[1].enterTime 등과 같이 MsgBox로 출력해봄으로써 테스트를 원활히 하실 수 있습니다.
즉, 완성된 배열의 모습은 아래와 같습니다.
GUI는 그저 배열을 쉽게 표현하기 위한 도구일 뿐이죠. 위 배열과 같은 모습으로 학생 관리가 된다면 성공입니다.
7. 독서실 관리 프로그램 (고급)
문제 6번의 독서실 관리 프로그램을 업그레이드 해봅시다. 이번엔 학생 추가 버튼뿐만 아니라 제거 버튼또한 만들어서, 제거 버튼을 누르면 선택한 학생을 배열과 ListBox에서 지워버리는 프로그램입니다.
[출력 예시]
아래 움직이는 사진 참고
[제약 요건]
- 문제 6의 제약 요건을 따를 것. 단, 이 문제용 GUI는 따로 지급함.
- 추가로, 학생을 추가/제거할 때 현재 배열의 모습을 MsgBox로 출력할 것(출력 예시 참고).
- 배열의 모습을 MsgBox로 출력할 땐 각 열을 `t, 각 행을 `n으로 구분지을 것
- 배열의 모습을 출력하는 부분은 함수로 작성할 것(학생 정보 추가/제거 두 부분에 사용되므로, 함수로 만드는 것이 깔끔하기 때문).
Hint: 문제 6과 7에서 학생 정보를 담기 위한 배열은 세로축은 단순 배열의 형태(1, 2, 3, ...), 가로축은 연관 배열의 형태(name, enterTime, exitTime, ...)를 쓰고 있습니다. 단순 배열에서 인덱스를 지우는 메서드가 있었죠?
GUI는 위 스크립트를 사용하세요.
여기서 ListBox의 항목을 삭제하는 부분은 프날 본편 강좌에는 나와있지 않습니다. 따라서 이 코드만 알려드립니다.
SendMessage, 0x182, 지울 줄 번호(0부터 시작하는 인덱스),, ListBox1, 창 이름
지울 줄 번호는 0부터 시작하는 인덱스이기 때문에, 세번째 항목을 지우기 위해선 "2"라는 숫자가 들어가야합니다. 0, 1, 2로 세면 2가 세번째이기 때문이죠. 창 이름은 지급드린 GUI창에선 "문제 7"이기 때문에, 아래와 같은 코드를 사용하시면 되겠습니다.
SendMessage, 0x182, 지울 줄 번호(0부터 시작하는 인덱스),, ListBox1, 문제 7
예를 들어서, 두 번째 줄을 지우고자 하는 경우엔
SendMessage, 0x182, 1,, ListBox1, 문제 7
이겠네요. 여기서 힌트를 하나 더 드리면, 문제 6에서 AltSubmit에 대한 설명을 드린 적 있습니다. ListBox의 선택한 항목의 줄 번호가 ListBox의 v레이블 값으로 나타나는데, 여기서 지울 줄 번호는 1부터 시작하는 인덱스입니다. 따라서, 최종적으로 ListBox에서 선택한 줄을 삭제하는 구문은 위의 "지울 줄 번호"에 (v레이블 값 - 1) 이 되겠습니다.
세번째 줄이 선택되어있으면 v레이블엔 3이 들어가있고, SendMessage에선 0부터 시작하는 인덱스를 사용하기 때문에 0, 1, 2. 즉 2가 들어가야하기 때문입니다. v레이블 값에서 1을 빼서 넣어주어야겠죠.
정답 스크립트
정답은 압축 파일로 모든 문제의 스크립트를 모아두었습니다. 초반에 말씀 드린것에 대해 다시 한번 언급드리면, 정답을 쉽게 보시지 말고 최대한 문제 풀이를 고민하신 뒤에 도저힘 못 풀 것 같을 때 확인하시면 좋습니다.
해설은 별도로 제공하지 않으나, 최대한 이해하려 노력해보시고 만약 이해가 안된다면 지금 보시는 화면의 오른쪽 아래에 있는 질문하기 버튼(모바일은 나타나지 않음)을 이용하여 문제 번호와 함께 질문 남겨주세요.
개인적으로 '배열 뒤집기' 혹은 '배열 회전하기' 같은 유구한 역사를 가진 문제들을 내고 싶었습니다만, 달팽이 배열 문제 하나만으로 충분히 난이도를 잡은거 같아서 비슷한 스타일의 문제들은 배제했습니다.
배열 뒤집기는 (보통 대각선을 기준으로) 이차원 배열을 뒤집는 문제고요(행과 열이 바뀌겠죠?), 회전은 말 그대로 이차원 배열의 값을 시계 방향으로 회전시키는 문제인데, 기왕 달팽이 배열을 만드셨으니 만들어진 달팽이 배열 가지고 회전시키고 뒤집고 스스로 연습해보시면 될 것 같습니다.