🦀

Rust で九九表を作ってみよう!さらに、 NN 表を作ってみよう!

2024/01/29に公開

九九表を作ってみよう

まずは 1 の段を作ってみよう

難しい問題はいくつかの易しい問題に分割して考えるとスムーズに解けることがある。今回は九九表を作るにあたって、いきなり全部作ろうとするのではなく、 1 の段を作ってみるという易しい問題に分割した。このことは他の問題にも応用できるので是非覚えておこう。

期待する出力
1 2 3 4 5 6 7 8 9

1 の段を作るためには上のような出力が得られるプログラムを書けば良い。 1 から 9 まで繰り返し処理させるためには for 文を使うのが自然なプログラムであろう。以下のプログラムがそれである。

main.rs
fn main() {
    for x in 1..=9 {
        print!("{} ", x * 1);
    }
}

1 以外の段も作ってみよう

1 の段だけではなく 2 の段、 3 の段、...、 9 の段を作れば九九表が出来上がる。ここでもやはり for 文によるアプローチを取るのが自然である。

main.rs
fn main() {
    for x in 1..=9 {
        for y in 1..=9 {
            print!("{} ", x * y);
        }
        println!();
    }
}

さて、これを実行してみると次のような出力が得られる。

出力結果
1 2 3 4 5 6 7 8 9 
2 4 6 8 10 12 14 16 18 
3 6 9 12 15 18 21 24 27 
4 8 12 16 20 24 28 32 36 
5 10 15 20 25 30 35 40 45 
6 12 18 24 30 36 42 48 54 
7 14 21 28 35 42 49 56 63 
8 16 24 32 40 48 56 64 72 
9 18 27 36 45 54 63 72 81 

うん、正しい。早速 NN 表も作ろう!...ちょっと待って。

出力結果をもう一度見てみよう。何かおかしいと思わない?

確かに数値はおかしくない。でも何かおかしい。

そう、見映えが悪いのだ。 1 桁と 2 桁の取るスペースが違うせいで見にくいのだ。これはすぐに解決する方法がある。

main.rs
fn main() {
    for x in 1..=9 {
        for y in 1..=9 {
            print!("{:2} ", x * y);
        }
        println!();
    }
}

print! の中身にある {}{:2} に変えるだけである。 :2 というのは、空白文字を 2 桁になるように必要な分だけ入れてねと指示しているのである。つまり、 0 文字なら 2 文字分、 1 文字なら 1 文字分、 2 文字なら 0 文字分の空白文字を元の文字列の左側に入れてくれるのである。

出力結果
 1  2  3  4  5  6  7  8  9 
 2  4  6  8 10 12 14 16 18 
 3  6  9 12 15 18 21 24 27 
 4  8 12 16 20 24 28 32 36 
 5 10 15 20 25 30 35 40 45 
 6 12 18 24 30 36 42 48 54 
 7 14 21 28 35 42 49 56 63 
 8 16 24 32 40 48 56 64 72 
 9 18 27 36 45 54 63 72 81 

ユーザーから入力を受け付ける形にしよう

これで九九表は完成である。ここで、キーボードから 9 が入力されたら九九表を出力してくれるようなものに書き換えよう。標準入力を受け取る形にするわけである。

main.rs
use std::io;

fn main() {
    // ユーザーに入力を促す
    println!("NN表へようこそ!");
    println!("サイズを入力してください。:");

    // 標準入力から値を取得する
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("エラー:1以上の整数を入力してください。");

    // 文字列を数値に変換する
    let SIZE: u32 = match input.trim().parse() {
        Ok(number) => number,
        Err(_) => panic!("エラー:1以上の整数を入力してください。"),
    };

    // 1以上の整数かどうかを判定する
    if SIZE < 1 {
        panic!("エラー:1以上の整数を入力してください。");
    }

    for x in 1..=SIZE {
        for y in 1..=SIZE {
            print!("{:2} ", x * y);
        }
        println!();
    }
}

NN 表を作ってみよう

九九表を一般化してみたい。例えば以下のように。

四四表
 1  2  3  4 
 2  4  6  8 
 3  6  9 12 
 4  8 12 16 
十十表
  1   2   3   4   5   6   7   8   9  10 
  2   4   6   8  10  12  14  16  18  20 
  3   6   9  12  15  18  21  24  27  30 
  4   8  12  16  20  24  28  32  36  40 
  5  10  15  20  25  30  35  40  45  50 
  6  12  18  24  30  36  42  48  54  60 
  7  14  21  28  35  42  49  56  63  70 
  8  16  24  32  40  48  56  64  72  80 
  9  18  27  36  45  54  63  72  81  90 
 10  20  30  40  50  60  70  80  90 100 

一部の人は、「さっきのプログラムに 10 と入力すれば上手くいくのでは?」と思ったかもしれない。実際にやってみよう。

出力結果(表のみ抜粋)
 1  2  3  4  5  6  7  8  9 10 
 2  4  6  8 10 12 14 16 18 20 
 3  6  9 12 15 18 21 24 27 30 
 4  8 12 16 20 24 28 32 36 40 
 5 10 15 20 25 30 35 40 45 50 
 6 12 18 24 30 36 42 48 54 60 
 7 14 21 28 35 42 49 56 63 70 
 8 16 24 32 40 48 56 64 72 80 
 9 18 27 36 45 54 63 72 81 90 
10 20 30 40 50 60 70 80 90 100 

数字は正しいようだ。でも空白がイマイチで見にくいね。

よくよく考えてみると、
九九表の場合は最大値が 81 なので 2 桁で揃えると綺麗になる。
十十表の場合は最大値が 100 なので 2 桁ではなく 3 桁で揃える必要がある。

そこで、入力された数値を 2 乗したものを文字列にし、そのサイズを求めれば良いことが分かる。例えば、 11 が入力されたときは 11 の 2 乗である 121 を文字列にすると "121" になり、その文字数は 3 である。これを空白文字で揃える基準の値とすればいいのである。

したがって、 NN 表の最終的なコードは以下のようなものとなる。

main.rs
use std::io;

fn main() {
    // ユーザーに入力を促す
    println!("NN表へようこそ!");
    println!("サイズを入力してください。:");

    // 標準入力から値を取得する
    let mut input = String::new();
    io::stdin().read_line(&mut input).expect("エラー:1以上の整数を入力してください。");

    // 文字列を数値に変換する
    let SIZE: u32 = match input.trim().parse() {
        Ok(number) => number,
        Err(_) => panic!("エラー:1以上の整数を入力してください。"),
    };

    // 1以上の整数かどうかを判定する
    if SIZE < 1 {
        panic!("エラー:1以上の整数を入力してください。");
    }

    for x in 1..=SIZE {
        for y in 1..=SIZE {
            print!("{:space$} ", x * y, space = (SIZE * SIZE).to_string().len());
        }
        println!();
    }
}

Discussion