using System;
using System.Collections.Generic;
class Program
{
const int UB = 8;
struct PieceInfoDef
{
internal int PieceID;
internal List<char[]> ColorArrList;
internal List<bool[]> IsShitenArrList;
}
static PieceInfoDef[] mPieceInfoArr;
struct JyoutaiDef
{
internal char[,] BanArrColor;
internal bool[,] BanArrIsShiten;
internal int Level;
internal List<int> UsedPieceIDList;
}
static void Main()
{
//ピースごとの情報を取得
DerivePieceInfo();
//回転解の排除で、ピース1は回転させない
mPieceInfoArr[0].ColorArrList.RemoveRange(1, mPieceInfoArr[0].ColorArrList.Count - 1);
mPieceInfoArr[0].IsShitenArrList.RemoveRange(1, mPieceInfoArr[0].IsShitenArrList.Count - 1);
var Stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
WillPush.BanArrColor = new char[UB + 1, UB + 1];
WillPush.BanArrIsShiten = new bool[UB + 1, UB + 1];
for (int X = 0; X <= UB; X++)
for (int Y = 0; Y <= UB; Y++)
WillPush.BanArrColor[X, Y] = '□';
WillPush.Level = 0;
WillPush.UsedPieceIDList = new List<int>();
Stk.Push(WillPush);
while (Stk.Count > 0) {
JyoutaiDef Popped = Stk.Pop();
//クリア判定
if (Popped.Level == 9) {
Console.WriteLine("解を発見");
PrintBan(Popped.BanArrColor, Popped.BanArrIsShiten, Popped.UsedPieceIDList);
continue;
}
int BaseX, BaseY;
DeriveShikitumePos(Popped.Level, out BaseX, out BaseY);
foreach (PieceInfoDef EachPieceInfo in mPieceInfoArr) {
if (Popped.UsedPieceIDList.Contains(EachPieceInfo.PieceID))
continue;
for (int I = 0; I <= EachPieceInfo.ColorArrList.Count - 1; I++) {
char[] wkColorArr = EachPieceInfo.ColorArrList[I];
WillPush.BanArrColor = (char[,])Popped.BanArrColor.Clone();
WillPush.BanArrColor[BaseX + 1, BaseY] = wkColorArr[0];
WillPush.BanArrColor[BaseX + 2, BaseY + 1] = wkColorArr[1];
WillPush.BanArrColor[BaseX + 1, BaseY + 2] = wkColorArr[2];
WillPush.BanArrColor[BaseX, BaseY + 1] = wkColorArr[3];
bool[] wkIsShitenArr = EachPieceInfo.IsShitenArrList[I];
WillPush.BanArrIsShiten = (bool[,])Popped.BanArrIsShiten.Clone();
WillPush.BanArrIsShiten[BaseX + 1, BaseY] = wkIsShitenArr[0];
WillPush.BanArrIsShiten[BaseX + 2, BaseY + 1] = wkIsShitenArr[1];
WillPush.BanArrIsShiten[BaseX + 1, BaseY + 2] = wkIsShitenArr[2];
WillPush.BanArrIsShiten[BaseX, BaseY + 1] = wkIsShitenArr[3];
if (IsValid(WillPush.BanArrColor, WillPush.BanArrIsShiten, Popped.Level) == false)
continue;
WillPush.Level = Popped.Level + 1;
WillPush.UsedPieceIDList = new List<int>(Popped.UsedPieceIDList);
WillPush.UsedPieceIDList.Add(EachPieceInfo.PieceID);
Stk.Push(WillPush);
}
}
}
}
//ピースごとの情報を取得
static void DerivePieceInfo()
{
var PieceInfoList = new List<PieceInfoDef>();
Action<int, string, bool[]> AddAct = (pID, pStr, pArr) =>
{
PieceInfoDef WillAdd;
WillAdd.PieceID = pID;
WillAdd.ColorArrList = DeriveHaitiArrList(pStr.ToCharArray());
WillAdd.IsShitenArrList = DeriveHaitiArrList(pArr);
PieceInfoList.Add(WillAdd);
};
AddAct(1, "赤緑黄青", new bool[] { true, false, false, true });
AddAct(2, "青赤黄緑", new bool[] { true, false, false, true });
AddAct(3, "黄緑青赤", new bool[] { false, false, true, true });
AddAct(4, "緑黄赤青", new bool[] { false, true, true, false });
AddAct(5, "青黄赤緑", new bool[] { false, true, true, false });
AddAct(6, "赤黄緑青", new bool[] { false, true, true, false });
AddAct(7, "赤青緑黄", new bool[] { false, true, true, false });
AddAct(8, "緑黄赤青", new bool[] { true, true, false, false });
AddAct(9, "青緑赤黄", new bool[] { false, false, true, true });
mPieceInfoArr = PieceInfoList.ToArray();
}
//回転させた配置を返す(4通り)
static List<TypeName[]> DeriveHaitiArrList<TypeName>(TypeName[] pBaseArr)
{
var WillReturn = new List<TypeName[]>();
for (int I = 0; I <= pBaseArr.GetUpperBound(0); I++) {
var WillAdd = new List<TypeName>();
int CurrInd = I;
for (int J = 1; J <= pBaseArr.Length; J++) {
WillAdd.Add(pBaseArr[I]);
if (++I > pBaseArr.GetUpperBound(0)) I = 0;
}
WillReturn.Add(WillAdd.ToArray());
}
return WillReturn;
}
//レベルを引数として、敷き詰めの座標を返す
static void DeriveShikitumePos(int pLevel, out int pX, out int pY)
{
pX = pY = -1;
if (pLevel == 0) { pX = 0; pY = 0; }
if (pLevel == 1) { pX = 3; pY = 0; }
if (pLevel == 2) { pX = 6; pY = 0; }
if (pLevel == 3) { pX = 0; pY = 3; }
if (pLevel == 4) { pX = 3; pY = 3; }
if (pLevel == 5) { pX = 6; pY = 3; }
if (pLevel == 6) { pX = 0; pY = 6; }
if (pLevel == 7) { pX = 3; pY = 6; }
if (pLevel == 8) { pX = 6; pY = 6; }
}
//盤面とレベルを引数として、有効な盤面かをチェック
static bool IsValid(char[,] pBanArrColor, bool[,] pBanArrIsShiten, int pLevel)
{
Func<int, int, int, int, bool> IsOKFunc = (pX1, pY1, pX2, pY2) =>
{
if (pBanArrColor[pX1, pY1] != pBanArrColor[pX2, pY2]) return false;
if (pBanArrIsShiten[pX1, pY1] == pBanArrIsShiten[pX2, pY2]) return false;
return true;
};
if (pLevel == 1 && IsOKFunc(2, 1, 3, 1) == false) return false;
if (pLevel == 2 && IsOKFunc(5, 1, 6, 1) == false) return false;
if (pLevel == 3 && IsOKFunc(1, 2, 1, 3) == false) return false;
if (pLevel == 4 && IsOKFunc(2, 4, 3, 4) == false) return false;
if (pLevel == 4 && IsOKFunc(4, 2, 4, 3) == false) return false;
if (pLevel == 5 && IsOKFunc(5, 4, 6, 4) == false) return false;
if (pLevel == 5 && IsOKFunc(7, 2, 7, 3) == false) return false;
if (pLevel == 6 && IsOKFunc(1, 5, 1, 6) == false) return false;
if (pLevel == 7 && IsOKFunc(2, 7, 3, 7) == false) return false;
if (pLevel == 7 && IsOKFunc(4, 5, 4, 6) == false) return false;
if (pLevel == 8 && IsOKFunc(5, 7, 6, 7) == false) return false;
if (pLevel == 8 && IsOKFunc(7, 5, 7, 6) == false) return false;
return true;
}
//盤面を出力
static void PrintBan(char[,] pBanArrColor, bool[,] pBanArrIsShiten, List<int> pUsedPieceIDList)
{
var sb = new System.Text.StringBuilder();
sb.AppendLine("ピースIDの配置");
for (int I = 0; I <= pUsedPieceIDList.Count - 1; I++) {
if (I == 3 || I == 6)
sb.AppendLine();
sb.Append(pUsedPieceIDList[I]);
}
sb.AppendLine();
sb.AppendLine("色の配置");
for (int Y = 0; Y <= UB; Y++) {
for (int X = 0; X <= UB; X++) {
sb.Append(pBanArrColor[X, Y]);
}
sb.AppendLine();
}
sb.AppendLine("矢印の配置");
for (int Y = 0; Y <= UB; Y++) {
for (int X = 0; X <= UB; X++) {
bool wkBool = pBanArrIsShiten[X, Y];
//3を法として分類
int ModX = X % 3;
int ModY = Y % 3;
if (ModX == 1 && ModY == 0) {
sb.Append(wkBool ? '↓' : '|');
}
else if (ModX == 2 && ModY == 1) {
sb.Append(wkBool ? '←' : '−');
}
else if (ModX == 1 && ModY == 2) {
sb.Append(wkBool ? '↑' : '|');
}
else if (ModX == 0 && ModY == 1) {
sb.Append(wkBool ? '→' : '−');
}
else sb.Append('□');
}
sb.AppendLine();
}
Console.WriteLine(sb.ToString());
}
}