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

逆ポーランド記法電卓 VB.NET

Imports System
Imports System.Collections.Generic
Imports System.Linq

Module RpnCalc

    '' <summary>
    '' 入力処理の結果
    '' </summary>
    '' <remarks></remarks>
    Enum OPERATION As Integer
        PLUS        ' 足し算
        MINUS       ' 引き算
        MULTIPLY    ' 掛け算
        DIVIDE      ' 割り算
        INVERSION   ' 符号反転
        CLEAR       ' クリア
        ENTER       ' 数値入力
        QUIT        ' 終了
    End Enum

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

    ''' <summary>
    ''' スタックのクラス
    ''' </summary>
    ''' <remarks></remarks>
    Class CalcStack
        Private Const StackSize As Integer = 10 ' スタックの大きさ
        Private mValues As Double()             ' 数値配列
        Private mCount As Integer               ' 要素数

        ''' <summary>
        ''' コンストラクタ
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()
            mValues = New Double(StackSize - 1) {}
            mCount = 0
        End Sub

        ''' <summary>
        ''' プッシュ
        ''' </summary>
        ''' <param name="value">プッシュする数値</param>
        ''' <remarks></remarks>
        Public Sub Push(value As Double)
            If mCount >= StackSize Then
                Throw New Exception("Stack がオーバーフローしました。")
            End If

            mValues(mCount) = value

            mCount += 1
        End Sub

        ''' <summary>
        ''' ポップ
        ''' </summary>
        ''' <returns>ポップされた数値</returns>
        ''' <remarks></remarks>
        Public Function Pop() As Double
            If mCount <= 0 Then
                Throw New Exception("Stack が空です。")
            End If

            mCount -= 1

            Return mValues(mCount)
        End Function

        ''' <summary>
        ''' 要素数
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public ReadOnly Property Count() As Integer
            Get
                Return mCount
            End Get
        End Property

        ''' <summary>
        ''' 指定されたインデックス位置にある要素を返す。
        ''' </summary>
        ''' <param name="idx">取得する要素の、0 から始まるインデックス。</param>
        ''' <returns>指定された位置にある要素。</returns>
        ''' <remarks></remarks>
        Public Function ElementAt(idx As IntegerAs Double
            If idx < 0 OrElse idx >= mCount Then
                Throw New Exception("パラメータ正しくありません。")
            End If

            Return mValues(mCount - idx - 1)
        End Function
    End Class

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

        Private mStack As New CalcStack()           ' (A)
        'Private mStack As New Stack(Of Double)()    ' (B)

        ''' <summary>
        ''' 入力処理
        ''' </summary>
        ''' <returns>入力処理の結果</returns>
        ''' <remarks></remarks>
        Private Function Input() As OPERATION
            Dim numbers As String = ""
            Dim ope As OPERATION = OPERATION.ENTER

            While True
                ' 文字を入力
                Dim kinfo As ConsoleKeyInfo = Console.ReadKey()

                If ("0"c <= kinfo.KeyChar AndAlso kinfo.KeyChar <= "9"c) OrElse kinfo.KeyChar = "."Then
                    ' 数字と小数点の場合

                    numbers += kinfo.KeyChar
                Else
                    ' 演算の場合

                    If kinfo.KeyChar = "+"Then
                        ope = OPERATION.PLUS
                    ElseIf kinfo.KeyChar = "-"Then
                        ope = OPERATION.MINUS
                    ElseIf kinfo.KeyChar = "*"Then
                        ope = OPERATION.MULTIPLY
                    ElseIf kinfo.KeyChar = "/"Then
                        ope = OPERATION.DIVIDE
                    ElseIf kinfo.KeyChar = "!"Then
                        ope = OPERATION.INVERSION
                    ElseIf kinfo.Key = ConsoleKey.C Then
                        ope = OPERATION.CLEAR
                    ElseIf kinfo.Key = ConsoleKey.Q Then
                        ope = OPERATION.QUIT
                    End If

                    ' 入力を終了
                    Exit While
                End If
            End While

            ' 数字の入力があれば、スタックにプッシュする。
            If Not String.IsNullOrWhiteSpace(numbers) Then
                mStack.Push(Double.Parse(numbers))
            End If

            Return ope
        End Function

        ''' <summary>
        ''' 電卓画面を表示
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub ShowCalculator()
            Const body As String = vbLf &
                "*** RPN Calculator *******************************" & vbLf &
                "*    +:加 -:減 *:乗 /:除 !:符号 c:削除 q:終了    *" & vbLf &
                "*                                                *"

            Console.WriteLine(body)

            ' スタックの内容を表示する
            For i As Integer = mStack.Count To 1 Step -1
                Console.WriteLine("* {0:00}: {1}", i, mStack.ElementAt(i - 1))
            Next

            Console.Write(">")
        End Sub

        ''' <summary>
        ''' 電卓の実行
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Run()
            While True
                Dim ope As OPERATION

                Try
                    ' 電卓画面を表示
                    ShowCalculator()

                    ' 入力
                    ope = Input()

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

                    If ope = OPERATION.INVERSION OrElse ope = OPERATION.CLEAR Then
                        ' 必要とする数値が1つの操作

                        Dim n As Double = mStack.Pop()

                        ' 符号反転
                        If ope = OPERATION.INVERSION Then
                            mStack.Push(n * (-1.0))
                        End If
                    ElseIf ope = OPERATION.PLUS OrElse ope = OPERATION.MINUS OrElse ope = OPERATION.MULTIPLY OrElse ope = OPERATION.DIVIDE Then
                        ' 必要とする数値が2つの操作

                        Dim n1 As Double = mStack.Pop()
                        Dim n2 As Double = mStack.Pop()

                        If ope = OPERATION.PLUS Then
                            ' 加算
                            mStack.Push(n1 + n2)
                        ElseIf ope = OPERATION.MINUS Then
                            ' 減算
                            mStack.Push(n2 - n1)
                        ElseIf ope = OPERATION.MULTIPLY Then
                            ' 乗算
                            mStack.Push(n1 * n2)
                        ElseIf ope = OPERATION.DIVIDE Then
                            ' 除算
                            If n1 = 0.0 Then
                                ' 0での除算
                                Console.WriteLine(vbLf & "Divide by Zero!")
                            Else
                                mStack.Push(n2 / n1)
                            End If
                        End If
                    ElseIf ope = OPERATION.QUIT Then
                        ' プログラムの終了
                        Exit While
                    End If
                Catch ex As Exception
                    Console.WriteLine(vbLf & ex.Message)
                End Try
            End While
        End Sub

    End Class

    ''' <summary>
    ''' Main
    ''' </summary>
    ''' <remarks></remarks>
    Sub Main()
        Dim calc As New RpnCalc()

        calc.Run()

    End Sub

End Module
PAPER BOWL
NEZEN