Mario(less comfortable)

World 1-1

任天堂スーパーマリオブラザーズのWorld 1-1の最後に、マリオは下のようなブロックの右揃えピラミッドを登らなければなりません。

以下のように、レンガにハッシュ (#) を使用して、テキストではありますが、Cでピラミッドを再作成しましょう。各ハッシュは幅よりも少し高いため、ピラミッド自体も幅よりも高さが高くなります。

       #
      ##
     ###
    ####
   #####
  ######
 #######
########

私たちが作成するプログラムはmarioと呼ばれます。そして、ユーザがピラミッドの高さを決めるために、例えば1から8までの正の整数を入力するようにしましょう。

ユーザがプロンプトに対して8を入力した場合のプログラムの動作を次に示します。

$ ./mario
Height: 8
       #
      ##
     ###
    ####
   #####
  ######
 #######
########

ユーザがプロンプトに対して4を入力した場合のプログラムの動作を次に示します。

$ ./mario
Height: 4
   #
  ##
 ###
####

ユーザがプロンプトに対して2を入力した場合のプログラムの動作を次に示します。

$ ./mario
Height: 2
 #
##

最後に、プロンプトが表示されたときに1を入力した場合のプログラムの動作を示します。

$ ./mario
Height: 1
#

プロンプトが表示されたときに、ユーザが実際に1~8の正の整数を入力しなかった場合、プログラムはユーザがそうするまでプロンプトを再表示します。

$ ./mario
Height: -1
Height: 0
Height: 42
Height: 50
Height: 4
   #
  ##
 ###
####

どうやって始めますか?この問題に一歩ずつ取り組みましょう。

擬似コード

まず、次のコマンドを実行して、pset1 ディレクトリ内にmario という新しいディレクトリ (フォルダ) を作成します。

~/ $ mkdir ~/pset1/mario

mario ディレクトリの中にpseudocode.txtという名前の新しいファイルを追加します。

まだどのようにコードを書くかわからない場合でも、このプログラムを実装する擬似コードをpseudocode.txtに書きましょう。疑似コードを書く正しい方法は1つではありませんが、短い英文で十分です。finding Mike Smithで擬似コードを書いたことを思い出しましょう。疑似コードでは1つ以上の関数、条件、ブール式、ループ、または変数が使用される (少なくとも使用されると示唆される) でしょう。

ネタバレ(まずは自身で考えてみましょう!)

複数の解法がありますが、ここでは1つだけを紹介します。

  1. ユーザに高さの入力を求める
  2. 高さが1より小さいか8より大きい (または整数でない) 場合は、1つ前のステップに戻る
  3. 1から高さまで繰り返し:
    1. iについての繰り返しとして、i個の#を出力し、次に改行を出力する

この擬似コードを見た後でこれを自分で編集してもかまいませんが、自分のコードにコピー&ペーストするだけではいけません。

入力を求めるプロンプト

どのような擬似コードを使用するにしても、まずは、ユーザに入力を求める (および必要に応じて再びプロンプトを出す) Cコードのみを記述してみましょう。mario ディレクトリ内にmario.cという名前の新しいファイルを作成します。

ここで、mario.cを修正してピラミッドの高さを入力するようユーザに促し、入力を変数に格納します。入力が1から8までの正の整数でない場合は、必要に応じて何度も再入力を促します。次に、単にその変数の値を出力し、以下のように、ユーザの入力が正しく保存されたことを (自分自身で) 確認します。

$ ./mario
Height: -1
Height: 0
Height: 42
Height: 50
Height: 4
Stored: 4

ヒント

  • makeを使ってプログラムをコンパイルできることを思い出してください。
  • %iを使用してprintfでintを出力できることを思い出してください。
  • get_intでユーザから整数を取得できることを思い出してください。
  • get_intはcs50.hで宣言されていることを思い出してください。
  • クラス内でpositive.cを使用して正の整数を入力するようにユーザに求めたことを思い出してください。

片側の構築

これでプログラムが (願わくば!) 指定された入力を受け入れ、次のステップに進みます。

下の画像のように、右揃えのピラミッドよりも左揃えのピラミッドを作る方が少し簡単です。

#
##
###
####
#####
######
#######
########

まず左揃えのピラミッドを構築し、それが機能したら右揃えにしましょう。

先ほどのmario.cを修正して、単にユーザの入力を印刷するのではなく、その高さの左揃えのピラミッドを印刷するようにします。

ヒント

  • ハッシュは他の文字と同様に単なる文字であるため、printfを使用して出力できることに注意してください。
  • ScratchがRepeat ブロックを持っているのと同じように、Cにもforループがあり、それを使って何かを繰り返すことができます。おそらく、各繰り返しiで、その数に対応した#を出力することができるでしょう。
  • ループは 「ネスト」 することができ、 「外側」 ループの1つの変数 (例えばi) と 「内側」 ループの別の変数 (例えば j) を使用して繰り返し処理を行うことができます。たとえば、以下は高さと幅がnの正方形を印刷します。もちろん、この問題では印刷したいのは正方形ではありません。
  for (int i = 0; i < n; i++)
  {
      for (int j = 0; j < n; j++)
      {
          printf("#");
      }
      printf("\n");
  }

ドットと右揃え

今度は、下の画像のように、ハッシュをドット (ピリオド) で区切って右側に配置します。

.......#
......##
.....###
....####
...#####
..######
.#######
########

mario.cをそのように修正します。

ヒント

各行に必要なドットの数は、その行の#の数の 「反対」 であることに注目してください。高さ8のピラミッドの場合、上の例のように、最初の行は#が1つしかないため、7つのドットになります。一方、一番下の行には8個のハッシュがあり、0個のドットがあります。どのような公式 (算数) を使って、これらのドットを印刷できるでしょうか。

コードのテスト方法

コードは以下の入力時に指定されたとおりに動作しますか。

  • -1 (または他の負の数)
  • 0
  • 1から8
  • 9または他の正の数
  • 文字・文字列
  • 何も入力せず、Enterキーだけを押したとき

ドットを削除する

今や残っているのは最後のステップだけです。mario.cを変更して、ドットではなくスペースをプリントするようにしてください。

コードのテスト方法

check50を使用して以下を実行し、コードの正確さを評価してください。ただし、コンパイルとテストは必ず自分で行ってください。

check50 cs50/problems/2021/x/mario/less

以下を実行し、style50を使用してコードのスタイルを評価します。

style50 mario.c

ヒント

スペースを入力するには、ピリオドのキーを押す要領で、スペースバーを押すだけです。printf では両端を二重引用符で囲む必要があることに注意してください。

提出方法

次のコマンドを実行し、GitHubのユーザ名とパスワードを入力してログインします。セキュリティのため、パスワードには実際の文字ではなくアスタリスク (*) が表示されます。

submit50 cs50/problems/2021/x/mario/less