トップページに戻る
次のC#のサンプルへ
前のC#のサンプルへ
Cマガ電脳クラブ(第023回) マッチング・パズル
問題
Fig.1のように、各辺にaからfの文字が書かれた正六角形の板が7枚ある。
これをFig.2のように配置するのだが、同じ文字の辺が接するように、というのが条件だ。
何通りの置き方があるだろうか。
ただし、板の裏面の各辺には、それぞれ表と同じ文字が書かれており、裏返して使うことが可能である。
ソース
using System;
using System.Collections.Generic;
class Program
{
struct JyoutaiDef
{
internal int Level;
internal List<int> NoList; //使用済の板のList
internal List<char[]> StrArrList; //文字の配置配列のList
}
//板を回転、裏返ししたDict
static Dictionary<int, List<char[]>> KaitenItaDict = new Dictionary<int, List<char[]>>();
static void Main()
{
for (int I = 1; I <= 7; I++) KaitenItaDict[I] = DeriveItaArrList(I);
var stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
foreach (var AnyPair in KaitenItaDict) {
WillPush.Level = 1;
WillPush.NoList = new List<int>() { AnyPair.Key };
AnyPair.Value.ForEach(X =>
{
WillPush.StrArrList = new List<char[]>() { X };
stk.Push(WillPush);
});
}
int AnswerCnt = 0;
while (stk.Count > 0) {
JyoutaiDef Popped = stk.Pop();
if (Popped.Level == 7) {
Console.WriteLine("解{0}を発見", ++AnswerCnt);
PrintAnswer(Popped.NoList, Popped.StrArrList);
continue;
}
foreach (var AnyPair in KaitenItaDict) {
if (Popped.NoList.Contains(AnyPair.Key)) continue; //使用済の板は除外
WillPush.Level = Popped.Level + 1;
WillPush.NoList = new List<int>(Popped.NoList) { AnyPair.Key };
//回転解の除外で、中央の板は回転も裏返しもせずに配置
if (WillPush.Level == 4) {
WillPush.StrArrList = new List<char[]>(Popped.StrArrList);
WillPush.StrArrList.Add(AnyPair.Value[0]);
if (IsValid(WillPush)) stk.Push(WillPush);
continue;
}
AnyPair.Value.ForEach(X =>
{
WillPush.StrArrList = new List<char[]>(Popped.StrArrList) { X };
if (IsValid(WillPush)) stk.Push(WillPush);
});
}
}
}
//裏返しと回転を含む板の配列のListを返す
static List<char[]> DeriveItaArrList(int pNo)
{
char[] BaseStrArr;
if (pNo == 1) BaseStrArr = "decbfa".ToCharArray();
else if (pNo == 2) BaseStrArr = "acdfeb".ToCharArray();
else if (pNo == 3) BaseStrArr = "dabfce".ToCharArray();
else if (pNo == 4) BaseStrArr = "bcadef".ToCharArray();
else if (pNo == 5) BaseStrArr = "defabc".ToCharArray();
else if (pNo == 6) BaseStrArr = "fdcbae".ToCharArray();
else BaseStrArr = "debfca".ToCharArray();
var ItaArrList = new List<char[]>();
int StrArrUB = BaseStrArr.GetUpperBound(0);
//始点変更の分
Action<char[]> AddSitenhenkouHaiti = pStrArr =>
{
for (int BaseInd = 0; BaseInd <= StrArrUB; BaseInd++) {
char[] WillAdd = new char[StrArrUB + 1];
for (int I = 0; I <= StrArrUB; I++) {
int FromInd = I + BaseInd;
if (FromInd > StrArrUB) FromInd -= (StrArrUB + 1);
WillAdd[I] = pStrArr[FromInd];
}
ItaArrList.Add(WillAdd);
}
};
//始点変更の分
AddSitenhenkouHaiti(BaseStrArr);
//回転と始点変更の分
char[] RevBaseStrArr = new char[StrArrUB + 1];
RevBaseStrArr[0] = BaseStrArr[5];
RevBaseStrArr[1] = BaseStrArr[4];
RevBaseStrArr[2] = BaseStrArr[3];
RevBaseStrArr[3] = BaseStrArr[2];
RevBaseStrArr[4] = BaseStrArr[1];
RevBaseStrArr[5] = BaseStrArr[0];
AddSitenhenkouHaiti(RevBaseStrArr);
return ItaArrList;
}
//有効な状態かを返す
static bool IsValid(JyoutaiDef pJyoutaiDef)
{
if (pJyoutaiDef.Level == 2) { //右上の六角形
if (pJyoutaiDef.StrArrList[1][4] != pJyoutaiDef.StrArrList[0][1]) return false;
}
if (pJyoutaiDef.Level == 3) { //左の六角形
if (pJyoutaiDef.StrArrList[2][0] != pJyoutaiDef.StrArrList[0][3]) return false;
}
if (pJyoutaiDef.Level == 4) { //中央の六角形
if (pJyoutaiDef.StrArrList[3][0] != pJyoutaiDef.StrArrList[1][3]) return false;
if (pJyoutaiDef.StrArrList[3][4] != pJyoutaiDef.StrArrList[2][1]) return false;
if (pJyoutaiDef.StrArrList[3][5] != pJyoutaiDef.StrArrList[0][2]) return false;
}
if (pJyoutaiDef.Level == 5) { //右の六角形
if (pJyoutaiDef.StrArrList[4][4] != pJyoutaiDef.StrArrList[3][1]) return false;
if (pJyoutaiDef.StrArrList[4][5] != pJyoutaiDef.StrArrList[1][2]) return false;
}
if (pJyoutaiDef.Level == 6) { //左下の六角形
if (pJyoutaiDef.StrArrList[5][0] != pJyoutaiDef.StrArrList[3][3]) return false;
if (pJyoutaiDef.StrArrList[5][5] != pJyoutaiDef.StrArrList[2][2]) return false;
}
if (pJyoutaiDef.Level == 7) { //右下の六角形
if (pJyoutaiDef.StrArrList[6][0] != pJyoutaiDef.StrArrList[4][3]) return false;
if (pJyoutaiDef.StrArrList[6][4] != pJyoutaiDef.StrArrList[5][1]) return false;
if (pJyoutaiDef.StrArrList[6][5] != pJyoutaiDef.StrArrList[3][2]) return false;
}
return true;
}
//解を表示
static void PrintAnswer(List<int> pSetNoList, List<char[]> pStrArrList)
{
var sb = new System.Text.StringBuilder();
for (int I = 0; I <= pSetNoList.Count - 1; I++) {
sb.AppendFormat("{0}枚目 ", I + 1);
if (I == 0) sb.Append("(左上) ");
if (I == 1) sb.Append("(右上) ");
if (I == 2) sb.Append("(左 ) ");
if (I == 3) sb.Append("(中央) ");
if (I == 4) sb.Append("(右 ) ");
if (I == 5) sb.Append("(左下) ");
if (I == 6) sb.Append("(右下) ");
sb.AppendFormat("板番号={0} ", pSetNoList[I]);
Array.ForEach(pStrArrList[I], X => sb.AppendFormat("{0} ", X));
sb.AppendLine();
}
Console.Write(sb.ToString());
}
}
実行結果
解1を発見
1枚目 (左上) 板番号=1 a f b c e d
2枚目 (右上) 板番号=5 d c b a f e
3枚目 (左 ) 板番号=3 c e d a b f
4枚目 (中央) 板番号=2 a c d f e b
5枚目 (右 ) 板番号=4 f e d a c b
6枚目 (左下) 板番号=6 f e a b c d
7枚目 (右下) 板番号=7 a c f b e d
解説
回転解の除外で、中央の板は回転も裏返しもせずに配置してます。