目次

 

 

 

 

 

 

 

Top >コンソール・アプリケーション集

逆ポーランド記法電卓 C#

using System;
using System.Collections.Generic;
using System.Linq;

/// <summary>
/// 入力処理の結果
/// </summary>
enum OPERATION : int
{
    PLUS,       // 足し算
    MINUS,      // 引き算
    MULTIPLY,   // 掛け算
    DIVIDE,     // 割り算
    INVERSION,  // 符号反転
    CLEAR,      // クリア
    ENTER,      // 数値入力
    EXIT        // 終了
};

/********************************************************************
 *  計算に使用するスタックについて
 *
 *  スタックは2つの方法を用意しています。
 *  1)自分で作成する、CalcStackクラスを使用する
 *  2).NETのStackコレクションを使用する
 *
 * 元のコードでは、1)になっています。
 * 2)にする場合は、RpnCalcクラスのmStack変数の定義を変更してください
 *
 *******************************************************************/


/// <summary>
/// スタックのクラス
/// </summary>
class CalcStack
{
    private const int StackSize = 10;   // スタックの大きさ

    private double[] mValues;   // 数値配列
    private int mCount;         // 要素数

    /// <summary>
    /// コンストラクタ
    /// </summary>
    public CalcStack()
    {
        mValues = new double[StackSize];
        mCount = 0;
    }

    /// <summary>
    /// プッシュ
    /// </summary>
    /// <param name="value">プッシュする数値</param>
    public void Push(double value)
    {
        if (mCount >= StackSize)
            throw new Exception("Stack がオーバーフローしました。");

        mValues[mCount++] = value;
    }

    /// <summary>
    /// ポップ
    /// </summary>
    /// <returns>ポップされた数値</returns>
    public double Pop()
    {
        if (mCount <= 0)
            throw new Exception("Stack が空です。");

        return mValues[--mCount];
    }

    /// <summary>
    /// 要素数
    /// </summary>
    public int Count
    {
        get { return mCount; }
    }

    /// <summary>
    /// 指定されたインデックス位置にある要素を返す。
    /// </summary>
    /// <param name="idx">取得する要素の、0 から始まるインデックス</param>
    /// <returns>指定された位置にある要素</returns>
    public double ElementAt(int idx)
    {
        if (idx < 0 || idx >= mCount)
            throw new Exception("パラメータ正しくありません。");

        return mValues[mCount - idx - 1];
    }
}

/// <summary>
/// 電卓本体のクラス
/// </summary>
class RpnCalc
{
    // 計算に使用するスタック
    // 1)作成した、CalcStackクラスを使用する場合は(A)を有効にする
    // 2).NETのStackコレクションを使用する場合は(B)を有効にする
    //   この場合は、CalcStackクラスの記述は不要

    private CalcStack mStack = new CalcStack();             // (A)
    //private Stack<double> mStack = new Stack<double>();   // (B)


    /// <summary>
    /// 入力処理
    /// </summary>
    /// <returns>入力処理の結果</returns>
    private OPERATION Input()
    {
        string numbers = "";
        OPERATION ope = OPERATION.ENTER;

        for (; ; )
        {
            // 文字を入力
            ConsoleKeyInfo kinfo = Console.ReadKey();

            if (('0' <= kinfo.KeyChar && kinfo.KeyChar <= '9') || kinfo.KeyChar == '.')
            {
                // 数字と小数点の場合

                numbers += kinfo.KeyChar;
            }
            else
            {
                // 演算の場合

                if (kinfo.KeyChar == '+')
                    ope = OPERATION.PLUS;
                else if (kinfo.KeyChar == '-')
                    ope = OPERATION.MINUS;
                else if (kinfo.KeyChar == '*')
                    ope = OPERATION.MULTIPLY;
                else if (kinfo.KeyChar == '/')
                    ope = OPERATION.DIVIDE;
                else if (kinfo.KeyChar == '!')
                    ope = OPERATION.INVERSION;
                else if (kinfo.Key == ConsoleKey.C)
                    ope = OPERATION.CLEAR;
                else if (kinfo.Key == ConsoleKey.Q)
                    ope = OPERATION.EXIT;

                break;  // 入力を終了
            }
        }

        // 数字の入力があれば、スタックにプッシュする。
        if (!string.IsNullOrWhiteSpace(numbers))
            mStack.Push(double.Parse(numbers));

        return ope;
    }

    /// <summary>
    /// 電卓画面を表示
    /// </summary>
    private void ShowCalculator()
    {
        const string body = "\n"
            + "*** RPN Calculator *******************************\n"
            + "*    +:加 -:減 *:乗 /:除 !:符号 c:削除 q:終了    *\n"
            + "*                                                *";

        Console.WriteLine(body);

        // スタックの内容を表示する
        for (int i = mStack.Count; i > 0; i--)
            Console.WriteLine("* {0:00}: {1}", i, mStack.ElementAt(i - 1));

        Console.Write(">");
    }

    /// <summary>
    /// 電卓の実行
    /// </summary>
    public void Run()
    {
        for (; ; )
        {
            OPERATION operation;

            try
            {
                // 電卓画面を表示
                ShowCalculator();

                // 入力
                operation = Input();

                // 必要な個数の数値をポップして演算を施し、結果をプッシュする

                if (operation == OPERATION.INVERSION || operation == OPERATION.CLEAR)
                {
                    // 必要とする数値が1つの操作

                    double n = mStack.Pop();    // ポップする

                    if (operation == OPERATION.INVERSION)   // 符号反転
                        mStack.Push(n * (-1.0));

                }
                else if (operation == OPERATION.PLUS || operation == OPERATION.MINUS
                    || operation == OPERATION.MULTIPLY || operation == OPERATION.DIVIDE)
                {
                    // 必要とする数値が2つの操作

                    double n1 = mStack.Pop();   // ポップする
                    double n2 = mStack.Pop();   // ポップする

                    if (operation == OPERATION.PLUS)            // 加算
                        mStack.Push(n1 + n2);
                    else if (operation == OPERATION.MINUS)      // 減算
                        mStack.Push(n2 - n1);
                    else if (operation == OPERATION.MULTIPLY)   // 乗算
                        mStack.Push(n1 * n2);
                    else if (operation == OPERATION.DIVIDE)     // 除算
                    {
                        if (n1 == 0.0)  // 0での除算
                            Console.WriteLine("\nDivide by Zero!");
                        else
                            mStack.Push(n2 / n1);
                    }
                }
                else if (operation == OPERATION.EXIT)
                {
                    // プログラムの終了
                    break;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("\n" + ex.Message);
            }
        }
    }

    /// <summary>
    /// Mainメソッド
    /// </summary>
    /// <param name="args"></param>
    static void Main(string[] args)
    {
        RpnCalc calc = new RpnCalc();

        calc.Run();
    }
}
AKABAS
NEZEN