忍者ブログ
趣味と実益を兼ねて将棋のプログラムを作ってみたいなと思っている私の試行錯誤や勉強したことを綴ってゆく予定です。 一番の目的はソフトウェア設計やオブジェクト指向に慣れること ・・・だったのですが、元々の興味や電王戦に触発されたこともあり、AI製作も目指してみたいと今は考えています。 ※はてなに移転しました。
カレンダー
04 2024/05 06
S M T W T F S
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
プロフィール
HN:
cwron
性別:
男性
自己紹介:
将棋の腕前はムラがあるのでなんとも言えませんが、将棋ウォーズや81Dojo基準だと約三段てことになってます。リアルで指す機会が希少です。
Share
ブログ内検索
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

将棋関係のプログラミングで何か題材ないかなと思い、実装してみました。


拍手[0回]

駒の種類を素直にサブクラス化しようとすると成駒をどうするか、という話が出てきます。 その辺の振る舞いをDecoratorを用いて実装します。正直なところ、歩~王までの種類をサブクラス化して「成り」はステート扱いするのが一番楽だとは思います。駒の定義って、八方桂とか鏡角とか、特殊ルールみたいなことでもしない限りは不変ですし。モデルになってる「将棋」部分では仕様が変わることがありえないので、駒でクラスを作る気ならどのようなインタフェースを持たせるかに頭使う方が良い気がします。まぁしかし、「委譲ってスゲー!OOスゲー!」と思う程度には勉強になったなと思ってます。

で、現物は(無駄っぽそうなサブクラス化も多そうですが)以下のようになりました。駒の利きを自分からの相対座標として表現しています。また、「利き」の英語が自信ないんですが、ここでは"effects"としています。

仕様(ざっくり)

  • 駒関係のスーパクラスは"AbstractPiece"
  • 不成状態の駒は"Piece",成り状態の駒は"PromotedPiece"を共通の親に持つ
  • AbstractPieceで定義するメソッドは四つ
    • getName() ... 駒の漢字表記を返す
    • promote() ... その駒の成り状態の駒を返す
    • unpromote() ... その(成)駒の不成状態にあたる駒を返す
    • getEffects() ... その駒の利きを盤上の相対座標(タプル形式)のリストにして返す
  • 不成り状態の駒をunpromoteしたり、成り駒をpromoteしようとすると例外を出すようにする
  • 全ての駒についての実装は面倒だったので、実装がない駒もあり。promote/unpromoteで都合が悪くなる(不成状態の方は実装したのに成状態の方はまだのケース)ので、その辺はひとまず例外で"未実装"メッセージを出すようにして対処

ソース

#!/usr/bin/env python
# -*- coding: utf-8 -*-

class AbstractPiece:
	def getEffects(self):
		return None
	def promote(self):
		pass
	def unpromote(self):
		pass
	def getName(self):
		pass

class Piece(AbstractPiece):
	def promote(self):
		raise CannotPromoting, "Not implements yet"
	def unpromote(self):
		raise CannotUnpromoting, "Non-promoted piece"

class Fu(Piece):
	def getEffects(self):
		return [(0,1)]
	def promote(self):
		return To()
	def getName(self):
		return "歩"

class Ky(Piece):
	def getEffects(self):
		return [(0,1),(0,2),(0,3),(0,4),(0,5),(0,6),(0,7),(0,8),(0,9)]
	def getName(self):
		return "香"

class Gi(Piece):
	def getEffects(self):
		return [(-1,1),(0,1),(1,1),(-1,-1),(-1,1)]
	def getName(self):
		return "銀"

class Ki(Piece):
	def getEffects(self):
		return [(-1,1),(0,1),(1,1),(0,-1),(0,1),(-1,0)]
	def promote(self):
		"""
		CannotPromotingを投げるべき?
		"""
		return self
	def getName(self):
		return "金"

class Hi(Piece):
	def getEffects(self):
		return [(0,-3),(0,-2),(0,-1),(0,1),(0,2),(0,3),
				(-3,0),(-2,0),(-1,0),(1,0),(2,0),(3,0)]
	def promote(self):
		return Ry()
	def getName(self):
		return "飛"

# Docorator
class PromotedPiece(AbstractPiece):
	def promote(self):
		raise CannotPromoting, "This piece already promoted"
	def unpromote(self):
		raise CannotUnpromoting, "Not implements yet"

class To(PromotedPiece):
	def __init__(self):
		self.org = Fu()
	def getEffects(self):
		return Ki().getEffects()
	def unpromote(self):
		return Fu()
	def getName(self):
		return "と"

class Ry(PromotedPiece):
	def __init__(self):
		self.org = Hi()
	def getEffects(self):
		l=[(-1,-1),(-1,1),(1,-1),(1,1)]
		return l + self.org.getEffects()
	def unpromote(self):
		return Hi()
	def getName(self):
		return "龍"

class PieceOperationException(Exception):
	pass
class CannotUnpromoting(PieceOperationException):
	pass
class CannotPromoting(PieceOperationException):
	pass

def test():
	lis = [Fu(),Fu(),To(),Ky(),Hi(),Ry()]
	for piece in lis:
		print piece.getName()

	print "\ngetEffects()"
	for piece in lis:
		print piece.getName(),": ",piece.getEffects()

	print "\npromoting"
	for piece in lis:
		try:
			print piece.promote().getName(),": ",piece.promote().getEffects()
		except PieceOperationException, e:
			print piece.getName(),": ",e

	print "\nunpromoting"
	for piece in lis:
		try:
			print piece.unpromote().getName(),": ",piece.unpromote().getEffects()
		except PieceOperationException, e:
			print piece.getName(),": ",e

if __name__=="__main__":
	test()

これのtest()関数実行結果は以下。

実行結果

歩
歩
と
香
飛
龍

getEffects()
歩 :  [(0, 1)]
歩 :  [(0, 1)]
と :  [(-1, 1), (0, 1), (1, 1), (0, -1), (0, 1), (-1, 0)]
香 :  [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9)]
飛 :  [(0, -3), (0, -2), (0, -1), (0, 1), (0, 2), (0, 3), (-3, 0), (-2, 0), (-1, 0), (1, 0), (2, 0), (3, 0)]
龍 :  [(-1, -1), (-1, 1), (1, -1), (1, 1), (0, -3), (0, -2), (0, -1), (0, 1), (0, 2), (0, 3), (-3, 0), (-2, 0), (-1, 0), (1, 0), (2, 0), (3, 0)]

promoting
と :  [(-1, 1), (0, 1), (1, 1), (0, -1), (0, 1), (-1, 0)]
と :  [(-1, 1), (0, 1), (1, 1), (0, -1), (0, 1), (-1, 0)]
と :  This piece already promoted
香 :  Not implements yet
龍 :  [(-1, -1), (-1, 1), (1, -1), (1, 1), (0, -3), (0, -2), (0, -1), (0, 1), (0, 2), (0, 3), (-3, 0), (-2, 0), (-1, 0), (1, 0), (2, 0), (3, 0)]
龍 :  This piece already promoted

unpromoting
歩 :  Non-promoted piece
歩 :  Non-promoted piece
歩 :  [(0, 1)]
香 :  Non-promoted piece
飛 :  Non-promoted piece
飛 :  [(0, -3), (0, -2), (0, -1), (0, 1), (0, 2), (0, 3), (-3, 0), (-2, 0), (-1, 0), (1, 0), (2, 0), (3, 0)]

仕様の良し悪しは自分ではちょっと評価しづらいです。あまり良いアイデアではない気はしますが。

成りについては表駒8種のみサブクラス化+Stateパターンがありそうな感じがします。パターン名の感じだけで言ってるので実際どうなのかは知りません。やる気があればまた今度実装してみようと思います。

参考書籍

p.s.

Stateの適用条件などを見ましたが、駒の成り/不成について適用すべきではなさそうです。適用可能性をデザパタ本より引用すると、次のいずれかに当てはまる場合にStateを使います。

  • オブジェクトの振る舞いが状態に依存し、実行時にはオブジェクトがその状態により振る舞いを変えなければならない場合。
  • オペレーションが、オブジェクトの状態に依存した多岐にわたる条件文を持っている場合。この状態はたいてい1つ以上の列挙型の定数で表されており、たびたび複数のオペレーションに同じ条件構造が現れる。Stateパターンでは、1つ1つの条件分岐を別々のクラスに受け持たせる。これにより、オブジェクトの各状態を1つのオブジェクトとして扱うことができる。

状態数が多岐に渡るわけではないことや、(例えばgetEffects()の場合)成り/不成りの「状態」がある振る舞いのキーとなるような場面が現状思いつかないことが理由です。

Stateを導入しても良さそうな場面...今思いついたのを挙げるとすれば、足の長い駒の移動先を計算する際に、とかでしょうか。正直、移動可能な座標をただリストで管理するだけでは、下段にある香車とかが盤上でどこまで動けるかを見る時に走査ができず不便です。ある方向に一直線に動く駒については、味方/敵の駒、もしくは盤の端までを走査するfor文的な実装によって対処したい。単純にリストを用意するだけではその辺(移動方向)の秩序がないため、盤上で移動可能なマスを走査するためのコードを書くのはかなり面倒だと思います。

PR
お名前
タイトル
文字色
URL
コメント
パスワード
Vodafone絵文字 i-mode絵文字 Ezweb絵文字
Copyright © nounai.output(spaghetiThinking); All Rights Reserved
Powered by ニンジャブログ  Designed by ピンキー・ローン・ピッグ
忍者ブログ / [PR]