麻雀の待ちリストアップ 「あなたのスキルで飯は食えるか?」より
同期に触発されて、麻雀の待ちを列挙するプログラムを書いてみた。
(ただし、字牌無し、マンズのみ、七対子非対応版)
また、元ネタ(※)を読んでいなかったので、出力形式がかなり要求仕様と異なる。
(※ http://www.itmedia.co.jp/enterprise/articles/1004/03/news002.html)
実行例
C:\etc\src\python>python majung_simple.py 1112345678999 set([1, 2, 3, 4, 5, 6, 7, 8, 9]) C:\etc\src\python>python majung_simple.py 1232344562226 set([3, 6])
ソース(所要時間1時間半くらい)
#! -*- encoding=utf-8 -*- #! -*- encoding=utf-8 -*- # 標準入力を扱うため、sysをインポート import sys ################################################################ # 標準入力を整形し、メインの再帰関数(list_mati)を呼び出す # ################################################################ def main(): # 初期化 li = map(lambda n: int(n), list(sys.argv[1])) li.sort() print list_mati(li) ################################################################ # メインの再帰関数 # # 渡された牌リストを調べ # # ・メンツが含まれない場合、待ちを調べる # # ・メンツが含まれない場合、メンツを取り除いた牌リストを用いて # # 自身を再帰的に呼び出す # ################################################################ def list_mati(li): rtn = set([]) ################################################### # メンツが含まれない場合(牌が1,2枚だった場合)# ################################################### # 残り1牌だった場合、その牌を返す if len(li) == 1: return set([li[0]]) # 残り2牌だった場合 elif len(li) == 2: # トイツができていた場合 if li[0] == li[1]: rtn.add(li[0]) # ターツができていた場合 elif li[0]+1 == li[1]: if li[0] != 1: rtn.add(li[0]-1) if li[1] != 9: rtn.add(li[1]+1) # カンチャン待ちの場合 elif li[0]+2 == li[1]: rtn.add(li[0]+1) # 役を作成出来ない場合 else: pass else: ################################################### # メンツが含まれる可能性がある場合 # #(牌が3枚以上だった場合) # # ※ただし、牌が0枚だった場合もここで処理される # ################################################### # 次局面(牌リスト)を列挙する if len(li) % 3 == 1: # まだターツを取り除いていない場合 # ターツを取り除いた各局面につき再帰する for p in enumerate_toitsu_del_situations(li): rtn |= list_mati(p) # シュンツを取り除いた各局面につき再帰する for p in enumerate_shuntsu_del_situations(li): rtn |= list_mati(p) # コーツを取り除いた各局面について再帰する for p in enumerate_kohtsu_del_situations(li): rtn |= list_mati(p) # 待ち牌のセットを返す return rtn ################################################################## # 与えられた牌リストについて、メンツ(またはコウツ)を取り除いた # # 牌リストのリストを返すメソッド群 # ################################################################## def enumerate_toitsu_del_situations(li): rtn = [] for toex in enumerate_toitsu(li): li_aft = li[:] li_aft.remove(toex) li_aft.remove(toex) rtn.append(li_aft) return rtn def enumerate_shuntsu_del_situations(li): rtn = [] for toex in enumerate_shuntsu(li): li_aft = li[:] li_aft.remove(toex) li_aft.remove(toex+1) li_aft.remove(toex+2) rtn.append(li_aft) return rtn def enumerate_kohtsu_del_situations(li): rtn = [] for toex in enumerate_kohtsu(li): li_aft = li[:] li_aft.remove(toex) li_aft.remove(toex) li_aft.remove(toex) rtn.append(li_aft) return rtn ################################################################## # 与えられた牌リストについて、メンツ(またはコウツ)を # # 列挙するメソッド群 # # ※ただし、返り値は各メンツ(またはコウツ)の先頭牌である # # 例) # # enumerate_shuntsu([1,2,3,4]) → [1,2] # ################################################################## def enumerate_toitsu(li): rtn = set([]) for i in range(0, len(li)-1): if li[i] == li[i+1]: rtn.add(li[i]) return rtn def enumerate_shuntsu(li): set0 = set(li) set1 = set(map(lambda x: x-1, li)) set2 = set(map(lambda x: x-2, li)) return set0 & set1 & set2 def enumerate_kohtsu(li): rtn = set([]) for i in range(0, len(li)-2): if li[i] == li[i+2]: rtn.add(li[i]) return rtn # main関数を呼び出す if __name__ == '__main__': main()