指針:モデルの再利用

既存のモジュール(Swing/Jython 版)を再利用することを最優先します。

from hexOthello import HexStone

ビュー(Swing)に依存しない、モデル(Jython)を記述した hexOthello.py を再利用します。ここでは、WPF アプリケーションとして実現するので、ビュー(Swing)に依存しない、独立したモジュール管理が肝要です。

生命体が占有するセルを配置する

テストケースの動作を確認するために、2つの生命体をコロニーに配置します。

class ExWindow(Window):
    def init(self):
        target = "canvas",
        self._Controls(target)
        self.colony = self._colony()

インスタンス属性 self.colony は、多数の生命体が集うコロニーを管理します。

    def _colony(self):
        colony = Colony()
        for e in [
            ExHexStone(self, 2, 2, False,
                Stroke=Brushes.Blue, Fill=Brushes.Cyan  ),
            ExHexStone(self, 4, 2, False,
                Stroke=Brushes.Red,  Fill=Brushes.Yellow),
            ]:
            self.canvas.Children.Add(e.shape)
            colony.addCell(e)
        return colony

2つの生命体(青/赤)が占有するセルを用意して、それぞれをコロニー colony に追加 addCell します。

生命体が占有するセルを生成する

既存のモジュール hexOthello.py を再利用するとともに、WPF に固有の情報を付加します。

class ExHexStone:
    def __init__(self, client, x, y, state, Stroke=None, Fill=None):
        self.client = client
        self.name = "_%d_%d"%(x, y)
        self.shape = self._shape(x, y)
        if Stroke:
            self.shape.Stroke = Stroke
        if Fill:
            self.shape.Fill = Fill

生命体が占有するセルを生成するときに、輪郭(Stroke=)内部(Fill=)の色を設定できるようにします。

    def _shape(self, x, y):
        name = "_%d_%d"%(x, y)
        x = HexStone._dx + x * HexStone._width
        y = HexStone._dy + y * HexStone._height
        
        points = PointCollection()
        for dx, dy in HexStone(x, y, False).vertices:
            points.Add(Point(x+dx*2, y+dy*2))

        s = Polygon(
            Name=name,
            HorizontalAlignment=HorizontalAlignment.Center,
            VerticalAlignment=VerticalAlignment.Center,
            Stroke=Brushes.Black,
            StrokeThickness=1,
            Fill=Brushes.Green,
            Points=points,
            )
        s.MouseUp += self.mouseUp
        return s

セルを構成するときには、既存のモジュール hexOthello.py を再利用します。プロバティー Name= を使って、各セルを識別します。

    def mouseUp(self, sender, e):
        life = self.client.combineLife(sender.Name)

        points = PointCollection()
        for e in life.points:
            points.Add(e)

        self.client.addShape(Polygon(
            HorizontalAlignment=HorizontalAlignment.Center,
            VerticalAlignment=VerticalAlignment.Center,
            Stroke=sender.Stroke,
            StrokeThickness=3,
            Points=points,
            ))

選択したセルの識別情報 sender.Name をもとに、一方の生命体を指定すると、隣接する他方の生命体と接合した、新たな多細胞生命体 life が得られます。その頂点の座標 life.points をもとに、新たな多角形をキャンバスに追加 addShape します。

《付録》organism.py

# -*- coding: utf-8 -*-
#===============================================================================
#    Copyright (C) 2000-2008, 小泉ひよ子とタマゴ倶楽部
#
# Change History: Games
#    1988/05, Smalltalk
#    2004/09, Java
#    2005/02, C#
#    2005/03, Jython
# Change History: WPF examples
#    2008/01/25, IronPython 1.1.1 (download)
#    2008/08/22, IronPython 1.1.2 (download)
#    2008/03/16, ver.2.0, WPF
#    2008/00/00, ver.2.1, IronPython 1.1.2 
#===============================================================================
from hexOthello import HexStone

## --------------------               
class Colony:                           # 生命体: life-form
    def __init__(self):
        self.lives = 

    def addCell(self, cell):
        life = Unicellular(cell)
        for e in self.lives:
            e.adjoin(life)
        self.lives.append(life)

    def detectLife(self, name):
        life = None
        for e in self.lives:            
            if e.cell.name == name:
                life = e; break
        return life

## --------------------               
class Organism:
    def merge(self, s1, i1, s2, i2):
        p = (i1+4)%len(s2)
        q = 6-i2; d = 5-q
        return s1[:i1+1] + self.circulate(s2, p, q) + s1[i1+d:]

    def circulate(self, s, p, q):
        size = len(s)
        start = p+1; stop = p+q+1
        if size < stop:
            s = s[start:] + s[:stop-size]
        else:
            s = s[start:stop]
        return s

## --------------------               
class Unicellular(Organism):            # 単細胞生物: unicellular organism
    def __init__(self, cell):
        self.cell = cell
        self.surroundings = 
        
    def __repr__(self):
        return str(self.cell)
        
    def adjoin(self, cell):
        self.surroundings.append(cell)
        cell.surroundings.append(self)

    def combine(self):
        target = self.surroundings[0]
        indexes = self.intersection(target)
        print "target::", target.name(), indexes
        points = self.merge(
            target.points(),
            indexes[0],
            self.points(),
            len(indexes),
            )
        return Multicellular([self, target], points)

    def intersection(self, target):
        return [i for i, e in enumerate(target.points()) if e in self.points()]

    def points(self):
        return self.cell.points()
    
    def name(self):
        return self.cell.name

## --------------------               
class Multicellular(Organism):          # 多細胞生物: multicellular organism
    def __init__(self, lives, points):
        self.lives = lives
        self.points = points

    def __repr__(self):
        s = []
        for e in self.points:
            s.append("(%d,%d) "%(e.X, e.Y))         
        return "%s %s"%(self.lives, "".join(s))

## --------------------