↑を作ってやろうと、予め生協で買ったナムルを使って「石焼きビビンバ-oid」である「パン焼きビビンバ」を作ってみました。

 

 

先ずご飯を炊いたら、フライパンを熱して胡麻油を敷いてからご飯を底に敷き詰めます。弱火でお焦げができる迄焼きます。(僕のように好きな方はひっくり返して両面を焼きましょう。)

 

「お焦げご飯」を丼に入れ、買っておいたナムル(ゼンマイ、モヤシ、人参、ホウレン草etc)に加え、

 

(1) 予め焼肉のタレで味付けした牛(または豚)挽肉と長ネギ(玉葱でもよいです)の微塵切りの胡麻油炒め

(2) 炒り卵

(3) キムチ(できれば「鶴橋」がベター)

 

をご飯に載せ、

 

(4) 韓国海苔(なければ焼きのり)をちぎったもの

(5) 磨り胡麻

 

を塗(まぶ)して出来上がり、です。

 

ビビンバ」は「(ビビンメンの)ビビン(混ぜる)」+「(キンパの)(ブ-ご飯)」で「混ぜご飯」を意味するので、食べる前にこいつらをしっかりと混ぜてください。そうそう

 

コチジャンは絶対にマスト!

)スーパーのドドメ色のコチジャンは好きになれません。私は真っ赤なコレ↓。

 

 

こういう状態になったら完成です。

 

本格的な食感の「お焦げご飯ビビンバ」ができました。お勧めです。

 

植物の「過密と過疎」環境に対する生存行動をシミュレートするライフゲームから、移動する偽生物(Cell)に発展させたCells for C#を何とか完結しましたが、実行テストを行っていてC++版の時代から感じていた「何か足りないんじゃないの?」というような違和感を再度感じました。

 

何かが足りない?...何が足りない!

 

今朝、(またまた)寝床の中でそれは

 

群れ

 

じゃないかと、気が付きました。そしてその

 

原因は私にある

 

事も併せて気が付きました。

 

私は元々ガキ大将で自分なりに社会性や社交性があると思っていたのですが、小学校の時から担任の女性教師に、クラスの他の女の子()と共に、教室の後ろに離れて座らされていました。その理由は、

:この子については、担任教師から「自閉症」(今でいうASD、自閉スペクトラム症)と説明を受けておりました。

 

勝手に発言したり、場合によっては行動するので他の児童の(教育の)為に良くない

「〇〇君、あなたは授業妨害をしているのよッ!」

 

という(キレられて言われました)ことでした。今でいえば、ADHD症状にある

  • 静かに座っていることができない
  • 絶え間なく喋り続ける
  • 無言で身体を動かさずにいることができない。
  • 無目的に喋り続ける
  • 他者の発言を遮って喋る
  • 自分の話す順番を待つことが出来ない

(近いっちゃー近かったのかな)なるのでしょう。まぁ、この「制裁」を食らった後は(少しの間)おとなしくするので、又クラスの「群れ」に戻るのですが...まぁ、昭和っていうのはこういうのが当たり前で私自身「当たり前」と感じていましたね。

 

いずれにしてもそんなこんなで、「右向け右の集団行動」が苦手で、現在も「同窓会や同期会といったあまりよく知りもしない)多数の集団でワイワイやる共同幻想状態の群れ」は苦手です。

 

そんな訳で、Cellの設計の中で「他者との関係論」を単純に「愛着と敵対の二元論」に纏めた結果、全てのCellは勝手にウロウロと彷徨し、愛着性は交尾に至りますが結局家族も集団も形成せず、

 

一人勝手に生きて死ぬ

 

だけでした。組織の中で孤立し、出世もしなかった自分の今までの生きざまに酷似していますねぇ...)

 

じゃ、群れってなんだよ?

 

というのが次の問いになります。これについて先ずは「ある区域に生息する全生物を一つの集団とみなしたもの」である「生物群集」という概念が参考になります。(「個体群」は単体なので「全生物」とは別物です。)Cellsでは「異種族」だけの簡素化された群集でした。又これら群集の個体や個体群はCellでも取り上げた「競争(敵対捕食被食(死亡以降、寄生、共生(愛着」の関係性があり、「食物連鎖や食物網のような関係、あるいは物質循環やエネルギー循環」を実現しています。

【ご参考】

生命の階層
生態系 ecosystem
生物群集 community
個体群 population
個体 individual
器官 organ
組織 tissue
細胞 cell
細胞小器官 organelle
分子 molecule
その他
群体 colony
定数群体 coenobium

 

この「群れ」が人間様の話になるとそれは「複数の人間の空間的、目的的、心理的な集まり」である「集団」の概念になります。人間の群れも「規範約束慣習等、集団凝縮性集団圧力集団目標リーダーシップ集団規範」によって支配されます。そうなれば話は自ずと

 

政治、社会

 

に及び、「政治は数、数は力、力は金」という言葉を想起してしまいます。

 

政治は数、数は力、力は金」と言うのは元内閣総理大臣()田中角栄の言葉です。私は決して角栄礼賛者ではありませんが、彼の慧眼が現れている言葉だと思います。

ロッキード事件で受託収賄の罪を問われましたが、本人死亡により公訴は棄却(刑は未確定)されました。


この考えを私なりに解釈し、別の言葉に置き換えれば、

 

「社会的支配力()を得るには、群れを作り、それを率い()なければならず、それに成功すれば社会的権力を得ることができ()、その社会的権力は経済力()を生む(又はへ転換する)ことができる」

:彼は「政治」を学問的一般論としていったのではなく、志向性を持つ課題としての「政治的に成功するには」と言う問いとして言っています。

 

と言う「社会の原理(誰もが認めざるを得ない、経験的事実)を指しているのだと考えられます。

ここで重要なのは、この「群れ」と言う人や動物に備わる性向です。これを「社会性」と捉えることもできますが、

 

現実に自然界で弱い種は「群れ」を作ることにより数をとして生き残ってきた

 

ことを想起すれば、これは生存のための力であると考えざるを得ないでしょう。田中角栄の言葉を生態学的に言えば、

 

生態系は群れ、群れは力、力は食物連鎖の上位化

 

につながると考えられます。ここまで調べたり、考えたりして次に

 

じゃ、群れの原理ってなんだよ?

 

という所に流れてゆき、発見したのが

 

boids(Bird-oid)

 

という「ボイド(人工生命シミュレーションプログラム)((wikiでは「鳥もどき」と書かれていますが、私は勝手に「擬鳥」という語を作っちゃいました!)でした。

 

先ずは"Seeing is believing"ということで

 

これ

 

 

を見てください。次回から(自分自身これから何をしようか未だ定まっていないのですが...)この"boids(擬鳥)"をテーマにブログを書いてゆこうかと考えています。

 

さてさて、【食い物話】ばかり書いていましたが、そろそろこのシリーズを手仕舞するときのようです。今回は最終回として、コンパイルの仕方とテスト実施後の評価を書いてみます。

 

このプログラムは、先ずEmbarcadero  C++とBCCSkeltonベースの

【Cell】シリーズ始動...

から始まり、それをC#へ

【無駄話】取り敢えず...Cell for C#?

単純移植した後、C#用に仕様変更

【無駄話】思いつきとひらめき-Cells

してきては、ということで進めてきました。

 

出来上がりは、

 

BCCFormandBCCSkeltonパッケージのサンプル】

("C: ... \BCCForm_and_BCCSkelton\SampleBCCSkelton\MSCompAss\Debug\Samples\Cells\")

 

のようになっていて、(MSCompAssを使ってもよいのですが、使わなくても)"Cells.bat"を起動すれば自動的にコンパイルされ、Cell_World.dllとCells.exeが出来上がる仕組みになっています。

 

起動すると

 

 

全く変わりのない姿(only except the "Cell" icon on the top of the Window )で現れ、(特に「データを開く」で「世界」の地形図を変更しない限り)ゲーム開始」に進み、

 

 

Cellの数」、「異種族間婚姻許可」、「アバターで参加」という3つのオプションを選択してゲーム開始となります。「アバターで参加」を選択しない限り、C++版と全く同じ展開となり、ゲームは「過疎による全滅

 

 

か、過密による「人口爆発」という結果に終わります。

 

 

仮に「アバターで参加」を選択すると、

 

 

ゲームウィンドウの右隣に「アバターコントローラー」ダイアログが(Max3秒間)現れ、濃いピンクの「アバターセル」を周囲の環境に従って操ることができますが、に書いた通り、

 

このゲームで、俺は主役にはなれない!

直ぐに大衆に飲み込まれてしまう...

という現実を嫌っていう程、味あわされます。

 

まぁ、

 

ライフゲームに代表される環境型のシミュレーションゲームにアバターで参加してみる

 

という発想は面白かったのですが、ゲームの楽しさ、という点では

 

んんんん(爆)

 

という感じでした。悪しからず...

 

Cells for C#を途中でほっぽらかして、食い物話に走っている私ですが、今回も又やらさせていただきます。

 

 

これが何か???

 

私の場合、

 

「何か作る(創作活動)が楽しくて好き」

 

なんですが、子供の時からプログラミングの他、

 

図工(電子回路作成含む)

音楽

絵画

料理 etc

 

なんかが好きでしたが、音楽や絵画は早々に才能がないことで見切りをつけ、現在も続いているのが(手が汚れない)プログラミング料理なのかな、と思っています。

 

今回のテーマは、お昼に「冷やし中華風ソーメン(↑参照-上から時計回りに、「サニーレタス」、「錦糸卵」、「茹でモヤシ

、「炒めた豚肉、ソーセージと玉葱」)」を作る際に、

 

「そういえば韓国冷麺って、どんな味だっけ?」

 

という素朴な疑問を持ったことが始まりで、さっそくwebで「本格冷麺スープ(日本の焼肉屋で出す奴では満足できないので)」のレシピなどを調べてスープの試作品を作ってみました。とはいえ"Risk Management"観点から矢張り、

1. 普通のツユ(保険、ですな)-↑の写真で下のガラス器(ネギ、大葉、生姜)
2. 韓国冷麺ツユ(今回の試作品)-↑の写真で上のセラミック器

の両方を用意。も「普通においしく」食べましたが、大半は2で食べてしまいました。

 

2は調べたところ、牛肉出汁と鶏肉出汁のミクスらしく、代用品としてビーフコンソメ鶏ガラスープを使いました。このツユは冷製スープとしてとても美味しく、食べ終わった後に飲み干してしまいましたが、これが

 

冷麺のスープかというと自信ありません。(笑)

 

まぁ、楽しく調理、食事できたので良しとしましょう。

 

ps. 今回の課題として分かったことは、「先ず、(コロナ禍でここしばらく行っていないので忘れてしまった)本格冷麺のスープの味を思い出す」ことから始めないといけない、ということでした。

 

いつもは体重を気にして夜はしっかりと食べない神さんが、バイトから夕刻に帰ってくるので、久々に夕食の提案をしたら「いいね!」ということで、昨晩神さんが作ったミートソースと私の摘み用にしこんでいた豚肉を野菜と添えて、(これも80gだけ残っていた)ペンネを合体して、ペンネボロネーゼ+豚の生姜焼き+サラダにしました。ペンネは(乾燥重量)40g、豚肉は50gづつ

 

夫婦で分かち合って

 

の夕食。確かに取り合わせに

 

 

は付きますが、でも、結構ハーモニーがあって大変美味しかったです。(「?」ついでに箸で食べちゃいました。こうするとペンネを一つづつ摘まむのでゆっくりと食べられ、満腹感もいっぱいで一種の「ダイエット食」になりました!)

 

 

前回、AvatarControllerをやりながら、このダイアログ

 

 

【拡大図】

 

について全く説明しなかったことに気が付きました!(ゴメンナサイ!)以下に概要を説明します。

 

(1)このダイアログがModal Dialogで、Worldクラスインスタンスを親(thisで呼ぶ)として呼んでいます。

 

(2)しかし、このダイアログは「3秒の命」しかなく、(何もしなくても)3秒経つと自動的に閉じられます

 

(3)↑ご覧のように多くのコントロールがありますが、「選択する動作は一つだけ」(動作はカラープッシュボタンを押すことにより実行しますが、ボタンは一つしか押せません)ので、その「3秒の命」の中で、ひとつだけ選択します。(カラープッシュボタンを押すとダイアログが閉じられます。)敢えて何もしない場合には最下段の「パス」ボタンを押してください。

 

(4)具体的に言うと、「遭遇したCellへの対応」では「親交」を結んだり、「威嚇」、「闘争」や「逃走」したりできます。又、食べ物があれば「食べる(への対応)」ことができ、野原があれば「移動(対応)」することができます。

 

(5)しかし、「ボタンを押しても、できないことがあるということを判断するには3秒間では難しい」だろうということで、「できないことはできない(グループボックスの.Enabledプロパティがfalse」ようにしていますので()、「押せるボタンが、今出来ること」になります。(さすがにそれはボタン状態からわかるでしょうと...)

:↑のイメージでいえば「遭遇したCellへの対応」と「食物への対応」がDisable状態です。

 

(6)また、、「遭遇したCellへの対応」では「異種族間婚姻が許可されているか」「自分と相手の種族、愛着性、敵対性」の数値が表示されるので、「親交を結ぶか、威嚇するか、即戦うか、逃げるか」を判断する素地になるでしょう。

 

(7)「食物への対応」動作も対象が複数ある場合は選択ができることも考えたのですが、余りに面倒にすると「特に反応が劣る高齢者」にはキツイのでPC判断と同じ対処にしました。

 

(8)「移動対応」も移動できる方向だけボタンを押せるよう、特に反応が劣る高齢者に対して「親切設計」にしています。

 

このように、従来のC++版のように単に「世界とCellの行く末を神の視座で眺める」というゲームから、「ユーザー自身がアバターを使って世界に入ってプレイする」というのが今回のC#版の売りなんですが、実際にプレイして思ったことは、

 

このゲームで、俺は主役にはなれない!

 

という

 

厳しい現実

 

でした。

 

Cell数を絞ってプレイする場合でも、採り得る戦略は「ひたすら食べ物を追っかけて、他のセルから逃れる」か、「なるべく戦わないで親交を深めるか」しかなく、「威勢よく他のセルを切り結ぶ」なんてことは考えない方がよい(直ぐに死ぬ)という現実です。

 

これがCellの数を多くすると

 

直ぐに大衆に飲み込まれてしまう...

 

という「しがない一個人の悲しい人生」を

 

嫌っていう程、味あわされます

 

正に「人生ゲーム」。期待した効果とは異なりましたが、それはそれで

 

大成功!!!

 

ps. 今回のプログラミングで初めて遭遇したエラーについて備忘として書いておきます。

 

最初AvatarControllerクラスからWorldクラスのフィールドやメソッドを使おうと思い、Worldクラス中の「Class in Class」にしようかと考えて進めたのですが、それでコンパイルすると、

 

CS0038: 入れ子になっている型 'Cell_World.World.AbatarController' を経由して、外の型 'Cell_World.World' の静的でないメンバーにアクセスすることはできません

というエラーが生じます。これはクラスインスタンスがスタックエリアに作られるために「アドレスが実際の実行まで確定できない」ことから来る問題()と考えました。

:言語設計により、相対距離でアクセスできる場合もあるようですが...一方、クラスの静的メンバーであれば、アドレスが確定しているためにアクセスが可能です。

【ご参考】

 

念のためにChat-GPTに確認すると矢張り、

 

C#でこのエラー(CS0038)が発生するのは、インナークラス(入れ子の型)から、外側のクラスの「静的ではない(non-static)メンバー」に直接アクセスしようとしたためです。C#の入れ子クラスは、Javaのインナークラスとは異なり、自動的に外側のクラスのインスタンス(this)への参照を持ちません。

(例)
csharpnamespace Cell_World
{
    public class World
    {
        public int worldSize = 100; // 静的ではないメンバー(インスタンス変数)

        public class AbatarController // 入れ子になっている型
        {
            public void Move()
            {
                // エラーCS0038:外側の非静的メンバーに直接アクセスできない
                int size = worldSize; 
            }
        }
    }
}

 

ということで、「Class in Class」は役に立たないので止め、コンストラクターの引数でWorldインスタンスを参照渡し(C++であれば「ポインター渡し」ですね)することにしました。ちょっとどんくさいですが...ご参考まで。

 

//////////////////////////////////////////////////

//  Cells for C#が長引いたので、閑話休題

//////////////////////////////////////////////////

using 赤ワイン

 

namespace 酒のつまみ

{

    赤ワインが少しあるので、これに合う摘みを考えていました。

    そんな時、手元に結構カリカリ感が半端ない、好みの生揚げが一切れあったので、

 

イタ風生揚げ

 

    にトライしてみました。赤ワインに合わせるように、

 

    (1) 揚げをカリカリに焼いて、

    (2) 火を通していた玉葱のみじん切りを載せて

    (3) ケチャップをかけ、

    (4) スライスチーズを載せて電子レンジで溶かします。

 

    思った以上に赤ワインに合いました。

 

    反省点は、

 

    (1) もぅ少し塩味を効かせたかった

    (2) レンジの時間が長すぎたのでチーズが流れ出した

 

    ことでしょうか?

 

    改善点としては、簡単に作るにはケチャップでよいのですが、しっかり作るには

 

    (1) 甘みを控えたトマトソースに

    (2) 少量のひき肉を入れたボロネーゼソース

 

    の方がいいかも、という感じです。

}

 

ps. この後、ハワイで買ったトリニダートスコーピオンのタバスコを使い()ましたが、効きまくり!危険なので「普通のタバスコ」をご使用ください。

:どの程度違うかというと、「普通のタバスコ:↑の摘みなら6振り程度かける」ところ、「スコーピオン:一滴をなすりつけるように6か所に伸ばしてゆく」くらいの差があります。最初普通にかけたら、頭が痛くなるような辛さでした。

 

文字数オーバー」エラーの為に"Worldクラス(3)"を更に分割しなければなりませんでしたが、前回の続きでアバター機能追加の為に新作した"AvatarController"ダイアログ

 

 

をやります。オリジナルのC++にはなかった機能ですので、適宜「解説:」を追加しておきます。

 

【Worldクラス後半】

    //////////////////////////////
    //AvatarController ダイアログ
    //(最長3秒で自動的に閉じる)

 

    //解説:最初は「長考可」でしたが、ゲームスピード、切迫感醸成の為に自動的に閉じるようにしました。
    //////////////////////////////

    class AvatarController : Form
    {
        ///////////////////////
        //定数定義(変更不可)
        ///////////////////////

        const int Wld_Width = 80;        //Worldの幅(セル数)
        const int Max_Dir = 8;            //↑:0、↗:1、→:2、↘:3、↓:4、↙:5、←:6、↖:7
        const int Not_Found = -1;        //Find_***処理用
        //クラスフィールド
        private World wld;            //Worldクラスインスタンス
        private Cell cell;                //自分(Avatar)セル自身
        private Cell you;                //遭遇する他のCell
        private int yDir;                //遭遇する他のCellの方向
        private int fDir = Not_Found;    //食べ物の方向
        //ダイアログコントロール
        //グループボックス

        GroupBox gBox;
        GroupBox gBoxFood;
        GroupBox gBoxMove;
        //ラベル
        private Label lblMe;
        private Label lblYou;
        private Label lblTribe;
        private Label lblAffection;
        private Label lblHostility;
        private Label lblMeTribe;
        private Label lblMeAffection;
        private Label lblMeHostility;
        private Label lblYouTribe;
        private Label lblYouAffection;
        private Label lblYouHostility;
        //チェックボックス
        private CheckBox InterMarriage;
        //ボタン
        private Button btnGetClose;        //親交
        private Button btnIntimidate;    //威嚇
        private Button btnFight;        //闘争
        private Button btnFlee;            //逃走
        private Button btnEat;            //摂食
        private Button[] btnDir;        //移動
        private Button btnPass;            //パス(何もしない)
        //自動終了タイマー
        Timer dlgTimer;

        //worldはcのいる世界、dirがNot_Foundでなければ、遭遇した他のセルがy(nullでない)
        public AvatarController(World world, Cell c, Cell y, int dir)
        {    //解説:引数はWorldクラスインスタンス、自分のセル、遭遇したセルとそれがいる方向
            //引数の記録
            wld = world;
            cell = c;
            you = y;
            yDir = dir;
            //ダイアログの属性設定
            this.Text = "アバターコントローラー";
            this.ClientSize = new Size(320, 460);
            this.ControlBox = false;    //システムボタンを無効化
            this.ShowInTaskbar = true;    //タスクバー上表示
            this.FormBorderStyle = FormBorderStyle.FixedDialog;    //境界のスタイル
            this.StartPosition = FormStartPosition.CenterScreen;//画面中央(解説:親の右隣にされますが...)
            InitControls();                //コントロールの配置
            SetControls(cell);            //コントロールの初期設定
            //3秒で閉じる設定にする
            dlgTimer = new Timer();
            dlgTimer.Tick += new EventHandler(OnPass_Click);
            dlgTimer.Interval = 3000;    //解説:ミリ秒単位なので「3秒」
               dlgTimer.Start();
        }

        private void InitControls()
        {
            //フォームのレイアウトを一時停止
            this.SuspendLayout();
            //グループボックス(相手セルへの対応)
            gBox = new GroupBox();
            gBox.Location = new Point(10, 10);
            gBox.Size = new Size(ClientSize.Width - 20, 180);
            gBox.Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left);
            gBox.Enabled = false;        //初期状態は使用不可
            gBox.Text = "遭遇したCellへの対応";
            //チェックボックスの属性設定
            InterMarriage = new CheckBox();
            InterMarriage.Location = new Point(10, 16);
            InterMarriage.Size = new Size(ClientSize.Width - 40, 18);
            InterMarriage.CheckAlign = ContentAlignment.MiddleRight;
            InterMarriage.TextAlign = ContentAlignment.MiddleLeft;
            InterMarriage.Text = "異種族婚許可";
            InterMarriage.AutoCheck = false;    //ユーザー変更不可
            //ラベルの属性設定
            lblTribe = new Label();
            lblTribe.Size = new Size(60, 18);
            lblTribe.Location = new Point(10, 68);
            lblTribe.BorderStyle = BorderStyle.Fixed3D;
            lblTribe.Text = "種族";
            lblTribe.TextAlign = ContentAlignment.MiddleCenter;
            lblTribe.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblAffection = new Label();
            lblAffection.Size = new Size(60, 18);
            lblAffection.Location = new Point(10, 94);
            lblAffection.BorderStyle = BorderStyle.Fixed3D;
            lblAffection.Text = "愛着性";
            lblAffection.TextAlign = ContentAlignment.MiddleCenter;
            lblAffection.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblHostility = new Label();
            lblHostility.Size = new Size(60, 18);
            lblHostility.Location = new Point(10, 120);
            lblHostility.BorderStyle = BorderStyle.Fixed3D;
            lblHostility.Text = "    敵対性";
            lblHostility.TextAlign = ContentAlignment.MiddleCenter;
            lblHostility.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblMe = new Label();
            lblMe.Size = new Size(100, 18);
            lblMe.Location = new Point(80, 42);
            lblMe.BorderStyle = BorderStyle.Fixed3D;
            lblMe.Text = "アバターセル";
            lblMe.TextAlign = ContentAlignment.MiddleCenter;
            lblMe.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblMe.BackColor = Color.SkyBlue;
            lblMeTribe = new Label();
            lblMeTribe.Size = new Size(100, 18);
            lblMeTribe.Location = new Point(80, 68);
            lblMeTribe.BorderStyle = BorderStyle.Fixed3D;
            lblMeTribe.Text = "";
            lblMeTribe.TextAlign = ContentAlignment.MiddleCenter;
            lblMeTribe.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblMeTribe.BackColor = Color.SkyBlue;
            lblMeAffection = new Label();
            lblMeAffection.Size = new Size(100, 18);
            lblMeAffection.Location = new Point(80, 92);
            lblMeAffection.BorderStyle = BorderStyle.Fixed3D;
            lblMeAffection.Text = "";
            lblMeAffection.TextAlign = ContentAlignment.MiddleCenter;
            lblMeAffection.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblMeAffection.BackColor = Color.SkyBlue;
            lblMeHostility = new Label();
            lblMeHostility.Size = new Size(100, 18);
            lblMeHostility.Location = new Point(80, 120);
            lblMeHostility.BorderStyle = BorderStyle.Fixed3D;
            lblMeHostility.Text = "";
            lblMeHostility.TextAlign = ContentAlignment.MiddleCenter;
            lblMeHostility.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblMeHostility.BackColor = Color.SkyBlue;
            lblYou = new Label();
            lblYou.Size = new Size(100, 18);
            lblYou.Location = new Point(190, 42);
            lblYou.BorderStyle = BorderStyle.Fixed3D;
            lblYou.Text = "相手のセル";
            lblYou.TextAlign = ContentAlignment.MiddleCenter;
            lblYou.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblYou.BackColor = Color.Violet;
            lblYouTribe = new Label();
            lblYouTribe.Size = new Size(100, 18);
            lblYouTribe.Location = new Point(190, 68);
            lblYouTribe.BorderStyle = BorderStyle.Fixed3D;
            lblYouTribe.Text = "";
            lblYouTribe.TextAlign = ContentAlignment.MiddleCenter;
            lblYouTribe.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblYouTribe.BackColor = Color.Violet;
            lblYouAffection = new Label();
            lblYouAffection.Size = new Size(100, 18);
            lblYouAffection.Location = new Point(190, 92);
            lblYouAffection.BorderStyle = BorderStyle.Fixed3D;
            lblYouAffection.Text = "";
            lblYouAffection.TextAlign = ContentAlignment.MiddleCenter;
            lblYouAffection.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblYouAffection.BackColor = Color.Violet;
            lblYouHostility = new Label();
            lblYouHostility.Size = new Size(100, 18);
            lblYouHostility.Location = new Point(190, 120);
            lblYouHostility.BorderStyle = BorderStyle.Fixed3D;
            lblYouHostility.Text = "";
            lblYouHostility.TextAlign = ContentAlignment.MiddleCenter;
            lblYouHostility.Font = new Font("MS明朝", 8, FontStyle.Regular);
            lblYouHostility.BackColor = Color.Violet;
            //ボタンの属性設定
            btnGetClose = new Button();                //親交
            btnGetClose.Size = new Size(60, 24);
            btnGetClose.Location = new Point(10, 148);
            btnGetClose.Text = "親交";
            btnGetClose.BackColor = Color.LimeGreen;
            btnGetClose.Click += new EventHandler(OnGetClose_Click);
            btnIntimidate = new Button();            //威嚇
            btnIntimidate.Size = new Size(60, 24);
            btnIntimidate.Location = new Point(82, 148);
            btnIntimidate.Text = "威嚇";
            btnIntimidate.BackColor = Color.Orange;
            btnIntimidate.Click += new EventHandler(OnIntimidate_Click);
            btnFight = new Button();                //闘争
            btnFight.Size = new Size(60, 24);
            btnFight.Location = new Point(154, 148);
            btnFight.Text = "闘争";
            btnFight.BackColor = Color.Red;
            btnFight.Click += new EventHandler(OnFight_Click);
            btnFlee = new Button();                    //逃走
            btnFlee.Size = new Size(60, 24);
            btnFlee.Location = new Point(226, 148);
            btnFlee.Text = "逃走";
            btnFlee.BackColor = Color.DeepSkyBlue;
            btnFlee.Click += new EventHandler(OnFlee_Click);
            //帰属関係設定
            gBox.Controls.Add(InterMarriage);
            gBox.Controls.Add(lblMe);
            gBox.Controls.Add(lblMeTribe);
            gBox.Controls.Add(lblMeAffection);
            gBox.Controls.Add(lblMeHostility);
            gBox.Controls.Add(lblYou);
            gBox.Controls.Add(lblYouTribe);
            gBox.Controls.Add(lblYouAffection);
            gBox.Controls.Add(lblYouHostility);
            gBox.Controls.Add(lblTribe);
            gBox.Controls.Add(lblAffection);
            gBox.Controls.Add(lblHostility);
            gBox.Controls.Add(btnGetClose);
            gBox.Controls.Add(btnIntimidate);
            gBox.Controls.Add(btnFight);
            gBox.Controls.Add(btnFlee);
            this.Controls.Add(gBox);
            //グループボックス(食物への対応)
            gBoxFood = new GroupBox();
            gBoxFood.Location = new Point(10, gBox.Height + 20);
            gBoxFood.Size = new Size(ClientSize.Width - 20, 48);
            gBoxFood.Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left);
            gBoxFood.Text = "食物への対応";
            gBoxFood.Enabled = false;    //初期状態は使用不可
            //ボタンの属性設定
            btnEat = new Button();
            btnEat.Size = new Size(gBoxFood.Width - 40, 24);
            btnEat.Location = new Point(20, 16);
            btnEat.Text = "食べる";
            btnEat.BackColor = Color.LawnGreen;
            btnEat.Click += new EventHandler(OnEat_Click);
            //帰属関係設定
            gBoxFood.Controls.Add(btnEat);
            this.Controls.Add(gBoxFood);
            //グループボックス(移動対応)
            gBoxMove = new GroupBox();
            gBoxMove.Location = new Point(10, gBox.Height + gBoxFood.Height + 30);
            gBoxMove.Size = new Size(ClientSize.Width - 20, 160);
            gBoxMove.Anchor = (AnchorStyles.Top | AnchorStyles.Right | AnchorStyles.Bottom | AnchorStyles.Left);
            gBoxMove.Text = "移動対応";
            //ボタンの属性設定
            btnDir  = new Button[8];    //↑:0、↗:1、→:2、↘:3、↓:4、↙:5、←:6、↖:7
            int btnW = 40, btnH = 40;
            int posX = (gBoxMove.Width - btnW * 3 - 8) / 2;
            int posY = 20;
            //本プログラムのリソースマネージャー作成(解説:".dll"なので、実行ファイル".exe"の場合とちょっと違います。)
            ResourceManager rm = new ResourceManager("Cell_World", Assembly.GetAssembly(typeof(World)));
            Bitmap bmp;    //解説:貼り付け処理用ビットマップフィールド。Dispose()処理が必要か否か調べ、".resource"ファイルのビットマップへのポインターとしてしか機能していないので、「不要」という結論になりました。
            btnDir[0] = new Button();    //解説:ボタンインスタンスを作ります。以下同じ。
            btnDir[0].Size = new Size(btnW, btnH);    //解説:大きさを決定します。以下同じ。
            btnDir[0].Location = new Point(posX + btnW + 4, posY);    //解説:位置決めします。以下同じ。
            btnDir[0].BackColor = Color.LightCyan;    //解説:ボタンの背景色を指定します。以下同じ。
            btnDir[0].Click += new EventHandler(OnUp_Click);    //解説:ボタンが押された場合の割り込みメソッドを指定します。
            bmp = (Bitmap)rm.GetObject("U");    //リソース埋め込みビットマップの読み込み(アドレスをbmpポインターへ)
            bmp.MakeTransparent(Color.White);    //解説:".resource"ファイルのビットマップを透明化します。以下同じ。
            btnDir[0].Image = bmp;    //解説:ボタンにビットマップを貼り付けます。
            btnDir[0].Enabled = false;    //初期状態は使用不可
            btnDir[1] = new Button();
            btnDir[1].Size = new Size(btnW, btnH);
            btnDir[1].Location = new Point(posX + (btnW + 4) * 2, posY);
            btnDir[1].BackColor = Color.LightCyan;
            btnDir[1].Click += new EventHandler(OnUpRight_Click);
            bmp = (Bitmap)rm.GetObject("UR");    //ビットマップの読み込み
            bmp.MakeTransparent(Color.White);
            btnDir[1].Image = bmp;
            btnDir[1].Enabled = false;    //初期状態は使用不可
            btnDir[2] = new Button();
            btnDir[2].Size = new Size(btnW, btnH);
            btnDir[2].Location = new Point(posX + btnW * 2 + 8, posY + btnH + 4);
            btnDir[2].BackColor = Color.LightCyan;
            btnDir[2].Click += new EventHandler(OnRight_Click);
            bmp = (Bitmap)rm.GetObject("R");    //ビットマップの読み込み
            bmp.MakeTransparent(Color.White);
            btnDir[2].Image = bmp;
            btnDir[2].Enabled = false;    //初期状態は使用不可
            btnDir[3] = new Button();
            btnDir[3].Size = new Size(btnW, btnH);
            btnDir[3].Location = new Point(posX + (btnW + 4) * 2, posY + btnH * 2 + 8);
            btnDir[3].BackColor = Color.LightCyan;
            btnDir[3].Click += new EventHandler(OnDownRight_Click);
            bmp = (Bitmap)rm.GetObject("DR");    //ビットマップの読み込み
            bmp.MakeTransparent(Color.White);
            btnDir[3].Image = bmp;
            btnDir[3].Enabled = false;    //初期状態は使用不可
            btnDir[4] = new Button();
            btnDir[4].Size = new Size(btnW, btnH);
            btnDir[4].Location = new Point(posX + btnW + 4, posY + btnH * 2 + 8);
            btnDir[4].Click += new EventHandler(OnDown_Click);
            btnDir[4].BackColor = Color.LightCyan;
            bmp = (Bitmap)rm.GetObject("D");    //ビットマップの読み込み
            bmp.MakeTransparent(Color.White);
            btnDir[4].Image = bmp;
            btnDir[4].Enabled = false;    //初期状態は使用不可
            btnDir[5] = new Button();
            btnDir[5].Size = new Size(btnW, btnH);
            btnDir[5].Location = new Point(posX, posY + btnH * 2 + 8);
            btnDir[5].BackColor = Color.LightCyan;
            btnDir[5].Click += new EventHandler(OnDownLeft_Click);
            bmp = (Bitmap)rm.GetObject("DL");    //ビットマップの読み込み
            bmp.MakeTransparent(Color.White);
            btnDir[5].Image = bmp;
            btnDir[5].Enabled = false;    //初期状態は使用不可
            btnDir[6] = new Button();
            btnDir[6].Size = new Size(btnW, btnH);
            btnDir[6].Location = new Point(posX, posY + btnH + 4);
            btnDir[6].BackColor = Color.LightCyan;
            btnDir[6].Click += new EventHandler(OnLeft_Click);
            bmp = (Bitmap)rm.GetObject("L");    //ビットマップの読み込み
            bmp.MakeTransparent(Color.White);
            btnDir[6].Image = bmp;
            btnDir[6].Enabled = false;    //初期状態は使用不可
            btnDir[7] = new Button();
            btnDir[7].Size = new Size(btnW, btnH);
            btnDir[7].Location = new Point(posX, posY);
            btnDir[7].BackColor = Color.LightCyan;
            btnDir[7].Click += new EventHandler(OnUpLeft_Click);
            bmp = (Bitmap)rm.GetObject("UL");    //ビットマップの読み込み
            bmp.MakeTransparent(Color.White);
            btnDir[7].Image = bmp;
            btnDir[7].Enabled = false;    //初期状態は使用不可
            //帰属関係設定
            gBoxMove.Controls.Add(btnDir[0]);
            gBoxMove.Controls.Add(btnDir[1]);
            gBoxMove.Controls.Add(btnDir[2]);
            gBoxMove.Controls.Add(btnDir[3]);
            gBoxMove.Controls.Add(btnDir[4]);
            gBoxMove.Controls.Add(btnDir[5]);
            gBoxMove.Controls.Add(btnDir[6]);
            gBoxMove.Controls.Add(btnDir[7]);
            this.Controls.Add(gBoxMove);
            //「パス」(Pass)ボタンの属性設定(解説:内容的には"Cancel"です。)
            btnPass = new Button();
            btnPass.Size = new Size(60, 24);
            btnPass.Location = new Point(ClientSize.Width - btnPass.Width - 10, ClientSize.Height - btnPass.Height - 10);
            btnPass.Text = "パス";
            btnPass.Click += new EventHandler(OnPass_Click);
            this.Controls.Add(btnPass);
            //フォームのレイアウトを再開
            this.ResumeLayout(false);
            this.PerformLayout();
        }

        private void SetControls(Cell cell)    //解説:ダイアログへの引数から、コントロールの初期状態を設定します。
        {
            //異種族間婚許可の確認
            InterMarriage.Checked = cell.Intmarg;
            //Avatarの属性表示(自分(引数cell)から自分の属性をラベルに表示します。)
            string[] tribes = new string[] {"ピンク", "ブルー", "グリーン", "死亡"};
            lblMeTribe.Text = tribes[cell.Tribe];
            lblMeAffection.Text = cell.Affection.ToString();
            lblMeHostility.Text = cell.Hostility.ToString();
            //Avatarセルの周囲状況をダイアログに反映させる

            //解説:コンピューター処理では周囲状況への対応優先順位が

            //「1-セル」「2-食物」「3-野原」ですが、ダイアログでは

            //アバター(ユーザー)が自由に選択できます。
            for(int i = 0; i < Max_Dir; i++)
            {
                switch(cell.Around[i])    //ダイアログ呼び出し前にCheck_Around実行済
                {
                    case 0:                //野原
                    //「移動」処理の矢印の.Enabledを変更(進める)
                        btnDir[i].Enabled = true;
                        break;
                    case 1:                //山(進めない)
                    case 2:                //河川(進めない)
                        break;    //解説:処理なし、です。
                    case 3:                //食物
                        //「食べる 」処理のgBoxFood.Enabledを変更(食べられる)
                        fDir = i;        //食物のある方向
                        gBoxFood.Enabled = true;
                        break;
                    default:            //セル(cell.Around[i] >= 4)
                        break;    //解説:↓でセルyとyDirを使って行いますので、ここでは処理なし、です。
                }
                if(yDir != Not_Found)    //他のセルと遭遇したならば(解説:Cell yがnullではなく、その方向(yDir)が-1ではない)
                {
                    if(you.Tribe < 3)            //生存するセル(Cell-P、Cell-B、Cell-G)なら
                    {
                        gBox.Enabled = true;    //他のセルへの対応が可能となる
                    }
                    else if(you.Tribe == 3)        //死亡したセルなら食物扱いとなるので
                    {
                        fDir = yDir;
                        gBoxFood.Enabled = true;
                    }
                    //他のセルの属性表示(解説:二つ以上いたとしても、yとyDirについて処理します。)
                    lblYouTribe.Text = tribes[you.Tribe];
                    lblYouAffection.Text = you.Affection.ToString();
                    lblYouHostility.Text = you.Hostility.ToString();
                }
            }
        }

        //終了処理
        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            base.OnFormClosing(e);
            //タイマーの停止と廃棄(解説:タイマーは開放<Dispose()>する必要があります。)
            dlgTimer.Stop();
            dlgTimer.Dispose();
        }
 

    //解説:以下ではWorldクラスインスタンスの「5つの"Inter-Cell relation/reaction(セル間関係/反応)」を処理します。
    //③-(セル間関係)(1) get_close()-親しくなり、愛着性が高まり、敵対性が低まります。
    //③-(セル間関係)(2) make_love()ー一定の愛着性を超えると交尾し、生殖力により出産します。
    //③-(セル間関係)(3) intimidate()ー敵対性と愛着性の度合いにより、相手を威嚇し、敵対性が高まり、愛着性が低まります。
    //③-(セル間関係)(4) fight()ー異種族婚許可、敵対性により、相互に攻撃、被害を受けます。
    //③-(セル間関係)(5) flee()ー敵対状態になっても、攻撃力、防御力の差が大きければ逃走します。」
    //その為にWorldクラスインスタンス(
wld)のアドレスが必要となり、本ダイアログの引数に入れています。

        private void OnGetClose_Click(object sender, EventArgs e)
        {
            wld.Get_Close(cell, you, yDir);
            Close();
        }

        private void OnIntimidate_Click(object sender, EventArgs e)
        {
            wld.Intimidate(cell, you, yDir);
            Close();
        }

        private void OnFight_Click(object sender, EventArgs e)
        {
            wld.Fight(cell, you, yDir);
            Close();
        }

        private void OnFlee_Click(object sender, EventArgs e)
        {
            wld.Flee(cell, you, yDir);
            Close();
        }

    //解説:以下は自分(Cellクラスインスタンスのcell)のメソッドで処理します。
        private void OnEat_Click(object sender, EventArgs e)
        {
            cell.Get_Food(fDir);
            Close();
        }

        private void OnUp_Click(object sender, EventArgs e)
        {
            cell.Get_Move(0);
            Close();
        }

        private void OnUpRight_Click(object sender, EventArgs e)
        {
            cell.Get_Move(1);
            Close();
        }

        private void OnRight_Click(object sender, EventArgs e)
        {
             cell.Get_Move(2);
            Close();
        }

        private void OnDownRight_Click(object sender, EventArgs e)
        {
            cell.Get_Move(3);
            Close();
        }

        private void OnDown_Click(object sender, EventArgs e)
        {
            cell.Get_Move(4);
            Close();
        }

        private void OnDownLeft_Click(object sender, EventArgs e)
        {
             cell.Get_Move(5);
            Close();
        }

        private void OnLeft_Click(object sender, EventArgs e)
        {
             cell.Get_Move(6);
            Close();
        }

        private void OnUpLeft_Click(object sender, EventArgs e)
        {
             cell.Get_Move(7);
            Close();
        }

//解説:お分かりの通り、全ての「5つの"Inter-Cell relation/reaction(セル間関係/反応)」、

//「摂食」、「移動」処理を実行すると本ダイアログを閉じます(Close())。

//従って、「一回の<3秒間の>ダイアログ表示でユーザーが選択した一つの行動」

//しかとれないことになります。
        private void OnPass_Click(object sender, EventArgs e)
        {
            Close();    //解説:「パス」はCancelと同じく何もしないでダイアログを閉じることです。
        }
    }
}    //解説:これはWorld_Cell(namespace)の閉じ括弧です。

 

以上で3回(実質的に4回ですが...)にわたって行ったWorldクラスの解説を終了します。

 

今後はこのCell_World.dll、Worldクラスインスタンスであるウィンドウコントロールの実際の使用例として、Cells.exeのソースを解説してゆきましょう。

 

前回に引き続き、今回はWorldクラス最後の解説として、PictureBoxから派生させてコントロールとなったWorldクラスの描画処理とアバター機能追加の為に新作した"AvatarController"ダイアログをやろうと思ったのですが、最後の最後で「文字数オーバーエラー」が出てしまいました。(エディターの「文字数:」はまだ16,140だったのですが...)

 

取り敢えず、PictureBoxから派生させてコントロールとなったWorldクラスの描画処理のみをやります。

 

【Worldクラス後半-その1】

        ///////////////////
        //描画関係メソッド
        ///////////////////
        //画面消去

        public void Clear()
        {
            gHandle.Clear(this.BackColor);    //解説:これは仮想画面Canvas(ビットマップ)の描画用ハンドルです。
        }

        //背景(Map)を表示する    //解説:Mapは文字ベースのオリジナル地形図です。
        public void ShowMap()
        {
            bool changed = false;                        //WorldのMapと論理マップ(PrevMap)との差異フラグ
            for(int j = 0; j < Wld_Height; j++)            //Y座標
            {
                for(int i = 0; i < Wld_Width; i++)        //X座標
                {
                    //ビットマップ表示
                    int n = Check_What(i, j);            //(i, j)の位置に何があるか
                    if(PrevMap[Wld_Width * j + i] != n)    //前回から変更があれば
                    {
                        PrevMap[Wld_Width * j + i] = n;    //記録して
                        changed = true;                    //差異フラグを立てる
                    }
                    Cell c;                                //Cell(解説:セルがいた場合の情報収集用)
                    switch(n)
                    {
                        case 0:    //野原
                        case 1:    //山
                        case 2:    //河川
                        case 3:    //食物
                            if(changed)                    //前回から変更があれば(解説:正確には「あった場合のみ」
                                gHandle.DrawImage(Terrain_Bmp[n], i * 16, j * 16);    //解説:nに応じた「地形ビットマップ配列」を表示
                            break;
                        default:
                            if(n > 3)                    //Cell(4 + ID)の場合
                            {
                                c = Get_Cell(i, j);        //(i, j)の位置あるCellを取得
                                if(c.ID == MyID && c.Alive)    //アバターの場合
                                    gHandle.DrawImage(Cell_Bmp[Max_Tribe], i * 16, j * 16);    //解説:アバタービットマップを表示
                                else                        //アバターではない場合
                                    gHandle.DrawImage(Cell_Bmp[c.Tribe], i * 16, j * 16);    //解説:死亡セルはTribeが"3"となり、ここで表示
                            }
                            else if(n == -1)
                                MessageBox.Show("地形ファイル(*.trn)に許容されない文字が含まれています。",
                                                "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        break;
                    }
                }
                if(changed)        //変化が一つでもあれば、World(描画領域)を更新
                    this.Image = (Image)Canvas;    //解説:Worldクラスインスタンスのコントロールの背景画面となる
            }
        }
    }
 

次回にAvatarControllerダイアログをすべてカバーできるとよいのですが...(心配)

 

前回単に移植しただけ前半」をやりましたので、今回は「アバターを入れた為に大きく変えたGoes_Aroundメソッド関連中盤」をやります。前回と同じく、オリジナルのC++の解説も適宜参考にしてください。

 

オリジナルのC++の解説で書いたように、ここでやっている機能は

 

③「世界が廻る(時が過ぎる)」(goes_around())-セルに日常活動を行わせるのですが、この内容はの通りです。
③-(セル間関係)(1) get_close()-親しくなり、愛着性が高まり、敵対性が低まります。
③-(セル間関係)(2) make_love()ー一定の愛着性を超えると交尾し、生殖力により出産します。
③-(セル間関係)(3) intimidate()ー敵対性と愛着性の度合いにより、相手を威嚇し、敵対性が高まり、愛着性が低まります。
③-(セル間関係)(4) fight()ー異種族婚許可、敵対性により、相互に攻撃、被害を受けます。
③-(セル間関係)(5) flee()ー敵対状態になっても、攻撃力、防御力の差が大きければ逃走します。」

 

という「5つの"Inter-Cell relation/reaction(セル間関係/反応)」です。今回もこの5つのメソッドは全く同じです。唯一の変更は

 

Avatar

 

の処理()だけです。コメントに加え、適宜解説:を付加しました。

:アバターはユーザーが世界の中のセルの一つになって生存活動をマニュアルで行うfeature(注の注)です。アバターの処理はユーザーが行いますが、3秒間何もしないと勝手に他のセルが(PCの判断により)行動を継続してゆきます。尚、今回のコードでは実際にアバターの行う処理は出てきません。それらは「アバターコントローラー」ダイアログで処理されます。

注の注:A software feature is "a prominent or distinctive user-visible aspect, quality, or characteristic of a software system or systems", as defined by Kang et al ... (wiki)

 

【Worldクラス中盤】

        public void Goes_Around()                        //「世界が廻る(時が過ぎる)」→セルに日常活動を行わせる
        {
            if(!Gameover)
            {
                //最大人口超の場合
                if(CellList.Count > Max_Population)
                {
                    Gameover = true;                    //ゲームオーバー
                    Message += "現在の人口過密が異常となりました!(人口爆発)" + 
                                Environment.NewLine + Get_Distribution() +
                                Environment.NewLine + "(詳細はログを参照ねがいます。)";
                    return;
                }
                bool extinction = true;                    //絶滅チェッカー
                int LastCell = CellList.Count;
                for(int i = 0; i < LastCell; i++)        //"foreach"は配列が変化するとエラーになる為
                {
                    Cell cell = CellList[i];            //IDから対象セルを求める
                    cell.VitalCheck();                    //対象セルの生死状態をチェック
                    if(cell.Alive)                        //生存している場合
                    {
                        Check_Around(cell);                //対象セルの周囲を確認する
                        Point loc = cell.Where();        //対象セルの位置を取得
                        Map[loc.Y * Wld_Width + loc.X] = ' ';    //対象セルの旧座標を' 'にする
                        //周囲のセルの有無を確認する
                        Cell y = null;                    //周囲のセル
                        int dir = Not_Found;            //周囲のセルのいる方向
                        int val = cell.Find_Cell();        //対象セルの周囲にセルがいるか確認
                        if(val != Not_Found)            //周囲にセルが見つかったならば
                        {
                            dir = val & 0x0F;            //dirは周囲のセルの絶対方向(0 - 7)
                            y = Get_Cell(val >> 4);        //周囲のセルのポインターを取得
                        }
                        //コンピューター処理とマニュアル処理へ分岐させる(解説:ここが最大の変更点)
                        if(i == MyID && cell.Alive)        //ユーザー判断による処理(アバターの場合)死んだcellは食物でしかない

                            AvatarProcess(this, cell, y, dir);    //解説:↓参照
                        else                            //コンピューター判断による処理
                            AutoProcess(cell, y, dir);    //解説:↓参照(PC判断による処理)
                        loc = cell.Where();                //対象セルの移動があり得るので再取得
                        Map[loc.Y * Wld_Width + loc.X] = 'C';    //マップのセルxの新座標を'C'にする
                        cell.Aging();                    //老化による減衰と生命力消耗
                        cell.Param_Change();            //状況変化から各種パラメーターを調整
                        //絶滅チェック(一つでもAliveがtrueであればfalse)
                        extinction = false;
                    }
                    cell.VitalCheck();                    //活動後の対象セルの生死状態をチェック(解説:既に↑で同じメソッドをやっているので、一見冗長処理のように感じますが、このメソッドの後描画処理になるので、このターンで死亡した場合に正常に表示されるように行っています。)
                }
                if(extinction)                            //全滅により終了
                {
                    Gameover = true;
                    Message += "全セルが死亡しました!(全滅)" + 
                                Environment.NewLine + Get_Distribution() +
                                Environment.NewLine + "(詳細はログを参照ねがいます。)";
                }
            }
        }

        private void AvatarProcess(World world, Cell cell, Cell y, int dir)
        {
            //解説:ここでは AvatarControlleダイアログを、メインウィンドウの右隣に呼び出す処理しかやっていません。

            AvatarController ac = new AvatarController(world, cell, y, dir);
            //Worldクラスインスタンスを持つ親フォームの右隣に表示する
            ac.StartPosition = FormStartPosition.Manual;//ダイアログ位置を「任意指定」にする
            Form parent = this.FindForm();                //親フォーム(C++なら「へのポインター」)
            ac.Location = new Point(parent.Location.X + parent.Width, parent.Location.Y);      //解説:Yは同じ、Xは右隣
            ac.ShowDialog(this);
            ac.Dispose();
            if(dir != Not_Found)                        //yが存在しない場合もあるので
                y.VitalCheck();                            //活動後の相手セルの生死状態をチェック(解説:yが死亡した場合の描画処理用)
        }

        private void AutoProcess(Cell cell, Cell y, int dir)
        {

            //解説:ここが従来の処理で、アバターがない場合、全てここで処理されます。

            if(dir != Not_Found)                        //周囲にセルが見つかったならば
            {
                y.VitalCheck();                            //相手セルの生死状態をチェック
                if(y.Alive)                                //相手セルが生きていれば
                {
                    if(cell.Intmarg)                    //異種族婚を許可しているか
                    {
                        //【調整項目】
                        if(cell.Affection < 30 &&        //愛着性が30未満で
                            cell.Hostility > 70)        //敵対性が70超であれば
                            Intimidate(cell, y, dir);    //相互に威嚇する
                        else if(cell.Affection > 40 &&    //愛着性が40超で
                            cell.Hostility < 50)        //敵対性が50未満であれば
                            Get_Close(cell, y, dir);    //親交を結ぶ
                        else                            //それ以外は
                            Flee(cell, y, dir);            //相手から離れる
                    }
                    else                                //異種族婚が認められなければ
                    {
                        if(cell.Tribe != y.Tribe)        //異種族なら
                            Intimidate(cell, y, dir);    //相互に威嚇する
                        else                            //同種族であっても
                        {
                            //【調整項目】
                            if(cell.Affection < 30 &&    //愛着性が30未満で
                                cell.Hostility > 70)    //敵対性が70超であれば
                                Intimidate(cell, y, dir);//相互に威嚇する
                            else if(cell.Affection > 40 &&    //愛着性が40超で
                                cell.Hostility < 50)    //敵対性が50未満であれば
                                Get_Close(cell, y, dir);//親交を結ぶ
                            else                        //敵対が強ければ
                                Flee(cell, y, dir);        //相手から離れる
                        }
                    }
                    y.VitalCheck();                        //活動後の相手セルの生死状態をチェック
                }
                else                                    //死んでいれば食物と同じ扱いとなる
                {
                    cell.Get_Food(dir);                    //移動して摂食する
                }
            }
            else                                        //周囲にセルがいないならば
            {
                dir = cell.Find_Food();                    //周囲に食物があるかどうか確認する
                if(dir != Not_Found)                    //あれば移動して、摂食する
                    cell.Get_Food(dir);
                else
                {
                    dir = cell.Find_Field();            //周囲に野原があるかどうか確認する
                    if(dir != Not_Found)                //あれば移動する
                        cell.Get_Move(dir);
                }
            }
        }

        public void Get_Close(Cell x, Cell y, int dir)    //親しくなり、愛着性が高まり、敵対性が低まる
        {
            //セルx, y両者の愛着性が50%を超える場合、交尾に進む
            if(x.Affection > 60 && y.Affection > 60)    //【調整項目】
                Make_Love(x, y, dir);
            //そうでなければセルx, y両者の愛着性が増え、敵対性が減る
            else {
                x.Affection += Increase;
                y.Affection += Increase;
                x.Hostility += Decrease;
                y.Hostility += Decrease;
            }
        }

        public void Make_Love(Cell x, Cell y, int dir)    //一定の愛着性を超えると交尾し、生殖力により出産する
        {
            //xと同種族のセルが何処か(!)に誕生する
            if(x.Fertility > 50)                        //【調整項目】50だとなかなか生まない
            {
                int n = CellList.Count;        //次のIDを控える
                Create_Cells(1, x.Intmarg);    //xと同じIntmargのセルを生成
                Cell z = Get_Cell(n);        //新生セルのポインターを取得
                z.Tribe = x.Tribe;            //新生セルをxと同じ種族に設定
                //【調整項目】出産後、相手yを殺し、摂食する
                //y.Killed();
                //x.Get_Food(dir);

            }
            else    //離別(逃走)する
                Flee(x, y, dir);
        }

        public void Intimidate(Cell x, Cell y, int dir)    //敵対性と愛着性の度合いにより、相手を威嚇し、敵対性が高まり、愛着性が低まる
        {
            //セルx, y両者の敵対性が50%を超える場合、闘争に進む
            if(x.Hostility > 50 && y.Hostility > 50)    //【調整項目】
                Fight(x, y, dir);
            //そうでなければセルx, y両者の敵対性が増え、愛着性が減る
            else
            {
                x.Affection += Decrease;
                y.Affection += Decrease;
                x.Hostility += Increase;
                y.Hostility += Increase;
            }
        }

        public void Fight(Cell x, Cell y, int dir)        //異種族婚許可、敵対性により、相互に攻撃、被害を受ける
        {
            //相手の攻撃力が自分の攻撃力よりMAX_PARAM / 4(25)以上、又は
            //相手の生命力が自分の生命力の倍以上あれば

            if((y.Power > x.Power + Max_Param / 4) ||
                (y.Power > x.Power * 2))
                Flee(x, y, dir);                                //逃走する
            else {
                //xの先制攻撃(xの攻撃力がyの防御力を上回る場合、被害を与える)
                y.Damaged(x.Power - y.Defense);
                //yの後攻攻撃
                x.Damaged(y.Power - x.Defense);
            }
        }

        public void Flee(Cell x, Cell y, int dir)        //敵対状態になっても、攻撃力、防御力の差が大きければ逃走する
        {
            int reverse = x.Find_Field(false, dir);        //相手yの反対方向の野原を探す
            x.Get_Move(reverse);                        //逃走する
        }

        public void Make_Log()                            //WorldのCell情報をログに記録
        {
            if(CellList.Count > 0)
            {
                //セルデータの出力ファイル名("CellOf(yyyy-mm-dd_hh_mm)from<Ini_Pop>.txt")
                string strNow = DateTime.Now.ToString("yyyy-MM-dd_HH_mm");
                 string path = ".\\Log\\CellsOf(" + strNow + ")from" + Ini_pop.ToString() + ".txt";
                //ファイル出力(解説:今回はファイルをすべてUnicode(UTF8)にしています。)
                using (StreamWriter file = new StreamWriter(path, false, Encoding.UTF8))
                {
                    file.Write(Show_Cell_Param());        //ファイルを書く
                    file.Close();                        // ファイルを閉じる
                }
            }
        }

 

さてさて、それでは次回は最後にAvatarControllerダイアログと描画処理について解説します。