codepad
[
create a new paste
]
login
|
about
Language:
C
C++
D
Haskell
Lua
OCaml
PHP
Perl
Plain Text
Python
Ruby
Scheme
Tcl
#coding: utf-8 import sys import re import copy def main(): hands = '1112345678999' _validate(hands) tiles = [0] * 9 for tile in hands: tiles[int(tile) - 1] += 1 # 5 枚以上あったら終了 if tiles[int(tile) - 1] > 4: sys.exit('Error') pong, chow, pair = _pickup_melds(tiles) _analyze(pong, chow, pair, tiles) def _validate(hands): """ とりあえず 13 文字で [1-9] であることだけチェック """ if not re.compile(r'^[1-9]{13}$').search(hands): sys.exit('Error') def _pickup_melds(tiles): """ 13 牌が取り得る全ての面子を抽出する。 """ # 刻子 pongs = [] for i, count in enumerate(tiles): if count >= 3: pongs.append(('pong', i)) # 順子 同じ面子が複数取れる場合も重複して抽出する。 chows = [] for i in xrange(7): for j in (1, 2, 3, 4): if tiles[i] < j or tiles[i + 1] < j or tiles[i + 2] < j: break chows.append(('chow', i)) # 対子 pairs = [] for i, count in enumerate(tiles): if count >= 2: pairs.append(('pair', i)) return pongs, chows, pairs def _analyze(pongs, chows, pairs, tiles): """ 聴牌しているかどうかを調べて、聴牌時は出力する。 """ fix_melds = [] # 単騎待ち (4面子確定) for cmb in _get_cmb(pongs + chows, 4): if cmb in fix_melds: continue fix_melds.append(cmb) is_ready, ready = _is_ready_hands(_inspect(cmb, tiles)) if is_ready: _print_melds(cmb, ready) # 単騎以外 (3面子 + 雀頭) for pair in pairs: for cmb in _get_cmb(pongs + chows, 3): if cmb + [pair] in fix_melds: continue fix_melds.append(cmb + [pair]) is_ready, ready = _is_ready_hands(_inspect(cmb + [pair], tiles)) if is_ready: _print_melds(cmb + [pair], ready) def _inspect(melds, tiles): """ tiles から全ての melds を取り出して、 tiles に矛盾(枚数が負になる) がなければ残りの _tiles を返す。 """ _tiles = copy.copy(tiles) for meld in melds: if meld[0] == 'pong': _tiles[meld[1]] -= 3 if _is_invalid(_tiles): break elif meld[0] == 'pair': _tiles[meld[1]] -= 2 if _is_invalid(_tiles): break elif meld[0] == 'chow': _tiles[meld[1]] -= 1 _tiles[meld[1] + 1] -= 1 _tiles[meld[1] + 2] -= 1 if _is_invalid(_tiles): break else: return _tiles def _is_ready_hands(tiles): """ 聴牌チェック ここでの聴牌チェックは、_inspect の結果、残った牌が単騎待ち であるか、または塔子を構成しているかのチェックである """ if not tiles: return False, None # tiles の枚数チェック 1 or 2 でなければならない tiles_count = sum(tiles) if tiles_count not in (1, 2): return False, None # 1 枚なら単騎待ち if tiles_count == 1: return True, '%d' % \ ([i for i, c in enumerate(tiles) if c == 1][0] + 1) # 1 枚以外 (== 2枚) なら待ちの形を調査して適切に返却する。 for idx, count in enumerate(tiles): tile = idx + 1 if count == 2: return True, '%d%d' % (tile, tile) elif count == 1: if tiles[idx + 1] == 1: return True, '%d%d' % (tile, tile + 1) elif tiles[idx + 2] == 1: return True, '%d%d' % (tile, tile + 2) else: break return False, None def _get_cmb(melds, n): """ melds から n 個をとる組み合わせを返す。n = 3 or 4 しか使えない。 """ if n not in (3, 4): sys.exit('Error') length = len(melds) for i in range(length): for j in range(i + 1, length): for k in range(j + 1, length): if n == 3: yield [melds[i], melds[j], melds[k]] else: for l in range(k + 1, length): yield [melds[i], melds[j], melds[k], melds[l]] def _is_invalid(tiles): """ tiles の要素がひとつでも負の値になっていた場合は False を返す。 """ return bool(len([count for count in tiles if count < 0])) def _print_melds(melds, ready): """ melds と ready を形式を整えて画面に出力する。 """ format_melds = [] for meld in melds: if meld[0] == 'pong': tile = meld[1] + 1 format_melds.append('(%d%d%d)' % tuple([tile] * 3)) if meld[0] == 'chow': tile = meld[1] + 1 format_melds.append('(%d%d%d)' % (tile, tile + 1, tile + 2)) if meld[0] == 'pair': tile = meld[1] + 1 format_melds.append('(%d%d)' % tuple([tile] * 2)) print '%s [%s]' % (' '.join(format_melds), ready) if __name__ == '__main__': main()
Private
[
?
]
Run code
Submit