LoginSignup
1
1

More than 3 years have passed since last update.

前記事のリファクタリングを咀嚼する(みんなでしりとり)

Last updated at Posted at 2019-09-22

趣旨

拙いながらBクラス問題についての記事を書いたが、
それについてコメントにてリファクタリングを受けたので咀嚼を行いたい。

おまじない

if __name__ == '__main__':

上記記述は、importされた時に内容が実行されることを避けるための記述である。
https://blog.pyq.jp/entry/Python_kaiketsu_180207

しりとり判定部分

def is_according_rules(word_list, last_word, next_word):
    if next_word[-1] == 'z' or next_word not in word_list:
        return False  # zで終わる発言、単語リストにない発言はNG(False)
    if last_word is None:
        return True  # 直前の発言がない/違反なら、どれでもOK(True)
    return last_word[-1] == next_word[0]  # しりとりしてるならOK、さもなくばNG

orはinより優先度が低いため、括弧は必要ない。
https://www.javadrive.jp/python/num/index3.html)

Noneとの比較はisを使用する。
https://qiita.com/i13602/items/6d8914e019c13e858c72 )と(https://www.python-izm.com/tips/difference_eq_is/#None)

return下に計算式や判定文を書くことで変数やif文を省略できる。

プレイヤー処理部分

def trace_spoken_words(number_of_members, word_list, spoken_words):
    alive_members = list(range(1, number_of_members + 1))
    available_words = word_list.copy()

    last_word = spoken_words[0]              # 最初の人の発言
    available_words.remove(last_word)        # 使用可能単語から最初の人の発言を削除
    member_index = 1                         # 最初に発言する人のインデックス番号

    for next_word in spoken_words[1:]:       # 次の人から発言を辿る
        if is_according_rules(available_words, last_word, next_word):
            last_word = next_word            # ルールOKなので最後の発言にする
            member_index += 1                # 次の人へ(インデックス番号を次へ)
        else:
            last_word = None                 # ルールを破ったので発言は無効
            del alive_members[member_index]  # ルールを破った人を外す
            # member_index += 0              # 次の人へ(インデックス番号は同じ)
        member_index %= len(alive_members)   # インデックス番号が越えたら0にする
        if next_word in available_words:
            available_words.remove(next_word)

    return alive_members

forはin内の様々な型を対象にループを行う。
https://arakan-pgm-ai.hatenablog.com/entry/2018/12/05/090000

疑問:1人目の違反は判定可能? 
リファクタリング本人様よりコメントがありました。1人目についても判定できるよう改良されています。

メイン部分

def solve():
    N, K, M = map(int, input().split())  # N:人数 K:単語数 M:発言数
    d = [input() for _ in range(K)]      # 単語リスト
    s = [input() for _ in range(M)]      # 発言ログ

    alive_members = trace_spoken_words(N, d, s)

    print(len(alive_members))
    for member_number in alive_members:
        print(member_number)

アンダースコア1個の変数名は、使用しない使い捨て変数であることを示す。
その他プライベートな変数の先頭にはアンダースコアを付けることが推奨される。
プライベートメンバ名には最初にアンダースコアを1個付けるが、
関数内のローカル変数は外部からアクセスできないのでアンダースコアを付ける必要はない。
予約語や定義済関数名との衝突を避けるときは、変数名の後にアンダースコアを1個付けます。
https://pep8-ja.readthedocs.io/ja/latest/#id24

感想

不必要な変数を定義しないことが徹底されている。
変数の命名が本人でなくてもわかりやい。

非常に勉強になりました。shiracamus様、ありがとうございました。

1
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1