概要
オブジェクト指向再学習のために「なぜ,あなたはJavaでオブジェクト指向開発ができないのか」を購入したが、Java・Rubyでしか公式サンプルがなかったのでPythonで作成してみました。
(あくまで参考程度にしてください。私も初心者です。)
Lesson 5 まで(ジャンケンプログラム)
全体の処理進行
object_janken.py
from judge import *
from player import *
from tactics import *
# 審判(斎藤さん)のインスタンス生成
saito = Judge()
# プレイヤー1(村田さん)の生成
murata_tactics = RandomTactics()
murata = Player("村田さん",murata_tactics)
# プレイヤー2(山田さん)の生成
yamada_tactics = StoneOnlyTactics()
yamada = Player("山田さん",yamada_tactics)
# yamada = Player_STONE("山田さん")
# 村田さんと山田さんをプレイヤーとしてジャンケンを開始する
saito.start_janken(murata, yamada)
プレイヤークラス
player.py
class Player:
# ジャンケンの手を表す定数
STONE = 0 # グー
SCISSORS = 1 # チョキ
PAPER = 2 # パー
def __init__(self, name, tactics):
self.name = name
self.win_count = 0
self.tactics = tactics
# ジャンケンの手を出す。
def show_hand(self):
hand = self.tactics.read_tactics()
return hand
# 審判から勝敗を聞く。勝ったら、引数 result は true
def notify_result(self,result):
if (result):
self.win_count += 1
# 自分の勝った回数を答える。
def get_win_count(self):
return self.win_count
# 自分の名前を答える。
def get_name(self):
return self.name
# 継承し子クラス作成
class Player_STONE(Player):
def show_hand(self):
return self.STONE
ジャッジクラス
judge.py
class Judge:
# ジャンケンを開始する。
def start_janken(self, player1, player2):
# ジャンケンの開始を宣言する
print("【ジャンケン開始】\n")
# ジャンケンを3回行う
for cnt in range(3):
# 何回戦目か表示する
print("【", (cnt + 1), "回戦目】")
# プレイヤーの手を見て、どちらが勝ちかを判定する。
winner = self.judge_janken(player1, player2)
if (winner != None):
# 勝者を表示する
print("\n", winner.get_name(), "が勝ちました!\n")
# 勝ったプレイヤーへ結果を伝える
winner.notify_result(True)
else:
# 引き分けの場合
print("\n引き分けです!\n")
# ジャンケンの終了を宣言する
print("【ジャンケン終了】\n")
# 最終的な勝者を判定する
final_winner = self.judge_final_winner(player1, player2)
print(player1.get_win_count(), " 対 ", player2.get_win_count(), "で")
if (final_winner != None):
print(final_winner.get_name(), "の勝ちです!\n")
else:
print("引き分けです!\n")
# プレイヤーの手を見て、どちらが勝ちかを判定する。
def judge_janken(self,player1, player2):
winner = None
hand_dict = {0: "STONE",
1: "SCISSORS",
2: "PAPER"}
# プレイヤーの手を出す
player1hand = player1.show_hand()
player2hand = player2.show_hand()
player1hand_name = hand_dict[player1hand]
player2hand_name = hand_dict[player2hand]
# それぞれの手を表示する
print(f"{player1hand_name} vs. {player2hand_name} \n")
# プレイヤー1が勝つ場合
if (player1hand_name == "STONE" and player2hand_name == "SCISSORS") or \
(player1hand_name == "SCISSORS" and player2hand_name == "PAPER") or \
(player1hand_name == "PAPER" and player2hand_name == "STONE") :
winner = player1
# プレイヤー2が勝つ場合
if (player1hand_name == "STONE" and player2hand_name == "PAPER") or \
(player1hand_name == "SCISSORS" and player2hand_name == "STONE") or \
(player1hand_name == "PAPER" and player2hand_name == "SCISSORS") :
winner = player2
# どちらでもない場合は引き分け(nilを返す)
return winner
# 最終的な勝者を判定する。
def judge_final_winner(self,player1, player2):
final_winner = None
# 勝ち数を聞く
player1_win_count = player1.get_win_count()
player2_win_count = player2.get_win_count()
# 勝者を決定
if (player1_win_count > player2_win_count):
final_winner = player1
elif(player1_win_count < player2_win_count):
final_winner = player2
else:
final_winner = None
return final_winner
戦略クラス
tactics.py
class RandomTactics():
def read_tactics(self):
# 0.0以上3.0未満の小数として乱数を得る
random_num = rm.random()* 3.0
if (random_num < 1.0):
hand = Player.STONE
elif (random_num < 2.0):
hand = Player.SCISSORS
elif (random_num < 3.0):
hand = Player.PAPER
# 決定した手を戻り値として返す
return hand
#==グーが大好き!」戦略クラス。
class StoneOnlyTactics():
def read_tactics(self):
# 必ずグーを出す
return Player.STONE
Lesson 6(ババ抜きプログラム)
カードクラス
card.py
class Card():
# ジョーカーを表す定数
JOKER = 0
# スペードを表す定数
SUIT_SPADE = 1
# ダイヤを表す定数
SUIT_DIAMOND = 2
# クラブを表す定数
SUIT_CLUB = 3
# ハートを表す定数
SUIT_HEART = 4
def __init__(self,suit,number):
self.suit = suit
self.number = number
def getNumber(self):
return self.number
# toString関数をオーバーライド
def toString(self):
# JOKERの場合
if self.suit == 0:
card_code = "JK"
# JOKER以外のカード
else:
suit_dict = {"SUIT_SPADE":"S", "SUIT_DIAMOND":"D",
"SUIT_CLUB":"C","SUIT_HEART":"H"}
number_dict = {1:"A", 2:"2", 3:"3", 4:"4", 5:"5",
6:"6", 7:"7", 8:"8", 9:"9", 10:"T", 11:"J", 12:"Q", 13:"K"}
card_code = suit_dict[self.suit] + number_dict[self.number]
return card_code
手札クラス
hand.py
import random as rm
class Hand():
# card クラスをリストとして保持
def __init__(self,list):
self.hand = list
# カードを追加
def add_card(self,card):
self.hand.append(card)
# カードを引く(先頭)
def pick_card(self):
picked_card = self.hand.pop(0)
return picked_card
# 所持枚数を返す
def getNumberOfCard(self):
return len(self.hand)
# 手札をシャッフル
def shuffle(self):
# カードをランダムに抜き取って最後に加える動作を繰り返す
number = self.getNumberOfCard()
for i in range(number):
pos = int(rm.random() * number)
picked_card = self.hand.pop(pos)
self.hand.append(picked_card)
# 同じ数のカードを探し、配列で戻す
def find_same_number_card(self):
same_cards = None
# 最後に追加されたカードの数字を取得する
last_added_card = self.hand[-1]
last_added_card_num = last_added_card.number
for index in range(len(self.hand)-1):
card = self.hand[index]
if card.number == last_added_card_num:
# 最後に追加されたカードと同じカードが見つかった場合
# 見つかった組み合わせをsameCardsに格納し、ループを抜ける
same_cards = [self.hand.pop(-1),self.hand.pop(index)]
break
return same_cards
# 手札にあるカードを文字列で表現する。
def toString(self):
hand_cards = ""
for card in self.hand:
hand_cards += card.toString() + " "
return hand_cards
テーブルクラス
table.py
class Table():
def __init__(self):
self.disposed_cards = []
# カードを捨てる。
def dispose_card(self,dispose_list):
for card in dispose_list:
print(f"{card.toString()} を捨てました")
self.disposed_cards.append(card)
# 捨てられたカードを文字列で表現する。
def toString(self):
disposed_cards = ""
for card in self.disposed_cards:
disposed_cards += card.toString() + " "
return disposed_cards
プレイヤークラス
player.py
class Player():
def __init__(self,name,hand,master,table):
self.hand = hand
self.name = name
self.master = master
self.table = table
# 順番を指名する(自分の番)
def play(self,next_player):
# 次のプレイヤーに手札を出してもらう
next_hand = next_player.show_hand()
# 相手の手札からカードを一枚引く
picked_card = next_hand.pick_card()
# 引いた結果を表示
print(self.name, ":", next_player.name, "さんから ", picked_card.toString()," を引きました\n")
# 引いたカードを自分の手札に加え、同じ数のカードがあったら捨てる
self.deal_card(picked_card)
# 手札がゼロになったかどうか調べる
if self.hand.getNumberOfCard() == 0:
# 進行役に上がりを宣言する
self.master.declare_win(self)
else:
# 現在の手札を表示する
print(self.name, ":残りの手札は ",self.hand.getNumberOfCard(), "です\n")
# 手札をシャッフルして見せる
def show_hand(self):
if self.hand.getNumberOfCard() == 1:
self.master.declare_win(self)
self.hand.shuffle()
return self.hand
# カードを受け取る
def receive_card(self,card):
self.deal_card(card)
# 同じカードがあったら捨てる
def deal_card(self,card):
# カードを自分の手札に加える
self.hand.add_card(card)
# 今加えたカードと同じカードを探す
same_cards = self.hand.find_same_number_card()
# 同じカードの組み合わせが存在した場合
if (same_cards != None):
# テーブルへカードを捨てる
self.table.dispose_card(same_cards)
# プレイヤー名を返す
def toString(self):
return self.name
マスタークラス
master.py
class Master():
def __init__(self,player_list):
self.player_list = player_list
def prepare_game(self,hand):
print("【カードを配ります】\n")
# トランプをシャッフルする
hand.shuffle()
# トランプの枚数を取得する
number_of_cards = hand.getNumberOfCard()
# プレイヤーの人数を取得する
number_of_players = len(self.player_list)
for index in range(number_of_cards):
# カードから一枚引く
card = hand.pick_card()
# 各プレイヤーに順番にカードを配る
player = self.player_list[index % number_of_players]
player.receive_card(card)
# ゲームを開始する。
def start_game(self):
print("\n【ばば抜きを開始します】\n")
# プレイヤーの人数を取得する
count = 0
while len(self.player_list) > 1:
player_index = count % len(self.player_list)
next_player_index = (count + 1) % len(self.player_list)
# 指名するプレイヤーの取得
player = self.player_list[player_index]
# 次のプレイヤーの取得
next_player = self.player_list[next_player_index]
# プレイヤーを指名する
print("\n", player.name, "さんの番です --- ({})".format(count), "\n")
player.play(next_player)
count += 1
# プレイヤーが上がって残り1名になるとループを抜ける
print("【ばば抜きを終了しました】\n")
# 上がりを宣言する。
def declare_win(self,winner):
# 上がったプレイヤー
print(winner.name, "さんが上がりました!\n")
# 上がったプレイヤーをリストからはずす
self.player_list.remove(winner)
# 残りプレイヤーが1人になった時は敗者を表示する
if len(self.player_list) == 1:
loser = self.player_list[0]
print(loser.name, "さんの負けです!\n")
# ゲームに参加するプレイヤーを登録する。
def register_player(self,player):
self.player_list.append(player)
実行プログラム
old_maid.py
from card import *
from hand import *
from master import *
from player import *
from table import *
# ばば抜きプログラム。
# 53枚のトランプを生成する。
def create_trump():
trump = Hand([])
# 各スート13枚のカードを生成する
for i in range(13):
number = i + 1
trump.add_card(Card("SUIT_CLUB", number))
trump.add_card(Card("SUIT_DIAMOND", number))
trump.add_card(Card("SUIT_HEART", number))
trump.add_card(Card("SUIT_SPADE", number))
# ジョーカーの作成
trump.add_card(Card(0, 0))
return trump
# 進行役の生成
master = Master([])
# 場の生成
field = Table()
# プレイヤーの生成
murata = Player("村田", Hand([]), master, field)
yamada = Player("山田", Hand([]), master, field)
saito = Player("斎藤", Hand([]),master, field)
# 進行役へプレイヤーを登録
master.register_player(murata)
master.register_player(yamada)
master.register_player(saito)
# トランプを生成する
trump = create_trump()
# ゲームの準備をする
master.prepare_game(trump)
# ゲームを開始する
master.start_game()
フレームワーク化(7並べ)
・読み飛ばしたため、省略。気をつけないといけないのは以下の2点
抽象クラス
・pythonで抽象クラスを作成する際はABC(Abstract Base Classes)をインポートし、抽象クラスを継承する必要がある
→参考:PythonのABC - 抽象クラスとダック・タイピング
値渡し
・テーブルクラスがテーブル情報を返すときに値渡しにする必要がある
table.py
class FantanTable(Table):
# テーブルはnumpyで作成
matrix = np.full((4,13),"..")
def getCard(self):
return self.matrix.copy()