忍者ブログ

Memeplexes

プログラミング、3DCGとその他いろいろについて

[PR]

×

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


Silverlightで『模型は心を持ちうるか』ver2

模型は心を持ちうるか』という人工知能の本があります。
私はまだろくに読んでないのですが、一部だけ見た感じだと、こんな感じのようです:

こんなロボットがあったとします。
(リンク先から引用)

Vehicle2.JPG



このロボットは本体+2つのセンサーと2つの車輪からなっています。
上にある手のように見えるものは実は手ではなく光センサーです。
そこから信号を伝える電線が下の車輪に伸びています。

このとき、電線のつなぎ方は2通りあります。
平行に繋ぐ方法とクロスさせる方法。
aとbはその2通りのつなぎ方を表しています。

実は、このつなぎ方によって振る舞いに大きな違いが生まれるのです。
というか、単にセンサーと車輪をつなぐだけでも、面白い振る舞いが生まれます。

Vehicle2Behavior.JPG

このとおり、aのようなつなぎ方をすると光を恐れるようになり、bのようなつなぎ方をすると光を追いかけるようになります。
単純な仕掛けから高等に見えるふるまいが出てくる。
人工知能のエッセンスですね。

さてこれをSilverlightで再現してみました。



このSilverlightでは光ではなくマウスポインタを追いかけます。
チェックボックスにチェックを入れると内部の配線が切り替わり、今度は逆に光から逃げるようになります。


おまけ

プロジェクトファイルです。
このようなケースでMVVMを使うのは難しいですね。











拍手[1回]

PR

Silverlightで細胞の分化をシミュレート(ブーリアンネットワーク)

細胞の状態のシミュレーター

Silverlightで ブーリアンネットワークというもののシミュレーターを作ってみました。
これは細胞の状態の単純化されたシミュレーションです。



このページを開くとすると模様が現れます。
(現れない場合は[新規作成]を押してください。最初の状態はランダムに決まるので、模様が生まれない場合があるのです)

その模様が一種類の細胞に相当します。
ある模様は皮膚の細胞かもしれませんし、別の模様は神経の細胞かもしれません。

模様は周期的です。
短い目で見ればある細胞の内部状態は変動しています。
しかし長い目で見れば変わりません。
たとえば皮膚を作る細胞がいきなり神経細胞に変わったりはしないのです。

青で縁どられている四角形をクリックしてみてください(一番上です)。
するとその場所の黒と白が反転します。
結果、次の2つのうちどちらかが起こります。

1.模様が一時的にかき乱されるが、次第に元の模様に戻っていく。
2.模様がかき乱され、以後全く別の模様になる。

1が何を意味しているかというと、細胞の自己復元機能のようなものです。
2は、細胞の分化(ES細胞が皮膚や神経の細胞に変わるようなこと)を意味しています。

場合によっては2は起こりにくいかもしれません。
その時は[新規作成]で別のネットワークにするか、複数の四角形を同時にクリックしてみてください(ポーズボタンは右下です)

ブーリアンネットワークとは

人間の細胞にはいろいろな種類があります。
皮膚の細胞、内臓の細胞、骨の細胞、さまざまです。
それらは内部の状態が違っています。

内部の状態が違うのは違うタンパク質が作られているから。
そしてタンパク質を作り出すのは遺伝子です。
遺伝子が、細胞をいろいろな種類にわけているのです。

普通私たちプログラマは状態の遷移をStateパターンなんかを使って実装しますが、細胞は違います。
無数の遺伝子がお互いをスイッチONしたりスイッチOFFしたりして状態が決まります。

遺伝子はタンパク質を作り出すだけが能ではありません。
他の遺伝子が「オン」になるかどうかを調節したりもするのです。
オンになった遺伝子は効力を発揮し、タンパク質を作ったり、あるいは別の遺伝子のオンオフを替えたりします。
遺伝子の集まり=ゲノムは状態を制御するネットワークなのです。

複雑系の研究者スチュアート・カウフマンがその著書の中で次のようにモデル化したのを紹介しています:
(彼の言ったままではありませんがだいたいそういうことです)

「ひとつの遺伝子をboolとする。そしてその状態は、以前の自分や他の遺伝子の状態によって決まる」

遺伝子の調節ネットワークを、相互作用するboolのネットワークとしてみたのです。
具体的には遺伝子a、遺伝子b, 遺伝子cがあったとすると:

a = and(b, c)
b = xor(c, a)
c = or(a, b)

というような具合です。(右辺は直前の状態)
ここではandやxorやorなどと言っていますが、実際には16種類のブール関数何でもかまいません。
2つのboolから一つのboolを導き出すやり方は全部で16種類ありますからね。

(厳密には16である必要すらありません。
2つより多い数の遺伝子の情報をとって次の状態を計算してはなぜいけないのでしょうか?
残念ながら、3つ以上の遺伝子の情報を取るとまずいことになる理由があります。
どうも数を増やすと振る舞いがカオスになりやすいのです。
秩序がなくなってしまうのです。
(逆に数を2より減らすと動きが凍り付いてしまいます。おもしろくありません)
そういうわけで、2つの遺伝子にのみ依存するようにここではプログラムしました)

遺伝子一つ一つをboolに見立て、次々と状態をアップデートしていくのがブーリアンネットワークです。
これは上で述べたように、細胞の恒常性(ちょっとばかり状態が変わっても、元の状態に戻ろうとする力)、分化(細胞が別のタイプに変わること)のような現象が現れます。

なお、このネットワークは幾つかの安定した状態を取りますが、それはだいたい√遺伝子数 です。
このシミュレーターでは最初10個の遺伝子ですが、つまり大体3つの状態を取るはずだ、ということです。

ちなみに人間の遺伝子の数は約2万2000個。
平方根をとると148です。
実際の人間の細胞の種類はたしか2百数十種類です。
完全に一致とは言えませんが、オーダーはだいたい合っているようですね。
ちょっと多めになっているのは自然淘汰の力でしょう。
本来作れる状態よりちょっと多めに状態を作り出せるよう、遺伝子が調節されているものと思われます。
たとえば動物なんかだとひとつの遺伝子が複数の形態を取ることがあるようです。


おまけ

プロジェクトファイルです。

























































拍手[0回]


SilverlightのDataTrigger

SilverlightでDataTrigger

以前
、WPFでDataTriggerを使いました。
今回はSilverlightでDataTriggerを使います。

しかし、SiverlightにはWPFのようなDataTriggerはありません。
(SilverlightはWPFの別バージョンというより.net frameworkのサブセットみたいなものなので、ちょっと正確性にかけた表現ですが。)

Silverlightはランタイムをコンパクトに保つため、機能がないことが多いのですね。
よってDataTriggerもありません。
おしまい。

……ではあまりにひどいので、Silverlightには別バージョンのDataTriggerが用意されています。
名前空間は別の場所にあり、微妙に使い方も違います。


準備

SilverlightでDataTriggerを使うには

Microsoft.Expression.Interactions.dll
System.Windows.Interactivity.dll

が必要です。
この2つはどうやらBlend SDKの最新バージョンに入っているようです。




片道切符

では早速Silverilghtで使ってみます。
次のようなコードになります:
※以前WPFで使った時とは違い、INotifyPropertyChangedの実装が必要なことに注意です。

using System.ComponentModel;

namespace SilverlightDataTriggerDemo
{
    public class MyViewModel:ViewModel
    {
        private bool isViewModelEnabled;
        public bool IsViewModelEnabled
        {
            get { return isViewModelEnabled; }
            set
            {
                isViewModelEnabled = value;
                NotifyPropertyChanged("IsViewModelEnabled");
            }
        }
    }

    public class ViewModel:INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        protected void NotifyPropertyChanged(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

XAMLの方はこうです:

<UserControl x:Class="SilverlightDataTriggerDemo.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:SilverlightDataTriggerDemo"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"

    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <vm:MyViewModel x:Key="viewModel"/>
    </UserControl.Resources>

    <CheckBox 
        DataContext="{StaticResource viewModel}"
        IsChecked="{Binding IsViewModelEnabled, Mode=TwoWay}">
        <TextBlock>
            <i:Interaction.Triggers>
                <ei:DataTrigger Binding="{Binding IsViewModelEnabled}" Value="true"> 
                    <ei:ChangePropertyAction PropertyName="Text" Value="Changed!!"/>
                </ei:DataTrigger>
            </i:Interaction.Triggers>
        </TextBlock>
    </CheckBox>
</UserControl>




これを実行したSilverlightがこちらです:
(本物です。画像ではありません。操作できます)

上のチェックボックスにチェックを入れてください。
Checked!!と表示されるはずです。
チェックを入れるとビューモデルのIsViewModelEnabledプロパティがtrueになり、それを察知したDataTriggerがテキストを"Checked!!"に変更するのです。

しかし問題もあります。
チェックを一度入れてから外してみてください。
以前のサンプルとは違い、テキストが表示されたままです。

一方通行で、もとに戻らないのです。

可逆変化

元に戻すには、チェックが入っていない状態にテキストを表示させなくさせる操作が、明示的に必要です。(多分)
具体的には、XAMLをこうします:

<UserControl x:Class="SilverlightDataTriggerDemo.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:SilverlightDataTriggerDemo"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"

    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <vm:MyViewModel x:Key="viewModel"/>
    </UserControl.Resources>

    <CheckBox 
        DataContext="{StaticResource viewModel}"
        IsChecked="{Binding IsViewModelEnabled, Mode=TwoWay}">
        <TextBlock>
            <i:Interaction.Triggers>
                <ei:DataTrigger Binding="{Binding IsViewModelEnabled}" Value="true"> 
                    <ei:ChangePropertyAction PropertyName="Text" Value="Changed!!"/>
                </ei:DataTrigger>
                <ei:DataTrigger Binding="{Binding IsViewModelEnabled}" Value="false"> 
                    <ei:ChangePropertyAction PropertyName="Text" Value=""/>
                </ei:DataTrigger>
            </i:Interaction.Triggers>
        </TextBlock>
    </CheckBox>
</UserControl>


こうしてできたSilverlightがこれです。
(本物です。画像ではありません。操作してみてください)


どうでしょう!!
今度はチェックを外したら文字が消えます!
意図したとおりの、以前のサンプルと同じ動作です。
・・・・・・しかしそれにしてももう少しスマートな方法はないのでしょうか?
コンバーターを使うという手もありますがなるべくXAMLだけで済ませたいものです・・・


拍手[1回]


DelegateCommandパターン。

 忘れては思い出しまた忘れないうちにメモしておこうシリーズ第二弾です。
今回はWPFで使われるコマンドのある種の使い方についてメモしておこうと思います。
DelegateCommandパターンです。

WPFに限った話ではありませんが、ある操作をするとき、ボタンをクリックしたり右クリックしてからメニューをクリックしたりあるいはキーボードのショートカットを使ったり複数の方法があるのが一般的です。
それぞれに別のイベントハンドラを使うのは美しくありません。
それに操作が実行不可能なときボタンを無効状態にしたりしますが、それも煩雑でめんどくさいものです。
そこで全部まとめてしまえるのがコマンドです。
具体的にはテキストのカットやペースト、ファイルを開くといった動作などいろいろなコマンドがあります。
コマンドが実行不可能なときには、コマンドをデータバインディングしたUIは自動的に使えなくなります。

コマンドはユーザー定義が可能です。
ICommandから継承するのです。
しかし継承したクラスにハードコードすると融通がきかないので、デリゲートを引数にとって柔軟性を持たせることがあります。
それがDelegateCommandパターンです。

なんのことだか分かりにくいのでコードを書いておきます。
かなり短くしました。

using System.Windows.Input;

namespace WpfApplication1
{
    public class TestViewModel
    {
        public DelegateCommand SqrtCommand { get; private set; }
        public double Number { get; set; }

        public TestViewModel()
        {
            SqrtCommand = new DelegateCommand(
                () => { System.Windows.MessageBox.Show(System.Math.Sqrt(Number).ToString()); },
                () => Number >= 0
                );
        }
    }

    public class DelegateCommand : ICommand
    {
        System.Action execute;
        System.Func<bool> canExecute;

        public bool CanExecute(object parameter)
        {
            return canExecute();
        }

        public event System.EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameter)
        {
            execute();
        }

        public DelegateCommand(System.Action execute, System.Func<bool> canExecute)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }
    }
}

これがViewModelのクラスです。
√を計算します。
たとえばNumberが9だったら3を、4だったら2を表示するわけですね。

その下にDelegateCommandクラスがあります。
今回の主役です。
これはユーザー定義のコマンドで、コマンドが「実行可能かどうか」と「何を実行するか」を司るのです。
これを次にデータバインドでボタンに突っ込むわけです。

XAMLのコードはこうなります。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:src="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="150" Width="225">
    <Window.Resources>
        <src:TestViewModel x:Key="viewModel"/>
    </Window.Resources>
    
    <StackPanel DataContext="{StaticResource viewModel}">
        <TextBox Text="{Binding Number}"/>
        <Button Content="sqrt" Command="{Binding SqrtCommand}"/>
    </StackPanel>
</Window>


スタックパネルで2つのコントロールを表示しています。
テキストボックスと、その下にボタンです。
テキストボックスには√する数字が入ります。
ボタンをクリックするとコマンドが実行されるようになっています。

実行するとこんな感じです。

wpfDelegateCommandSample.jpg

さてテキストボックスに数字の4を入れてみましょう。
そしてsqrtボタンをクリックしてください。
するとこうなります:

wpfDelegateCommandSampleSqrt4.jpg

√4 = 2

です。
予想どうりの結果ですね。

さて、今度はテキストボックスに-4を入れてみましょう。
そしてsqrtボタンをクリックしてください。
すると・・・

wpfDelegateCommandSampleSqrt-4.jpg

なんと!!
ボタンがかってに無効状態になりました!
どんなに頑張っても押せません。

コマンドオブジェクトのCanExecuteプロパティがfalseなので、それをボタンが読み取って無効状態になってくれたのです。

ここではコマンドを実行するUIはボタンひとつだけですが、例えばメニューで実行出来るようにしても同じことです。
メニューとボタン両方が無効状態になってくれます。
-4などという値になったときには。

ちなみにこのサンプルプログラム、あまりに単純化しすぎてボタンが無効状態から戻ってくれません。
この問題はクリック出来るUIの数の少なさに由来します。
しかし普通のアプリケーションレベルのUIでは、戻ってくれます。
sqrtボタンの下にもう一つ別のボタンを作り、それをクリックすると、テキストボックスの中身が0以上なら、無効化状態から戻ってくれます。













拍手[5回]


DataTriggerの使い方(WPF)

個人的に WPFは覚えたと思ってしばらく経つとすぐ忘れるということを繰り返しています。
恥ずかしながらDataTriggerも以前使ったはずなのに、すっかり使い方を忘れてしまいました。

二度と忘れないよう、DataTriggerの使い方をメモしておこうと思います。
と言ってもしばらく立つと忘れるんでしょうねーと思いつつ。


目的

DataTriggerはどういうときに使うのか?
それはあるデータがある値を取るとき、あることをする、というものです。

なんのこっちゃなので、具体例を出しましょう。
ウィンドウの中にチェックボックスが一つあったとします。

wpfDataTriggerNotChecked.jpg


これにチェックを入れるとCheckBoxのContentプロパティが変わって欲しいとしましょう。

wpfDataTriggerChecked.jpg


Contentプロパティが

""→"Checked!!"

と変わったのです。
チェックを外すとテキストは元に戻ります。
"Checked!!"→""

これを実現するにはC#のコードを書く必要はなく(DataTriggerを使う必要もなく)、下のようなXAMLで十分です。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="150" Width="225">
    <CheckBox>
        <CheckBox.Style>
            <Style TargetType="CheckBox">
                <Style.Triggers>
                    <Trigger Property="IsChecked" Value="true">
                        <Setter Property="Content" Value="Checked!!"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </CheckBox.Style>
    </CheckBox>
</Window>

つまりCheckBoxのIsCheckedがtrueになったとき、CheckBoxのContentを"Checked!!"にする、という意味です。

DataTriggerを使う

さて、上の例ではこのXAMLで十分ですが、実際にはもうちょっと凝ったことをしたくなることがあります。
例えばMVVMパターン。
ViewModelのプロパティXをIsCheckedにバインドして、そしてプロパティXの値を元にトリガー(たとえばTextBlockのTextなんかを変更するのでしょう)を起動すると考えてください。

つまり

CheckBox.IsChecked → ViewModel.X → TextBlock.Text

というようなデータの流れです。

このケースでは、コントロールではなく、ViewModelのプロパティの値によってトリガーを起動する必要があります。
そういったときにDataTriggerが使えます。
 
今度も上と同じ仕様にしてみましょう。
チェックを入れると文字が表示されるのです。
ただし今度はテキストブロックを明示的に使ってみます。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:src="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="150" Width="225">
    <Window.Resources>
        <src:TestViewModel x:Key="viewModel"/>

        <Style x:Key="style" TargetType="TextBlock">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsViewModelEnabled}" Value="true">
                    <Setter Property="Text" Value="Checked!!"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    
    <CheckBox DataContext="{StaticResource viewModel}" IsChecked="{Binding IsViewModelEnabled}" >
        <TextBlock Style="{StaticResource style}"/>
    </CheckBox>
</Window>



今度はC#側も必要です。 
ViewModelを使うからです。

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class TestViewModel
    {
        public bool IsViewModelEnabled { get; set; }
    }
}


 
このプログラムは上のプログラムと同じように動作します。
違うのは、ViewModelを介して、動いているというところです。
(と言っても、ViewModelにはプロパティしか有りませんが。)
(不思議なことにINotifyPropertyChangedインターフェースは必要ありません)
 
アプリケーションが動くときにはUIだけで完結するよりもViewModelなC#ロジックで動くことが多いのではないでしょうか。(多分)
そういうときにDataTriggerは役立つかもしれません。

もっともこれ、boolとstringを変換するConverterで同じことが出来ますが。

拍手[6回]