スキルはあるが飯は食えないかもしれない
仕事が一段落したので、久しぶりの更新です。
あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定
面白そうなのでPythonで解いてみました、実装時間は1時間くらいです。
Pythonすごいなー、C++やJavaでやれって言われたら3時間では終わらんわ・・・
#!/usr/bin/env python #-*- coding:utf-8 -*- import sys import itertools def main(input): # 牌情報を"牌が何個あるか"という数値配列形式に変換 # 例) 1223344888999 => [1, 2, 2, 2, 0, 0, 0, 3, 3] t = sorted([int(x) for x in input]) num_hi = [t.count(x) for x in range(1,10)] # 順子・刻子・アタマのすべての要素を列挙します pieces = getPieces(num_hi) #すべての要素から4要素の組み合わせでサーチします ans = set() for p in itertools.combinations(pieces, 4): # 牌情報から4要素を抜き取る t_num_hi = num_hi[:] subHi(t_num_hi, p[0]) subHi(t_num_hi, p[1]) subHi(t_num_hi, p[2]) subHi(t_num_hi, p[3]) # 残り枚数2枚以上、または値がマイナスだったら無効 if sum(t_num_hi) > 2 or min(t_num_hi) < 0: continue # 残った配牌から最後の要素を取得 last = getLastPices(t_num_hi) if last: # 有効な要素が取得できたら、その組み合わせは有効 # 文字列変換&ソートして集合へ追加する t = sorted(["".join([str(x) for x in y]) for y in p]) t = "".join(["("+x+")" for x in t]) t += "["+"".join([str(x) for x in last])+"]" ans.add(t) #結果表示 for a in ans: print a def getPieces(num_hi): # 順子・刻子・アタマのすべての要素を列挙します ret = [] #刻子 ret += [[i+1]*3 for (i,x) in enumerate(num_hi) if x>=3] #アタマ ret += [[i+1]*2 for (i,x) in enumerate(num_hi) if x>=2] #順子 for i in range(10-3): m = min(num_hi[i:i+3]) if m > 0: ret += [[i+1,i+2,i+3]]*m return ret def getLastPices(num_hi): # 残り1〜2牌から有効な要素を取得 sum_num = sum(num_hi) if sum_num == 1: # 残り1枚の場合は裸単騎 return [num_hi.index(1)+1] elif sum_num == 2: if 2 in num_hi: # 残り2枚、かつ同種類の場合はシャンポン待ち return [num_hi.index(2)+1, num_hi.index(2)+1] else: for i in range(10-3): if sum(num_hi[i:i+3]) == 2: # 残り2枚、かつ牌が数字が連続または1枚飛ばしなら # 両面 or ペンチャン or カンチャン待ち return [idx+1 for idx,x in enumerate(num_hi) if x==1] return None def subHi(num_hi, elm): # 牌情報から要素を抜き取る for x in elm: num_hi[x-1] -= 1 if __name__ == "__main__": main(sys.argv[1])
出力結果は以下の通り。
>mahjong.py 1223344888999 (234)(234)(888)(999)[1] (123)(44)(888)(999)[23] (123)(234)(888)(999)[4] >mahjong.py 1112345678999 (111)(234)(678)(999)[5] (11)(123)(456)(999)[78] (123)(456)(789)(99)[11] (11)(123)(456)(789)[99] (111)(345)(678)(999)[2] (11)(123)(678)(999)[45] (111)(456)(789)(99)[23] (111)(234)(567)(999)[8] (111)(234)(567)(99)[89] (111)(234)(789)(99)[56] (11)(345)(678)(999)[12]
コードは"シンプル&わかりやすさ"を重視しました。
「組み合わせ」はitertoolsを使っています、反則・・・?
きっと出題者は再帰を使って欲しいんだろうな、使いませんけど。
ほどよい難易度で問題自体はすごく楽しかったけど、これでプログラマの実力は測れるかな・・・?
麻雀ルールを知らないと準備にかなり時間かかる気がします。
でも、実際にスキルあっても飯が食えないよなー、ゲーム業界は大手(任天堂除く)でも給料安いし。
本当に人材を探したいならゲーム業界を探すといいかもしれませんよ。
安くてスキルが高い人はゴロゴロいるよー(泣)
P.S
要件定義に同牌は4枚までと明記されていない事に気づきました。
てことは「1111111111111」も待ちアリにしないとダメ・・・?
同牌を4枚以上に対応したい場合は、getPieces()を以下のように書き換えればOK
def getPieces(num_hi): # 順子・刻子・アタマのすべての要素を列挙します ret = [] #刻子 #ret += [[i+1]*3 for (i,x) in enumerate(num_hi) if x>=3] #アタマ #ret += [[i+1]*2 for (i,x) in enumerate(num_hi) if x>=2] # ↓のように書き換えます #刻子&アタマ for (i,x) in enumerate(num_hi): for y in range(x//3): ret += [[i+1]*3] for y in range(x//2): ret += [[i+1]*2] #順子 for i in range(10-3): m = min(num_hi[i:i+3]) if m > 0: ret += [[i+1,i+2,i+3]]*m return ret
出力結果は以下の通り。
>majong.py 1111111111111 (111)(111)(111)(111)[1] (11)(111)(111)(111)[11]
うーん、考えすぎかな・・・?