/////////////////////////////////////////////
// Ccell_world.h - A new life game for C++
//		Copyright (c) 2025 by Ysama
// Caveat: In this file, Ysama tried to write
// codes in compliance with C++library an
// not to use Windowsss API or BCCSkelton.
/////////////////////////////////////////////
///////////////////
//システムヘッダー
///////////////////
#include	<fstream>			//C++言語のファイル入出力システムヘッダー
#include	<vector>			//C++言語の文字列STLコンテナvectorライブラリー
#include	<string>			//C++言語の文字列stringライブラリー
#include	<random>			//非決定的乱数を使用する為

///////////////////////
//定数定義（変更不可）
///////////////////////
#define		MAX_WIDTH	80		//「世界」の幅の最大値
#define		MAX_HEIGHT	40		//「世界」の高さの最大値
#define		MAX_POPU	MAX_WIDTH * MAX_HEIGHT / 2	//「世界」に棲めるセルの最大人口
#define		MAX_TRIBE	4		//現在はCell-P, Cell-B, Cell-G, Cell-D（死亡）
#define		MAX_DIR		8		//↑:0、1、→:2、3、↓:4、5、←:6、7
#define		NOT_FOUND	-1		//find_***処理用
/////////////////////////////////
//【調整項目】定数定義（変更可）
/////////////////////////////////
#define		MAX_LEFT	17520	//セルの最長余命（単位1時間、2年で24hours x 365days x 2years = 17,520）
#define		MAX_LIFE	4320	//セルの最大初期エネルギー（半年で24hours x 180days = 4320）
#define		MAX_PARAM	100		//cellの属性の最大値
#define		LIVING_COST	24		//余命（m_left）、生命力（m_life）の消耗量（時間を表す）
#define		INCREASE	1		//パラメーターの増加幅
#define		DECREASE	-1		//パラメーターの減少幅

using namespace std;

/////////////
//構造体定義
/////////////
typedef struct {
	int X;
	int Y;
} location;

/////////////
//クラス定義
/////////////

/////////////
//Ccellクラス
/////////////
class Ccell
{
private:
	//生存フラグ
	bool m_alive;				//生存（true）、死亡（false）
	//繁殖フラグ
	bool m_intmarg;				//異種族間婚の許可
	//位置
	location m_location;		//cellの位置（world内の位置座標）
	int m_around[8];			//cell周囲の存在物（野原:0、山:1、河川:2、食物：3、セル：4 + ID、それ以外：-1）
	//性格系
	int m_affection = 0;		//愛着性
	int m_hostility = 0;		//敵対性
	//能力系
	int m_left = 0;				//余命（MAX_LEFT: 単位1時間、2年で24hours x 365days x 2years = 17,520）
	int m_life = 0;				//生命力（MAX_LIFE: 半年分で24hours x 180days = 4320）
	int m_power = 0;			//攻撃力（m_lifeによる）
	int m_defense = 0;			//防御力（m_lifeとm_left<経験>による）
	int m_fertility = 0;		//生殖力（m_leftによる）
	//識別系
	int m_id = -1;				//cellのゼロベースの固有番号
	int m_tribe = -1;			//種族（色で表し、ピンク、ブルー、グリーン、モノ（死亡）の4色）
	//運動系
	int m_dir;					//現在の移動方向（↑:0、1、→:2、3、↓:4、5、←:6、7）
public:
	Ccell(bool);				//コンストラクター
	void init(bool);			//cellの初期化
	bool born_at(int ,int, int);				//cellのID、座標設定（どこに、誰として生まれるのか）
	bool is_alive() {return m_alive;};			//生死確認
	void set_intmarg(bool OK) {m_intmarg = OK;}	//異種族間婚を許可する
	bool get_intmarg() {return m_intmarg;}		//異種族間婚許可か否かをチェックする
	void set_id(int n) {m_id = n;}				//cellのIDを設定
	int get_id() {return m_id;}					//cellのIDを取得
	int set_tribe(int n) {m_tribe = n;}			//種族設定
	int get_tribe() {return m_tribe;}			//種族確認
	void set_affection(int n) {m_affection = n;}//愛着性の設定
	int get_affection() {return m_affection;}	//愛着性の取得
	void set_hostility(int n) {m_hostility = n;}//敵対性の設定
	int get_hostility() {return m_hostility;}	//敵対性の取得
	void set_life(int n) {m_life = n;}			//生命力の設定
	int get_life() {return m_life;}				//生命力の取得
	int get_power() {return m_power;}			//攻撃力の取得
	int get_defense() {return m_defense;}		//防御力の取得
	int get_fertility() {return m_fertility;}	//生殖力の取得
	int* get_around() {return m_around;}		//cell周囲の存在物(int[8])のポインターを返す
	string show_param();		//パラメーターの表示
	location where();			//cellの座標の取得
	void get_there(location);	//指定locationへ移動する
	void vitalcheck();			//死亡要因をチェックし、m_aliveを決定する
	int find_cell();			//周囲にセルがいるか否かチェックする（戻り値は複合）
	int find_food();			//周囲に食物があるか否かチェックする
	void get_food(int);			//周囲に食物があるか否かチェックし、あれば移動して摂食する
	int find_field(bool, int);	//周囲に（進むことが出来る）野原があるか否かチェックする
	void get_move(int);			//野原があれば一つ移動する（m_locationを変更する）
	void aging();				//加齢変化（老化）
	void param_change();		//【調整項目】状態変化により、各種パラメーターが変化する
	void damaged(int);			//加害を受け、生命力、余命が減少する
	void killed();				//殺されて、生命力、余命が0になる
};

//コンストラクター
Ccell::Ccell(bool intmarg) {

	init(intmarg);	//異種族婚許可、性格系、能力系、運動系パラメーターは生成時決定
}

//cellの初期化
void Ccell::init(bool intmarg) {

	//生存フラグ
	m_alive = true;
	//繁殖フラグ（原則異種族間婚はタブー）
	m_intmarg = intmarg;
	//位置（周囲状況－Cworldのcheck_aroundで更新される）
	for(int i = 0; i < 8; i++)	m_around[i] = -1;	//-1はエラー値
	//ハードウェア乱数をシードにして初期化（uint32_t版）
	std::random_device seed;		//Windowsではrandom_deviceが有効でない可能性がある
	std::mt19937 engine(seed());
	std::uniform_int_distribution<> dist(10, 100);	//10から100までの整数乱数を生成
	//性格系
	m_affection = dist(engine);		//愛着性
	m_hostility = dist(engine);		//敵対性
	//余命
	m_left = MAX_LEFT * dist(engine) / 100;		//最長余命 X 10 - 100%
	//生命力（半年分）
	m_life = MAX_LIFE * dist(engine) / 100;		//最大初期エネルギー X 10 - 100%
	//能力系
	m_power = dist(engine);			//攻撃力（m_lifeとm_leftによる）
	m_defense = dist(engine) / 2;	//防御力（Ditto）－一般に防御力は攻撃力より弱い
	m_fertility = dist(engine);		//生殖力（m_leftによる）
	//識別系（種族表示色－ピンク、ブルー、グリーン、モノ（死亡）の4色）
	m_tribe = dist(engine) % (MAX_TRIBE - 1);
	//運動系
	m_dir = dist(engine) % MAX_DIR;	//↑:0、1、→:2、3、↓:4、5、←:6、7
}

//cellの座標設定
bool Ccell::born_at(int id, int x, int y) {

	if(m_id != -1)		//既に生まれている場合、エラー
		return false;
	else {
		m_id = id;
		m_location.X = x;
		m_location.Y = y;
		return true;
	}
}

//パラメーターの表示
string Ccell::show_param() {

	string param = "No.";
	if(m_id < 9)
		param += " " + to_string(m_id + 1) + " ";
	else
		param += to_string(m_id + 1) + " ";
	param += m_alive ? "生存状態：存命" : "生存状態：死亡";
	param += "（余命：" + to_string(m_left) + "）";
	string tribe[4] = {"ピンク", "ブルー", "グリーン", "モノトーン（死亡）"};
	param += "、種族：" + tribe[m_tribe];
	param +=  "、愛着性：" + to_string(m_affection) + "、敵対性：" + to_string(m_hostility)
			+ "、生命力：" + to_string(m_life) + "、攻撃力：" + to_string(m_power)
			+ "、防御力：" + to_string(m_defense) + "、生殖力：" + to_string(m_fertility) + "\r\n";
	return param;
}

//一座標の取得
location Ccell::where() {

	return m_location;
}

//指定locationへ移動する
void Ccell::get_there(location there) {

	m_location = there;
}

//死亡要因をチェックし、m_aliveを決定する
void Ccell::vitalcheck() {

	if(m_left > 0 && m_life > 0) {	//余命があり、且つ生命力がある
		m_alive = true;
	}
	else {
		m_alive = false;			//死亡
		m_tribe = 3;				//セルの色をモノ（死亡色－3）に変える
	}
}

//周囲にセルがいるか否かチェックする（戻り値は複合）
//戻り値(val)：絶対方向（val & 0x1111）、周囲のセルのm_id（val >> 4）
int Ccell::find_cell() {

	int dir = 0;			//戻り値（全bitが0）
	int id = -1;
	//方向は↑:0、1、→:2、3、↓:4、5、←:6、7
	for(int i = 0; i < MAX_DIR; i++) {
		dir = (m_dir + 7 + i) % MAX_DIR;	//進行方向斜め左から
		if(m_around[dir] >= 4) {			//セルがいる場合
			id = m_around[dir] - 4;			//idはセルのm_id
			return dir | (id << 4);			//idはdir（0 - 7）がかからないよう16倍にする
		}
	}
	return NOT_FOUND;		//セルがいない場合は-1を返す
}

//周囲に食物があるか否かチェックする
int Ccell::find_food() {

	//方向は↑:0、1、→:2、3、↓:4、5、←:6、7
	for(int i = 0; i < MAX_DIR; i++) {
		int val = (m_dir + 7 + i) % MAX_DIR;//進行方向斜め左から
		if(m_around[val] == 3)
			return val;		//戻り値は絶対方向(0－7）
	}
	return NOT_FOUND;		//ない場合は-1を返す
}

//指定方向に移動して食物を摂食する
void Ccell::get_food(int dir) {

	if(dir < 0 || dir > 7)
		return;		//エラーチェック
	switch(dir) {
	case 0:		//↑
		m_location.Y--;
		break;
	case 1:		//斜め右上
		m_location.X++;
		m_location.Y--;
		break;
	case 2:		//→
		m_location.X++;
		break;
	case 3:		//斜め右下
		m_location.X++;
		m_location.Y++;
		break;
	case 4:		//↓
		m_location.Y++;
		break;
	case 5:		//斜め左下
		m_location.X--;
		m_location.Y++;
		break;
	case 6:		//←
		m_location.X--;
		break;
	case 7:		//斜め左上
		m_location.X--;
		m_location.Y--;
		break;
	}
	m_life += 168;		//【調整項目】7日分（24h x 7d）のエネルギー回復
}

//周囲に（進むことが出来る）野原があるか否かチェックする
//	進行方向（m_dir）と前進、後退を指定できる
//	前進→m_dir、後退→(m_dir + 4) % 8;
//	7 0 1
//	6 C 2
//	5 4 3
int Ccell::find_field(bool forward = true, int d = -1) {

	//進行方向指示がある場合（エラーチェック付）
	if(d > -1 && d < 8)
		m_dir = d;
	//ハードウェア乱数をシードにして初期化（uint32_t版）
	std::random_device seed;		//Windowsではrandom_deviceが有効でない可能性がある
	std::mt19937 engine(seed());
	//野原の方角を記録（nは野原のある方向の数、dirは戻り値）
	int field[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
	int n = 0, dir = -1;
	//方向は↑:0、1、→:2、3、↓:4、5、←:6、7
	for(int i = 0; i < MAX_DIR; i++) {
		if(m_around[i] == 0) {				//m_around[]に野原があれば
			field[n] = i;					//fieldにその方向を記録してゆく
			if(forward) {					//前進可で
				if(i == m_dir)				//進行方向に野原があれば
					dir = i;				//その方向
			}
			else {							//後退で
				if(i == (m_dir + 4) % 8)	//逆方向に野原があれば
					dir = i;				//その方向
			}
			n++;
		}
	}
	if(!n)									//ない場合（n == 0）は
		return NOT_FOUND;					//-1を返す（エラー）
	else {
		if(dir == -1)						//真前または後ろへ進めないなら
			dir = field[engine() % n];		//乱数による選択
		//dirがm_dirの場合でも「1/8（12.5%)」の確率で（パニック状態）
		else if(dir == m_dir && engine() % MAX_DIR == 0)
			dir = field[engine() % n];		//乱数による選択
	}
	return dir;
}

//指定方向の野原へ移動する（m_locationとm_dirを変更する）
void Ccell::get_move(int dir) {

	if(dir < 0 || dir > 7)
		return;		//エラーチェック
	switch(dir) {
	case 0:		//↑
		m_location.Y--;
		m_dir = 0;
		break;
	case 1:		//斜め右上
		m_location.X++;
		m_location.Y--;
		m_dir = 1;
		break;
	case 2:		//→
		m_location.X++;
		m_dir = 2;
		break;
	case 3:		//斜め右下
		m_location.X++;
		m_location.Y++;
		m_dir = 3;
		break;
	case 4:		//↓
		m_location.Y++;
		m_dir = 4;
		break;
	case 5:		//斜め左下
		m_location.X--;
		m_location.Y++;
		m_dir = 5;
		break;
	case 6:		//←
		m_location.X--;
		m_dir = 6;
		break;
	case 7:		//斜め左上
		m_location.X--;
		m_location.Y--;
		m_dir = 7;
		break;
	}
}

//加齢変化（老化）と活動による消耗
void Ccell::aging() {

	m_left -= LIVING_COST;	//寿命
	m_life -= LIVING_COST;	//生命力
}

//【調整項目】状態変化により、各種パラメーターが変化する
void Ccell::param_change() {

	//ハードウェア乱数をシードにして初期化（uint32_t版）
	std::random_device seed;		//Windowsではrandom_deviceが有効でない可能性がある
	std::mt19937 engine(seed());
	//【余命とライフステージ】
	//余命（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(m_left > 8000) {			//幼年期
		if(m_life > 1000 && engine() % 2 == 0)
			m_power++;
		if(engine() % 2 == 0)
			m_fertility++;
	}
	else if(m_left > 5000) {	//青年期
		if(m_life > 2000 && engine() % 2 == 0)
			m_power++;
		if(engine() % 2 == 0)
			m_fertility++;
	}
	else if(m_left > 2000) {	//壮年期
		if(m_life > 2000 && engine() % 3 == 0)
			m_power++;
		if(engine() % 3 == 0)
			m_defense++;
		if(engine() % 3 == 0)
			m_fertility++;
	}
	else {						//老年期
		if(engine() % 3 == 0)
			m_defense++;
	}
}

//加害を受け、生命力、余命が減少する
void Ccell::damaged(int d) {

	//ダメージ(d) = 相手攻撃力(m_power) - 自分の防御力(m_defense)とする
	if(d > 0) {
		m_life -= d;
		m_left -= d;
	}
}

//他のセルに殺される
void Ccell::killed() {

	m_left = 0;
	m_life = 0;
	m_alive = false;
}

//////////////
//worldクラス
//////////////
class Cworld
{
private:
	bool m_gameover = false;				//ゲーム終了サイン
	string m_message;						//ゲームオーバーの際に、呼び出しユーザーに返すメッセージ
	int m_width = MAX_WIDTH;				//世界の幅
	int m_height = MAX_HEIGHT;				//世界の高さ
	char m_map[MAX_WIDTH * MAX_HEIGHT] = {};//世界地形図（0で初期化）
	int m_ini_pop = 0;						//開始時のセル数
	vector<Ccell*> m_celllist;				//セルリスト
	int m_tribe_status[4] =  {0};			//ピンク、ブルー、グリーンと死亡の状況を記録（0で初期化）
public:
	Cworld();								//コンストラクター
	~Cworld();								//デストラクター
	void init();							//「世界」の初期化
	void gameover() {m_gameover = true;}	//強制終了
	bool is_gameover() {return m_gameover;}	//ゲーム終了サインの取得
	string get_message() {return m_message;}//ゲーム終了時のメッセージを取得
	bool read_map(char*);					//「世界」の地図を読み込む
	int check_what(int, int);				//m_mapの桝目をチェックし、何があるかを返す（野原:0、山:1、河川:2、食物：3、セル：4 + m_id、それ以外：-1）
	bool create_cells(int, bool);			//指定個数のcellを作る
	int how_many_cells();					//m_celllistの登録されたcellの数を返す
	void check_around(Ccell*);				//周囲の状況をチェックし、指定cellのm_around[8]を更新する
	Ccell* get_cell(int);					//m_celllistの指定番目のセルのポインターを返す
	Ccell* get_cell(int, int);				//座標位置にあるセルのポインターを返す
	int* get_distribution();				//ピンク、ブルー、グリーン種族の生死状況を返す（整数配列[6]）
	string show_cell_param();				//cell属性を表示する
	void goes_around();						//「世界が廻る（時が過ぎる）」→セルに日常活動を行わせる
	void get_close(Ccell*, Ccell*, int);	//親しくなり、愛着性が高まり、敵対性が低まる
	void make_love(Ccell*, Ccell*, int);	//一定の愛着性を超えると交尾し、生殖力により出産し、相手を摂食する
	void intimidate(Ccell*, Ccell*, int);	//敵対性と愛着性の度合いにより、相手を威嚇し、敵対性が高まり、愛着性が低まる
	void fight(Ccell*, Ccell*, int);		//異種族婚許可、敵対性により、相互に攻撃、被害を受ける
	void flee(Ccell*, Ccell*, int);			//敵対状態になっても、攻撃力、防御力の差が大きければ逃走する
	void make_log();						//Cworldのセル情報をログに記録
};

//コンストラクター
Cworld::Cworld() {

	init();					//「世界」の初期化
}

//デストラクター
Cworld::~Cworld() {

	init();					//「世界」の初期化
}

//「世界」の初期化
void Cworld::init() {

	//「世界」地図の初期化
	fill(m_map, m_map + MAX_WIDTH * MAX_HEIGHT, 0);
	//cellが存在すれば、初期化してリストを空にする
	if(m_celllist.size() > 0) {
		for(Ccell *x : m_celllist)
			delete x;
	}
	m_celllist.clear();
	m_gameover = false;		//ゲーム開始
	m_message = "";			//メッセージの初期化
}

//「世界」の地図を読み込む
bool Cworld::read_map(char* fn) {

	string strline;
	ifstream in_file(fn);	//worldの地形データファイルを開く
	if(in_file.is_open()) {
		for(int i = 0; i < MAX_HEIGHT; i++) {
			getline(in_file, strline);		//1行ずつ読み込む
			//読み込んだ地形データをマップに複写する（ファイルの1行の長さに関わらず、MAX_WIDTHのみ使用）
			strncpy(m_map + MAX_WIDTH * i, strline.c_str(), MAX_WIDTH);	//文字列長 < MAX_WIDTHの場合\0が挿入される
		}
		in_file.close();					//ファイルを閉じる
		return true;
	}
	else {
//		m_message += "Couldn't open and read the terrain file(";
		m_message += "地形ファイル（";
		m_message += fn;
//		m_message += ")\r\n";
		m_message += "）を読み込めませんでした\r\n";
		return false;
	}
}

//m_mapの桝目をチェックし、何があるかを返す（野原:0、山:1、河川:2、食物：3、セル：4 + m_id、それ以外：-1）
int Cworld::check_what(int x, int y) {

	int val = -1;	//戻り値
	//エラーチェック
	if(x >= MAX_WIDTH || x < 0 || y >= MAX_HEIGHT || y < 0)
		return val;
	Ccell *c;		//周囲にcellがいる場合のID取得用
	switch(m_map[y * MAX_WIDTH + x]) {
	case '\0':	//「NULL(0X0)」 - 0
	case ' ':	//「野原(0X20)」- 0
		val = 0;
		break;
	case '^':	//「山(0X5E)」- 1
		val = 1;
		break;
	case '~':	//「河川(0X7E)」- 2
		val = 2;
		break;
	case 'O':	//「食物(0X4F)」- 3
		val = 3;
		break;
	case 'C':	//「cell(0X43)」- 4 + m_id
		c = get_cell(x, y);		//その位置にいるセルのポインターを取得
		val = 4 + c->get_id();	//セルであることとm_idを通知する
		break;
	default:	//エラー処理
//		m_message += "There is something illegal in the terrain map\r\n";
		m_message += "地形地図に規定外のものが発見されました\r\n";
		break;
	}
	return val;
}

//指定個数のcellを作る
bool Cworld::create_cells(int n, bool intmarg) {

	//開始時のセルの数を記録
	if(m_ini_pop == 0)	m_ini_pop = n;
	//ハードウェア乱数をシードにして初期化（uint32_t版）
	std::random_device seed;	//Windowsではrandom_deviceが有効でない可能性がある
	std::mt19937 engine(seed());
	//cellの生成
	for(int i = 0; i < n; i++) {
		Ccell *c = new Ccell(intmarg);		//cellインスタンスを生成
		//誕生位置決定
		while(true) {
			location loc;
			loc.X = engine() % MAX_WIDTH;	//X座標
			loc.Y = engine() % MAX_HEIGHT;	//Y座標
			if(check_what(loc.X, loc.Y) == 0) {	//そこが「野原(0)」か否かチェック
				c->born_at(m_celllist.size(), loc.X, loc.Y);//空白であれば誕生位置として登録
				m_map[loc.Y * MAX_WIDTH + loc.X] = 'C';		//cellをマップに書き込む
				check_around(c);							//cellの周囲情報を取得させる
				break;
			}
		}
		m_celllist.push_back(c);			//セルリストへ登録
	}
	get_distribution();						//開始段階の種族生死状況を記録
	return true;
}

//m_celllistの登録されたcellの数を返す
int Cworld::how_many_cells() {

	return m_celllist.size();
}

//周囲の状況をチェックし、指定cellのm_around[8]を更新する
void Cworld::check_around(Ccell* cell) {

	int *around = cell->get_around();	//cell周囲の存在物（野原:0、山:1、河川:2、食物：3、セル：4、それ以外：-1）
	location loc = cell->where();		//cellのm_locationを取得
	//エラーチェック（圏外は-1）
	if(loc.Y == 0) {					//上チェック不要
		if(loc.X % MAX_WIDTH == 0) {	//左チェック不要
			//around[0, 1, 5, 6, 7]は不要
			around[0] = around[1] = around[5] = around[6] = around[7] = -1;
			around[2] = check_what(loc.X + 1, loc.Y);
			around[3] = check_what(loc.X + 1, loc.Y + 1);
			around[4] = check_what(loc.X, loc.Y + 1);
		}
		else if(loc.X % MAX_WIDTH == MAX_WIDTH - 1) {	//右チェック不要
			//around[0, 1, 2, 3, 7]は不要
			around[0] = around[1] = around[2] = around[3] = around[7] = -1;
			around[4] = check_what(loc.X, loc.Y + 1);
			around[5] = check_what(loc.X - 1, loc.Y + 1);
			around[6] = check_what(loc.X - 1, loc.Y);
		}
		else {							//左右チェック要
			//around[0, 1, 7]は不要
			around[0] = around[1] = around[7] = -1;
			around[2] = check_what(loc.X + 1, loc.Y);
			around[3] = check_what(loc.X + 1, loc.Y + 1);
			around[4] = check_what(loc.X, loc.Y + 1);
			around[5] = check_what(loc.X - 1, loc.Y + 1);
			around[6] = check_what(loc.X - 1, loc.Y);
		}
	}
	else if(loc.Y == MAX_HEIGHT - 1) {	//下チェック不要
		if(loc.X % MAX_WIDTH == 0) {	//左チェック不要
			//around[3, 4, 5, 6, 7]は不要
			around[3] = around[4] = around[5] = around[6] = around[7] = -1;
			around[0] = check_what(loc.X, loc.Y - 1);
			around[1] = check_what(loc.X + 1, loc.Y - 1);
			around[2] = check_what(loc.X + 1, loc.Y);
		}
		else if(loc.X % MAX_WIDTH == MAX_WIDTH - 1) {	//右チェック不要
			//around[1, 2, 3, 4, 5]は不要
			around[1] = around[2] = around[3] = around[4] = around[5] = -1;
			around[0] = check_what(loc.X, loc.Y - 1);
			around[6] = check_what(loc.X - 1, loc.Y);
			around[7] = check_what(loc.X - 1, loc.Y - 1);
		}
		else {									//左右チェック要
			//around[3, 4, 5]は不要
			around[3] = around[4] = around[5] = -1;
			around[0] = check_what(loc.X, loc.Y - 1);
			around[1] = check_what(loc.X + 1, loc.Y - 1);
			around[2] = check_what(loc.X + 1, loc.Y);
			around[6] = check_what(loc.X - 1, loc.Y);
			around[7] = check_what(loc.X - 1, loc.Y - 1);
		}
	}
	else{								//上下チェック要
		if(loc.X % MAX_WIDTH == 0) {	//左チェック不要
			//around[5, 6, 7]は不要
			around[5] = around[6] = around[7] = -1;
			around[0] = check_what(loc.X, loc.Y - 1);
			around[1] = check_what(loc.X + 1, loc.Y - 1);
			around[2] = check_what(loc.X + 1, loc.Y);
			around[3] = check_what(loc.X + 1, loc.Y + 1);
			around[4] = check_what(loc.X, loc.Y + 1);
		}
		else if(loc.X % MAX_WIDTH == MAX_WIDTH - 1) {	//右チェック不要
			//around[1, 2, 3]は不要
			around[1] = around[2] = around[3] = -1;
			around[0] = check_what(loc.X, loc.Y - 1);
			around[4] = check_what(loc.X, loc.Y + 1);
			around[5] = check_what(loc.X - 1, loc.Y + 1);
			around[6] = check_what(loc.X - 1, loc.Y);
			around[7] = check_what(loc.X - 1, loc.Y - 1);
		}
		else {							//左右チェック要
			//全て必要
			around[0] = check_what(loc.X, loc.Y - 1);
			around[1] = check_what(loc.X + 1, loc.Y - 1);
			around[2] = check_what(loc.X + 1, loc.Y);
			around[3] = check_what(loc.X + 1, loc.Y + 1);
			around[4] = check_what(loc.X, loc.Y + 1);
			around[5] = check_what(loc.X - 1, loc.Y + 1);
			around[6] = check_what(loc.X - 1, loc.Y);
			around[7] = check_what(loc.X - 1, loc.Y - 1);
		}
	}
}

//m_celllistの指定番目のセルのポインターを返す
Ccell* Cworld::get_cell(int n) {

	return m_celllist[n];
}

//座標位置にあるセルのポインターを返す
Ccell* Cworld::get_cell(int x, int y) {

	for(Ccell *c : m_celllist) {
		location loc = c->where();
		if(loc.X == x && loc.Y == y)
			return c;
	}
	return NULL;
}

//ピンク、ブルー、グリーン種族の生死状況を返す（整数配列[6]）
int* Cworld::get_distribution() {

	fill(m_tribe_status, m_tribe_status + 4, 0);	//m_tribe_statusの初期化
	for(Ccell *c : m_celllist) {
		switch(c->get_tribe()) {
		case 0:		//ピンク
			m_tribe_status[0]++;
			break;
		case 1:		//ブルー
			m_tribe_status[1]++;
			break;
		case 2:		//グリーン
			m_tribe_status[2]++;
			break;
		default:	//死亡（モノ）
			m_tribe_status[3]++;
			break;
		}
	}
	return m_tribe_status;
}

//総てのcell属性を表示する（paramsをメッセージボックスまたはダイアログに表示する）
string Cworld::show_cell_param() {

	string params;
	for(Ccell *x : m_celllist)
		params += x->show_param();
	return params;
}

//「世界が廻る（時が過ぎる）」→セルに日常活動を行わせる（ここを別スレッドで廻す）
void Cworld::goes_around() {

//	while(!m_gameover) {	//別スレッド版はループ文として繰り返し処理とし
	if(!m_gameover) {		//WM_TIMER版はif文による毎回の呼び出しとなる
		//最大人口超の場合
		if(m_celllist.size() > MAX_POPU) {
			m_gameover = true;	//ゲームオーバー
//			m_message += "Current population got excessive! (Population-Overflow)\r\n";
			m_message += "現在の人口過密が異常となりました！（人口爆発）\r\n";
			return;
		}
		bool extinction = true;					//絶滅チェッカー
		for(Ccell *x : m_celllist) {
			x->vitalcheck();					//対象セルの生死状態をチェック
			if(x->is_alive()) {
				check_around(x);				//対象セルxの周囲を確認する
				location loc = x->where();		//対象セルxの位置を取得
				m_map[loc.Y * MAX_WIDTH + loc.X] = ' ';	//対象セルxの旧座標を' 'にする
				int val = x->find_cell();		//対象セルxの周囲にセルがいるか確認
				int dir = val & 0x1111;			//dirは周囲のセルの絶対方向（0 - 7）
				int id = val >> 4;				//idはそのセルのm_id（16倍されている）
				if(val != NOT_FOUND) {			//周囲にセルが見つかったならば
					Ccell *y = get_cell(id);	//idから周囲のセルのポインターを取得
					y->vitalcheck();			//相手セルの生死状態をチェック
					if(y->is_alive()) {			//yの生死を確認し、生きていれば
						if(x->get_intmarg()) {	//異種族婚を許可しているか
							//【調整項目】
							if(x->get_affection() < 30 &&		//愛着性が30未満で
								x->get_hostility() > 70)		//敵対性が70超であれば
								intimidate(x, y, dir);			//相互に威嚇する
							else if(x->get_affection() > 40 &&	//愛着性が40超で
								x->get_hostility() < 50)		//敵対性が50未満であれば
								get_close(x, y, dir);			//親交を結ぶ
							else								//それ以外は
								flee(x, y, dir);				//相手から離れる
						}
						else {					//異種族婚が認められなければ
							if(x->get_tribe() != y->get_tribe())//異種族なら
								intimidate(x, y, dir);			//相互に威嚇する
							else {								//同種族であっても
								//【調整項目】
								if(x->get_affection() < 30 &&	//愛着性が30未満で
									x->get_hostility() > 70)	//敵対性が70超であれば
									intimidate(x, y, dir);		//相互に威嚇する
								else if(x->get_affection() > 40 &&	//愛着性が40超で
									x->get_hostility() < 50)	//敵対性が50未満であれば
									get_close(x, y, dir);		//親交を結ぶ
								else							//敵対が強ければ
									flee(x, y, dir);			//相手から離れる
							}
						}
					}
					else {						//死んでいれば食物と同じ扱いとなる
						location loc = y->where();				//死亡したyの位置
						m_map[loc.Y * MAX_WIDTH + loc.X] = 0;	//野原に戻す
						x->get_food(dir);						//移動して摂食する
					}
					y->vitalcheck();			//活動後の相手セルの生死状態をチェック
				}
				else {							//周囲にセルがいないならば
					dir = x->find_food();		//周囲に食物があるかどうか確認する
					if(dir != NOT_FOUND)		//あれば移動して、摂食する
						x->get_food(dir);
					else {
						dir = x->find_field();	//周囲に野原があるかどうか確認する
						if(dir != NOT_FOUND)	//あれば移動する
							x->get_move(dir);
					}
				}
				loc = x->where();				//対象セルの移動があり得るので再取得
				m_map[loc.Y * MAX_WIDTH + loc.X] = 'C';	//マップのセルxの新座標を'C'にする
				x->aging();						//老化による減衰と生命力消耗
				x->param_change();				//状況変化から各種パラメーターを調整
				//絶滅チェック（一つでもx->is_alive()がtrueであればfalse）
				extinction = false;
			}
			x->vitalcheck();					//活動後の対象セルの生死状態をチェック
		}
		if(extinction) {						//全滅により終了
			m_gameover = true;
//			m_message += "All cells passed away! (Extinction)\r\n";
			m_message += "全セルが死亡しました！（全滅）\r\n";
		}
	}
}

//親しくなり、愛着性が高まり、敵対性が低まる
void Cworld::get_close(Ccell *x, Ccell *y, int dir) {

	//セルx, y両者の愛着性が50%を超える場合、交尾に進む
	if(x->get_affection() > 60 && y->get_affection() > 60)	//【調整項目】
		make_love(x, y, dir);
	//そうでなければセルx, y両者の愛着性が増え、敵対性が減る
	else {
		x->set_affection(x->get_affection() + INCREASE);
		y->set_affection(y->get_affection() + INCREASE);
		x->set_hostility(x->get_hostility() + DECREASE);
		y->set_hostility(y->get_hostility() + DECREASE);
	}
}

//一定の愛着性を超えると交尾し、生殖力により出産
void Cworld::make_love(Ccell *x, Ccell *y, int dir) {

	//xと同種族のセルが何処か（！）に誕生する
	if(x->get_fertility() > 50) {			//【調整項目】50だとなかなか生まない
		int n = m_celllist.size();			//次のm_idを控える
		create_cells(1, x->get_intmarg());	//xと同じm_intmargのセルを生成
		Ccell *z = get_cell(n);				//新生セルのポインターを取得
		z->set_tribe(x->get_tribe());		//新生セルをxと同じ種族に設定
		//【調整項目】出産後、相手yを殺し、摂食する
		//y->killed();
		//x->get_food(dir);
	}
	else	//離別（逃走）する
		flee(x, y, dir);
}

//敵対性と愛着性の度合いにより、相手を威嚇し、敵対性が高まり、愛着性が低まる
void Cworld::intimidate(Ccell *x, Ccell *y, int dir) {

	//セルx, y両者の敵対性が50%を超える場合、闘争に進む
	if(x->get_hostility() > 50 && y->get_hostility() > 50)	//【調整項目】
		fight(x, y, dir);
	//そうでなければセルx, y両者の敵対性が増え、愛着性が減る
	else {
		x->set_affection(x->get_affection() + DECREASE);
		y->set_affection(y->get_affection() + DECREASE);
		x->set_hostility(x->get_hostility() + INCREASE);
		y->set_hostility(y->get_hostility() + INCREASE);
	}
}

//異種族婚許可、敵対性により、相互に攻撃、被害を受ける
void Cworld::fight(Ccell *x, Ccell *y, int dir) {

	//相手の攻撃力が自分の攻撃力よりMAX_PARAM / 4（25）以上、又は
	//相手の生命力が自分の生命力の倍以上あれば
	if((y->get_power() > x->get_power() + MAX_PARAM / 4) ||
		(y->get_power() > x->get_power() * 2))
		flee(x, y, dir);	//逃走する
	else {
		//xの先制攻撃（xの攻撃力がyの防御力を上回る場合、被害を与える）
		y->damaged(x->get_power() - y->get_defense());
		//yの後攻攻撃
		x->damaged(y->get_power() - x->get_defense());
	}
}

//敵対状態になっても、攻撃力、防御力の差が大きければ逃走する
void Cworld::flee(Ccell *x, Ccell *y, int dir) {

	int reverse = x->find_field(false, dir);	//相手yの反対方向の野原を探す
	x->get_move(reverse);						//逃走する
}

//Cworldのセル情報をログに記録
void Cworld::make_log() {

	if(m_celllist.size() > 0) {
		//セルデータの出力ファイル名（"CellOf(yyyy-mm-dd_hh_mm)from<m_ini_pop>.txt"）
		time_t t = time(NULL);
		tm* d = localtime(&t);
	 	string path = ".\\Log\\CellsOf(" + to_string(d->tm_year + 1900) + "-" + to_string(d->tm_mon + 1) + "-" + to_string(d->tm_mday);
 		path += "_" + to_string(d->tm_hour) + "_" + to_string(d->tm_min) + ")from" + to_string(m_ini_pop) + ".txt";
		//ファイル出力
		ofstream out_file;
		out_file.open(path.c_str());
		if(out_file.is_open()) {
			for(Ccell *x : m_celllist)
				out_file << x->show_param() << std::endl;
			out_file.close();
		}
	}
}
