わさっきhb

大学(教育研究)とか ,親馬鹿とか,和歌山とか,とか,とか.

構造体プログラミングの実例(2)〜仕様と入出力

総当たり戦の対戦結果を表にして出力するプログラムを作りなさい.入出力は適当に定めること.

…これだけではプログラムにできません.まずはプログラムにしやすいように,ルールを定めることにします.「仕様の作成」です.
一人で閉じたプログラムを作る場合,仕様は,プログラミングの方向性を示したもの,つまり「方針」ととらえるといいでしょう.すなわち,とりあえず何か決めて,コードを書いていきながら,追加したり変更したりしてもいいやという考え方です.複数人が関わる場合の仕様は,意味が違ってきます.
さてその仕様…方向づけですが,私はこう考えました.

  • 入力は標準入力から,出力は標準出力へ.
  • ASCII文字を使う.表もASCII文字のみで(等幅フォントとする).
  • プレイヤー名も入力から受け取る.1プレイヤーの名前を,ASCIIの1文字で表す.

仕様はまた追加することにして,次に,「出力のイメージ」を,具体的な形にしてみましょう.

 WNM
W-oo
Nx-x
Mxo-

プレイヤーは,WとNとM*1です.出力の1行目は,1文字スペースを置いてから,全プレイヤーを並べます.
2行目以降は,最初にプレイヤー名,次に対戦結果です.例えば2行目だけを取り出すと,「W-oo」ですが,これは,行の最初の文字(W)を基準として,それぞれの列のプレイヤーとの対戦結果を表現したものです.まずWとWは対戦しないので,「-」*2です.WとNは,Wの勝ちということで,「o」.WとMも,Wの勝ちで「o」.
ところで,WはNに勝った,ということは,NはWに負けた,という意味です.実際,Nから始まる行の2文字目は「x」です.負けの文字ですね.
最後まで勝敗が決まった状況を作りましたが,一部勝敗の決まっていない,「途中経過」もあっていいでしょう.それについては,1文字スペースでいいでしょうね.
引き分けは…考慮しないことにします.勝つか,負けか,同一プレイヤーなので対戦しないか,未対戦か.この4種類だけとします.
ではここまでの検討を,より一般的なルールとして,表現しましょう.これも仕様に含まれます.

  • 出力の1行目は,最初に1文字スペースのあと,全プレイヤーの名前を並べる.
  • 2行目の最初の文字は,プレイヤーの名前で,2文字目以降は,1行目の列のプレイヤーとの対戦結果を1文字で表す.「o」は勝ち,「x」は負け,「-」は対戦しない,「 」(1文字スペース)は未対戦とする.
  • i≧2,j≧2に対して,i行j列の文字と,j行i列の文字には対応関係がある.すなわち一方が「o」なら,もう一方は「x」である.一方が「 」なら,もう一方も「 」である.

対応関係を一般化するために,iとjという変数を置きましたが,その上限,すなわちプレイヤーの数について,検討を忘れていることに気づきました.何人でもいいというのは,処理が難しくなるので,避けるとします.3や5では,少なすぎますね.ここは20としておきます.標準的な端末ソフトウェアで,1画面で結果の表が見えますね.
出力の次は,入力です.まずはこんな感じで.

WNM
W>N
W>M
M>N

入力の最初の行に,出場したプレイヤーを並べます.この行は,人数によって変わってきます.上限は20文字,下限は…1人のみの表はおかしいので,2文字(2人)としましょう*3
2行目以降は,「勝ちプレイヤー」「>」「負けプレイヤー」の形で,結果を書きます.2文字目を「<」にして,「負けプレイヤー」「<」「勝ちプレイヤー」もOKにするか…いや,プログラムを簡単にしたい*4ので,これは却下ということでI turn it down
そういえば,「途中経過もあっていい」と書いたのに,上の入力例では,このことを無視しています.ちょっと入力例を変えましょう.

WNM
!
W>N
!
W>M
!
M>N
!

このとき,「!」のみの行が見つければ,プログラムは,その時点での勝敗表を出力することとします.最後に「!」がなく,入力が終わったら,表を出すことにするか…いや,処理を簡単にしましょう,「!」があるときだけ表出力,最後に「!」がなければ,表出力しない,と決めます.
これで入力についても,仕様として表現できるでしょうか.箇条書きにします.

  • 入力の1行目は,全プレイヤーの名前を並べる.文字数(プレイヤー数)は,2以上20以下とする.
  • 2行目以降の各行は,「!」または「α>β」のいずれかとする.
    • 「!」があれば,その時点での総当たり表を出力する.
    • 「α>β」(ただし,αとβは1行目にある文字とする)があれば,αはβに勝ち,βはαに負けとなるよう,勝敗を記録する.

ここまで書けば,プログラミングに進めそうでしょうか.何か抜けている気もしますが,それは,プログラムを作りながら,詰めていきましょう.

*1:和歌山と奈良と三重です.勝敗は特に意味ありません.架空の対戦とはいえ,和歌山を勝たせたいという気持ちはあります.

*2:ここに,右向き斜線,すなわちバックスラッシュが使えるといいのですが,「\」は実行環境によって円記号になったりするので,やめときましょう.無難な「-」にしています.

*3:実用上,2人の対戦を「表」にすることはないですけど.

*4:ここまで書いてきた仕様の中に,プログラムを複雑にさせる要素もいろいろ入れています.例えば,プレイヤー名を出力せずに「表のみ」を出すことにすれば,たぶん少しは簡単になるでしょう.仕様を決めていくにあたり,何を採用して何を却下するかは,結局のところ,プログラムを作っていく自分の好みで決め,自分がその責任を負えばいいということです.