解答例 - j1.lesson10.Alphametic3

package j1.lesson10;

import java.io.*;

/**
 * 課題1005 - 解答例.
 @author s.arakawa
 @version $Id: Alphametic3_java.rps,v 1.1 2006/03/06 12:56:15 java2005 Exp $
 */
public class Alphametic3 {

    /**
     * 虫食い算を解くプログラム。 課題にある虫食い算は以下のようなものである
     * (Xには0~9の任意の値が入り、a,bにはユーザから入力された0~9の値が入る)。
     <pre>
     *     X X
     * *   X X
     * --------
     *   X X X
     * X a X
     * --------
     * X b X X
     </pre>
     
     * 以下のような擬似コードで表される。
     
     <pre>
     * プログラム全体
     *     &quot;aの値を入力:&quot; と表示
     *     a = コンソールへの入力
     *     if a が負の値 または a が 10 以上
     *         &quot;不正な入力です&quot; と表示
     *         終了
     *     &quot;bの値を入力:&quot; と表示
     *     b = コンソールへの入力
     *     if b が負の値 または b が 10 以上
     *         &quot;不正な入力です&quot; と表示
     *         終了
     *     a, b の値を使って、虫食い算の全ての可能性を算出して表示する
     </pre>
     @param args 無視される
     @throws IOException 入力時に例外が発生した場合
     */
    // プログラムの入り口(args)
    public static void main(String[] argsthrows IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        
        // "aの値を入力:" と表示
        System.out.print("aの値を入力:");
        
        // a = コンソールへの入力
        int a = Integer.parseInt(reader.readLine());
        
        // if a が負の値 または a が 10 以上
        if (a < || a >= 10) {
            // "不正な入力です" と表示
            System.out.println("不正な入力です");
            // 終了
            return;
        }
        
        // "bの値を入力:" と表示
        System.out.print("aの値を入力:");
        
        // b = コンソールへの入力
        int b = Integer.parseInt(reader.readLine());

        // if b が負の値 または b が 10 以上
        if (b < || b >= 10) {
            // "不正な入力です" と表示
            System.out.println("不正な入力です");
            // 終了
            return;
        }

        // a, b の値を使って、全ての可能性を算出して表示する
        solve(a, b);
    }

    /**
     * 課題で指定された虫食い算を解き、結果を全て表示する。
     * 結果は被乗数が小さい順に並べ、被乗数が同じ値のものがあればさらに乗数が小さい順に並べて表示する。
     * 以下の擬似コードで表される。
     <pre>
     * 与えられた虫食い算を解く(a, b)
     *     for 被乗数 を 10 から 99 まで
     *         for 乗数 を 10 から 99 まで
     *             1段目 = 被乗数 * (乗数の1桁目)
     *             2段目 = 被乗数 * (乗数の2桁目)
     *             結果 = 1段目 + 2段目 * 10
     *             if 1段目が 3桁 かつ
     *                2段目が 3桁 かつ
     *                結果が 4桁 かつ
     *                2段目の2桁目が a と等しい かつ
     *                結果の3桁目が b と等しい ならば
     *                         &quot;(被乗数, 乗数)&quot; を表示して改行
     </pre>
     @param a 虫食い算の a に当てはまる数字
     @param b 虫食い算の b に当てはまる数字
     */
    // 与えられた虫食い算を解く(a, b)
    public static void solve(int a, int b) {
        // for 被乗数 を 10 から 99 まで
        for (int x = 10; x <= 99; x++) {
            // for 乗数 を 10 から 99 まで
            for (int y = 10; y <= 99; y++) {
                
                // 1段目 = 被乗数 * (乗数の1桁目)
                int line1 = x * columnAt(y, 1);

                // 2段目 = 被乗数 * (乗数の2桁目)
                int line2 = x * columnAt(y, 2);
                
                // 結果 = 1段目 + 2段目 * 10
                int result = line1 + line2 * 10;
                
                // if 1段目が 3桁 かつ
                //    2段目が 3桁 かつ
                //    結果が 4桁 かつ
                //    2段目の2桁目が a と等しい かつ
                //    結果の3桁目が b と等しい ならば
                //   "(被乗数, 乗数)" を表示して改行
                if (digitNumberOf(line1== && digitNumberOf(line2== 3
                        && digitNumberOf(result== && columnAt(line2, 2== a
                        && columnAt(result, 3== b) {
                    System.out.println("(" + x + ", " + y + ")");
                }
            }
        }
    }

    /**
     * 引数で指定した値の桁数を計算する。
     * 以下の擬似コードで表される。
     <code>
     * 桁数を計算する(value)
     *     桁数の初期値を0に設定
     *     while value が 0 でない
     *        value の値を10で割って、小数点以下を切り捨て
     *        桁数を 1 増やす
     *     ここまでの桁数を返す
     </code>
     @param value
     @return 引数で指定した値の桁数、引数に負の値が指定された場合は <code>-1</code>
     */
    // 桁数を計算する(value)
    public static int digitNumberOf(int value) {
        // if value が 0 未満
        if (value < 0) {
            // -1 を返して終了
            return -1;
        }

        // 桁数の初期値を0に設定
        int digits = 0;
        
        // while value が 0 でない
        while (value != 0) {
            // value の値を10で割って、小数点以下を切り捨て
            value /= 10;
            
            // 桁数を 1 増やす
            digits++;
        }
        
        // ここまでの桁数を返す
        return digits;
    }

    /**
     * 指定した値の指定した桁の値を取得する。
     * 以下の擬似コードで表される。
     <pre>
     * 指定した桁の値を取得する (value, n)
     *     10 の n-1 乗を作成する
     *     value の値を10のn-1乗で割って、小数点以下を切り捨て
     *     さらにその値を10で割った余りを返す
     </pre>
     @param value 対象の値
     @param n 取得する桁の位置
     @return 指定した桁の値。ただし、引数に不正な値が指定された場合は <code>-1</code>
     */
    // 指定した桁の値を取得する (value, n)
    public static int columnAt(int value, int n) {
        // if n が 0 未満
        if (n < 0) {
            // -1 を返して終了
            return -1;
        }
        // if value が 0 未満
        if (value < 0) {
            // -1 を返して終了
            return -1;
        }
        
        // 10 の n-1 乗を作成する
        int unit = 1;
        for (int i = 1; i < n; i++) {
            unit *= 10;
        }
        
        // value の値を10のn-1乗で割って、小数点以下を切り捨て
        // さらにその値を10で割った余りを返す
        return value / unit % 10;
    }
}