CS193pのLecture 4の課題(RPN電卓アプリの課題2)

Lecture 4の宿題となっていた課題です。課題はここをクリックしてダウンロードできます。
課題を行う前に課題を全て読んだ方が良いです。
私は、ちらっと課題を見て、どうやって変数の値を入力するのか悩み、さらにその入力部分を勝手に自分で考えて実装してしまって、それが間違っていたことに後で気が付きました(涙)

私のようにそそっかしい人はそんなにいないと思いますが、同じような不幸が起こらないように課題の内容を日本語にしておきます。

 

課題の内容

ゴール

  • ユーザに変数を入力出来るようにさせる
  • ユーザが入力した内容(計算スタックの内容)を表示する

※変数の値をユーザが入力出来るようにするとはゴール設定されていない。

事前準備

Lecture 4のデモで実装されたCalculatorBrain API(programプロパティ, descriptionOfProgram:, runProgram:)を前回の電卓アプリに実装する。
このソースはサイトからダウンロードできるので、自分で必要な部分をマージする。

Required Task

1. CalculatorBrainに変数を受け入れられるようにする(数字は今まで通り受け付ける)

変数は、NSStringのオブジェクトとする。実装をシンプルにするためにsqrtなどの演算子と同じ名前の変数は無視できるようにする。
変数の値は計算スタックのprogramが演算されるときにのみ与えられる。
そのため、runProgram:を次のように変更する。

    + (double)runProgram:

                           (id)program

                           usingVariableValues:(NSDictionary *)variableValues;

この引数のvariableValues disctionaryのキーは演算スタックprogramの中で使われる変数名に対応するNSStringオブジェクトで、dictionaryに格納されるその値はNSNumberオブジェクトとする。(この割当は"test"の値として与えられる。Required Task #3を参照。)
もし演算スタックの中で指定された変数に対してdictionaryで値が設定されていなければ、その値を0として演算する。

加えて、programの中で使われる全ての変数の名前を取得するクラスメソッドを作成すること。
(このメソッドはNSStringオブジェクトのNSSetを返す)
+ (NSSet *)variablesUsedInProgram:(id)program;
programに変数がなければnilを返す。

2. 講義で仮実装されたdescriptionOfProgram:メソッドをprogramの内容を分かりやすく表示するように再実装する

a. オペランドが1つしかない演算子は関数表記にする
    例) 10 sqrt は、 sqrt(10)と表示する
b. 全ての複数オペランドをもつ演算子は中置記法(算数で使われる表記法)で表示する
    例) 3 Enter 5 + は、 3 + 5 と表示する
c. オペランドを持たない演算子はそのまま表示する
    例) π は、π と表示する
d. 変数(Required Task #1)はそのまま表示する
    例) x は、x と表示する

演算の組み合わせを適切に表示する(例のEはEnterキーを示す)

a. 3 E 5 E 6 E 7 + * - は、 3 - (5 * (6 + 7) と表示する
    もしくは、もっと簡潔に、3 - 5 * (6 + 7) と表示する
b.  3 E 5 + sqrt は、 sqrt(3 + 5) と表示する
c. 3 sqrt sqrt は、 sqrt(sqrt(3)) と表示する
d. 3 E 5 sqrt + は、 3 + sqrt(5) と表示する
e. π r r * * は、 π * (r * r) と表示する
    もっと良いのは、π * r * r と表示する

演算を正確に表すように括弧を使う。
例えば、
    3 E 5 + 6 * は、 3 + 5 * 6 ではなく、 (3 + 5) * 6 が正しい。
必要のない括弧は省いて最小限で表現にする(ヒント参照)
スタックには複数の事象が存在しているかもしれない。その場合は、コンマで区切って、スタックの上位のものを先に表示する。
例えば、
    3 E 5 E は、 “5, 3” と表示する
    3 E 5 + 6 E 7 * 9 sqrt は、 “sqrt(9), 6 * 7, 3 + 5” と表示する

 

3. 上記をテストするためにCalculatorのユーザインタフェイスを更新する

a. brainに送った内容を表示していたUILabelを最新の演算の内容を常に表示しするように変更する。表示には、descriptionOfProgram:メソッドを使用する
変数は値に置き換えず、そのまま表示する(descriptionOfProgram:は変数と値のdictionaryを引数にとらない)
b. 変数のボタンを追加する(例えば、x,y,fooなど)。これはCalculatorBrainに変数をプッシュするボタン
c. runProgram:usingVarableValue:メソッドのコールで計算結果の表示が更新されるように変更する。このメソッドに渡される変数と値のdictionaryはコントローラのプロパティとする。(testVariableValuessという名前にしましょう)
d. UILabelのUIを追加する。その内容は、variablesUsedInProgram:の結果からtestVariableValues に設定されている値を繰り返し取得したものにする。
例えば、次のように表示する。
    “x = 5 y = 4.8 foo = 0”
e. いくつかの"test"ボタンを追加する。そのボタンは、testVariableValuesにプリセットのテスト値を設定する。1つは、testVariableValuesをnilに設定する。
ボタンを押してtestVariableValuesを変更した時には、忘れずに他のUIを更新すること。

 

4. Undoボタンを追加する

数字を入力している最中にUndoを押した場合は、最後の数字もしくは小数点の入力がなかったことにする。それは、画面を全部クリアするまでやり直すことができ、そうなった場合は、brainがその時点の演算スタックを演算した結果を表示する。(そして、この時には明らかに入力途中の状態ではなくなるのでそれに気をつける)入力途中ではない時にUndoを押した時は、演算スタックの最上位のアイテムを取り除いてユーザインタフェイスを更新する。
    ※この課題は、コントローラのメソッド1つ(5、6ステップのコード)    とモデルのメソッド(1ステップのコード)として実装可能である。

 

5. CalculatorBrainは決してクラッシュさせないこと

 

ヒント

1. NSMutableArrayのreplaceObjectAtIndex:withObject:メソッドがこの課題には役に立つ

このメソッドはfor-inのような列挙型ループの中では使わないこと。インデックスを使ったforループの中で使う。

 

2. runProgram:usingVariableValues: は、popOperandOffStack: メソッドを全く変更しなくても実装できる

 

3. descriptionOfProgram:を実装する時にきっと再帰処理を使いたくなるだろう

descriptionOfTopOfStack:メソッドを作れば役に立つことも分かるかもしれない。
再帰処理が難しく感じたら、シンプルに考えよう。より複雑に考えるのではない。descriptionOfTopOfStack:メソッドは20ステップ以下のコードでpopOperandOffStack:にとても似ている。

 

4. descriptionOfProgram:メソッドは、次の状態を知る必要がある

スタック上の文字が2つのオペランドを必要とする演算か、1つのオペランドを必要とする演算か、オペランドが必要ない演算か、変数かを知る必要がある。これを知るのにプライベートなヘルパーメソッドをいくつか実装するのは良い考えだ。その実装にはたくさんのif-then文が使われるかもしれないが、NSSet(とそのcontainsObject:メソッド)が役立たないか考えてみよう。

 

5. ヒント#4のプライベートなヘルパーメソッドは、他のメソッドで変数と演算子を区別するのにも役に立つかもしれない。次のメソッドがきっと必要になるだろう

+ (BOOL)isOperation:(NSString *)operation

 

6. 最初は、descriptionOfProgram:の出力に必要のない括弧が含まれることを気にしないようにするのが良いかもれしれない

そして、それが上手く動作するようになったらどうやって不要な括弧を省略するかを戻って考えれば良い。
そのとき、明らかに括弧が不要な最優先の演算のハンドリングを最低限考慮すればいい。そして、関数表記の際に、括弧の中の括弧の必要性を考える。(例えば、sqrt((5 + 3))は見栄えが悪い)

 

7. NSDictionaryのクラスメッソドのdictionaryWithObjectsAndKeys:はRequried Task #3のeをするのに役に立つ

 

8. コードはなるべく少なくするのが良い

CalculatorBrainは100ステップ以下のコードで実装できる(その半分でも可能)。コントローラはもっと少なくできる。

 

 

さて、今から課題やり直します!

<前の記事 

CS193p LEcture 4     -   電卓アプリの課題2完成 次の記事>

コメントをお書きください

コメント: 1
  • #1

    buytadalafilonline (水曜日, 07 11月 2012 00:37)

    I intended to draft you this bit of remark in order to say thank you once again for the pretty guidelines you've documented here. It is quite strangely open-handed of you to present unhampered precisely what a lot of people could have made available as an electronic book to generate some cash for themselves, and in particular now that you could have tried it if you decided. Those good tips likewise served as a good way to recognize that some people have a similar dream the same as my personal own to understand a whole lot more concerning this condition. I am sure there are lots of more fun periods ahead for many who take a look at your website.