Skip to content

Instantly share code, notes, and snippets.

@YSRKEN
Created January 7, 2019 13:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YSRKEN/8b3b85bdb69e1e847d883afbd3c9d378 to your computer and use it in GitHub Desktop.
Save YSRKEN/8b3b85bdb69e1e847d883afbd3c9d378 to your computer and use it in GitHub Desktop.
「大石泉すきポーカー」の手役の強さ判定プログラムをPythonで書きました ref: https://qiita.com/YSRKEN/items/d17a93ef36b1dcb758b4
def judge_hand(name: str) -> int:
"""役を判定する
Parameters
----------
name : str
「大石泉すき」から重複を許して5文字取って並べたもの
Returns
-------
int
判定された役(0がロイヤルストレートフラッシュ、ブタが8)
"""
# 各文字をバラす
name_char = list(name)
# 各文字の出現回数を数え、出現回数部分だけ抽出したもの。
# 例:「大大すすき」→[2, 2, 1]
char_count = collections.Counter(name_char).values()
# 手役の判定処理
if name == '大石泉すき':
# 説明不要
return 0
elif len(set(name_char)) == 1:
# uniq処理を施して1つしか残らない=ファイブカード
return 1
elif 4 in char_count:
# ある文字が4つある=フォーカード
return 2
elif len(char_count) == 5:
# 5種類ある=元の文字列が5文字なので各文字ある=ストレートフラッシュ
return 3
elif 2 in char_count and 3 in char_count:
# 出現回数に「2」と「3」がある=フルハウス
return 4
elif 'すき' in name:
# すき
return 5
elif 3 in char_count:
# 出現回数に「3」がある=スリーカード
return 6
elif 2 in char_count and len(char_count) == 3:
# 出現回数が3文字分あって「2」が含まれる=消去法からツーペア
return 7
return 8
def compare_hand(a: str, b: str) -> int:
"""手役を比較する
Parameters
----------
a : str
「大石泉すき」から重複を許して5文字取って並べたもの1
b : str
「大石泉すき」から重複を許して5文字取って並べたもの2
Returns
-------
int
aが強ければ-1、同じなら0、bが強ければ1
"""
# 役が異なれば当然そこで判定できる
hand1 = judge_hand(a)
hand2 = judge_hand(b)
if hand1 != hand2:
if hand1 < hand2:
return -1
if hand1 > hand2:
return 1
# 「同じ強さの場合「すき」が(より後ろで)揃っているものが勝つ。」
# 「同じ強さですきの位置も同じの場合正位置に近い文字数が多いものが勝つ。」
# 「上記2つのいずれも同数の場合、正位置にある文字の画数が多いものが勝つ。」
return 0
# 「同じ強さの場合「すき」が(より後ろで)揃っているものが勝つ。」
pos1 = a.find('すき')
pos2 = b.find('すき')
if pos1 != pos2:
if pos1 < pos2:
return 1
if pos1 > pos2:
return -1
def calc_pos_score(x: str) -> int:
p1: int = '大石泉すき'.find(x[0:1])
p2: int = max('石泉すき'.find(x[1:2]), '石大'.find(x[1:2]))
p3: int = max('泉すき'.find(x[2:3]), '泉石大'.find(x[2:3]))
p4: int = max('すき'.find(x[3:4]), 'す泉石大'.find(x[3:4]))
p5: int = 'きす泉石大'.find(x[4:5])
sum = 0
sum += 1 if p1 == 0 else 0
sum += 1 if p2 == 0 else 0
sum += 1 if p3 == 0 else 0
sum += 1 if p4 == 0 else 0
sum += 1 if p5 == 0 else 0
return sum
# 「同じ強さですきの位置も同じの場合正位置に近い文字数が多いものが勝つ。」
ssd1 = calc_pos_score(a)
ssd2 = calc_pos_score(b)
if ssd1 != ssd2:
if ssd1 < ssd2:
return 1
if ssd1 > ssd2:
return -1
def calc_stroke_score(x: str) -> int:
p1: int = '大石泉すき'.find(x[0:1])
p2: int = max('石泉すき'.find(x[1:2]), '石大'.find(x[1:2]))
p3: int = max('泉すき'.find(x[2:3]), '泉石大'.find(x[2:3]))
p4: int = max('すき'.find(x[3:4]), 'す泉石大'.find(x[3:4]))
p5: int = 'きす泉石大'.find(x[4:5])
sum = 0
sum += 3 if p1 == 0 else 0
sum += 5 if p2 == 0 else 0
sum += 9 if p3 == 0 else 0
sum += 2 if p4 == 0 else 0
sum += 4 if p5 == 0 else 0
return sum
# 「上記2つのいずれも同数の場合、正位置にある文字の画数が多いものが勝つ。」
stroke1 = calc_stroke_score(a)
stroke2 = calc_stroke_score(b)
if stroke1!= stroke2:
if stroke1< stroke2:
return 1
if stroke1> stroke2:
return -1
大大大大石/大大大大泉
大大大大石/大大大大す
大大大大石/大大大石大
大大大大石/大大大泉大
(中略)
287564通り
大大大大石/大大大石大
(中略)
24942通り
import collections
import itertools
def judge_hand(name: str) -> int:
"""役を判定する
Parameters
----------
name : str
「大石泉すき」から重複を許して5文字取って並べたもの
Returns
-------
int
判定された役(0がロイヤルストレートフラッシュ、ブタが8)
"""
# 各文字をバラす
name_char = list(name)
# 各文字の出現回数を数え、出現回数部分だけ抽出したもの。
# 例:「大大すすき」→[2, 2, 1]
char_count = collections.Counter(name_char).values()
# 手役の判定処理
if name == '大石泉すき':
# 説明不要
return 0
elif len(set(name_char)) == 1:
# uniq処理を施して1つしか残らない=ファイブカード
return 1
elif 4 in char_count:
# ある文字が4つある=フォーカード
return 2
elif len(char_count) == 5:
# 5種類ある=元の文字列が5文字なので各文字ある=ストレートフラッシュ
return 3
elif 2 in char_count and 3 in char_count:
# 出現回数に「2」と「3」がある=フルハウス
return 4
elif 'すき' in name:
# すき
return 5
elif 3 in char_count:
# 出現回数に「3」がある=スリーカード
return 6
elif 2 in char_count and len(char_count) == 3:
# 出現回数が3文字分あって「2」が含まれる=消去法からツーペア
return 7
return 8
def calc_pos_score(x: str) -> int:
p1: int = '大石泉すき'.find(x[0:1])
p2: int = max('石泉すき'.find(x[1:2]), '石大'.find(x[1:2]))
p3: int = max('泉すき'.find(x[2:3]), '泉石大'.find(x[2:3]))
p4: int = max('すき'.find(x[3:4]), 'す泉石大'.find(x[3:4]))
p5: int = 'きす泉石大'.find(x[4:5])
sum = 0
sum += 1 if p1 == 0 else 0
sum += 1 if p2 == 0 else 0
sum += 1 if p3 == 0 else 0
sum += 1 if p4 == 0 else 0
sum += 1 if p5 == 0 else 0
return sum
def calc_stroke_score(x: str) -> int:
p1: int = '大石泉すき'.find(x[0:1])
p2: int = max('石泉すき'.find(x[1:2]), '石大'.find(x[1:2]))
p3: int = max('泉すき'.find(x[2:3]), '泉石大'.find(x[2:3]))
p4: int = max('すき'.find(x[3:4]), 'す泉石大'.find(x[3:4]))
p5: int = 'きす泉石大'.find(x[4:5])
sum = 0
sum += 3 if p1 == 0 else 0
sum += 5 if p2 == 0 else 0
sum += 9 if p3 == 0 else 0
sum += 2 if p4 == 0 else 0
sum += 4 if p5 == 0 else 0
return sum
def calc_stroke_not_score(x: str) -> int:
p1: int = '大石泉すき'.find(x[0:1])
p2: int = max('石泉すき'.find(x[1:2]), '石大'.find(x[1:2]))
p3: int = max('泉すき'.find(x[2:3]), '泉石大'.find(x[2:3]))
p4: int = max('すき'.find(x[3:4]), 'す泉石大'.find(x[3:4]))
p5: int = 'きす泉石大'.find(x[4:5])
stroke_dict = {
"大": 3,
"石": 5,
"泉": 9,
"す": 2,
"き": 4
}
sum = 0
sum += stroke_dict[x[0:1]] if p1 != 0 else 0
sum += stroke_dict[x[1:2]] if p2 != 0 else 0
sum += stroke_dict[x[2:3]] if p3 != 0 else 0
sum += stroke_dict[x[3:4]] if p4 != 0 else 0
sum += stroke_dict[x[4:5]] if p5 != 0 else 0
return sum
def compare_hand(a: str, b: str) -> int:
"""手役を比較する
Parameters
----------
a : str
「大石泉すき」から重複を許して5文字取って並べたもの1
b : str
「大石泉すき」から重複を許して5文字取って並べたもの2
Returns
-------
int
aが強ければ-1、同じなら0、bが強ければ1
"""
if a == b:
return 0
# 役が異なれば当然そこで判定できる
hand1 = judge_hand(a)
hand2 = judge_hand(b)
if hand1 != hand2:
if hand1 < hand2:
return -1
if hand1 > hand2:
return 1
# 「同じ強さの場合「すき」が(より後ろで)揃っているものが勝つ。」
pos1 = a.find('すき')
pos2 = b.find('すき')
if pos1 != pos2:
if pos1 < pos2:
return 1
if pos1 > pos2:
return -1
# 「同じ強さですきの位置も同じの場合正位置に近い文字数が多いものが勝つ。」
ssd1 = calc_pos_score(a)
ssd2 = calc_pos_score(b)
if ssd1 != ssd2:
if ssd1 < ssd2:
return 1
if ssd1 > ssd2:
return -1
# 「上記2つのいずれも同数の場合、正位置にある文字の画数が多いものが勝つ。」
stroke1 = calc_stroke_score(a)
stroke2 = calc_stroke_score(b)
if stroke1 != stroke2:
if stroke1 < stroke2:
return 1
if stroke1 > stroke2:
return -1
# 「正位置にない文字の画数が少ないものが勝つ。」
stroke1 = calc_stroke_not_score(a)
stroke2 = calc_stroke_not_score(b)
if stroke1 != stroke2:
if stroke1 < stroke2:
return -1
if stroke1 > stroke2:
return 1
# 単純な比較関数
return -1 if stroke1 < stroke2 else 1
# メインルーチン
if __name__ == '__main__':
# テスト用
print(compare_hand('大石泉きす', '大石大石泉')) # -1
print(compare_hand('泉す泉すき', '大大泉石石')) # -1
print(compare_hand('す泉太すき', '泉泉すきす')) # -1
print(compare_hand('大石すき泉', '泉大すき石')) # -1
print(compare_hand('泉泉石きき', '大大石泉泉')) # -1
print(compare_hand('すき泉きす', 'すき石石き')) # -1
# 以下、全通りをテストするためのコード
# 使用する文字の種類
chars = '大石泉すき'
# itertools.productを利用して、重複順列を作り出し、1セットづつname_charに取り出す
name_list = []
for name_char in itertools.product(chars, repeat=5):
# name_charの全文字を結合したものをnameとする
name = ''.join(name_char)
name_list.append(name)
# 検証を行う
sum = 0
for a_name in name_list:
for b_name in name_list:
if a_name != b_name:
result = compare_hand(a_name, b_name)
if result == 0:
if sum < 10:
print(a_name + "/" + b_name)
sum += 1
print("{0}通り".format(str(sum)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment