2010年12月22日水曜日

そういえばブログに書いてなかったけど

iPhoneアプリ作りました。
http://itunes.apple.com/jp/app/id407479350

2010年12月15日水曜日

subversion-controlledなXcode Projectの新規作成手順

何回やっても忘れるのでもう備忘録を付けます。
(Xcodeと銘打ってますが手順そのものは汎用的だと思います。どちらかと言うとsubversionの備忘録です)
抜けとかがあったら指摘お願いします。

前提
  • 既存 svn リポジトリ: http://your.svnhost/
  • プロジェクトのURL: http://your.svnhost/path/to/project/NewProject/
  • プロジェクトの場所: ~/work/NewProject/
  • trunk/tag/brunches などはよく分からないので使わない

手順
途中でエラーが出たら最初からやり直すのが無難。
  1. http://your.svnhost/ をXcodeのSCMリポジトリに登録していない場合は登録する
    Setting up your XCode SCM Repositories
  2. Xcode起動→プロジェクト新規作成→テンプレート選択
  3. 場所: ~/work/ プロジェクト名: NewProject → OK
  4. Xcodeを終了
  5. Finderで~/work/に行き、NewProjectフォルダをデスクトップに移動
  6. ターミナルを起動
  7. $ svn mkdir -m "Making a new directory for NewProject." http://your.svnhost/path/to/project/NewProject/
  8. $ cd ~/work/
  9. $ mkdir NewProject
  10. $ svn co http://your.svnhost/path/to/project/NewProject/ NewProject
  11. $ cd NewProject
  12. $ cp -r ~/Desktop/NewProject/* .
  13. $ vi .svnignore
  14. i → 以下をコピペ → :wq
    .DS_Store
    build
    *.pbxuser
    *.perspectiv*
  15. $ svn propset svn:ignore -R -F .svnignore .
  16. $ svn add --force .
  17. $ svn st
    buildフォルダやNewProject.xcodeproj以下にproject.pbxproj以外が無いことを確認
  18. XcodeでメニューのSCM→このプロジェクトのSCMを設定
  19. 右上あたりのSCMルート設定をクリック
  20. Noneをクリック→リポジトリ選択(Recommendedになっているはず、なってなかったら手順1が抜けてるか、そうでなければやり直す)
  21. メニューのSCM→プロジェクト全体をリフレッシュ (一応)
  22. メニューのSCM→プロジェクト全体をコミット
  23. メニューのSCM→SCM Results→何も表示されていないことを確認
  24. デスクトップのNewProjectフォルダを捨てる
以上です。以降はコマンドラインでsubversion管理擦る必要はないでしょう。

参考

この後は

2010年12月8日水曜日

第21章 Proxyパターン : 必要になってから作る



Proxyパターンもそんなに難しくないですね。RealSubject役がProxy役を意識しないところが味噌ですね。


  • Virtual Proxy ... 今回の例
  • Remote Proxy ... ネットワーク越しのメソッド呼び出しに
  • Access Proxy ... メソッド呼び出しにアクセス制限を設けたい時に




timeモジュールのsleep(sec)はスレッドをブロックするので、マルチスレッド化しなければsynchronizeを意識する必要はなさそうです。

実行結果
名前は現在Aliceです。
名前は現在Bobです。
Printerのインスタンス(Bob)を生成中
生成完了
=== Bob ===
Hello, world

ソースコード
#!/usr/bin/env python
# -*- coding: utf8 -*-

# Subject interface
class __Printable:
    def __init__(self): raise NotImplementedError
    def setPrinterName(self, n): raise NotImplementedError
    def getPrinterName(self): raise NotImplementedError
    def printIt(self): raise NotImplementedError

from time import sleep
# RealSubject class
class Printer(__Printable):
    def __init__(self, name):
        self.__name = name
        print "Printerのインスタンス(%s)を生成中" % name
        self.__heavyjob()

    def getPrinterName(self):
        return self.__name
    def setPrinterName(self, n):
        self.__name = n

    def printIt(self, msg):
        print "=== %s ===" % self.__name
        print msg

    def __heavyjob(self):
        sleep(3)
        print '生成完了'

# Proxy class
class PrinterProxy(__Printable):
    def __init__(self, name):
        self.__name = name
        self.__real = None

    def getPrinterName(self):
        return self.__name
    def setPrinterName(self, n):
        self.__name = n
        if not self.__real == None:
            self.__real.setPrinterName(n)

    def printIt(self, msg):
        if self.__real == None:
            self.__realize()
        self.__real.printIt(msg)


    def __realize(self):
        self.__real = Printer(self.__name)

# Client
def main():
    m_printer = PrinterProxy("Alice")
    print "名前は現在%sです。" % m_printer.getPrinterName()
    m_printer.setPrinterName("Bob")
    print "名前は現在%sです。" % m_printer.getPrinterName()
    m_printer.printIt("Hello, world")

if __name__=='__main__': main()

2010年12月6日月曜日

第20章 Flyweightパターン : 同じものを共有して無駄をなくす



今回のFlyweightパターンは分かりやすいですね。
factoryにpool作っておいて、同じものを表すオブジェクトはpoolに入っているものを共有するだけです。

注意点は2つ。詳細は省きます。

  1. 共有しているものを変更すると、複数箇所に影響が及ぶ
  2. 管理されているインスタンスは、ガベージコレクションされない



今回もオリジナルで。とは言っても『元の文字に空白を一文字追加して新しい文字列とする』だけなので全く大したことないですが。
あとpythonにsynchronizedが無くてちょっとがっかり。threading.Queueとか使うとよさそうです。

実行結果
L o r e m   i p s u m   d o l o r   s i t   a m e t ,   c o n s e c t e t u r   a d i p i s c i n g   e l i t .   P r a e s e n t   d i g n i s s i m   d i g n i s s i m   e r o s ,   a c   c o n d i m e n t u m   o r c i   i n t e r d u m   s e d .   U t   e t   d o l o r   a t   e s t   e l e m e n t u m   p o s u e r e .   M a u r i s   i a c u l i s   e u i s m o d   l a c u s ,   e g e t   d a p i b u s   a u g u e   i n t e r d u m   v i t a e .   D o n e c   i d   c o n g u e   e l i t .   D o n e c   e r o s   d i a m ,   c o n s e c t e t u r   s i t   a m e t   v a r i u s   i d ,   f e r m e n t u m   e g e t   n i s i .   V i v a m u s   l a o r e e t   a u c t o r   m a s s a   e g e t   p o r t t i t o r .   C r a s   a   e s t   a   n i s i   e g e s t a s   s a g i t t i s   e t   s i t   a m e t   p u r u s .   F u s c e   n e c   u l l a m c o r p e r   p u r u s .   N u l l a   f a c i l i s i .   V e s t i b u l u m   i n   o r c i   s e d   n i b h   r u t r u m   v e n e n a t i s . 
 
 P r a e s e n t   f a c i l i s i s ,   n i s l   t i n c i d u n t   m a l e s u a d a   s u s c i p i t ,   d o l o r   u r n a   f a c i l i s i s   d o l o r ,   v i t a e   i a c u l i s   l o r e m   l i b e r o   s e d   r i s u s .   Q u i s q u e   e t   p l a c e r a t   m a u r i s .   I n   e g e t   a d i p i s c i n g   n i b h .   P e l l e n t e s q u e   i m p e r d i e t   u l t r i c i e s   f e l i s ,   q u i s   p o r t t i t o r   a u g u e   v i v e r r a   a t .   C u r a b i t u r   s e d   n i b h   i p s u m .   E t i a m   c o n d i m e n t u m   l e c t u s   i d   m a u r i s   l a o r e e t   e g e t   r u t r u m   n u n c   r h o n c u s .   F u s c e   e g e s t a s   s a g i t t i s   l a c u s ,   s e d   u l l a m c o r p e r   s a p i e n   m o l e s t i e   a .   M a u r i s   o r n a r e   t u r p i s   u t   l i g u l a   f a u c i b u s   e t   p o r t a   e s t   l a o r e e t .   U t   e u   p u r u s   a c   d i a m   v a r i u s   f a u c i b u s   e l e m e n t u m   v i t a e   a u g u e .   N u n c   i d   o d i o   v e l i t ,   v e l   r h o n c u s   n u n c .   S e d   e g e s t a s   t r i s t i q u e   s o l l i c i t u d i n .   I n   v i v e r r a   m a u r i s   a t   i p s u m   v u l p u t a t e   m o l l i s .   D o n e c   l e c t u s   f e l i s ,   r h o n c u s   v e l   e l e i f e n d   s e d ,   f a c i l i s i s   a c c u m s a n   l e c t u s .   P r a e s e n t   n e c   m a g n a   v e l   e s t   g r a v i d a   p r e t i u m   s a g i t t i s   v i t a e   d u i .   S u s p e n d i s s e   p o t e n t i .   C u r a b i t u r   l o b o r t i s   t o r t o r   n e c   e s t   a d i p i s c i n g   l a c i n i a . 
 
 L o r e m   i p s u m   d o l o r   s i t   a m e t ,   c o n s e c t e t u r   a d i p i s c i n g   e l i t .   P e l l e n t e s q u e   f e u g i a t   a u g u e   v e l   m a s s a   v o l u t p a t   f r i n g i l l a .   N u l l a m   m a t t i s   a c c u m s a n   s a p i e n   e t   d i c t u m .   S u s p e n d i s s e   n e c   u r n a   e g e t   n i s i   p e l l e n t e s q u e   s e m p e r   s i t   a m e t   q u i s   v e l i t .   A e n e a n   a c c u m s a n   d i a m   i n   s e m   c o n s e c t e t u r   i d   u l t r i c i e s   d o l o r   l o b o r t i s .   I n   e g e s t a s   s e m   u t   n u n c   c o n v a l l i s   s o d a l e s   i n   u t   t o r t o r .   P r a e s e n t   n e c   m a g n a   n e q u e .   P r a e s e n t   s e m p e r   s a g i t t i s   d o l o r   a   d a p i b u s .   N a m   h e n d r e r i t ,   l o r e m   n e c   f a u c i b u s   v e h i c u l a ,   n u n c   e n i m   i n t e r d u m   s e m ,   n o n   e g e s t a s   s a p i e n   a n t e   e u   l e c t u s .   P e l l e n t e s q u e   h a b i t a n t   m o r b i   t r i s t i q u e   s e n e c t u s   e t   n e t u s   e t   m a l e s u a d a   f a m e s   a c   t u r p i s   e g e s t a s .   D u i s   v e l   m a u r i s   t e l l u s ,   e g e t   p l a c e r a t   m i .   P e l l e n t e s q u e   m e t u s   m i ,   e l e i f e n d   u t   t e m p u s   i n ,   f e r m e n t u m   q u i s   l i g u l a .   A l i q u a m   e r a t   l e o ,   m o l l i s   a c   c u r s u s   a c ,   f e u g i a t   i n   n i s i .   E t i a m   g r a v i d a   e u i s m o d   l e c t u s   e t   c o n s e c t e t u r .   E t i a m   i a c u l i s   e l e m e n t u m   r i s u s ,   i n   e l e i f e n d   v e l i t   a u c t o r   a c .   V i v a m u s   u l l a m c o r p e r ,   l o r e m   n o n   m o l e s t i e   c o n v a l l i s ,   t e l l u s   a n t e   p u l v i n a r   s a p i e n ,   v e l   p o r t t i t o r   m a s s a   o d i o   e u   l e c t u s .   D o n e c   a c   r i s u s   t r i s t i q u e   n i s l   e u i s m o d   c o n s e c t e t u r .   D o n e c   m o l l i s   s e m p e r   a n t e ,   q u i s   f e u g i a t   l a c u s   i m p e r d i e t   a t .   N a m   e u   l o r e m   s i t   a m e t   v e l i t   s a g i t t i s   c o n s e c t e t u r   a   v o l u t p a t   m i .   S u s p e n d i s s e   s e d   a d i p i s c i n g   l e c t u s . 
 
 C l a s s   a p t e n t   t a c i t i   s o c i o s q u   a d   l i t o r a   t o r q u e n t   p e r   c o n u b i a   n o s t r a ,   p e r   i n c e p t o s   h i m e n a e o s .   N a m   c o n v a l l i s   f e r m e n t u m   e n i m ,   v e l   b l a n d i t   n i s l   b l a n d i t   v e l .   I n t e g e r   a c   j u s t o   n u l l a .   N u l l a   e r o s   e l i t ,   u l l a m c o r p e r   s e d   c o n d i m e n t u m   v e l ,   p o r t a   s e d   e n i m .   S e d   a t   l i b e r o   v e l   l a c u s   p r e t i u m   d i c t u m .   M a u r i s   h e n d r e r i t   u r n a   s i t   a m e t   m i   r h o n c u s   n o n   a l i q u a m   e n i m   i m p e r d i e t .   C u r a b i t u r   a   e r o s   a   d i a m   u l l a m c o r p e r   r h o n c u s .   P r o i n   e t   m a g n a   i n   n i s i   e l e m e n t u m   d i c t u m   v e l   s i t   a m e t   l e c t u s .   U t   t r i s t i q u e   d u i   q u i s   v e l i t   a u c t o r   m o l e s t i e   d a p i b u s   n u l l a   v a r i u s .   F u s c e   v i t a e   v e l i t   p e l l e n t e s q u e   m a g n a   c o n s e q u a t   p l a c e r a t .   M a e c e n a s   d i g n i s s i m   r i s u s   n o n   e s t   s o l l i c i t u d i n   v u l p u t a t e .   M a u r i s   v i t a e   o r c i   f r i n g i l l a   n u l l a   p r e t i u m   p h a r e t r a .   C u r a b i t u r   a c   f a c i l i s i s   t o r t o r .   C u r a b i t u r   e g e t   m o l l i s   v e l i t .   I n   a c   l e c t u s   e l i t ,   a c   p o s u e r e   r i s u s .   Q u i s q u e   q u i s   l i g u l a   m e t u s ,   u t   b l a n d i t   l i b e r o .   C u r a b i t u r   s e d   n i b h   v i t a e   m i   e l e m e n t u m   m o l e s t i e .   D o n e c   e u i s m o d   a r c u   u t   t u r p i s   u l t r i c e s   v i v e r r a .   N u l l a   f a c i l i s i . 
 
 N u l l a   i d   p u l v i n a r   m a u r i s .   N u n c   m a t t i s   f a c i l i s i s   a u g u e ,   s e d   t r i s t i q u e   e s t   i n t e r d u m   s e d .   P r a e s e n t   u l t r i c i e s   n i b h   i d   a u g u e   s u s c i p i t   i d   u l t r i c i e s   m e t u s   a d i p i s c i n g .   A l i q u a m   e r a t   v o l u t p a t .   V e s t i b u l u m   u t   i p s u m   i n   u r n a   l o b o r t i s   f e u g i a t   v i t a e   s i t   a m e t   a r c u .   A l i q u a m   d i a m   p u r u s ,   p r e t i u m   n e c   c o n s e q u a t   v e l ,   p l a c e r a t   a   n i b h .   A e n e a n   l e o   n i s l ,   u l l a m c o r p e r   i n   p l a c e r a t   c o n g u e ,   m o l e s t i e   u l t r i c e s   t o r t o r .   P r a e s e n t   d i a m   l i g u l a ,   e g e s t a s   a   f e r m e n t u m   s e d ,   u l t r i c i e s   i d   o d i o .   D o n e c   a t   p u r u s   i p s u m .   P h a s e l l u s   p o r t a   p l a c e r a t   s c e l e r i s q u e .   S u s p e n d i s s e   h e n d r e r i t   r u t r u m   q u a m   u t   p o r t t i t o r . 

ソースコード
#!/usr/bin/env python
# -*- coding: utf8 -*-

import sys

# Flyweight class
class SparseChar:
    def __init__(self, char):
        self.__char = char[0]

    def draw(self):
        sys.stdout.write(self.__char+" ")

# FlyweightFactory class
class SparseCharFactory:
    def __init__(self):
        self.__pool = {}

    def getSparseChar(self, char):
        if not self.__pool.has_key(char):
            self.__pool[char] = SparseChar(char)
        return self.__pool[char]

# Client class
class SparseString:
    def __init__(self, string):
        self.__string = string
        self.factory = SparseCharFactory()

    def draw(self):
        for s in self.__string:
            self.factory.getSparseChar(s).draw()
        print ""


def main():
    m_sparseString = SparseString("""Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent dignissim dignissim eros, ac condimentum orci interdum sed. Ut et dolor at est elementum posuere. Mauris iaculis euismod lacus, eget dapibus augue interdum vitae. Donec id congue elit. Donec eros diam, consectetur sit amet varius id, fermentum eget nisi. Vivamus laoreet auctor massa eget porttitor. Cras a est a nisi egestas sagittis et sit amet purus. Fusce nec ullamcorper purus. Nulla facilisi. Vestibulum in orci sed nibh rutrum venenatis.

Praesent facilisis, nisl tincidunt malesuada suscipit, dolor urna facilisis dolor, vitae iaculis lorem libero sed risus. Quisque et placerat mauris. In eget adipiscing nibh. Pellentesque imperdiet ultricies felis, quis porttitor augue viverra at. Curabitur sed nibh ipsum. Etiam condimentum lectus id mauris laoreet eget rutrum nunc rhoncus. Fusce egestas sagittis lacus, sed ullamcorper sapien molestie a. Mauris ornare turpis ut ligula faucibus et porta est laoreet. Ut eu purus ac diam varius faucibus elementum vitae augue. Nunc id odio velit, vel rhoncus nunc. Sed egestas tristique sollicitudin. In viverra mauris at ipsum vulputate mollis. Donec lectus felis, rhoncus vel eleifend sed, facilisis accumsan lectus. Praesent nec magna vel est gravida pretium sagittis vitae dui. Suspendisse potenti. Curabitur lobortis tortor nec est adipiscing lacinia.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque feugiat augue vel massa volutpat fringilla. Nullam mattis accumsan sapien et dictum. Suspendisse nec urna eget nisi pellentesque semper sit amet quis velit. Aenean accumsan diam in sem consectetur id ultricies dolor lobortis. In egestas sem ut nunc convallis sodales in ut tortor. Praesent nec magna neque. Praesent semper sagittis dolor a dapibus. Nam hendrerit, lorem nec faucibus vehicula, nunc enim interdum sem, non egestas sapien ante eu lectus. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Duis vel mauris tellus, eget placerat mi. Pellentesque metus mi, eleifend ut tempus in, fermentum quis ligula. Aliquam erat leo, mollis ac cursus ac, feugiat in nisi. Etiam gravida euismod lectus et consectetur. Etiam iaculis elementum risus, in eleifend velit auctor ac. Vivamus ullamcorper, lorem non molestie convallis, tellus ante pulvinar sapien, vel porttitor massa odio eu lectus. Donec ac risus tristique nisl euismod consectetur. Donec mollis semper ante, quis feugiat lacus imperdiet at. Nam eu lorem sit amet velit sagittis consectetur a volutpat mi. Suspendisse sed adipiscing lectus.

Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam convallis fermentum enim, vel blandit nisl blandit vel. Integer ac justo nulla. Nulla eros elit, ullamcorper sed condimentum vel, porta sed enim. Sed at libero vel lacus pretium dictum. Mauris hendrerit urna sit amet mi rhoncus non aliquam enim imperdiet. Curabitur a eros a diam ullamcorper rhoncus. Proin et magna in nisi elementum dictum vel sit amet lectus. Ut tristique dui quis velit auctor molestie dapibus nulla varius. Fusce vitae velit pellentesque magna consequat placerat. Maecenas dignissim risus non est sollicitudin vulputate. Mauris vitae orci fringilla nulla pretium pharetra. Curabitur ac facilisis tortor. Curabitur eget mollis velit. In ac lectus elit, ac posuere risus. Quisque quis ligula metus, ut blandit libero. Curabitur sed nibh vitae mi elementum molestie. Donec euismod arcu ut turpis ultrices viverra. Nulla facilisi.

Nulla id pulvinar mauris. Nunc mattis facilisis augue, sed tristique est interdum sed. Praesent ultricies nibh id augue suscipit id ultricies metus adipiscing. Aliquam erat volutpat. Vestibulum ut ipsum in urna lobortis feugiat vitae sit amet arcu. Aliquam diam purus, pretium nec consequat vel, placerat a nibh. Aenean leo nisl, ullamcorper in placerat congue, molestie ultrices tortor. Praesent diam ligula, egestas a fermentum sed, ultricies id odio. Donec at purus ipsum. Phasellus porta placerat scelerisque. Suspendisse hendrerit rutrum quam ut porttitor.""")
    m_sparseString.draw()


if __name__=='__main__': main()

第19章 Stateパターン : 状態をクラスとして表現する



今回はStateパターン。なかなかエキセントリックなデザインパターンです。

要は
  • メソッドの実装をある状態に応じて切り替える(条件分岐させる)
ような実装を
  • ある状態というクラスがメソッドの実装を記述する
という、説明しても『???』なデザインパターンです。

もう少し概念的な説明すると、

  • 普通の条件分岐…『この状態ならこういう処理にする』
  • Stateパターン…『この状態こういう処理をする』

というように、状態が主語になるイメージです。


いつ使うのか。メリットは何か。

使う場面を間違えると却って混乱しそうなStateパターン。自分で例を考えて実装してみて、有効だと感じた点を列挙します。

  1. どのメソッドにも同じような条件分岐が散らばるほどに重要な『状態』がある時
    まあこれは当たり前っちゃあ当たり前。『この状態の時に呼ばれたらこう動く』という説明のメソッドがあったら要チェック。

  2. 将来状態が増減しそうな時
    これも当たり前かな

  3. 状態を矛盾なく取り扱える
    本書でも触れてますが、このパターンを適用する時は各Stateは排反である必要があるので、必竟自己矛盾が起きません
    これはプログラミングする上でとても大事です。『このifはelse ifにしないと動かない』みたいな分かりづらさから解放されます。
逆にデメリットは以下のような点。
  1. 状態が増えすぎるとしんどい
    特にベクトルの違う複数の状態の組み合わせだと、状態数が指数的に増えるおそれがある




今回は完全オリジナル。どこかのブログのパクリで、『マリオでStateパターン』です。
1ターンにランダムで

  • きのこを食べる
  • フラワーを食べる
  • スターを食べる(スターは3ターンで切れる)
  • 敵に当たる
  • 穴に落ちる

のなかから一つの行動をします。State(状態)は

  • チビマリオ
  • デカマリオ
  • フラワーマリオ
  • 上記3種のスター状態

の計6種類です。
これだと、例えば『しっぽマリオを追加する』なんて時にSippoMarioStateクラスとStarSippoMarioStateクラスを追加するだけで実現できてしまいます(他所はいじる必要なし!)。Stateパターンの有効なケースですね。


実行結果
[残5:チビマリオ] スターを食べた!  チビマリオ★ になった!
[残5:チビマリオ★] ...
[残5:チビマリオ★] キノコを食べた!  デカマリオ★ になった!
[残5:デカマリオ★] スターが切れた!  デカマリオ になった!
[残5:デカマリオ] スターを食べた!  デカマリオ★ になった!
[残5:デカマリオ★] 敵に接触!  敵を倒した!
[残5:デカマリオ★] スターを食べた!  デカマリオ★ になった!
[残5:デカマリオ★] 穴に落ちた!  死んだ! 残り残機:4
[残4:チビマリオ] キノコを食べた!  デカマリオ になった!
[残4:デカマリオ] ...
[残4:デカマリオ] 穴に落ちた!  死んだ! 残り残機:3
[残3:チビマリオ] ...
[残3:チビマリオ] フラワーを食べた!  デカマリオ になった!
[残3:デカマリオ] スターを食べた!  デカマリオ★ になった!
[残3:デカマリオ★] フラワーを食べた!  ファイアーマリオ★ になった!
[残3:ファイアーマリオ★] フラワーを食べた!  意味はない!
[残3:ファイアーマリオ★] スターが切れた!  ファイアーマリオ になった!
[残3:ファイアーマリオ] ...
[残3:ファイアーマリオ] 穴に落ちた!  死んだ! 残り残機:2
[残2:チビマリオ] フラワーを食べた!  デカマリオ になった!
[残2:デカマリオ] 敵に接触!  チビマリオ になった!
[残2:チビマリオ] 穴に落ちた!  死んだ! 残り残機:1
[残1:チビマリオ] キノコを食べた!  デカマリオ になった!
[残1:デカマリオ] スターを食べた!  デカマリオ★ になった!
[残1:デカマリオ★] フラワーを食べた!  ファイアーマリオ★ になった!
[残1:ファイアーマリオ★] キノコを食べた!  意味はない!
[残1:ファイアーマリオ★] スターが切れた!  ファイアーマリオ になった!
[残1:ファイアーマリオ] フラワーを食べた!  意味はない!
[残1:ファイアーマリオ] 敵に接触!  チビマリオ になった!
[残1:チビマリオ] フラワーを食べた!  デカマリオ になった!
[残1:デカマリオ] 敵に接触!  チビマリオ になった!
[残1:チビマリオ] 敵に接触!  死んだ! 残り残機:0
[残0:チビマリオ] 穴に落ちた!  GAME OVER
30ターンプレイしました

ソースコード
#!/usr/bin/env python
# -*- coding: utf8 -*-

class __MarioState:
    def __init__(self): raise NotImplementedError
    def doGetKinoko(self, context): raise NotImplementedError # キノコ取得
    def doGetFlower(self, context): raise NotImplementedError # フラワー取得
    def doGetStar(self, context): raise NotImplementedError # スター取得
    def doLostStar(self, context): raise NotImplementedError # スター消滅
    def doEncounter(self, context): raise NotImplementedError # 敵に接触
    def doFall(self, context): raise NotImplementedError # 穴に落ちる
    def __str__(self): raise NotImplementedError


class NormalMario(__MarioState):
    def __init__(self): pass
    def doGetKinoko(self, context): context.changeState(BigMario())
    def doGetFlower(self, context): context.changeState(BigMario())
    def doEncounter(self, context): context.dead()
    def doGetStar(self, context): context.changeState(StarNormalMario())
    def doLostStar(self, context): print "bug"
    def doFall(self, context): context.dead()
    def __str__(self): return "チビマリオ"

class BigMario(__MarioState):
    def __init__(self): pass
    def doGetKinoko(self, context): context.nope()
    def doGetFlower(self, context): context.changeState(FlowerMario())
    def doEncounter(self, context): context.changeState(NormalMario())
    def doGetStar(self, context): context.changeState(StarBigMario())
    def doLostStar(self, context): print "bug"
    def doFall(self, context): context.dead()
    def __str__(self): return "デカマリオ"

class FlowerMario(__MarioState):
    def __init__(self): pass
    def doGetKinoko(self, context): context.nope()
    def doGetFlower(self, context): context.nope()
    def doEncounter(self, context): context.changeState(NormalMario())
    def doGetStar(self, context): context.changeState(StarFlowerMario())
    def doLostStar(self, context): print "bug"
    def doFall(self, context): context.dead()
    def __str__(self): return "ファイアーマリオ"

class StarNormalMario(__MarioState):
    def __init__(self): pass
    def doGetKinoko(self, context): context.changeState(StarBigMario())
    def doGetFlower(self, context): context.changeState(StarBigMario())
    def doGetStar(self, context): context.changeState(StarNormalMario())
    def doLostStar(self, context): context.changeState(NormalMario())
    def doEncounter(self, context): context.defeat()
    def doFall(self, context): context.dead()
    def __str__(self): return "チビマリオ★"

class StarBigMario(__MarioState):
    def __init__(self): pass
    def doGetKinoko(self, context): context.nope()
    def doGetFlower(self, context): context.changeState(StarFlowerMario())
    def doGetStar(self, context): context.changeState(StarBigMario())
    def doLostStar(self, context): context.changeState(BigMario())
    def doEncounter(self, context): context.defeat()
    def doFall(self, context): context.dead()
    def __str__(self): return "デカマリオ★"

class StarFlowerMario(__MarioState):
    def __init__(self): pass
    def doGetKinoko(self, context): context.nope()
    def doGetFlower(self, context): context.nope()
    def doGetStar(self, context): context.changeState(StarFlowerMario())
    def doLostStar(self, context): context.changeState(FlowerMario())
    def doEncounter(self, context): context.defeat()
    def doFall(self, context): context.dead()
    def __str__(self): return "ファイアーマリオ★"



class __Context:
    def __init__(self): raise NotImplementedError
    def changeState(self, mariostate): raise NotImplementedError # 状態が変化した
    def defeat(self): raise NotImplementedError # 敵を倒した
    def dead(self): raise NotImplementedError # 死んだ
    def nope(self): raise NotImplementedError # 何も起きない

import sys
from threading import Timer
class Game(__Context):
    def __init__(self):
        self.state = NormalMario()
        self.zanki = 5 # 残機
        self.turncount = 0 # 何ターン目か
        self.starcount = 99999 # スター用カウンタ

    def changeState(self, mariostate):
        self.state = mariostate
        print str(mariostate)+" になった!"

    def defeat(self):
        print "敵を倒した!"

    def dead(self):
        self.zanki -= 1
        if self.zanki < 0:
            print "GAME OVER"
            print "%dターンプレイしました" % self.turncount
            sys.exit(0)
        print "死んだ! 残り残機:%d" % self.zanki
        self.state = NormalMario()
        self.starcount = 99999

    def nope(self):
        print "意味はない!"

    #--

    def youGetKinoko(self):
        print "[残%d:%s] キノコを食べた! " % (self.zanki, self.state),
        self.state.doGetKinoko(self)
    def youGetFlower(self):
        print "[残%d:%s] フラワーを食べた! " % (self.zanki, self.state),
        self.state.doGetFlower(self)
    def youEncounter(self):
        print "[残%d:%s] 敵に接触! " % (self.zanki, self.state),
        self.state.doEncounter(self)
    def youFall(self):
        print "[残%d:%s] 穴に落ちた! " % (self.zanki, self.state),
        self.state.doFall(self)
    def nothingHappened(self):
        print "[残%d:%s] ..." % (self.zanki, self.state)

    def youGetStar(self):
        print "[残%d:%s] スターを食べた! " % (self.zanki, self.state),
        self.state.doGetStar(self)
        self.starcount = 0
    def __youLostStar(self):
        print "[残%d:%s] スターが切れた! " % (self.zanki, self.state),
        self.state.doLostStar(self)

    def youCountTurn(self):
        self.turncount += 1
        self.starcount += 1
        if self.starcount == 3:
            self.__youLostStar()



from time import sleep
from random import randint
def main():
    m_game = Game()
    while True:
        # random action
        m_game.youCountTurn()
        act = randint(1,6)
        if   act==1: m_game.youGetKinoko()
        elif act==2: m_game.youGetFlower()
        elif act==3: m_game.youGetStar()
        elif act==4: m_game.youEncounter()
        elif act==5: m_game.youFall()
        elif act==6: m_game.nothingHappened()
        sleep(0.1)

if __name__=='__main__': main()

第18章 Memento : 状態を保存する



今回はMementoパターン。undo/redo/snapshotといった機能をカプセル化を破壊することなく提供する方法です。

  • Originator役はMemento役のオブジェクトを生成し、
  • Caretaker役はMemento役のオブジェクトを保持します。

オブジェクトの状態を保存する』という機能は、undo以外にも用途がありそうです。

--

簡単のため、所持金のみ増減するゲームにしてあります。

実行結果
4の目が出た!... 
2の目が出た!... 所持金が半分になった!
1の目が出た!... 所持金が100増えた!
所持金が増えたので状態を保存。現在150円
5の目が出た!... 
3の目が出た!... 
5の目が出た!... 
2の目が出た!... 所持金が半分になった!
2の目が出た!... 所持金が半分になった!
所持金がかなり減ったので状態を復元。現在150円
(中略)
6の目が出た!... 
2の目が出た!... 所持金が半分になった!
所持金がかなり減ったので状態を復元。現在1412円
5の目が出た!... 
2の目が出た!... 所持金が半分になった!
2の目が出た!... 所持金が半分になった!
所持金がかなり減ったので状態を復元。現在1412円
1の目が出た!... 所持金が100増えた!
所持金が増えたので状態を保存。現在1512円
6の目が出た!... 
終了。最終金額1512円

ソースコード
game.py
# -*- coding: utf8 -*-

from random import randint
class Gamer:
    def __init__(self, money):
        self.__money = money

    def getMoney(self): return self.__money
    def bet(self):
        dice = randint(1,6)
        print "%dの目が出た!..." % (dice),
        if dice==1:
            self.__money += 100
            print "所持金が100増えた!"
        elif dice==2:
            self.__money /= 2
            print "所持金が半分になった!"
        else:
            print ""

    def createMemento(self):
        return Memento(self.__money)

    def restoreMemento(self, memento):
        self.__money = memento.getMoney()



class Memento:
    # protected constructor
    def __init__(self, money):
        self.__money = money

    def getMoney(self): return self.__money

main.py
#!/usr/bin/env python
# -*- coding: utf8 -*-

from game import Gamer, Memento
from time import sleep
def main():
    gamer = Gamer(100)
    memento = gamer.createMemento()
    for i in xrange(100):
        gamer.bet()
        if gamer.getMoney() > memento.getMoney():
            memento = gamer.createMemento()
            print "所持金が増えたので状態を保存。現在%d円" % (gamer.getMoney())
        elif gamer.getMoney() < memento.getMoney() / 2:
            gamer.restoreMemento(memento)
            print "所持金がかなり減ったので状態を復元。現在%d円" % (gamer.getMoney())
        sleep(0.5)

    print "終了。最終金額%d円" % (gamer.getMoney())

if __name__=='__main__': main()