윈도우즈 프로그래밍 수업 과제로 제출한 숫자 야구 게임 코드 분석 및 리뷰. 문제 해결을 위한 논리 구조와 코딩 원칙을 기준으로 각 모듈의 역할을 분리하여 정리함.
문제 접근 방식 및 논리 구조 설계
코드를 작성할 때 핵심으로 삼은 것은 '사람이 손으로 직접 야구 게임을 계산하는 절차를 왜곡 없이 코드로 옮기는 것'이다. 무리하게 수학적으로 로직을 압축하거나 복잡한 추상화를 도입하는 것을 지양하고, 디버깅 시 계산 과정을 직관적으로 추적할 수 있도록 논리를 구성했다.
- 데이터 구조화: 컴퓨터 정답과 사용자 입력을 길이 3의 1차원 정수 배열로 정의하여, 인덱스(0~2)를 기준으로 위치와 값을 동시에 비교할 수 있는 기반을 마련한다.
- 제어 흐름의 표준화: 배열 순회 및 난수 생성 반복문은 반드시 초기값을 0으로 설정하고, 조건식은 <= 대신 < 3을 고수하여 경계값 오류(Off-by-one error)를 원천 차단한다.
- 단계적 모듈화: 코드의 흐름을 [전역/지역 변수 선언부] → [초기화 및 검증] → [핵심 연산부] → [결과 출력부]로 철저히 분리한다.
- 명시적 변수 사용: 한 줄 계산으로 끝내기보다 중간 변수(num, val, strike, ball)를 두어 상태 변화를 명시적으로 추적한다.
1. 변수 선언부 (상태 관리)
프로그램 전체에서 유지되어야 하는 상태 변수들은 클래스 최상단에 몰아서 선언한다. 변수 선언부를 기능과 섞지 않고 상단에 배치해야 전체적인 데이터 구조를 파악하기 용이하다.
' 게임 상태 변수
Dim answer(2) As Integer ' 컴퓨터가 선택한 정답 숫자 3개 (인덱스 0~2)
Dim tryCount As Integer ' 시도 횟수 카운터
2. 초기화 및 난수 생성
정답 배열을 세팅하는 로직이다. 루프 변수 i는 0부터 시작해 < 3 조건으로 통제한다.
Dim rnd As New Random()
Dim used As New List(Of Integer)
Dim i As Integer = 0
Do While i < 3
Dim num As Integer = rnd.Next(1, 10) ' 1 이상 10 미만 → 1~9
If Not used.Contains(num) Then
answer(i) = num
used.Add(num)
i += 1
End If
Loop
뽑아낸 난수를 곧바로 배열에 넣지 않고 num이라는 중간 변수에 담은 뒤 중복 여부를 확인한다. 문제가 생겼을 때 어떤 숫자가 중복으로 뽑혔는지 변수값을 찍어보며 확인하기 가장 좋은 직관적인 구조다.
3. 지역 변수 선언 및 데이터 유효성 검증
연산부에 진입하기 전, 사용자의 입력값이 연산 가능한 정상적인 데이터인지 필터링하는 단계다. 연산 중 쓰일 지역 변수들도 상단에 미리 선언해 둔다.
Dim input(2) As Integer
Dim txtBoxes() As TextBox = {txtNum1, txtNum2, txtNum3}
Dim parseOK As Boolean = True
For idx As Integer = 0 To 2
Dim val As Integer
If Not Integer.TryParse(txtBoxes(idx).Text.Trim(), val) OrElse val < 1 OrElse val > 9 Then
parseOK = False
Exit For
End If
input(idx) = val
Next
Integer.TryParse와 OrElse(단축 평가 연산자)를 조합하여 문자가 입력되거나 1~9 범위를 벗어난 값이 들어올 때의 예외를 차단한다. 검증을 완벽히 통과한 값만 val 변수를 거쳐 input 배열에 담긴다.
4. 핵심 연산부 (판정 알고리즘)
프로그램의 핵심 판정 논리다. 내장 함수로 코드를 줄이기보다는 문제 해결의 흐름이 눈에 보이도록 작성했다.
Dim strike As Integer = 0
Dim ball As Integer = 0
For i As Integer = 0 To 2
If input(i) = answer(i) Then
strike += 1
ElseIf answer.Contains(input(i)) Then
ball += 1
End If
Next
인덱스 0부터 2까지 순회하면서, 값과 위치가 모두 같으면 스트라이크, 위치는 다르지만 배열 안에 값이 존재하면 볼을 누적한다. 인간의 사고방식을 분기문(If ~ ElseIf)으로 완벽하게 나누어 구현했다.
5. 화면 출력부 (결과 반영)
연산이 끝난 후, 도출된 strike와 ball 데이터를 바탕으로 UI를 업데이트한다. 출력부는 철저히 연산 결과를 화면에 뿌려주는 역할만 담당하도록 분리했다.
tryCount += 1
Dim resultMsg As String = $"{tryCount}번째 시도 │ 입력: {input(0)} {input(1)} {input(2)}"
Dim judgeMsg As String
If strike = 3 Then
judgeMsg = "🎉 3 Strike → 정답!"
lblResult.ForeColor = Color.DarkGreen
ElseIf strike = 0 AndAlso ball = 0 Then
judgeMsg = "아웃(Out) - 숫자가 하나도 없습니다."
lblResult.ForeColor = Color.Crimson
Else
judgeMsg = $"{strike} Strike {ball} Ball"
lblResult.ForeColor = Color.DarkOrange
End If
lstHistory.Items.Add($"{resultMsg} → {judgeMsg}")
문자열 보간($"")을 사용해 메시지를 조합하고, 결과 상태에 따라 라벨 색상을 변경했다. AndAlso를 사용해 아웃 판정 조건도 명확하게 걸러냈다.