忍者ブログ
趣味と実益を兼ねて将棋のプログラムを作ってみたいなと思っている私の試行錯誤や勉強したことを綴ってゆく予定です。 一番の目的はソフトウェア設計やオブジェクト指向に慣れること ・・・だったのですが、元々の興味や電王戦に触発されたこともあり、AI製作も目指してみたいと今は考えています。 ※はてなに移転しました。
カレンダー
03 2024/04 05
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
プロフィール
HN:
cwron
性別:
男性
自己紹介:
将棋の腕前はムラがあるのでなんとも言えませんが、将棋ウォーズや81Dojo基準だと約三段てことになってます。リアルで指す機会が希少です。
Share
ブログ内検索
×

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

なんかデザインパターンぽいことをしつつインタプリタを書こうと思ったので。正直自分でもあまり理解できてない気がする。書いたコードのメリットもいまいち掴みきれてない。Stateパターン、あとメソッドチェーンのテクニックを(適切かどうかは置いといて)使っています。Interpreterも練習してみたかったし一部のアイデアは今回のコードに盛り込んだつもりだけど、多分Interpreterにはなってないです。どっちかというとFacadeとかに近いのかもしれない。

なんかトリッキーにやろうとしてごちゃごちゃしてる感じ。


拍手[0回]

とりあえず目的はCSA棋譜のインタプリタを書くことですが、まだ途中段階です。1行の中身(トークン単位)まで踏み込んで、CSAフォーマット仕様に準拠しているかどうかはチェックしません。CSAでは、例えば指し手表記より後に開始局面の表記があっちゃいけないなど、行(が属しているセクション)の順番を規程してます。今回書いたコードは、ポリモーフィズムとか委譲(デリゲート)とか使いながらその辺のチェックをOO的にやろうとするのが狙いです。 その行がフォーマット仕様においてどのセクションを表すのか、それを「状態」としてクラスにします。で、当然状態がとこなればAcceptできる行(セクション)は異なるわけです。よって、「状態」クラスにiterpret()メソッドを持たせ、「状態」に依存する振る舞いであるinterpret=解釈のやり方をサブクラスの実装に任せるようにします。この辺はStateパターンが入ってます。

「状態」を表すクラスは"State"クラスとその配下です。コードでは初期状態(最初の行がinterpret()された時の状態),状態1,状態2,状態3が取りうる全ての状態としています。
ポイント?としては、状態は連結リストの構造をしていることです。for文で解釈の対象となる文章の各行についてのループを回し、Stateを得るわけですが、メソッドチェーンと委譲を用いることで自動的にStateが(状態を遷移するごとに)自分の前の状態を参照に持つような連結リストとして繋がっていくようにしました。結果を得る場合は前状態の参照をたどって逆順にすればOKです。現状、クライアント側には連結リストとなったStateを返すような形になります。以下実装。

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

class Interpreter:
	def __init__(self, context):
		self.cn = context
	def interpret(self):
		status = SIni()
		for s in self.cn:
			print "======================================="
			status.setCurrent(s)
			status = status.interpret()
		return status

class State:
	SONE=1
	STWO=2
	STHREE=3
	OWN=-1
	#status=[S1,S2,S3]
	#status={SONE:S1, STWO:S2, STHREE:S3}
	
	def __init__(self, current=None):
		if(self.__class__.__name__=="State"):
			raise Exception,"abstract class \"State\""
		self.current = current
		self.prestate = None
	
	def setCurrent(self, s):
		self.current = s
		return self

	def setPrestate(self, pre):
		self.prestate = pre
		return self
	
	def getStateCode(self):
		if(self.current == State.SONE): return State.SONE
		elif(self.current == State.STWO): return State.STWO
		elif(self.current == State.STHREE): return State.STHREE
		else:
			raise Exception, "SyntaxError"
	
	def isMatch(self):
		#s = (self.line)
		#print "isMatch(): "+str(self.__class__.OWN)
		if(self.getStateCode()==self.__class__.OWN):
			#print "T"
			return True
		#print "F"
		return False
	
	def delegate(self):
		#print "		DELEGATE *** "+StateFactory.Create(self.getStateCode(), self.current).__class__.__name__
		#cstate = self
		#return StateFactory.Create(self.getStateCode(), self.current).setPrestate(cstate).interpret()
		s = StateFactory.Create(self.getStateCode(), self.current)
		s.setPrestate(self)
		print "DELEGATE: "+s.prestate.tostring()
		return s.interpret()
		
	def interpret(self):
		if(self.isMatch()):
			# do approximate processing....
			return self
		else:
			return self.delegate()
			i
	def tolist(self):
		ret = [self]
		elm = self
		while not elm.prestate is None:
			ret.insert(0,elm.prestate)
			elm = elm.prestate
		return ret

	def __iter__(self):
		for el in self.tolist():
			yield el
	
	def tostring(self):
		return "State"+str(self.__class__.OWN)

class SIni(State):
	OWN=0
	def interpret(self):
		if(not self.isMatch()):
			return self.delegate()

class S1(State):
	OWN=1
	def interpret(self):
		if(self.isMatch()):
			print "! STATE(1) printing by "+self.__class__.__name__
			print "    > pre: "+self.prestate.__class__.__name__
			return self
		else:
			return self.delegate()
			
class S2(State):
	OWN=2
	def interpret(self):
		if(self.isMatch()):
			print "# state[2] printing by "+self.__class__.__name__
			print "    > pre: "+self.prestate.__class__.__name__
			return self
		else:
			return self.delegate()

class S3(State):
	OWN=3
	def interpret(self):
		if(self.isMatch()):
			print "% sTaTe{3} printing by "+self.__class__.__name__
			print "    > pre: "+self.prestate.__class__.__name__
			return self
		else:
			return self.delegate()
class StateFactory:
	status={State.SONE:S1, State.STWO:S2, State.STHREE:S3}
	@classmethod
	def Create(cls, scode, current):
		return StateFactory.status[scode](current)
		
def test():
	lis = [1,2,3,2,3]
	intp = Interpreter(context=lis)
	result = intp.interpret()
	
	print result.prestate
	print "\n"
	#for elm in result.tolist():
	for elm in result:
		print elm.__class__.__name__
	
	#while not result.prestate is None:
	#	print result.tostring()
	#	result = result.prestate
if __name__=="__main__":
	test()

そして実行結果。

=======================================
DELEGATE: State0
! STATE(1) printing by S1
    > pre: SIni
=======================================
DELEGATE: State1
# state[2] printing by S2
    > pre: S1
=======================================
DELEGATE: State2
% sTaTe{3} printing by S3
    > pre: S2
=======================================
DELEGATE: State3
# state[2] printing by S2
    > pre: S3
=======================================
DELEGATE: State2
% sTaTe{3} printing by S3
    > pre: S2
<__main__.S2 instance at 0x7f0a44f36b90>


SIni
S1
S2
S3
S2
S3

状態の遷移も一応ちゃんとできてます。で、Stateとそのサブクラスは解釈したい行の「大分類」にあたるクラスです。interpret()の中身で内部的、「小分類」的な状態管理や遷移条件を記述することでもうちょい繊細な動作も実現できるはず。「大分類」に関するコードが各サブクラスに分離できるあたりはメリットと言えるかもしれません。

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