こんにちは、みやびのです。

本講座はPythonistaを活用してポーカーゲームを作成する方法について解説するものです。(全5回を予定)

第1回となる今回は、Pythonでポーカーの基本となる処理を作成します。

本記事の内容は以下の通り。

・Pythonでポーカーを作成する場合の基本処理
・Pythonでポーカー作成の実装例と実行例

本記事を読めばPythonでポーカーを作る時にどんな処理を作成すればよいか理解できます。

Pythonでポーカーを作成する場合の基本処理

まずはポーカーの基本処理をPythonで作成する方法を紹介します。

トランプゲームの基本処理

トランプの基本処理は以下の3つです。

・山札の作成
・シャッフル
・カードを引く処理

山札を作成する処理は以下の通り。

for symbol in symbol_list:
	for number in range(1, 14):
		card = {
			'number' : number,
			'symbol' : symbol
		}
		# マークと数字を合体させる
		# 11以上と1は置き換え
		if number == 1:
			card['string'] = symbol + 'A'
		elif number == 11:
			card['string'] = symbol + 'J'
		elif number == 12:
			card['string'] = symbol + 'Q'
		elif number == 13:
			card['string'] = symbol + 'K'
		else:
			# 10以下ならそのまま
			card['string'] = symbol + str(number)

		# カードをリストに追加
		card_list.append(card)
			
	self.card_list = card_list

トランプカードのデータは比較しやすいように以下の辞書型で作成します。

card = {
	'number' : number, # 数字
	'symbol' : symbol, # マーク
	'string' : symbol + str(number), # マーク + 数字の文字列。
}

シャッフル処理の方法は以下の通り。
random.shuffle()を使うことで簡単に配列のシャッフルができます。

random.shuffle(card_list)

カードを引く処理は以下の通り。
pop(0)とした場合先頭の値を取り出します。

card_list.pop(0)

具体的な手順については「【Python】random.shuffle()の活用例」をお読みください。

ポーカーの役

ポーカーの役を知るために最低限必要な情報は、

・フラッシュが成立しているかどうか?
・ストレートが成立しているかどうか?
・同じ数字は枚数あるか?
・ペアの数はいくつあるか?
・数字が「10,J,Q,K,A」か?

の5つです。

上記情報がわかればポーカーの役を全て表現することができます。

ポーカーの役と条件は以下の通り。

条件
ロイヤルストレートフラッシュ「ストレート」かつ「フラッシュ」かつ「数字が10,J,Q,K,A」
ストレートフラッシュ「ストレート」かつ「フラッシュ」
4カード同じ数字が4枚
フルハウス「3カード」かつ残り2枚が「1ペア」
フラッシュ全て同じマーク
ストレート連続した数字。「数字が10,J,Q,K,A」の場合もストレートが成立
3カード同じ数字が3枚
2ペア同じ数字のペアが2つ
1ペア同じ数字のペアが1つ
ぶたどの役も成立しない

役の比較チェックループ

まずはループで1枚ずつ比較して4つの条件をチェックします。
・フラッシュが成立しているかどうか?
・ストレートが成立しているかどうか?
・同じ数字は枚数あるか?
・ペアの数はいくつあるか?

昇順に並べかえると「同じ数字」と「連続した数字」が並ぶので隣同士の比較だけで全チェックができるのでループは4回ですみます。

◆フラッシュが成立しているかどうか?
・フラッシュフラグをTrueにしておく
・直前のカードと現在のカードを比較してマークが違う場合はFalseにする
・同じ場合はそのまま
・最終的にTrueのままならフラッシュ成立

◆ストレートが成立しているかどうか?
・ストレートフラグをTrueにしておく
・直前のカードと現在のカードを比較して連続した数字の場合は継続。違う場合はフラグを落とす
・直前のカードがAかつ現在のカードが10の場合は継続(10,J,Q,K,Aの可能性があるため)
・最終的にTrueのままならストレート成立

◆同じ数字は枚数あるか?
・直前のカードと現在のカードを比較して同じ数字の場合はマッチカウントをカウントアップ
・違う数字の場合はマッチカウントを0に戻す

◆違う数字及び最終ループでやること
・マッチカウントが1の場合はペアカウントをカウントアップ
・マッチカウントが2の場合は3カード(ペアカウントはアップしない)
・カウントが3の場合は4カード(ペアカウントはアップしない)

後はフラグとカウントを見て条件をチェックしていきます。
上記条件をまとめたコードは以下の通り。

	# 役のチェック処理
	def check_poker_hand(self):
		# ペア数
		pair_count = 0
		# 同じ数字のカウント
		match_count = 0
		# 同じ数字の枚数(3カード,4カードチェック用)
		match_number = 0
		# フラッシュの有無フラグ
		flash_flag = True
		# ストレートの有無フラグ
		straight_flag = True
		
		# 数字の昇順に並び替える
		cards = sorted(self.draw_cards, key=lambda x:x['number'])
		
		# 比較チェックループ(2枚目から)
		for i in range(1,5):
				# 前の数字が同じかチェック
				if cards[i]['number'] == cards[i - 1]['number']:
					match_count += 1
					# 最終ループチェック
					if i == 4:
						if match_count == 1:
							pair_count += 1
						# 3カード以上の場合
						elif match_count > 1:
							match_number = match_count + 1
				else:
					# 違う数字の場合
					if match_count == 1:
						pair_count += 1
					# 3カード以上の場合
					elif match_count > 1:
						match_number = match_count + 1
					match_count = 0
				# 同じマークが続いているかチェック
				if flash_flag == True and cards[i]['symbol'] != cards[i - 1]['symbol']:
					flash_flag = False
				# 数字が連続しているかチェック
				if straight_flag == True and cards[i]['number'] != cards[i - 1]['number'] + 1:
					if cards[i]['number'] != 10 or cards[i-1]['number'] != 1:
						straight_flag = False 
		
		# 最終手札チェック
		if straight_flag == True and flash_flag == True:
			if cards[0]['number'] == 1 and cards[4]['number'] == 13:
				# ロイヤルストレートフラッシュ
				hand = 'ロイヤルnストレートフラッシュ'
			else:
				# ストレートフラッシュ
				hand = 'ストレートフラッシュ'
		elif match_number > 2:
			if match_number == 4:
				# 4カード
				hand = '4カード'
			else:
				if pair_count > 0:
					# フルハウス
					hand = 'フルハウス'
				else:
					# 3カード
					hand = '3カード'
		elif flash_flag == True:
			# フラッシュ
			hand = 'フラッシュ'
		elif straight_flag == True:
			# ストレート
			hand = 'ストレート'
		elif pair_count > 0:
			if pair_count > 1:
				# 2ペア
				hand = '2ペア'
			else:
				# 1ペア
				hand = '1ペア'
		else:
			# なし
			hand = 'ぶた'
		
		return hand

Pythonでポーカー作成の実装例と実行例

これまでの処理を全てまとめたコードは以下の通り。

import random

class TrumpGame:
	def make_card_list(self):	
		# マークのリスト
		symbol_list = ['Clubs', 'Hearts', 'Spades', 'Diamonds']
		# カードリスト
		card_list = []

		# カードのデータを作成
		for symbol in symbol_list:
			for number in range(1, 14):
				card = {
					'number' : number,
					'symbol' : symbol
				}
				# マークと数字を合体させる
				# 11以上と1は置き換え
				if number == 1:
					card['string'] = symbol + 'A'
				elif number == 11:
					card['string'] = symbol + 'J'
				elif number == 12:
					card['string'] = symbol + 'Q'
				elif number == 13:
					card['string'] = symbol + 'K'
				else:
					# 10以下ならそのまま
					card['string'] = symbol + str(number)

				# カードをリストに追加
				card_list.append(card)
			
		self.card_list = card_list
	def shuffle(self):
			# カードをシャッフルする
			random.shuffle(self.card_list)
			
	# 手札を作成する
	def reset_draw_cards(self, number):
		card_list = self.make_card_list()
		self.shuffle()
		self.draw_cards = []

		for i in range(0, number):
			self.draw_cards.append(
				self.card_list.pop(0)
			)	
	
	# 役のチェック処理
	def check_poker_hand(self):
		# ペア数
		pair_count = 0
		# 同じ数字のカウント
		match_count = 0
		# 同じ数字の枚数(3カード,4カードチェック用)
		match_number = 0
		# フラッシュの有無フラグ
		flash_flag = True
		# ストレートの有無フラグ
		straight_flag = True
		
		# 数字の昇順に並び替える
		cards = sorted(self.draw_cards, key=lambda x:x['number'])
		
		# 比較チェックループ
		for i in range(1,5):
				# 前の数字が同じかチェック
				if cards[i]['number'] == cards[i - 1]['number']:
					match_count += 1
					# 最終ループチェック
					if i == 4:
						if match_count == 1:
							pair_count += 1
						# 3カード以上の場合
						elif match_count > 1:
							match_number = match_count + 1
				else:
					# 違う数字の場合
					if match_count == 1:
						pair_count += 1
					# 3カード以上の場合
					elif match_count > 1:
						match_number = match_count + 1
					match_count = 0
				# 同じマークが続いているかチェック
				if flash_flag == True and cards[i]['symbol'] != cards[i - 1]['symbol']:
					flash_flag = False
				# 数字が連続しているかチェック
				if straight_flag == True and cards[i]['number'] != cards[i - 1]['number'] + 1:
					if cards[i]['number'] != 10 or cards[i-1]['number'] != 1:
						straight_flag = False 
		
		# 最終手札チェック
		if straight_flag == True and flash_flag == True:
			if cards[0]['number'] == 1 and cards[4]['number'] == 13:
				# ロイヤルストレートフラッシュ
				hand = 'ロイヤルnストレートフラッシュ'
			else:
				# ストレートフラッシュ
				hand = 'ストレートフラッシュ'
		elif match_number > 2:
			if match_number == 4:
				# 4カード
				hand = '4カード'
			else:
				if pair_count > 0:
					# フルハウス
					hand = 'フルハウス'
				else:
					# 3カード
					hand = '3カード'
		elif flash_flag == True:
			# フラッシュ
			hand = 'フラッシュ'
		elif straight_flag == True:
			# ストレート
			hand = 'ストレート'
		elif pair_count > 0:
			if pair_count > 1:
				# 2ペア
				hand = '2ペア'
			else:
				# 1ペア
				hand = '1ペア'
		else:
			# なし
			hand = 'ぶた'
		
		return hand

if __name__ == '__main__':
	tg = TrumpGame()
	tg.reset_draw_cards(5)
	for card in tg.draw_cards:
		print(card['string'])
	print(tg.check_poker_hand())
	
		

※判定に冗長な部分があるのでリファクター予定

>>ソースコードをGitHubで見る

◆実行例

Hearts5
Hearts9
Spades4
Clubs9
Hearts2
1ペア

以上、Pythonでポーカーを作成する方法でした。
次回は今回作成したポーカーをPythonistaで画面表示する方法について紹介します。

次回>>第2回 Pythonistaでポーカーゲームを画面表示する

講座TOP>>Pythonista+sceneポーカー作成講座