【プログラミング】良い命名規則とは。問題指向の命名規則。
だんだんコードがよくなってきたけど、
さらに学ぶことはあるはずだ、、と思ってCODE COMPLETEを読んでみる。
Code Complete第2版〈上〉―完全なプログラミングを目指して
- 作者: スティーブマコネル,Steve McConnell,クイープ
- 出版社/メーカー: 日経BPソフトプレス
- 発売日: 2005/03
- メディア: 単行本
- 購入: 44人 クリック: 1,166回
- この商品を含むブログ (283件) を見る
10章11章を読んだ。
発見したことをいくつか。
自分の解いている問題「宣教師と人食い問題」を例にとってメモ。
現在のコードでは、「移動した人数の合計」をmoverとしている。
数を表す変数はnumberOfXXXX
ふんふん。確かにそのほうが分かりやすい。
number_of_movers
かな。
適切な長さにする
最長でも10~16文字になるよう変数名を工夫する。
「number_of_movers」は問題ないけれど、
ほかにも「~の数」が出てきた場合に長くなりすぎる懸念がある。
こういうときはnumをつかう
num_movers
か。
numは混乱のもと
総数を表すのはcountまたはtotalを使う。
特定の対象をあらわすときはindexを使う(customerIndexなど)
total_mover
か。
なるほど。
問題指向の名前
社員データのレコードにはinputRecまたはemployeeDataという名前をつけることが出来る・・・ employeeDataの方は計算ではなく問題に言及しいているので良い
なるほど。
自分のコードも改善点があるかもしれない。
mover -> total_mover results -> answers x -> state
よし!これでどうだ!
total_moverという変数名から移動の合計を表しているのが明らかになったので、
コメントも省略できた。
def cases answers = ["000000"] #人人人食食食が左岸 6.times do |i| copy = answers.dup copy.each do |state| new_state = state.dup new_state[i] = "1" answers << new_state end end answers end #食べられないケースだけ抽出 def sieve(cases) answers = [] cases.each do |caze| caze_to_int = caze.split("").map{|a|a.to_i} a = caze_to_int[0,3].inject(:+) b = caze_to_int[3,3].inject(:+) #全人間がどちらかの端に存在 もしくは 左岸&&右岸がOK answers << caze if (a==3 || a==0) || ((3-a)>=(3-b) && a>=b) end answers end def possible?(state, next_state) return false if state == next_state total_mover = 0 if @history.length%2 == 0 #右から左へ state.each_with_index do |n, i| if n == 0 return false if next_state[i] != 0 #0->1(右岸に移動)は出来ない else total_mover += 1 if next_state[i] != 1 end end return false if total_mover > 2 #ボートの定員は2名 else #左から右へ state.each_with_index do |n, i| if n == 1 return false if next_state[i] != 1 #1->0(左岸に移動)は出来ない else total_mover += 1 if next_state[i] != 0 end end return false if total_mover > 2 end true end def dejavu?(state) @history.each_with_index do |previous_string, i| previous = previous_string.split("").map{|a|a.to_i} p1 = previous[0,3].inject(:+) p2 = previous[3,3].inject(:+) s1 = state[0,3].inject(:+) s2 = state[3,3].inject(:+) return true if (p1 == s1) && (p2 == s2) && (i%2 == (@history.length)%2) end false end @history = [] @patterns = sieve(cases) def _solve(state) state_to_string = state.join("") @history << state_to_string return true if state_to_string == "111111" @patterns.each do |pattern| next_state = pattern.split("").map{|a|a.to_i} if possible?(state, next_state) && !dejavu?(next_state) return true if _solve(next_state) == true end end @history.pop end def solve_missionaries_cannibals(init) init_to_int = init.split("").map{|a|a.to_i} _solve(init_to_int) return @history end p solve_missionaries_cannibals("000000")