using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
//ダイス番号(1〜8)と、6面の配置候補の配列のList
static Dictionary<int, List<char[]>> Use6MenArrListDict =
new Dictionary<int, List<char[]>>();
struct JyoutaiDef
{
internal int Level;
internal List<int> SetDiceNo; //配置したダイス番号
internal List<char[]> Set6MenArrList; //配置したダイスの展開図のList
}
static void Main()
{
DeriveUse6MenArrListDict();
//デバッグ用の6面の配置候補の出力
//DebugPrintUse6MenArrListDict();
var stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
WillPush.Level = 0;
WillPush.SetDiceNo = new List<int>();
WillPush.Set6MenArrList = new List<char[]>();
stk.Push(WillPush);
while (stk.Count > 0) {
JyoutaiDef Popped = stk.Pop();
if (Popped.Level == 8) {
Console.WriteLine("解を発見");
PrintAnswer(Popped);
return;
}
WillPush.Level = Popped.Level + 1;
foreach (var EachPair in Use6MenArrListDict) {
//最初に配置するダイスは、固定で1番とする
if (WillPush.Level == 1 && EachPair.Key != 1) continue;
//回転解の除外で
//上段右後のダイス番号 < 上段左前のダイス番号
if (WillPush.Level == 3)
if (Popped.SetDiceNo[1] < EachPair.Key == false)
continue;
if (Popped.SetDiceNo.Contains(EachPair.Key)) continue;
foreach (char[] EachKouhoArr in EachPair.Value) {
WillPush.SetDiceNo = new List<int>(Popped.SetDiceNo) { EachPair.Key };
WillPush.Set6MenArrList = new List<char[]>(Popped.Set6MenArrList);
WillPush.Set6MenArrList.Add(EachKouhoArr);
if (IsValid(WillPush.Set6MenArrList) == false) continue;
stk.Push(WillPush);
}
}
}
}
//8つのダイスの、使用する6面の候補を求める
static void DeriveUse6MenArrListDict()
{
//この展開図と配列の添字を対応させて、8つのダイスの展開図を定義
// 0
//1234
// 5
//展開図とダイスとの対応は、下記の1対1対応とする
// 上
//左前右後
// 下
var Base6MenArrList = new List<char[]>();
Base6MenArrList.Add("↑↑→←→→".ToCharArray());
Base6MenArrList.Add("↑↑↓↑↑→".ToCharArray());
Base6MenArrList.Add("↑↑↓↑→→".ToCharArray());
Base6MenArrList.Add("↑↑↓→↑→".ToCharArray());
Base6MenArrList.Add("↑↑↓↓↑↑".ToCharArray());
Base6MenArrList.Add("↑↑↓↓↑→".ToCharArray());
Base6MenArrList.Add("↑↑←↓↑→".ToCharArray());
Base6MenArrList.Add("↑→→→↓↑".ToCharArray());
for (int I = 0; I <= Base6MenArrList.Count - 1; I++) {
Use6MenArrListDict[I + 1] = DeriveUse6MenArrList(Base6MenArrList[I]);
}
}
//1つのダイスの、配置の候補を求める(ダイス1つにつき24通り)
static List<char[]> DeriveUse6MenArrList(char[] pBase6MenArrList)
{
var WillReturn = new List<char[]>();
Action<char[]> wkAct = (pKaiten6MenArr) =>
WillReturn.AddRange(DeriveUse4MenArrList(pKaiten6MenArr));
//0が上面、5が下面
wkAct(Kaiten6MenArr(pBase6MenArrList, new int[] { 0, 1, 2, 3, 4, 5 },
new int[] { 0, 0, 0, 0, 0, 0 },
new int[] { }, new int[] { }));
//5が上面、0が下面
wkAct(Kaiten6MenArr(pBase6MenArrList, new int[] { 5, 3, 2, 1, 4, 0 },
new int[] { 2, 2, 2, 2, 2, 2 },
new int[] { }, new int[] { }));
//1が上面、3が下面
wkAct(Kaiten6MenArr(pBase6MenArrList, new int[] { 1, 5, 2, 0, 4, 3 },
new int[] { 1, 1, 1, 1, 1, 1 },
new int[] { 4 }, new int[] { 4 }));
//3が上面、1が下面
wkAct(Kaiten6MenArr(pBase6MenArrList, new int[] { 3, 0, 2, 5, 4, 1 },
new int[] { -1, -1, -1, -1, -1, -1 },
new int[] { 4 }, new int[] { 4 }));
//2が上面、4が下面
wkAct(Kaiten6MenArr(pBase6MenArrList, new int[] { 2, 5, 3, 0, 1, 4 },
new int[] { 1, 0, 1, 2, 1, 1 },
new int[] { 4 }, new int[] { 4 }));
//4が上面、2が下面
wkAct(Kaiten6MenArr(pBase6MenArrList, new int[] { 4, 0, 3, 5, 1, 2 },
new int[] { -1, 0, -1, -2, -1, -1 },
new int[] { 4 }, new int[] { 4 }));
//重複データの削除
for (int I = WillReturn.Count - 1; 0 <= I; I--) {
bool WillRemove = false;
for (int J = 0; J <= I - 1; J++) {
if (WillReturn[J].SequenceEqual(WillReturn[I])) {
WillRemove = true;
break;
}
}
if (WillRemove) WillReturn.RemoveAt(I);
}
return WillReturn;
}
//元の展開図の配列、元になる添字の配列と、90度回転の回数の配列
//上下鏡像になる元になる添字の配列
//左右鏡像になる元になる添字の配列
//を引数として、ダイスと対応した展開図の各矢印を求める
static char[] Kaiten6MenArr(char[] pBase6MenArr, int[] pBaseIndArr, int[] pKaitenArr,
int[] JyougeKyouzouIndArr, int[] SayuuKyouzouIndArr)
{
var WillReturn = new List<char>();
for (int I = 0; I <= pBaseIndArr.GetUpperBound(0); I++) {
char WillAdd = Kaiten90do(pBase6MenArr[pBaseIndArr[I]], pKaitenArr[I]);
if (JyougeKyouzouIndArr.Contains(I))
WillAdd = DeriveKyouzouArrow(WillAdd, true);
if (SayuuKyouzouIndArr.Contains(I))
WillAdd = DeriveKyouzouArrow(WillAdd, false);
WillReturn.Add(WillAdd);
}
return WillReturn.ToArray();
}
//Nが正数なら、右に90度回転をN回行った矢印を返す
//Nが負数なら、左に90度回転をN回行った矢印を返す
static char Kaiten90do(char pArrow, int pN)
{
if (pN < 0) pN += 4;
for (int I = 1; I <= pN; I++) {
if (pArrow == '↑') pArrow = '→';
else if (pArrow == '→') pArrow = '↓';
else if (pArrow == '↓') pArrow = '←';
else if (pArrow == '←') pArrow = '↑';
}
return pArrow;
}
//上下鏡像もしくは左右鏡像の矢印を返す
static char DeriveKyouzouArrow(char pArrow, bool pIsJyougeKyouzou)
{
if (pIsJyougeKyouzou) {
if (pArrow == '↑') return '↓';
if (pArrow == '↓') return '↑';
return pArrow;
}
else {
if (pArrow == '→') return '←';
if (pArrow == '←') return '→';
return pArrow;
}
}
//使用する4面の並び順を求める(4通り)
static List<char[]> DeriveUse4MenArrList(char[] pKaiten6MenArr)
{
var WillReturn = new List<char[]>();
//正順での共通処理
Action<int[], int> CommonAct = (pBaseIndArr, pN) =>
{
char[] WillAddArr = new char[6];
for (int I = 0; I <= pBaseIndArr.GetUpperBound(0); I++) {
WillAddArr[I] = pKaiten6MenArr[pBaseIndArr[I]];
}
//上面と下面は90度回転を行う
WillAddArr[0] = Kaiten90do(WillAddArr[0], pN);
WillAddArr[5] = Kaiten90do(WillAddArr[5], -pN);
WillReturn.Add(WillAddArr);
};
//正順の4つ
CommonAct(new int[] { 0, 1, 2, 3, 4, 5 }, 0);
CommonAct(new int[] { 0, 2, 3, 4, 1, 5 }, 1);
CommonAct(new int[] { 0, 3, 4, 1, 2, 5 }, 2);
CommonAct(new int[] { 0, 4, 1, 2, 3, 5 }, 3);
return WillReturn;
}
//デバッグ用の6面の配置候補の出力
static void DebugPrintUse6MenArrListDict()
{
foreach (var EachPair in Use6MenArrListDict) {
Console.WriteLine("ダイス{0}の配置リスト", EachPair.Key);
for (int I = 0; I <= EachPair.Value.Count - 1; I++) {
Console.Write("配置{0,2} ", I + 1);
Array.ForEach(EachPair.Value[I], A => Console.Write(A));
Console.WriteLine();
}
}
Console.WriteLine();
}
//上段左後 上段右後
//上段左前 上段右前
//下段左後 下段右後
//下段左前 下段右前
//の順番でダイスを配置するので、有効な状態かをチェックする
static bool IsValid(List<char[]> pSet6MenArrList)
{
//上段右後の配置
if (pSet6MenArrList.Count == 2) {
//後面 = 上段左後のダイスの後面
if (pSet6MenArrList[1][4] != pSet6MenArrList[0][4]) return false;
//上面 = 上段左後のダイスの上面
if (pSet6MenArrList[1][0] != pSet6MenArrList[0][0]) return false;
}
//上段左前の配置
if (pSet6MenArrList.Count == 3) {
//左面 = 上段左後のダイスの左面
if (pSet6MenArrList[2][1] != pSet6MenArrList[0][1]) return false;
//上面 = 上段左後のダイスの上面
if (pSet6MenArrList[2][0] != pSet6MenArrList[0][0]) return false;
}
//上段右前の配置
if (pSet6MenArrList.Count == 4) {
//右面 = 上段右後のダイスの右面
if (pSet6MenArrList[3][3] != pSet6MenArrList[1][3]) return false;
//前面 = 上段左前のダイスの前面
if (pSet6MenArrList[3][2] != pSet6MenArrList[2][2]) return false;
//上面 = 上段左後のダイスの上面
if (pSet6MenArrList[3][0] != pSet6MenArrList[0][0]) return false;
}
//下段左後の配置
if (pSet6MenArrList.Count == 5) {
//後面 = 上段左後のダイスの後面
if (pSet6MenArrList[4][4] != pSet6MenArrList[0][4]) return false;
//左面 = 上段左後のダイスの左面
if (pSet6MenArrList[4][1] != pSet6MenArrList[0][1]) return false;
}
//下段右後の配置
if (pSet6MenArrList.Count == 6) {
//後面 = 上段左後のダイスの後面
if (pSet6MenArrList[5][4] != pSet6MenArrList[0][4]) return false;
//下面 = 下段左後のダイスの下面
if (pSet6MenArrList[5][5] != pSet6MenArrList[4][5]) return false;
//右面 = 上段右後のダイスの右面
if (pSet6MenArrList[5][3] != pSet6MenArrList[1][3]) return false;
}
//下段左前の配置
if (pSet6MenArrList.Count == 7) {
//左面 = 上段左後のダイスの左面
if (pSet6MenArrList[6][1] != pSet6MenArrList[0][1]) return false;
//下面 = 下段左後のダイスの下面
if (pSet6MenArrList[6][5] != pSet6MenArrList[4][5]) return false;
//前面 = 上段左前のダイスの前面
if (pSet6MenArrList[6][2] != pSet6MenArrList[2][2]) return false;
}
//下段右前の配置
if (pSet6MenArrList.Count == 8) {
//下面 = 下段左後のダイスの下面
if (pSet6MenArrList[7][5] != pSet6MenArrList[4][5]) return false;
//右面 = 上段右後のダイスの右面
if (pSet6MenArrList[7][3] != pSet6MenArrList[1][3]) return false;
//前面 = 上段左前のダイスの前面
if (pSet6MenArrList[7][2] != pSet6MenArrList[2][2]) return false;
}
return true;
}
//配置したダイスを展開図で表示する
//上段左後 上段右後
//上段左前 上段右前
//下段左後 下段右後
//下段左前 下段右前
//の順番で展開図を表示する
static void PrintAnswer(JyoutaiDef pJyoutaiDef)
{
Action<int> PrintPairTenkaizu = pBaseSoeji =>
{
var sb = new System.Text.StringBuilder();
sb.AppendFormat("Dice{0} Dice{1}",
pJyoutaiDef.SetDiceNo[pBaseSoeji], pJyoutaiDef.SetDiceNo[pBaseSoeji + 1]);
sb.AppendLine();
Action<int> CommonSyori = (pTargetMen) =>
{
sb.AppendFormat(" {0} {1}",
pJyoutaiDef.Set6MenArrList[pBaseSoeji][pTargetMen],
pJyoutaiDef.Set6MenArrList[pBaseSoeji + 1][pTargetMen]);
sb.AppendLine();
};
CommonSyori(0);
sb.AppendFormat("{0}{1}{2}{3} {4}{5}{6}{7}",
pJyoutaiDef.Set6MenArrList[pBaseSoeji][1],
pJyoutaiDef.Set6MenArrList[pBaseSoeji][2],
pJyoutaiDef.Set6MenArrList[pBaseSoeji][3],
pJyoutaiDef.Set6MenArrList[pBaseSoeji][4],
pJyoutaiDef.Set6MenArrList[pBaseSoeji + 1][1],
pJyoutaiDef.Set6MenArrList[pBaseSoeji + 1][2],
pJyoutaiDef.Set6MenArrList[pBaseSoeji + 1][3],
pJyoutaiDef.Set6MenArrList[pBaseSoeji + 1][4]);
sb.AppendLine();
CommonSyori(5);
Console.WriteLine(sb.ToString());
};
for (int I = 0; I <= pJyoutaiDef.SetDiceNo.Count - 1; I += 2) {
if (I == 0) Console.WriteLine("上段左後と上段右後の展開図");
if (I == 2) Console.WriteLine("上段左前と上段右前の展開図");
if (I == 4) Console.WriteLine("下段左後と下段右後の展開図");
if (I == 6) Console.WriteLine("下段左前と下段右前の展開図");
PrintPairTenkaizu(I);
}
//完成した大きな立方体の展開図を出力
PrintTenkaizu(pJyoutaiDef.Set6MenArrList);
}
//完成した大きな立方体の展開図を出力
static void PrintTenkaizu(List<char[]> pSet6MenArrList)
{
Console.WriteLine("完成した大きな立方体の展開図");
var sb = new System.Text.StringBuilder();
Action<char, char> Out2CharAct = (pChar1, pChar2) =>
{
sb.AppendFormat(" {0}{1}", pChar1, pChar2);
sb.AppendLine();
};
Action<char[]> Out8CharAct = (pCharArr) =>
{
Array.ForEach(pCharArr, A => sb.Append(A));
sb.AppendLine();
};
Out2CharAct(pSet6MenArrList[0][0], pSet6MenArrList[1][0]);
Out2CharAct(pSet6MenArrList[2][0], pSet6MenArrList[3][0]);
Out8CharAct(new char[] {pSet6MenArrList[0][1], pSet6MenArrList[2][1],
pSet6MenArrList[2][2], pSet6MenArrList[3][2],
pSet6MenArrList[3][3], pSet6MenArrList[1][3],
pSet6MenArrList[1][4], pSet6MenArrList[0][4]});
Out8CharAct(new char[] {pSet6MenArrList[4][1], pSet6MenArrList[6][1],
pSet6MenArrList[6][2], pSet6MenArrList[7][2],
pSet6MenArrList[7][3], pSet6MenArrList[5][3],
pSet6MenArrList[5][4], pSet6MenArrList[4][4]});
Out2CharAct(pSet6MenArrList[4][5], pSet6MenArrList[5][5]);
Out2CharAct(pSet6MenArrList[6][5], pSet6MenArrList[7][5]);
Console.WriteLine(sb.ToString());
}
}