Rustで作る数当てゲーム

# はじめに
今回は、Rustで数当てゲームを作成してみた。という記事になります。
ちなみに数当てゲームとは、1から100までの乱数整数を生成し、プレーヤーに予想値を入力させます。
その後、その予想が小さいか大きいかを出力します。予想が当たっていれば、勝ちです。

# 新規プロジェクトの作成
*  Cargoを使って新規プロジェクトを作成します。

```
❯ cargo new guessing-game --bin
     Created binary (application) `guessing-game` package
```

# 実装
## 入力部分
* 数当てゲームの最初の部分は、ユーザに入力を求めその入力を処理し、求めた形式になっていることを確認します。

```Rust
use std::io;

fn main() {
    println!("Guess the number!");
    println!("Please input your guess.");

    let mut guess = String::new();

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

    println!("You guessed: {}", guess);
}
```

## 解説
* ユーザ入力を受け付け、結果を出力するためには、**ioライブラリ**をスコープに導入する必要があります。 
* **ioライブラリ**は、標準ライブラリ(**std**)に存在します。

```Rust
use std::io;
```

* fn構文が関数を新しく宣言し、( ) は引数がないことを示します。

```Rust
fn main() {
```

* printlnは、文字列を画面に表示するマクロです。

```Rust
println!("Guess the number!");
println!("Please input your guess.");
```

* ユーザが入力する値を保持する場所は、下記のように宣言します。
* また、Rustでは、変数は標準で不変(immutable)です。
* そのため、 変数名の前に**mut**をつけて変数を可変にします。
* = の右側には、変数guessが束縛される値があります。
* この値は、**String::new関数**の呼び出し結果であり、この関数は、**String型のオブジェクト**を返します。
* **String型**は、標準ライブラリによって提供される文字列型で、**サイズ可変**、**UTF-8エンコードされたテキスト**になります。
* **::new**にある、**::**という記法は、newがString型の**関連関数**であることを表しています。
* **関連関数**とは、String型の特定のオブジェクトよりも型に対して実装された関数のことです。
* **new関数**は、新しく空の文字列を生成します。

=> なので、**let mut guess = String::new();**は、新たに空のStringオブジェクトに束縛されている可変変数を作っている。

```Rust
let mut guess = String::new();
```

* **stdin関数**は、 std:: io::Stdinオブジェクトを返し、この型はターミナルの標準入力へのハンドルを表す型になります。
* **.read_line(&mut guess)**は、標準入力ハンドルの**read_lineメソッド**を呼び出して、ユーザから入力を受け付けます。

=> **read_lineメソッド**は、ユーザが標準入力したものすべてを取り出し、文字列に格納することなので、格納する文字列を引数として取ります。

* この文字列引数は、**可変**である必要がある。 
* つまりこれにより、ユーザ入力を追記して、文字列の中身を変えられるようになります。

* **&**は、この引数が参照であることを表します。
* これのおかげで、データを複数回メモリにコピーせずに複数箇所で同じデータにアクセスできるようになります。

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

* **read_lineメソッド**は、渡された文字列にユーザが入力したものを入れ込むだけでなく、値を返却します。

=> 今回は**io::Result**です。

* **Result型**は、列挙型(enum)です。
* Result型では、列挙子は**Ok**か**Err**です。

* Ok列挙子は、処理が成功したことを表し、中に生成された値を保持します。
* Err列挙子は、処理が失敗したことを意味し、Errは、処理が失敗した過程や、理由などの情報を保有します。
* **io::Resultオブジェクト**には、呼び出し可能な**expectメソッド**があります。 
* この**io::Resultオブジェクト**が**Err**の場合、**expectメソッドは**引数として渡されたメッセージを表示します。

```Rust
.expect("Failed to read line");
```

* 値を出力するには、下記のような書き方をします。
* 下記は、入力を保存した文字列の中身を出力します。{ }は、プレースホルダーの役目を果たします。

```Rust
println!("You guessed: {}", guess);
```

## 入力部分についてテストしてみる

```
❯ cargo run
   Compiling guessing-game v0.1.0 (/Users/yoshitaka.koitabashi/Desktop/guessing-game)
    Finished dev [unoptimized + debuginfo] target(s) in 5.44s
     Running `target/debug/guessing-game`
Guess the number!
Please input your guess.
6
You guessed: 6
```

## 数字の生成

* ユーザが数当てに挑戦する数字の生成をする必要があります。
* 今回は、1から100までの乱数を使用します。
* ちなみに、Rustの標準ライブラリには、乱数機能はまだ含まれていません。

### クレートを使用して機能を追加
* クレートはRustコードのパッケージです。
* このプロジェクトもバイナリクレートであり、これは実行可能形式になります。

外部クレートを使用するには、下記のようにします。

**ファイル名: Cargo.toml**

```Rust
[dependencies]

rand = "0.3.14"
```

### ビルドしてみる

```
❯ cargo build
    Updating crates.io index
  Downloaded rand v0.3.23
  Downloaded rand v0.4.6
  Downloaded libc v0.2.88
  Downloaded 3 crates (601.9 KB) in 1.55s
   Compiling libc v0.2.88
   Compiling rand v0.4.6
   Compiling rand v0.3.23
   Compiling guessing-game v0.1.0 (/Users/yoshitaka.koitabashi/Desktop/guessing-game)
    Finished dev [unoptimized + debuginfo] target(s) in 29.23s
```

### 乱数の生成するコードを実装する

* **use rand::Rng**では、乱数生成器が実装するメソッドを定義しています。
* **rand::thread_rng関数**は、特定の乱数生成器を返します。
* **gen_rangeメソッド**は二つの数字を引数に取り、それらの間の乱数を生成してくれます。
* 範囲は下限値を含み、上限値を含みません。

```Rust
use std::io;
use rand::Rng;

fn main() {
    println!("Guess the number!");

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

    println!("The secret number is: {}", secret_number);

    println!("Please input your guess.");

    let mut guess = String::new();

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

    println!("You guessed: {}", guess);
}
```

### 予想と数字を比較
* ユーザの入力した値と乱数生成された数字の比較が行えるようになったので、そこを実装していこうと思います。

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

fn main() {
    println!("Guess the number!");

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

    println!("The secret number is: {}", secret_number);
    println!("Please input your guess.");

    let mut guess = String::new();

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

    let guess: u32 = guess.trim().parse()
        .expect("Please type a number!"); 

    println!("You guessed: {}", guess);

    match guess.cmp(&secret_number) {
        Ordering::Less => println!("Too small!"),
        Ordering::Greater => println!("Too big!"),
        Ordering::Equal => println!("You win!"),
    }
}
```

* **std::cmp::Ordering 型**を標準ライブラリからスコープに導入しています。
* Resultと同じくOrderingも**enum**です。
* ただ、Orderingの列挙子は、**Less**、**Greater**、**Equal**です。
* **match式**を使用して、guess変数とsecret_numberをcmpに渡して返ってきたOrderingの列挙子に基づき、動作します。
* 下記のmatch式では、ユーザが50を入力し、ランダム生成された数字は38だったとします。
* コードが50と38を比較すると、 cmpメソッドはOrdering::Greaterを返します。

```Rust
    match guess.cmp(&secret_number) {
        Ordering::Less => println!("Too small!"),
        Ordering::Greater => println!("Too big!"),
        Ordering::Equal => println!("You win!"),
    }
```

* 下記を見ると**guess**という変数を生成しています。
* しかし、guessはその前の行で一度変数宣言を行っています。実は、Rustでは新しい値でguessの値を覆い隠すことが許されています。
* この機能は、値を別の型に変換したいシチュエーションでよく使われます。
* **シャドーイング(shadowing)**のおかげで別々の変数を2つ作らされることなく、guessという変数名を再利用することができます。
* 次に、guessを**guess.trim().parse()**という式に束縛しています。
* Stringオブジェクトの**trimメソッド**は、両端の空白をすべて除去します。
* **u32型**は、数字しか含むことができませんが、ユーザは、read_lineの処理を終えるためにエンターを押します。**=> ユーザがエンターを押したら、改行文字が文字列に追加されます。** 
* trimメソッドは、\nを削除するので、ただの数値になります

```Rust
let guess: u32 = guess.trim().parse()
    .expect("Please type a number!");
```

### 細かい調整を行う(ループ,バリデーション,ゲーム終了方法)
* loopを利用し、ユーザが何回も予想できるようにする。
* loopキーワードは、無限ループを作り出します。
* break文を追加して、ユーザが勝った時にゲームを終了させます。
* ユーザが数値以外を入力した時にプログラムをクラッシュさせるのではなく、非数値を無視してユーザが数当てを続けられるようにします。


[完成したコード]

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

fn main() {
    println!("Guess the number!");

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

    println!("The secret number is: {}", secret_number);
    loop {
        println!("Please input your guess.");

        let mut guess = String::new();

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

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

        println!("You guessed: {}", guess);

        match guess.cmp(&secret_number) {
            Ordering::Less => println!("Too small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal => {
                println!("You win!");
                break;
            }
        }
    }
}
```

## 成果物を実行してみる

```
❯ cargo run
   Compiling guessing-game v0.1.0 (/Users/yoshitaka.koitabashi/Desktop/guessing-game)
    Finished dev [unoptimized + debuginfo] target(s) in 0.28s
     Running `target/debug/guessing-game`
Guess the number!
The secret number is: 45
Please input your guess.
2
You guessed: 2
Too small!
Please input your guess.
4
You guessed: 4
Too small!
Please input your guess.
45
You guessed: 45
You win!
```

# まとめ
* 今回は、Rustで数当てゲームを作成してみました。
* いい感じにできたのではと思います！

# 参考文献
* [THE BOOK ２章](https://doc.rust-lang.org/book/)