![](https://blog.kakaocdn.net/dn/lYfik/btraVTxBYYX/sKwFairqyADKTpn9sJDcD0/img.jpg)
종이와 게임으로 했었던 게임인데 룰은 간단합니다. 먼저 두 사람이 0 ~ 9까지의 겹치지 않는 숫자 3개를 생각해 둡니다.
첫 번째 A 사람이 2 6 3을 생각해두었고, 두 번째 B 사람이 5 4 1을 생각했다고 가정했을 때, 각자 자기 차례가 되면 숫자 3개를 말합니다. A 사람이 1 2 3이라고 했을 때 B는 상대방이 말한 숫자와 자신이 생각한 숫자와 비교를 합니다.
그래서 자리도 같고 숫자도 같으면 '스트라이크', 숫자는 같지만 자리가 다르면 '볼'이 됩니다.
그러면 B는 5 4 1을 생각했었고, A는 1 2 3을 외쳤으니 1 볼이 되죠.
그렇게 해서 B차례가 되었고, A에게 마찬가지로 1 2 3을 외쳤을 때 2 6 3과 1 2 3을 비교해보면 2는 숫자가 있지만 자리가 다르고,
3은 자리와 숫자가 같기 때문에 1 볼 1 스트라이크가 됩니다.
그래서 A가 B에게 1 볼 1 스트라이크라고 말해 줍니다. 이렇게 서로 차례를 반복하여 나온 결과를 토대로 추리하여 상대방이 생각한 숫자를 맞히는 게임입니다.
이걸 컴퓨터가 생각한 숫자를 몇 번 만에 맞추는지의 형태를 가진 프로그램으로 만들어서 컴퓨터가 먼저 겹치지 않는 0~9 숫자 3개를 뽑은 다음에 사용자의 입력(숫자 3개)을 받아서 그걸 가지고 컴퓨터가 비교해서 결과를 출력하여 3 스트라이크가 될 때까지 입력받고 결과받는 만들어 봅니다.
순서도를 그려보자면 아래와 같습니다.
![](https://blog.kakaocdn.net/dn/b3TtKZ/btra6InLlF5/wnyDkwARoslyA6AGZ9FDB1/img.png)
우선 GoPath에 임의적인 폴더를 하나 만들어 놓고, 그 안에 NumberBaseball폴더를 생성하여 Go파일을 만들어 줍니다. NumberBaseball/main.go
package main
import (
"fmt"
)
func main() {
// 무작위 숫자 3개를 만든다.
numbers := MakeNumbers()
cnt := 0
for {
cnt++
// 사용자의 입력을 받는다.
inputNubers := InputNumbers()
// 결과를 비교한다.
result := CompareNumbers(numbers, inputNumbers)
PrintResult(result)
// 게임이 3S인가?
if IsGameEnd(result) {
// 게임 끝
break
}
}
fmt.Printf("%d번만에 맞췄습니다.\n", cnt)
}
먼저 이런 식으로 큰 그림만 그려 줍니다. 게임이 끝이 나지 않으면 for문으로 무한루프를 3 스트라이크가 나올 때까지 돌려서 결과를 알려주고, 게임 결과가 3 스트라이크이면 break로 무한루프를 빠져나오고, 3 스트라이크가 아니라면 다시 돌아와서 사용자에게 입력을 받는 식입니다.
for문이 빠져나온 경우는 게임이 끝이난 경우 이므로 몇 번 만에 이것을 맞추었는지 출력시켜 줍니다.
다시 정리하면 처음에 숫자 3개를 만들어주고 반복문을 돌고 매 반복문마다 cnt를 증가시키고 사용자에게 숫자 3개를 입력받고, 입력받은 값과 비교를 해서 결과를 출력시키고, 결과가 게임이 끝이면 break로 반복문을 빠져나오고, 그렇지 않으면 다시 입력을 받아 반복하여 게임이 끝이 나면 몇 번 만에 맞추었는지 출력시켜 줍니다.
먼저 이것을 빌드시키면 해당하는 함수들을 만들어주지 않고 선언만 했기 때문에 아래와 같이 에러가 뜨게 됩니다.
![](https://blog.kakaocdn.net/dn/rgAAe/btra8mree7W/PEQKCNLuOQhcErqQXmhfK1/img.png)
항상 빌드가 가능한 상태로 만들어 놓는 게 좋은데 지금은 큰 그림만 그렸기 때문에 동작하진 않더라도 빌드가 되는 상태만 만들어보죠!
하나하나 차례차례 함수들을 만들어보죠!
func main() {
// 무작위 숫자 3개를 만든다.
numbers := MakeNumbers()
cnt := 0
for {
cnt++
// 사용자의 입력을 받는다.
inputNumbers := InputNumbers()
// 결과를 비교한다.
result := CompareNumbers(numbers, inputNumbers)
PrintResult(result)
// 게임이 3S인가?
if IsGameEnd(result) {
// 게임 끝
break
}
}
fmt.Printf("%d번만에 맞췄습니다.\n", cnt)
}
func MakeNumbers() [3]int { // 1
// 0~9사이의 겹치지 않는 무작위 숫자 3개를 반환한다.
var rst [3]int
return rst
}
func InputNumbers() [3]int { // 2
// 키보드로부터 0~9사이의 겹치지 않는 숫자 3개를 입력받아 반환한다.
var rst [3]int
return rst
}
func CompareNumbers(numbers, intputNumbers [3]int ) bool { // 3
// 두 개의 숫자 3개를 비교해서 결과를 반환한다.
return true
}
func PrintResult(result bool) { // 4
fmt.Println(result)
}
func IsGameEnd(result bool) bool { // 5
// 비교 결과가 3 스트라이크인지 확인
return result
}
1 : 숫자 3개가 return 되는 MakeNumbers함수.
2 : 숫자 3개가 return 되는 InputNumbers함수.
3 : 컴퓨터가 뽑은 숫자와 사용자가 입력한 3개의 숫자를 받고, bool형을 반환하는 CompareNumbers함수.
4 : 결과 출력 함수. 나중에는 스트라이크, 볼이 몇 개 있는지에 대한 Struct로 바뀔 예정이지만 간단하게 빌드가 되게 하기 위해 bool로 했습니다.
5 : IsGameEnd함수 생성.
![](https://blog.kakaocdn.net/dn/b8WcmL/btraP9OiCy3/vKyOEjkEjrmxqcO2vNKlxK/img.png)
이제 정상적으로 빌드가 되는 것을 확인할 수 있습니다.
지금부터 할 일은 함수들 마다 주석 처리해서 설명한 대로 구현시켜주면 완성됩니다.
첫 번째 함수부터 만들어보죠!
무작위 숫자를 뽑아내는 방법을 찾아야 합니다. 여기가 그 방법을 어떻게 사용하는지에 대해 나옵니다.
rand.Intn()이라는 함수를 사용하여 값을 뽑아낸다고 쓰여 있는데 Intn()에 대한 자세한 설명은 여기에 있는데
Intn()을 호출하면 그 결과로 0~n사이의 랜덤 한 숫자가 반환된다는 것을 알 수 있습니다. 정확히 말하면 n-1까지의 값이 나오는 것입니다.
그래서 이것을 사용해보자!
import (
"fmt"
"math/rand"
)
func MakeNumbers() [3]int { // 1
// 0~9사이의 겹치지 않는 무작위 숫자 3개를 반환한다.
var rst [3]int
for i := 0; i < 3; i++ {
n := rand.Intn(10)
}
return rst
}
이렇게 해서 3개의 숫자를 뽑아주는데 문제는 겹치지 않아야 합니다.
겹치지 않으려면 자기 순서보다 앞에 있는 것을 비교해서 같으면 안 되고, 모두 다르다면 겹치지 않는 것이 됩니다.
그래서 다음과 같이 수정해 줍니다.
import (
"fmt"
"math/rand"
)
func MakeNumbers() [3]int { // 1
// 0~9사이의 겹치지 않는 무작위 숫자 3개를 반환한다.
var rst [3]int
for i := 0; i < 3; i++ { // 1
for { // 2
n := rand.Intn(10)
duplicated := false // 4
for j := 0; j < i; j++ { // 3
if rst[j] == n { // 5
// 겹쳐서 다시 뽑아준다.
duplicated = true
break
}
}
if !duplicated { // 6
rst[i] = n
break
}
}
}
fmt.Println(rst)
return rst
}
1 : 3개의 숫자를 뽑아야 하기 때문에 3번 반복해 줍니다.
2 : 아래 if문에서 숫자가 겹치지 않으면 if문 위에 있는 반복문을 빠져나가고, 겹치는 경우엔 다시 뽑게 하기 위해 for문을 추가했습니다.
3 : 자기 순서보다 앞에 있는 것을 비교해주기 위해 사용합니다.
4 : 겹치는지 안 겹치는지에 대한 Flag입니다.
5 : 겹치는지 여부 확인.
6 : 모두 다 돌고 나서 겹치지 않은 경우 반복문을 빠져나가서 결괏값에 뽑은 숫자들을 넣어 줍니다.
이제 결과가 제대로 나오는지 확인해보죠.
![](https://blog.kakaocdn.net/dn/UDHGs/btraVoY0Mh8/COkXuLFFoZ3A1buxCObO50/img.png)
여기서 문제가 하나 생기는데 계속 실행하면 그 문제를 알 수 있습니다.
![](https://blog.kakaocdn.net/dn/LOWeF/btraTcwZ52p/bfigOhlqfNdzD6DGpUzeQ0/img.png)
이렇게 같은 숫자가 나오면 무작위 숫자가 아니게 됩니다. 그 이유는 랜덤을 만드는 로직에 대해 알아야 하는데
랜덤을 만드는 방법은 컴퓨터가 정해진 작업만 하기 때문에 아예 아무도 모르는 숫자 3개를 만들 수 있다는 건 말이 안 됩니다.
그래서 어떻게 해볼 것이냐면 랜덤을 만들기 위해서 변하는 Seed라는 것을 만들어주면 변하는 Seed 값을 기반으로 숫자들을 뽑아내 줍니다. 그래서 이 Seed 값이 같으면 항상 같은 값이 나오게 되는 것인데 지금 Seed값을 지정한 게 없기 때문에 같은 숫자가 나오는 것입니다.
생각해보면 항상 변하는 가장 쉬운 값은 'Time'입니다.
여기를 보게 되면
![](https://blog.kakaocdn.net/dn/cczevj/btraP9OjiQn/cDhzqqLkk7EaaAL82qyxr0/img.png)
Seed값은 time의 now의 UnixNano()를 많이 사용한다고 되어 있습니다.
그래서 여기에도 사용하고 있는 것을 확인할 수 있습니다.
![](https://blog.kakaocdn.net/dn/wIwQC/btraSYlUXhz/fxA218sgt0luRw0w7zdtJ0/img.png)
이것을 프로그램 처음 시작할 때 Seed값을 지정해주고 시작해보죠.
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// 무작위 숫자 3개를 만든다.
rand.Seed(time.Now().UnixNano()) // 추가
numbers := MakeNumbers()
cnt := 0
for {
cnt++
// 사용자의 입력을 받는다.
inputNumbers := InputNumbers()
// 결과를 비교한다.
result := CompareNumbers(numbers, inputNumbers)
PrintResult(result)
// 게임이 3S인가?
if IsGameEnd(result) {
// 게임 끝
break
}
}
fmt.Printf("%d번만에 맞췄습니다.\n", cnt)
}
이제 다시 빌드해보죠.
![](https://blog.kakaocdn.net/dn/GqwFX/btraP9gvQf5/PkV7Qmk0lTVdRO2fKBJsA0/img.png)
같은 값이 나오지 않는 것을 확인할 수 있습니다.
'프로그래밍(Basic) > Golang' 카테고리의 다른 글
[바미] Go - Garbage Collector에 대해 알아보자! (0) | 2020.12.22 |
---|---|
[바미] Go - 숫자야구를 만들어보자!(2) (0) | 2020.12.22 |
[바미] Go - 포인터에 대해 알아보자! (0) | 2020.12.22 |
[바미] Go - 구조체에 대해 알아보자! (0) | 2020.12.21 |
[바미] TDD의 장단점에 대해 알아보자! (0) | 2020.12.21 |