前回からの続きです。今回はCell_World共通部分とCellクラスを取り上げます。

 

【World_Cellコード-共通部分とCellクラス】

//////////////////////////////////
// Cell_World.cs
// Class Definitions for Cells.cs
// Copyright (c) 2026 by Y-sama
//////////////////////////////////

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;        //Graphicsクラス(アンチエイリアス)使用の為
using System.Collections.Generic;    //List使用の為
using System.IO;                    //FileStream使用の為
using System.Text;                    //Encording使用の為
using System.Reflection;            //Assemblyを使う為
using System.Resources;                //リソース使用の為

namespace Cell_World
{
    /////////////////
    //Cellクラス定義
    /////////////////

    public class Cell
    {
        ///////////////////////
        //ゲーム関係フィールド
        //     定数定義
        ///////////////////////

        int Max_Left = 17520;                    //セルの最長余命(単位1時間、2年で24hours x 365days x 2years = 17,520)
        int Max_Life = 4320;                    //セルの最大初期エネルギー(半年で24hours x 180days = 4320)
        const int Max_Tribe = 4;                //現在はCell-P, Cell-B, Cell-G, Cell-D(死亡)
        const int Max_Dir = 8;                    //↑:0、↗:1、→:2、↘:3、↓:4、↙:5、←:6、↖:7
        const int Not_Found = -1;                //Find_***処理用
        int Living_Cost = 24;                    //【調整項目】余命(Left)、生命力(Life)の消耗時間
        /////////////////////////////////
        //メンバーフィールドとプロパティ
        /////////////////////////////////
        //生存フラグ

        public bool Alive {get; private set;}    //生存(true)、死亡(false)
        //繁殖フラグ
        public bool Intmarg {get; set;}            //異種族間婚の許可
        //位置
        private Point Location;                    //Cellの位置(World内の位置座標)
        private int[] m_Around = new int[8];    //環境情報フィールド(Aroundの実体)
        public int[] Around                        //Cell周囲の存在(野原:0、山:1、河川:2、食物:3、セル:4 + ID)
        {    get
            {
                return m_Around;
            }
            private set
            {
                m_Around = value;
            }
        }
        //性格系
        public int Affection {get; set;}        //愛着性
        public int Hostility {get; set;}        //敵対性
        //能力系
        public int Left {get; set;}                //余命(Max_Left: 単位1時間、2年で24hours x 365days x 2years = 17,520)
        public int Life {get; set;}                //生命力(Max_Life: 半年分で24hours x 180days = 4320)
        public int Power {get; private set;}    //攻撃力(Lifeによる)
        public int Defense {get; private set;}    //防御力(LifeとLeft<経験>による)
        public int Fertility {get; private set;}//生殖力(Leftによる)
        //識別系
        public int ID {get; set;}                //Cellのゼロベースの固有番号
        public int Tribe {get; set;}            //種族(ピンク:0、ブルー:1、グリーン:2、モノ(死亡):3の4色)
        //運動系
        public int Dir {get; set;}                //Cellの移動方向(↑:0、↗:1、→:2、↘:3、↓:4、↙:5、←:6、↖:7)

        ///////////////////
        //メンバーメソッド
        ///////////////////

        public Cell(bool intmarg)                //コンストラクター
        {
            //異種族婚許可、性格系、能力系、運動系パラメーターは生成時決定
            Init(intmarg);
        }

        public void Init(bool intmarg)            //Cellの初期化
        {
            //CellのIDはWorldクラスのCreate_Cellで与えられ、Born_Atで記録される
            ID = Not_Found;
            //生存フラグ
            Alive = true;
            //繁殖フラグ(原則異種族間婚はタブー)
            Intmarg = intmarg;
            //位置(周囲状況-WorldのCheck_Aroundで更新される)
            for(int i = 0; i < 8; i++)
                Around[i] = Not_Found;    //Not_Found(-1)はエラー値
            //性格系
            Affection = World.rand.Next(10, 101);        //愛着性(10から100まで)
            Hostility = World.rand.Next(10, 101);        //敵対性(10から100まで)
            //余命
            Left = (Max_Left * World.rand.Next(10, 101)) / 100;    //最長余命 X 10 - 100%
            //生命力(半年分)
            Life = (Max_Life * World.rand.Next(10, 101)) / 100;    //最大初期エネルギー X 10 - 100%
            //能力系
            Power = World.rand.Next(10, 101);            //攻撃力(LifeとLeftによる)
            Defense = World.rand.Next(5, 51)        ;    //防御力(Ditto)-一般に防御力は攻撃力より弱い
            Fertility = World.rand.Next(10, 101);        //生殖力(Leftによる)
            //識別系(種族表示色-ピンク、ブルー、グリーン、モノ(死亡)の4種-前3種を使用)
            Tribe = World.rand.Next(Max_Tribe - 1);
            //運動系
            Dir = World.rand.Next(8);                    //↑:0、↗:1、→:2、↘:3、↓:4、↙:5、←:6、↖:7
        }

        public bool Born_At(int id, int x, int y)        //CellのID、座標設定(どこに、誰として生まれるのか)
        {
            if(ID != Not_Found)                            //既に生まれている場合、エラー
                return false;
            else
            {
                ID = id;
                Location.X = x;
                Location.Y = y;
                return true;
            }
        }

        public string Show_Param()                        //パラメーターの表示
        {
            string param = "No.";
            if(ID < 9)
                param += " " + (ID + 1).ToString() + " ";
            else
                param += (ID + 1).ToString() + " ";
            param += Alive ? "生存状態:存命" : "生存状態:死亡";
            param += "(余命:" + Left.ToString() + ")";
            string[] tribe = new string[4] {"ピンク", "ブルー", "グリーン", "モノトーン(死亡)"};
            param += "、種族:" + tribe[Tribe];
            param +=  "、愛着性:" + Affection.ToString() + "、敵対性:" + Hostility.ToString()
            + "、生命力:" + Life.ToString() + "、攻撃力:" + Power.ToString()
            + "、防御力:" + Defense.ToString() + "、生殖力:" + Fertility.ToString() + Environment.NewLine;
            return param;
        }

        public Point Where()                    //Cellの座標の取得
        {
            return Location;
        }

        public void Get_There(Point there)        //指定locationへ移動する
        {
            Location = there;
        }

        public void VitalCheck()                //死亡要因をチェックし、Aliveを決定する
        {
            if(Left > 0 && Life > 0)            //余命があり、且つ生命力がある
            {
                Alive = true;
            }
            else
            {
                Alive = false;                    //死亡
                Tribe = 3;                        //セルの色をモノ(死亡-3 <食物>)に変える
            }
        }

        public int Find_Cell()                    //周囲にセルがいるか否かチェックする(戻り値は複合)
        {                                        //戻り値(val):絶対方向(val & 0x0F)、周囲のセルのID(val >> 4)
            int dir = 0;                        //戻り値(全bitが0)
            int id = Not_Found;                    //戻り値(全bitが1)
            //方向は↑:0、↗:1、→:2、↘:3、↓:4、↙:5、←:6、↖:7
            for(int i = 0; i < Max_Dir; i++)
            {
                dir = (Dir + 7 + i) % Max_Dir;    //進行方向斜め左から
                if(Around[dir] >= 4)            //セルがいる場合
                {
                    id = Around[dir] - 4;        //idはセルのID
                    return dir | (id << 4);        //idはdir(0 - 7)がかからないよう16倍にする
                }
            }
            return Not_Found;                    //セルがいない場合は-1を返す
        }

        public int Find_Food()                    //周囲に食物があるか否かチェックする
        {
            //方向は↑:0、↗:1、→:2、↘:3、↓:4、↙:5、←:6、↖:7
            for(int i = 0; i < Max_Dir; i++)
            {
                int f_dir = (Dir + 7 + i) % Max_Dir;    //進行方向斜め左から
                if(Around[f_dir] == 3)
                    return f_dir;                //戻り値は絶対方向(0-7)
            }
            return Not_Found;                    //ない場合は-1を返す
        }

        public void Get_Food(int dir)            //周囲に食物があれば移動して摂食する
        {
            if(dir < 0 || dir > 7)
                return;                            //エラー(何もしない)
            Get_Move(dir)    ;                    //食物へ移動する
            Life += 168;                        //【調整項目】7日分(24h x 7d)のエネルギー回復
        }

        //周囲に(進むことが出来る)野原があるか否かチェックする |7|0|1|
        //進行方向(Dir)と前進、後退を指定できる(forward)         |6|C|2|
        //前進→Dir、後退→(Dir + 4) % 8;                         |5|4|3|

        public int Find_Field(bool forward = true, int d = -1)
        {
            //進行方向指示がある場合(エラーチェック付)
            if(d > -1 && d < 8)
                Dir = d;
            //野原の方角を記録(nは野原のある方向の数、dirは戻り値)
            int[] field = new int[Max_Dir] {-1, -1, -1, -1, -1, -1, -1, -1};
            int n = 0, dir = Not_Found;
            //方向は↑:0、↗:1、→:2、↘:3、↓:4、↙:5、←:6、↖:7
            for(int i = 0; i < Max_Dir; i++)
            {
                if(Around[i] == 0)                //Around[]に野原があれば
                {
                    field[n] = i;                //fieldにその方向を記録してゆく
                    if(forward)                    //前進可で
                    {
                        if(i == Dir)            //進行方向に野原があれば
                            dir = i;            //その方向
                    }
                    else                        //後退で
                    {
                        if(i == (Dir + 4) % 8)    //逆方向に野原があれば
                            dir = i;            //その方向
                    }
                    n++;
                }
            }
            if(n == 0)                            //ない場合は
                return Not_Found;                //-1を返す(エラー)
            else
            {
                if(dir == -1)                    //真前または後ろへ進めないなら
                    dir = field[World.rand.Next() % n];    //乱数による選択
                //dirがDirの場合でも「1/8(12.5%)」の確率で(パニック状態)
                else if(dir == Dir && World.rand.Next() % Max_Dir == 0)
                    dir = field[World.rand.Next() % n];    //乱数による選択
            }
            return dir;
        }

        public void Get_Move(int dir)            //野原があれば一つ移動する(Locationを変更する)
        {
            if(dir < 0 || dir > 7)
                return;                            //エラーチェック
            switch(dir)
            {
                case 0:        //↑
                    Location.Y--;
                    break;
                case 1:        //↗
                    Location.X++;
                    Location.Y--;
                    break;
                case 2:        //→
                    Location.X++;
                    break;
                case 3:        //↘
                    Location.X++;
                    Location.Y++;
                    break;
                case 4:        //↓
                    Location.Y++;
                    break;
                case 5:        //↙
                    Location.X--;
                    Location.Y++;
                    break;
                case 6:        //←
                    Location.X--;
                    break;
                case 7:        //↖
                    Location.X--;
                    Location.Y--;
                    break;
            }
            Dir = dir;
        }

        public void Aging()                            //加齢変化(老化)
        {
            Left -= Living_Cost;                    //寿命
            Life -= Living_Cost;                    //生命力
        }

        public void Param_Change()                    //【調整項目】状態変化により、各種パラメーターが変化する
        {
            //【余命とライフステージ】
            //余命(MAX_LEFT-17,520)の90%(15,768)が最大なので、人間の平均余命80歳として
            //幼年期0-15歳(20%)、青年期16-29歳(16%)、壮年期30-49歳(25%)、老年期50-80歳(37.5%)
            //の分布を考えれば、m_leftは、
            //幼年期(~12,951)、青年期(12,950~9,801)、壮年期(9,800~5,901)、老年期(5,900~0)
            //程度と考えられるが、余命の最小値が10%の1,752なので以下のように調整
            //幼年期(~8,001)、青年期(8,000~5,001)、壮年期(5,000~2,001)、老年期(2,000~0)
            //【攻撃力】
            //生命力の初期値は半年分のエネルギー(MAX_LIFE-4320)の10 - 90%であり、食物と死体を摂食
            //することでしか増加できない為、攻撃力(m_power)増加要因として幼年期は1000あれば1/2の
            //確率でm_powerが増加、青年期、壮年期は2000あれば1/2、1/3で増加
            //【防衛力】
            //これは「亀の甲より年の効」で「(見做し)経験を積んだ」として壮年期、老年期に1/3の確率
            //で増加
            //【生殖力】
            //これは若さだけなので、幼少期、青年期に1/2、壮年期に1/3の確率で増加、老年期は1/2の確率
            //で減少

            if(Left > 8000)            //幼年期
            {
                if(Life > 1000 && World.rand.Next() % 2 == 0)
                    Power++;
                if(World.rand.Next() % 2 == 0)
                    Fertility++;
            }
            else if(Left > 5000)    //青年期
            {
                if(Life > 2000 && World.rand.Next() % 2 == 0)
                    Power++;
                if(World.rand.Next() % 2 == 0)
                    Fertility++;
            }
            else if(Left > 2000)    //壮年期
            {
                if(Life > 2000 && World.rand.Next() % 3 == 0)
                    Power++;
                if(World.rand.Next() % 3 == 0)
                    Defense++;
                if(World.rand.Next() % 3 == 0)
                    Fertility++;
            }
            else                    //老年期
            {
                if(World.rand.Next() % 3 == 0)
                    Defense++;
            }
        }

        public void Damaged(int d)                    //加害を受け、生命力、余命が減少する
        {
            //ダメージ(d) = 相手攻撃力(Power) - 自分の防御力(Defense)とする
            if(d > 0)
            {
                Life -= d;
                Left -= d;
            }
        }

        public void Killed()                        //殺されて、生命力、余命が0になる
        {
            Left = 0;
            Life = 0;
            Tribe = 3;
            Alive = false;
        }
    }

 

Worldクラスはもっと長いので、これも適宜分割して解説します。