#2 Rustでしりとり
はじめに
前回に続き、初心者向けにプログラムを書いたので記事にしてみました。
今回「しりとり」を作ってみました。
プログラムの全体は最後に載せるのですがGitHubにもあります。
本編
変数宣言
まず最初に入力した単語を記録する変数と、現在のプレイヤーを記録する変数を宣言します。
// 入力した単語を保存する配列
let mut content: Vec<String> = vec![];
// プレイヤー
let mut player = true;
player1ならtrue
、player2ならfalse
表します
println!("プレイヤー: {}", if player { 1 } else { 2 });
最初の単語
// 最初の単語
let first_section = "しりとり".to_string();
// 最後の一文字
let mut previous_last = last(&first_section);
first_section
変数には最初の単語が入っています。
previous_last
変数にはfirst_section
の最後の一文字が入っています。
last関数に文字列を渡すと、最後の一文字が戻り値として返されます。
last関数
fn last(section: &str) -> char {
let chars: Vec<char> = section.chars().collect();
chars[chars.len() - 1]
}
section
をchars
メソッドを使い一文字区切りにします
let section = "こんにちは";
let chars: Vec<char> = section.chars();
println!("{:?}", chars);
// 出力結果
// ['こ', 'ん', 'に', 'ち', 'は']
そしてその配列の最後の要素を取り出すことで最後の一文字を取り出せます
他のやり方
他にもこんなやり方があります
let section = "こんにちは";
let last = section.chars().last().unwrap();
println!("{}", last);
この方法はchars
メソッドを使った後に一度配列にするのではなく、chars
メソッドの戻り値はIterator
トレイトを実装している型なのでlast
メソッドを呼び出しています。
last
メソッドの説明はこちら
最初の単語の表示と保存
println!("{}", first_section);
content.push(first_section);
この行では最初の単語を表示し、content
変数に最初の単語を保存しています。
push
メソッドは配列の最後に要素を追加します。
単語の入力
fn input() -> String {
let mut line = String::new();
std::io::stdin().read_line(&mut line).unwrap();
line.trim().to_string()
}
この関数を呼び出すとターミナルで入力した文字列を取得することができます。
難しいので説明はしまっておきます。
説明
let mut line = String::new();
入力した文字列を入れるための配列を作成します。
std::io::stdin().read_line(&mut line).unwrap();
この行は少し難しいのですが、簡単に説明します。
&line
と&mut line
の違いは変更できるかできないか、です。
std::io::stdin().read_line(&line).unwrap();
let input = input();
この行で入力した値をinput
変数として宣言します。
入力した単語の判定
check関数
fn check(section: &str, previous_last: char) -> bool {
let chars: Vec<char> = section.chars().collect();
if chars[0] == previous_last {
return true;
} else {
return false;
}
}
このは第一引数の文字列の最後が第二引数と一致するかを判定する関数です。
if input.is_empty() || !check(&input, previous_last) {
println!("{}で始まる単語を入力してください", previous_last);
continue;
}
入力した単語が空白、最初の文字が前回の単語の最後の文字か、のどちらかがtrue
なら中のif文を実行します。
input.is_empty()
はinput
が空白ならtrue
を返すので、先に判定することでもし空白ならすぐにif
文内のプログラムを実行します。
その後、check関数を使用して前回の単語の最後の文字から始まっているか確認します。
もし一致しなかったら{前回の単語の最後}で始まる単語を入力してください
と表示してもう一度入力させます。
input.is_empty() || !check(&input, previous_last)
がどちらともfalse
ならそのまま処理を進めていきます。
previous_lastの更新
次に単語の最後の文字を更新します。
入力した単語の最後の文字をlast関数を使用して取得します。
previous_last = last(&input);
単語を記録
content.push(input.clone());
プレイヤーのターン変更
// !true == false
// !false == true
player = !player;
プレイヤーはbool
型で表現されているので、!
演算子を使って意味を反転させて代入します。
game_over_check関数
fn game_over_check(section: &str) -> bool {
let last = last(section);
if last == 'ん' {
return true;
} else {
return false;
}
}
この関数は引数の文字列の最後の文字が「ん」だったらtrue
を返します。
「ん」がついたか判定
if game_over_check(&input) {
println!("`ん`がついたので負けです");
break;
}
入力した文字列をgame_over_check関数にわたしてtrue
ならメッセージを表示してループを終了します。
おわりに
修正やアドバイスがあればぜひコメントお願いします!
全体
fn main() {
let mut content: Vec<String> = vec![];
let mut player = true;
let first_section = "しりとり".to_string();
let mut previous_last = last(&first_section);
println!("{}", first_section);
content.push(first_section);
loop {
println!("プレイヤー: {}", if player { 1 } else { 2 });
let input = input();
if input.is_empty() || !check(&input, previous_last) {
println!("{}で始まる単語を入力してください", previous_last);
continue;
}
previous_last = last(&input);
content.push(input.clone());
player = !player;
if game_over_check(&input) {
println!("`ん`がついたので負けです");
break;
}
}
println!("プレイヤー{}の負けです", if player { 1 } else { 2 });
}
fn game_over_check(section: &str) -> bool {
let last = last(section);
if last == 'ん' {
return true;
} else {
return false;
}
}
fn check(section: &str, previous_last: char) -> bool {
let chars: Vec<char> = section.chars().collect();
if chars[0] == previous_last {
return true;
} else {
return false;
}
}
fn last(section: &str) -> char {
let chars: Vec<char> = section.chars().collect();
chars[chars.len() - 1]
}
fn input() -> String {
let mut line = String::new();
std::io::stdin().read_line(&mut line).unwrap();
line.trim().to_string()
}
Discussion