#include <iostream>
#include <vector>
#include <limits>

enum class Operator{
	None,
	Plus,
	Minus,
	Multi,
	Div,
	Mod,
	Wall,
	Max,
};

static const int Top = 0;
static const int Right = 1;
static const int Bottom = 2;
static const int Left = 3;

struct Wall{
	Operator Op;
	double Value;
	bool IsWalked;
};

struct Floor{

	union{
		struct{
			int Top;
			int Right;
			int Bottom;
			int Left;
		};
		int Dir[4];
	};
	Floor(int Top_, int Right_, int Bottom_, int Left_){
		Dir[0] = Top_;
		Dir[1] = Right_; 
		Dir[2] = Bottom_;
		Dir[3] = Left_;
	}
};

struct FootPrint;
typedef std::pair<std::vector<std::vector<Floor>>,std::vector<Wall>> Map;
typedef std::vector<FootPrint> Stack;

struct Point{
	int X, Y;
};


struct FootPrint{
	Point Pos;
	int From, To;
	int Score;
	//Stack MB;
};

Point Direction[4]{{ 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 }};

static const int Width = 7;
static const int Height = 7;

Map MakeData(){
	std::vector<Wall> WallData = {
		{ Operator::Minus, 2, false }, { Operator::Plus, 5, false }, { Operator::Minus, 1, false }, { Operator::Plus, 3, false }, { Operator::Plus, 2, false }, { Operator::Minus, 1, false },///
		{ Operator::Plus, 1, false }, { Operator::Plus, 3, false }, { Operator::Plus, 2, false }, { Operator::Minus, 1, false }, { Operator::Plus, 2, false }, { Operator::Minus, 1, false }, { Operator::Plus, 3, false },///
		{ Operator::Plus, 1, false }, { Operator::Plus, 4, false }, { Operator::Multi, 2, false }, { Operator::Minus, 1, false }, { Operator::Plus, 4, false }, { Operator::Minus, 2, false },///
		{ Operator::Plus, 4, false }, { Operator::Plus, 2, false }, { Operator::Plus, 1, false }, { Operator::Plus, 3, false }, { Operator::Plus, 3, false }, { Operator::Plus, 5, false }, { Operator::Minus, 1, false },///
		{ Operator::Plus, 3, false }, { Operator::Plus, 2, false }, { Operator::Minus, 1, false }, { Operator::Plus, 4, false }, { Operator::Plus, 1, false }, { Operator::Multi, 3, false },///
		{ Operator::Minus, 2, false }, { Operator::Minus, 1, false }, { Operator::Minus, 1, false }, { Operator::Plus, 5, false }, { Operator::Minus, 1, false }, { Operator::Minus, 2, false }, { Operator::Plus, 2, false },///
		{ Operator::Plus, 4, false }, { Operator::Minus, 1, false }, { Operator::Plus, 3, false }, { Operator::Minus, 2, false }, { Operator::Plus, 5, false }, { Operator::Plus, 1, false },///
		{ Operator::Plus, 3, false }, { Operator::Plus, 5, false }, { Operator::Plus, 4, false }, { Operator::Minus, 1, false }, { Operator::Plus, 2, false }, { Operator::Plus, 2, false }, { Operator::Plus, 1, false },///
		{ Operator::Minus, 2, false }, { Operator::Multi, 3, false }, { Operator::Plus, 1, false }, { Operator::Plus, 2, false }, { Operator::Minus, 1, false }, { Operator::Plus, 3, false },///
		{ Operator::Minus, 1, false }, { Operator::Plus, 1, false }, { Operator::Minus, 2, false }, { Operator::Plus, 4, false }, { Operator::Plus, 4, false }, { Operator::Plus, 1, false }, { Operator::Minus, 2, false },///
		{ Operator::Plus, 5, false }, { Operator::Plus, 1, false }, { Operator::Plus, 3, false }, { Operator::Minus, 1, false }, { Operator::Multi, 2, false }, { Operator::Plus, 4, false },///
		{ Operator::Plus, 1, false }, { Operator::Plus, 2, false }, { Operator::Plus, 2, false }, { Operator::Minus, 2, false }, { Operator::Plus, 1, false }, { Operator::Plus, 5, false }, { Operator::Plus, 3, false },///
		{ Operator::Plus, 3, false }, { Operator::Minus, 1, false }, { Operator::Plus, 2, false }, { Operator::Plus, 4, false }, { Operator::Minus, 2, false }, { Operator::Plus, 1, false },///
	};
	std::vector<std::vector<Floor>> FloorData = {//これは自動生成できそうだけど、わからん。脳弱になるー。うぎゃーーーー！！！上下幅は7*7で13。
		{ { -1, 0, 6, -1 }, { -1, 1, 7, 0 }, { -1, 2, 8, 1 }, { -1, 3, 9, 2 }, { -1, 4, 10, 3 }, { -1, 5, 11, 4 }, { -1, -1, 12, 5 }, },
		{ { 6, 13, 19, -1 }, { 7, 14, 20, 13 }, { 8, 15, 21, 14 }, { 9, 16, 22, 15 }, { 10, 17, 23, 16 }, { 11, 18, 24, 17 }, { 12, -1, 25, 18 }, },
		{ { 19, 26, 32, -1 }, { 20, 27, 33, 26 }, { 21, 28, 34, 27 }, { 22, 29, 35, 28 }, { 23, 30, 36, 29 }, { 24, 31, 37, 30 }, { 25, -1, 38, 31 }, },
		{ { 32, 39, 45, -1 }, { 33, 40, 46, 39 }, { 34, 41, 47, 40 }, { 35, 42, 48, 41 }, { 36, 43, 49, 42 }, { 37, 44, 50, 43 }, { 38, -1, 51, 44 } },
		{ { 45, 52, 58, -1 }, { 46, 53, 59, 52 }, { 47, 54, 60, 53 }, { 48, 55, 61, 54 }, { 49, 56, 62, 55 }, { 50, 57, 63, 56 }, { 51, -1, 64, 57 }, },
		{ { 58, 65, 71, -1 }, { 59, 66, 72, 65 }, { 60, 67, 73, 66 }, { 61, 68, 74, 67 }, { 62, 69, 75, 68 }, { 63, 70, 76, 69 }, {64,-1,77,70}, },
		{ { 71, 78, -1, -1 }, { 72, 79, -1, 78 }, { 73, 80, -1, 79 }, { 74, 81, -1, 80 }, { 75, 82, -1, 81 }, { 76, 83, -1, 82 }, {77,-1,-1,83}, },
	};

	return std::make_pair(FloorData,WallData);
}

bool ShowMap(Map& M,bool ViewType = true ){
	bool F2 = false;

	for (auto& oo : M.first){
		if (ViewType == true){
			std::cout << "  ";
			for (auto& o : oo){
				if (o.Dir[Right] == -1)continue;
				if (M.second[o.Dir[Right]].Op == Operator::Plus) std::cout << '+';
				if (M.second[o.Dir[Right]].Op == Operator::Minus) std::cout << '-';
				if (M.second[o.Dir[Right]].Op == Operator::Multi) std::cout << '*';
				if (M.second[o.Dir[Right]].Op == Operator::Div) std::cout << '/';
				std::cout << M.second[o.Dir[Right]].Value << "  ";
			}
			std::cout << std::endl;
			for (auto& o : oo){
				if (o.Dir[Bottom] == -1)continue;
				if (M.second[o.Dir[Bottom]].Op == Operator::Plus) std::cout << '+';
				if (M.second[o.Dir[Bottom]].Op == Operator::Minus) std::cout << '-';
				if (M.second[o.Dir[Bottom]].Op == Operator::Multi) std::cout << '*';
				if (M.second[o.Dir[Bottom]].Op == Operator::Div) std::cout << '/';
				std::cout << M.second[o.Dir[Bottom]].Value << "  ";
			}
			std::cout << std::endl;
		}
		else{
			for (auto& o : oo){
				if (o.Dir[Top] == -1)continue;
				F2 = true;
				if (M.second[o.Dir[Top]].Op == Operator::Plus) std::cout << '+';
				if (M.second[o.Dir[Top]].Op == Operator::Minus) std::cout << '-';
				if (M.second[o.Dir[Top]].Op == Operator::Multi) std::cout << '*';
				if (M.second[o.Dir[Top]].Op == Operator::Div) std::cout << '/';
				std::cout << M.second[o.Dir[Top]].Value << "  ";
			}
			if(F2 == true) std::cout << std::endl;
			for (auto& o : oo){
				if (o.Dir[Left] == -1)continue;
				std::cout << "  ";
				if (M.second[o.Dir[Left]].Op == Operator::Plus) std::cout << '+';
				if (M.second[o.Dir[Left]].Op == Operator::Minus) std::cout << '-';
				if (M.second[o.Dir[Left]].Op == Operator::Multi) std::cout << '*';
				if (M.second[o.Dir[Left]].Op == Operator::Div) std::cout << '/';
				std::cout << M.second[o.Dir[Left]].Value;
			}
			std::cout << std::endl;


		}
	}

	return 0;
}

bool Find(Stack& ST,Point P,int D){

	for (auto& o : ST){
		if ((o.Pos.X == P.X) && (o.Pos.Y == P.Y) && ((o.From == D) || (o.To == D))) return true;
	}

	return false;
}

int CalcScore(Operator Op, int SA, int SB){
	switch (Op)
	{
		case Operator::Plus:
			return SA + SB;
		case Operator::Minus:
			return SA - SB;
		case Operator::Multi:
			return SA*SB;
		case Operator::Div:
			return SA / SB;
		case Operator::Mod:
			return SA%SB;
		default:
			break;
	}
	return std::numeric_limits<int>::min() / 16;
}

int From(Point A, Point B){

	Point To{ A.X - B.X, A.Y - B.Y };


	for (int i = 0; i < 4; i++){
		if (Direction[i].X == To.X && Direction[i].Y == To.Y) return (i + 2) % 4;
	}

	return -1;

}


bool IsMove(Point P, Point L){
	if (P.X < 0) return false;
	if (P.Y < 0) return false;
	if (P.X < L.X) return false;
	if (P.Y < L.Y) return false;

	return true;
}

bool Search(Map& M,Stack& S,int& Score,const Point& Start,const Point& End){
	Point Now = Start;
	Stack ST;
	Stack MST;
	int MaxScore = 0;
	int ScoreT = Score;
	int Dir = 0;
	FootPrint FP{ Now, -1, Dir, Score };


	while (!((Now.X == End.X) && (Now.Y == End.Y))){
	//while (true){
		
		if (ST.size() >= 1){
			FP.From = From(Now, ST[ST.size() - 1].Pos);
		}
		ST.push_back(FP);

		if (IsMove({ Now.X + Direction[Dir].X, Now.Y + Direction[Dir].Y }, { Width, Height })){
			Dir++;
			L1:
			if (Dir == 4){
				ST.pop_back();
				Dir = ST.back().To+1;
			}
			if (Dir == 4) goto L1;
			if (ST.size() == 0){
				S = MST;
				Score = MaxScore;
				return true;
			}
			Dir %= 4;
			continue;
		}
		if (Find(ST, { Now.X + Direction[Dir].X, Now.Y + Direction[Dir].Y }, Dir) == true){
			Dir++;
			L2:
			if (Dir == 4){
				ST.pop_back();
				Dir = ST.back().To+1;
			}
			if (Dir == 4) goto L2;
			if (ST.size() == 0){
				S = MST;
				Score = MaxScore;
				return true;
			}
			Dir %= 4;
			continue;
		}
		Point PT{ Now.X + Direction[Dir].X, Now.Y + Direction[Dir].Y };
		Operator Op = M.second[M.first[PT.Y][PT.X].Dir[Dir]].Op;
		int V = M.second[M.first[PT.Y][PT.X].Dir[Dir]].Value;
		ScoreT = CalcScore(Op, V, ScoreT);

		FP.Pos = PT;
		FP.Score = ScoreT;
		FP.To=Dir

	}


}


int main(){

	auto M = MakeData();
	ShowMap(M);
	std::cout << std::endl;
	ShowMap(M, false);
	return 0;

}

