nounai.output(spaghetiThinking);

趣味と実益を兼ねて将棋プログラム(研究ツールなど)を作ってみたいと思う私の試行錯誤とか勉強したことを綴ってゆく予定です。 主目的はプログラミングの経験値稼ぎですが、コンピュータ将棋の製作も目指してみたいとも考えています。

棋譜インタプリタっぽいものについて、その後の考察

前回の続き的なこと。もうちょい実装にしても設計にしてもいい形があるように思うので。


まず前回の実装と実行結果。それぞれラベルをクリックすると開きます。

コード

#!/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は「行」が表す情報の「大分類」に相当します。Stateパターンもどきを適用していることで、サブクラス内ではそのクラスが表す「大分類」の内側、内部的な状態遷移に専念させることができます。

なんとなくですが、どうなの?と思ってる部分がいくつかかあって、

  • 内部遷移を各Stateで分離するだけで十分なの?もうちょい分離を進めるべき?
  • Stateはたとえ遷移がない場合であっても新しいStateを作成し、行の数だけStateのリスト構造を持たせるようにした方が良いのではないか
  • Interpretにどの程度の情報を持たせるか?どれだけの責任を持たせるか?

最後のに関して言えば、生のテキストが入ったファイルオブジェクトの参照を保持し、簡単のため除去しているメタ情報の類とか消費時間とかの情報の削除もこのクラス(もしくは内部で持ってるオブジェクト)の責任とすべきか?というようなことになります。インタプリタクラスの責任ってどこまでなのか?クライアントや他のクラスで責任を受け持つべきことって何なのか?というような部分になります。

現状の自分の答えとしては、おそらくInterpreterはファイルを渡して結果を返すまで、つまり最初から最後までの責任を持ち、クライアントにあたる側からはその詳細はある程度隠蔽されているべき。で、「結果を返すまで」だと責任が大きすぎるから、内部では委譲を活用しながらこまごました責任を分担していく。という形が良いのかなと。フォーマット、もしくはバージョン、または実装のバージョンアップに対応するためには、分担するオブジェクトたちの生成や構造の設計についてはAbstractFactory, Builder, Bridge, Decorator, Strategyあたりが必要となってきそうです。あとはComposite, Facadeとかでしょうか。もちろん全部が全部適用可能なわけではないし、必要以上のデザインパターンの使用はかえってコードを理解しづらくし、保守を難しくさせるとも言います。そのあたりはあまり調子に乗らず、デザインパターン至上主義に陥らないよう気をつけたい所ですけどね。とりあえず、このプロトタイプはもっと良いものになる余地があると思うので、もうちょい考察しながら第2弾を作っていきたいです。

p.s

今回久々にjQueryに触りました。だいぶ忘れてたからちょっとは復習できてよかった。