Rust

[2 - 2] Rust 간단한 숫자 맞추기 게임

초코민트냠냠 2022. 10. 5. 12:17
반응형

지난글에 이어서 랜덤 정수를 만들어보겠습니다.

2022.09.30 - [Rust] - [2 - 1] Rust 간단한 숫자 맞추기 게임

 

[2 - 1] Rust 간단한 숫자 맞추기 게임

Rust의 구체적인 내용을 배우기 전에 몸풀기로 간단한 숫자 맞추기 게임을 만들어보고 시작하겠습니다. 이 게임은 콘솔로 숫자를 입력받고 입력받은 숫자가 맞춰야 될 숫자에 비해서 큰지 작은

supern0va.tistory.com

 

 

랜덤 정수 생성하기

 

Rust 크레이트(Crate)를 사용하여 외부 라이브러리 가져오기

 

Rust 크레이트(Crate)를 사용하여 외부 라이브러리 가져오기

러스트에서도 외부 라이브러리를 사용할 수 있습니다. 우선 러스트에서 pakage는 크레이트(Crate) 라고 부릅니다. 컴파일 해서 실행 가능한 것은 binary crate이고 아래서 살펴볼 rand와 같은 다른 프로

supern0va.tistory.com

지난 글에서 rand crate를 가져오는 방법에 대해서 알아보았는데요. 그 방법대로 진행해보겠습니다.

crate는 Rust에서 pakage를 부르는 말입니다.

 

 

Cargo.toml 파일을 열어 [dependencies] 아래에 다음 코드를 추가해줍니다.

 

[dependencies]

rand = "0.8.5"

 

그리고 cargo build를 실행하여 rand를 가져옵니다.

 

이제 rand를 사용해봅시다.

 

use rand::Rng;
use std::io;

fn main() {
    println!("==== 숫자 맞추기 게임! ====");

    let secret_number = rand::thread_rng().gen_range(1..=100);

    println!("숫자를 입력해주세요.");

    let mut guess = String::new();

    io::stdin()
        .read_line(&mut guess)
        .expect("입력받지 못했습니다.");

    println!("당신의 예측: {}정답: {}", guess, secret_number);
}

 

우선 첫번째 줄에 use rand::Rng를 추가했습니다. Rng는 랜덤 숫자를 만들어내기 위한 메서드를 모아놓은 trait입니다.

 

그리고 gen_range메서드는 범위 내의 숫자를 랜덤으로 뽑아서 돌려줍니다. 인자로 1..=100을 넣었는데 start..=end는 start부터 end까지의 범위를 나타냅니다. 따라서 1부터 100사이의 숫자 중에서 랜덤하게  뽑아 secret_number 변수에 값이 들어갑니다.

 

cargo run으로 실행해봅시다.

 

 

여기서 줄바꿈이 일어나는 이유는 read_line을 했을 때 개행문자도 같이 저장되었기 때문입니다.

 

 

숫자를 비교하기

 

다음 코드를 작성해봅시다.

 

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("==== 숫자 맞추기 게임! ====");

    let secret_number = rand::thread_rng().gen_range(1..=100);

    println!("숫자를 입력해주세요.");

    let mut guess = String::new();

    io::stdin()
        .read_line(&mut guess)
        .expect("입력받지 못했습니다.");

    println!("당신의 예측: {}정답: {}", guess, secret_number);

    match guess.cmp(&secret_number) {
        Ordering::Less => println!("업!"),
        Ordering::Greater => println!("다운!"),
        Ordering::Equal => println!("정답!"),
    }
}

 

현재 guess는 String이고 secret_number는 i32입니다. 그러므로 바로 비교를 할 수 없기 때문에 geuss를 i32로 변환해야 합니다.

 

변환하지 않고 비교하면 컴파일러가 에러를 냅니다.

 

 

 

 

코드를 다음과 같이 수정해줍니다.

 

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("==== 숫자 맞추기 게임! ====");

    let secret_number = rand::thread_rng().gen_range(1..=100);

    println!("숫자를 입력해주세요.");

    let mut guess = String::new();

    io::stdin()
        .read_line(&mut guess)
        .expect("입력받지 못했습니다.");

    let guess: u32 = guess.trim().parse().expect("숫자가 아닙니다.");

    println!("당신의 예측: {}\n정답: {}", guess, secret_number);

    match guess.cmp(&secret_number) {
        Ordering::Less => println!("업!"),
        Ordering::Greater => println!("다운!"),
        Ordering::Equal => println!("정답!"),
    }
}

 

추가된 코드를 살펴보죠.

 

let guess: u32 = guess.trim().parse().expect("숫자가 아닙니다.");

 

여기서 trim은 앞뒤 공백과 개행문자를 제거해줍니다. parse는 문자열을 숫자형으로 변환해줍니다. 만약 숫자가 입력되지 않을 경우를 위해 expect를 사용해 에러를 처리해줍니다.

 

guess에서 개행문자가 사라졌기 때문에 println!도 수정해줍니다.

 

guess.cmp(&secret_number)guesssecret_number를 비교해 Ordering::Less,  Ordering::Greater또는 Ordering::Equal 반환합니다. 그리고 match안에서는 매칭이 되면 => 연산자 뒤에 코드를 작성하여 해당 조건에 맞는 코드를 실행시킬 수 있습니다.

 

실행해봅시다.

 

 

잘 동작하네요. 이제 반복문을 사용해서 여러번 맞출 수 있게 만들어봅시다.

 

 

반복문

 

loop 키워드는 범위 안의 코드를 무한루프로 실행합니다.

 

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("==== 숫자 맞추기 게임! ====");

    let secret_number = rand::thread_rng().gen_range(1..=100);

    loop {
        println!("숫자를 입력해주세요.");

        // --snip--

        match guess.cmp(&secret_number) {
            Ordering::Less => println!("업!"),
            Ordering::Greater => println!("다운!"),
            Ordering::Equal => println!("정답!"),
        }
    }
}

 

실행시켜보면 

 

무한루프

 

위와 같이 무한루프로 동작합니다. 숫자가 아니라 문자를 입력하면 에러를 발생시키고 중단됩니다.

 

 

정답일 경우 종료하려면 Ordering::Equal 조건에 break를 추가합니다.

 

	match guess.cmp(&secret_number) {
            Ordering::Less => println!("업!"),
            Ordering::Greater => println!("다운!"),
            Ordering::Equal => {
            	println!("정답!");
                break;
            }
        }

 

 

그리고 잘못된 문자를 받았을 경우에 오류를 발생시키지 않고 다시 입력받도록 코드를 작성해줍니다.

 

	// --snip--

        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        println!("당신의 예측: {}\n정답: {}", guess, secret_number);

        // --snip--

 

 

횟수 제한 설정하기

 

마지막으로 7번 안에 맞추면 성공 아니면 실패하도록 만들어보겠습니다.

우선 현재 몇번째 예측인지 확인할 guess_number변수를 만듭니다. 

 

let mut guess_number = 0;

 

그리고 비교가 끝난 뒤에 guess_number에 1을 더해주고 이 값이 7인지 확인을 합니다.

 

	match guess.cmp(&secret_number) {
            Ordering::Less => println!("업!"),
            Ordering::Greater => println!("다운!"),
            Ordering::Equal => {
                println!("정답!");
                break;
            }
        }

        guess_number += 1;
        println!(" ({}번 남았습니다.)\n", 7 - guess_number);

        if guess_number == 7 {
            println!("실패!");
            println!("정답은 {}입니다!\n", secret_number);
            break;
        }

 

그리고 보기 좋게 약간의 수정을 해줍니다. 다음은 전체 코드입니다.

 

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("==== 숫자 맞추기 게임! ====");

    let secret_number = rand::thread_rng().gen_range(1..=100);
    let mut guess_number = 0;

    loop {
        println!("숫자를 입력해주세요!");

        let mut guess = String::new();

        io::stdin()
            .read_line(&mut guess)
            .expect("입력받지 못했습니다.");

        let guess: u32 = match guess.trim().parse() {
            Ok(num) => num,
            Err(_) => continue,
        };

        match guess.cmp(&secret_number) {
            Ordering::Less => print!("업!"),
            Ordering::Greater => print!("다운!"),
            Ordering::Equal => {
                print!("정답!");
                break;
            }
        }

        guess_number += 1;
        println!(" ({}번 남았습니다.)\n", 7 - guess_number);

        if guess_number == 7 {
            println!("실패!");
            println!("정답은 {}입니다!\n", secret_number);
            break;
        }
    }
}

 

실행시켜봅시다.

 

 

잘 동작하네요!

반응형