社内のRust勉強会に参加した
以前の記事にも書いたように、社内の勉強会でRustの勉強会があり、私も参加いたしました。
内容は、講師がRustの基本的な文法などを解説し、その後参加者がそれぞれ好きなアプリケーションを作るというものでした。
Hit & Blow
私が作ったアプリはHit & Blowという古くからあるゲームでした。
細かいルールの違いは方々であるようですが、私が作ったHit & Blowは
-
- 4桁の数字を当てる
-
- 4桁の数字は1~9を使う
-
- 同じ数字は使わない
-
- 数字を推理し、その推理した数字にたいする評価を得る
-
- 評価は
場所も数字も合っている場合はhitにカウントされる
数字は合っているが場所が間違っている場合はblowにカウントされる
4桁の数字を当てるまで推理と評価を繰り返す
例えば4桁の数字が 4738 の場合
推理した数字が 1932 なら hit: 1 blow: 0
推理した数字が 8395 なら hit: 0 blow: 2
推理した数字が 4837 なら hit: 2 blow: 2
となります。
この推理に対する評価をもとに、4桁の数字を絞っていくのですがやってみると適度な難しさでなかなか面白いです。
何回か推理すると必ず正解にたどりつけるので難しすぎるということもありません。
Rustでの実装
このアプリの肝となるのは「ランダムな4桁の数字を生成」という部分と「推理した数字の評価」の部分になると思います。
ぶっちゃけ、自分の得意な言語ならこの程度の処理は5分程度でコーディングできると思うのですが、不慣れなRust言語だったため色々調べたりしながらでかなり時間がかかりました。
以下はその部分のコードです
extern crate rand;
use rand::seq::SliceRandom;
//判定結果構造体
pub struct JudgeResult {
pub hit: i32,
pub blow: i32
}
//4桁の数値を生成
pub fn create_numbers() -> Vec<i32> {
let mut v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9];
let mut rng = rand::thread_rng();
v.shuffle(&mut rng);
vec![v[0], v[1], v[2], v[3]]
}
//判定
pub fn judge(numbers: String, answer: Vec<i32>) -> JudgeResult {
let mut h = 0;
let mut b = 0;
let mut nums = numbers.chars();
for i in 0..4 {
//charをi32に変換(この方法以外わからなかった)
let n = nums.next().unwrap() as i32 - 48;
if n == answer[i] {
h += 1;
} else if answer.contains(&n) {
b += 1;
}
}
JudgeResult {
hit: h,
blow: b
}
}
Rustプログラマから見れば「なんじゃこれ!」みたいなコードかもしれませんが、初心者のため良いのか悪いのかさえあまり分かりません。
もしアドバイスなどありましたらコメントを頂ければ嬉しいです。
特に気になっているところは、4桁の数字(文字列)をcharに分解してそれを数値に変換しているところです。
方法がわからず
let n = nums.next().unwrap() as i32 – 48;
とやけっぱちな実装になっています。
ちなみに、実際のアプリはWeb APIの部分(RustでIronを使いました)とHTMLの画面(Riot.jsとMaterializeを使いました)も含んでいるのですが、長くて退屈なコードなので省略させていただきます。
以上、RustでHit & Blowを作ってみた話でした。