《付録》ex_amorphous.py

# -*- coding: utf-8 -*-
#===============================================================================
#    Copyright (C) 2000-2008, 小泉ひよ子とタマゴ倶楽部
#
# 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 
# Change History: Games
#    1988/05, Smalltalk
#    2004/09, Java
#    2005/02, C#
#    2005/03, Jython
#===============================================================================
from _ant import *
from System.Windows import *
from System.Windows.Media import *
from System.Windows.Shapes import *

from hexOthello import HexStone
from organism import *
## --------------------               
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

    def __repr__(self):
        return self.name
        
    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

    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,
            ))

    def points(self):
        return list(self.shape.Points)
    
## --------------------               
class ExWindow(Window):
    def __init__(self, Content=None, **args):
        self.InitializeComponent(Content)
        self.init()

    def InitializeComponent(self, Content):
        self.Content = LoadXaml(Content)
        
    def init(self):
        target = "canvas",
        self._Controls(target)
        self.colony = self._colony()

    def _Controls(self, target):
        controls = xaml_controls(self)
        for e in target:
            setattr(self, e, controls[e])

    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

    def combineLife(self, name):
        return self.colony.detectLife(name).combine()
    
    def addShape(self, shape):
        return self.canvas.Children.Add(shape)
        
## --------------------               
if __name__ == "__main__":
    xaml = __file__.replace(".py",".xaml")
    win = ExWindow(
        Title=__file__,
        Width=250, Height=150,
        Content=xaml,
        )
    Application().Run(win)

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

テストケース:単細胞生命体の頂点

環状リストがあると便利ですが、Python の組み込み型 list には、その機能がありません。幸いにも、当面の問題を解決するには、環状リストを2巡するだけで十分です。そこで、組み込み型 list を利用します。


s = "abcdef"
for p in range(6):
    print "%d:"%p, circulate(s, p, q=4)

一方の生命体(右赤: abcdef)に着目します。他方の生命体(左青: ABCDEF)と接合した後で、残される頂点を獲得します。頂点 a からのオフセット位置 p(0〜5)を指定したときに、残される4つの頂点(q=4)が得られます。このテストケースを実行すると、

0: bcde
1: cdef
2: defa
3: efab
4: fabc
5: abcd

頂点 a(オフセット位置 p=0)で接合すると、4つの頂点(bcde)が残されるのが分かります。

def circulate(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

テストケース:多細胞生命体の頂点

2つの生命体が接合した後で形成された、多細胞生命体の頂点を獲得します。


s1 = list("ABCDEF")
s2 = list("abcdef")
for e in range(6):
    print "%d:"%e, merge(s1, e, s2, 2)

一方の生命体 s1 に他方の生命体 s2 が接合した後で、形成される多細胞生命体の頂点が得られます。このテストケースを実行すると、

0: ['A', 'f', 'a', 'b', 'c', 'B', 'C', 'D', 'E', 'F']
1: ['A', 'B', 'a', 'b', 'c', 'd', 'C', 'D', 'E', 'F']
2: ['A', 'B', 'C', 'b', 'c', 'd', 'e', 'D', 'E', 'F']
3: ['A', 'B', 'C', 'D', 'c', 'd', 'e', 'f', 'E', 'F']
4: ['A', 'B', 'C', 'D', 'E', 'd', 'e', 'f', 'a', 'F']
5: ['A', 'B', 'C', 'D', 'E', 'F', 'e', 'f', 'a', 'b']

頂点 A(オフセット位置 p=0)で接合すると、10個の頂点(AfabcBCDEF)が残されるのが分かります。

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