#include <iostream>
#include <algorithm>
#include <vector>
#define NOMINMAX
#include <Windows.h>

//Question by ttp://toro.2ch.net/test/read.cgi/tech/1354393458/909-910

//License is GPLv3
//if need chenge license to fish me.
//this is Dev for FillField Algorithm for me.
//dev on windows!
//need more debug!!!!!

//oh this puzzle algorithm license is i dont know.fish and tell to auther!

static const int ScreenWidth = 80;
static const int ScreenHeight = 20;
static const int Width = 3;
static const int Height = 2;
static const int FireValue = 6;
static const int FirstValue = 7;

enum class MoveState{
	None,
	MoveRight,
	MoveLeft,
	MoveUp,//コンソールで開発してる関係で2次元配列的にマイナス側が上
	MoveDown,//MoveUpの逆側
	DrawRight,
	DrawLeft,
	DrawUp,
	DrawDown,
	Wait,
	End,
	GiveUp,
	Confuse,
};
namespace Console{//環境依存部分！
	bool MoveCursor(int X, int Y){
		COORD Pos = { X, Y };
		SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Pos);
		return true;
	}
	bool Clear(char(&Screen)[ScreenHeight][ScreenWidth], int X, int Y, int Width = 16, int Height = 16){
		Console::MoveCursor(X, Y);
		for (int i = Y; i < Y + Height; i++){
			Console::MoveCursor(X, i);
			for (int j = X; j < X + Width; j++){
				std::cout << ' ';
			}
		}
		Console::MoveCursor(X, Y);
		return true;
	}
	void Wait(DWORD Time){
		Sleep(Time);
	}
}
bool Fill(char (&Screen)[ScreenHeight][ScreenWidth],char Ch=' '){
	for (int i = 0; i < ScreenHeight; i++){
		for (int j = 0; j < ScreenWidth; j++){
			Screen[i][j] = Ch;
		}
	}
	return true;
}

bool ShowField(char (&Screen)[ScreenHeight][ScreenWidth],int Width,int Height){
	int w = std::max(std::min(Width, ScreenWidth), 0);
	int h = std::max(std::min(Height, ScreenHeight), 0);

	Console::MoveCursor(0, 0);
	for (int i = 0; i < h; i++){
		Console::MoveCursor(0, i);
		for (int j = 0; j < w; j++){
			if (Screen[i][j] == 0) std::cout << 'o';
			if (Screen[i][j] == 1) std::cout << '1';
			if (Screen[i][j] == 2) std::cout << '2';
			if (Screen[i][j] == 3) std::cout << '3';
			if (Screen[i][j] == 4) std::cout << '4';
			if (Screen[i][j] == 5) std::cout << '5';
			if (Screen[i][j] == FireValue) std::cout << 'F';
			if (Screen[i][j] == FirstValue) std::cout << '+';
		}
	}
	return true;
}
bool ShowPlayer(int PX,int PY){
	int X = std::max(std::min(PX, ScreenWidth), 0);
	int Y = std::max(std::min(PY, ScreenHeight), 0);

	Console::MoveCursor(X, Y);
	std::cout << 'P';
	return true;
}
bool ProcessCoolDown(char (&Screen)[ScreenHeight][ScreenWidth],int Width,int Height){
	int w = std::max(std::min(Width, ScreenWidth), 0);
	int h = std::max(std::min(Height, ScreenHeight), 0);

	for (int i = 0; i < h; i++){
		for (int j = 0; j < w; j++){
			if (Screen[i][j] == 0) continue;
			if (Screen[i][j]  < FirstValue) Screen[i][j]--;
		}
	}
	return true;
}

bool IsClear(char(&Screen)[ScreenHeight][ScreenWidth], int Width, int Height){
	int w = std::max(std::min(Width, ScreenWidth), 0);
	int h = std::max(std::min(Height, ScreenHeight), 0);

	for (int i = 0; i < h; i++){
		for (int j = 0; j < w; j++){
			if (Screen[i][j] == FirstValue) return false;
		}
	}
	return true;
}

bool ProcessOne(MoveState MS, char(&Screen)[ScreenHeight][ScreenWidth], int& Width, int& Height, int& PX, int& PY){

	int X = PX;
	int Y = PY;

	switch (MS)
	{
	case MoveState::MoveRight:
		if (X < Width)X++;
		if (!((Screen[Y][X]>0) && (Screen[Y][X] <= FireValue))) PX = X;
		return true;
		break;
	case MoveState::MoveLeft:
		if (X > 0 ) X--;
		if (!((Screen[Y][X]>0) && (Screen[Y][X] <= FireValue))) PX = X;
		return true;
		break;
	case MoveState::MoveUp:
		if (Y > 0) Y--;	
		if (!((Screen[Y][X]>0) && (Screen[Y][X] <= FireValue))) PY = Y;
		return true;
		break;
	case MoveState::MoveDown:
		if (Y < Height) Y++;
		if (!((Screen[Y][X]>0) && (Screen[Y][X] <= FireValue))) PY = Y;
		break;
	case MoveState::DrawRight:
		if (X + 1 < Width) Screen[Y][X + 1] = FireValue;
		break;
	case MoveState::DrawLeft:
		if (X - 1 >= 0) Screen[Y][X - 1] = FireValue;
		break;
	case MoveState::DrawUp:
		if (Y - 1 >= 0) Screen[Y - 1][X] = FireValue;
		break;
	case MoveState::DrawDown:
		if (Y+1<Height) Screen[Y + 1][X] = FireValue;
		break;
	case MoveState::Wait:
		return true;
		break;
	case MoveState::End:
		return true;
		break;
	case MoveState::GiveUp:
		return true;
		break;
	case MoveState::Confuse://未対応
		return true;
		break;
	default:
		break;
	}

	return false;
}
MoveState Think_by_hand(char(&Screen)[ScreenHeight][ScreenWidth], int Width, int Height, int PX, int PY){
	static int i = 0;
	//std::vector<MoveState> Vec{MoveState::Wait, MoveState::MoveRight, MoveState::MoveLeft, MoveState::MoveDown, MoveState::MoveUp ,MoveState::End};
	std::vector<MoveState> Vec{MoveState::DrawDown, MoveState::MoveRight, MoveState::DrawLeft, MoveState::DrawRight, MoveState::MoveDown ,MoveState::DrawUp,MoveState::DrawRight,MoveState::MoveLeft,MoveState::DrawRight,MoveState::End};
	return Vec[i++];	
}

MoveState Think(char(&Screen)[ScreenHeight][ScreenWidth], int Width, int Height, int PX, int PY){
	MoveState MS = MoveState::End;

	//Write Code Here...
	//this is example.
	//MS = Think_by_hand(Screen, Width, Height, PX, PY);

	return MS;
}
int Process(char (&Screen)[ScreenHeight][ScreenWidth],int Width,int Height,int PX, int PY){
	int X = PX, Y = PY;
	Fill(Screen, FirstValue);
	int Count = 0;
	MoveState MS = MoveState::None;

	while (MS != MoveState::End){

		MS = Think(Screen, Width, Height, X, Y);
		ProcessOne(MS, Screen, Width, Height, X, Y);
		ProcessCoolDown(Screen, Width, Height);
		ShowField(Screen, Width, Height);
		ShowPlayer(X, Y);
		Console::Wait(1000);
		if (MS == MoveState::End) goto End;//break の　代わりにgoto使ってる。今回は開発効率の問題で・・・。Orz
	
		Count++;

		if (MS == MoveState::GiveUp) goto End;
		if (MS == MoveState::Confuse) goto End;

	}
End:

	return Count;
}

int main(){
	char Screen[ScreenHeight][ScreenWidth] = { 0, };
	int X = 0, Y = 0;

	Fill(Screen, FirstValue);
	Console::Clear(Screen, 0, 0, ScreenWidth, ScreenHeight);

	ShowField(Screen, Width, Height);
	ShowPlayer(X, Y);

	int C = Process(Screen,Width,Height,X, Y);
	
	Console::MoveCursor(0, Height + 1);
	bool F = IsClear(Screen, Width, Height);
	char *str[] = { "This is Valid!", "This is Invalid..." };
	std::cout << "I use " << C << " Steps!" << std::endl << (F ? str[0] : str[1]) << std::endl;

	return 0;
}