美しいプログラムコードとは-2。
「コメントと能書きを少々。」
まずは、コメントを入れたソースコードをご覧いただきたい。
# Ruby のままだけど…。
class Player attr_accessor :games attr_reader :name def initialize(name) @name = name @games = 0 end def won @games += 1 end end # ルール定義 (勝利条件定義 [COM:ゲーム数 ADV:ゲーム差]) CONDITIONS = [{:COM=>7,:ADV=>1}, {:COM=>6,:ADV=>2}] # メッセージ MSG = {:OVER=>"%s wins the set %s - %s", :TIE=>"Set is tied at %s", :PLAYING=>"%s leads %s - %s"} def games_as_string(player1, player2) # 順位付け temp = [player1, player2].sort{|a, b| a.games <=> b.games} other = temp.shift leader = temp.shift # ゲーム状態を評価 status = :PLAYING status = :TIE if leader.games == other.games CONDITIONS.each {|con| if con[:COM] == leader.games && con[:ADV] <= (leader.games - other.games) status = :OVER end } # メッセージオプション編集 if status == :TIE options = leader.games else options = [leader.name, leader.games, other.games] end # メッセージ出力 return MSG[status] % options end # テスト p1 = Player.new("Player1") p2 = Player.new("Player2") (0..7).each {|i| (0..7).each {|j| p1.games = i p2.games = j puts "[#{i}:#{j}] #{games_as_string(p1, p2)}" } }
もう一つも。
# プレイヤー名 NAMES = ["Player1", "Player2"] # メッセージ MSG = { :OVER => "%s wins the set %s - %s", :TIE => "Set is tied at %s", :PLAYING => "%s leads %s - %s" } def get_set_score(games1, games2) # ルール定義 (ゲーム状態マトリックス) statuses = 8.times {|i| statuses << Array.new(8, :PLAYING)} (0..6).each {|i| statuses[6][i] = :OVER if i < 5 statuses[i][6] = :OVER if i < 5 statuses[7][i] = :OVER if i >= 5 statuses[i][7] = :OVER if i >= 5 statuses[i][i] = :TIE } # ゲーム状態を評価 status = statuses[games1][games2] # メッセージオプション編集 options = if status == :TIE options = [games1] else options << NAMES[games1>games2 ? 0 : 1] options << [games1, games2].sort.reverse end # メッセージ出力 return MSG[status] % options.flatten end # テスト (0..7).each {|i| (0..7).each {|j| puts "[#{i}:#{j}] #{get_set_score(i, j)}" } }
上のプログラムコードは、"ルール定義"、"判定"、"メッセージ出力" と、複雑な問題を段階的に解決している。一つ一つの段階が小さな問題領域に絞られているから、おそらく理解は難しくないだろう。しかし、@IT の件の記事は、一塊の条件分岐ブロックですべてを表現している。これは、"異なる問題領域の条件分岐を混ぜている" のだから、場合分けが多くなり、頭の中で整理するのに集中を要することになる。
今回は、参照元に習って、あえて一つの関数で処理するような書き方をしたが、クラス設計としては、段階毎に別々のメッソッドとして定義する方が、より分かりやすく、使いやすくなると思われる。ま、どういうクラス設計をするのが望ましいかは、ここでは大事な話題ではないので、これ以上は触れないけれど。
さて…。
もし、「片方が 5 ゲームを勝利した時点で、相手の勝利ゲームが 0 の場合にコールド勝ちとする。」と云うルールが追加されたとすると、どのプログラムコードが一番楽に対応できるだろうか?
こーゆー仕様変更が容易くできることが、プログラムコードが "見やすかった/分かりやすかった" ことの目安になる。見やすさにこだわる理由は、デバッグがやり易く、変更し易いことなのだから。