using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static void Main()
{
var sw = System.Diagnostics.Stopwatch.StartNew();
var stk = new Stack<Dictionary<char, int>>();
stk.Push(new Dictionary<char, int>());
int AnswerCnt = 0;
while (stk.Count > 0) {
Dictionary<char, int> PoppedDict = stk.Pop();
if (PoppedDict.Count == 15) {
Console.WriteLine("{0}個目の解を発見。経過時間={1}", ++AnswerCnt, sw.Elapsed);
PrintBan(PoppedDict);
continue;
}
for (char AddChar = 'A'; AddChar <= 'O'; AddChar++) {
if (PoppedDict.ContainsKey(AddChar)) continue;
for (int I = 2; I <= 16; I++) {
if (PoppedDict.ContainsValue(I)) continue;
//回転解の除外で C < J とする
if (AddChar == 'J' && PoppedDict['C'] > I)
continue;
Dictionary<char, int> WillPushDict = new Dictionary<char, int>(PoppedDict);
WillPushDict[AddChar] = I;
if (IsEdakiri(WillPushDict)) continue;
stk.Push(WillPushDict);
}
break;
}
}
}
//枝切り判定
static bool IsEdakiri(Dictionary<char, int> pHaitiDict)
{
Func<char, char, char, int> DeriveSumFrom3 = (pStr1, pStr2, pStr3) => (
pHaitiDict[pStr1] + pHaitiDict[pStr2] + pHaitiDict[pStr3]);
Func<char, char, char, char, int> DeriveSumFrom4 = (pStr1, pStr2, pStr3, pStr4) => (
pHaitiDict[pStr1] + pHaitiDict[pStr2] + pHaitiDict[pStr3] + pHaitiDict[pStr4]);
char MaxStr = pHaitiDict.Keys.Max();
//各値は2回ずつ加算されるので、8本の直線の和の総合計は、1から16までの等差数列の和の2倍である。
//8本の直線の和は、それぞれ等しいので、8で割れば、各直線の和が求まる。
const int SumVal = 16 * (16 + 1) / 2 * 2 / 8;
//途中の合計で枝切り
if (MaxStr == 'C' && DeriveSumFrom3('A', 'B', 'C') > SumVal - 2) return true;
if (MaxStr == 'G' && DeriveSumFrom3('E', 'F', 'G') > SumVal - 2) return true;
if (MaxStr == 'I' && DeriveSumFrom3('B', 'F', 'I') > SumVal - 2) return true;
if (MaxStr == 'J' && DeriveSumFrom3('I', 'J', 'H') > SumVal - 2) return true;
//直線の合計で枝切り
if (MaxStr == 'D' && SumVal != DeriveSumFrom4('A', 'B', 'C', 'D')) return true;
if (MaxStr == 'H' && SumVal != DeriveSumFrom4('E', 'F', 'G', 'H')) return true;
if (MaxStr == 'K' && SumVal != 1 + DeriveSumFrom3('J', 'K', 'E')) return true;
if (MaxStr == 'L' && SumVal != DeriveSumFrom4('I', 'J', 'L', 'H')) return true;
if (MaxStr == 'N' && SumVal != DeriveSumFrom4('I', 'B', 'F', 'N')) return true;
if (MaxStr == 'N' && SumVal != DeriveSumFrom4('D', 'L', 'M', 'N')) return true;
if (MaxStr == 'O' && SumVal != 1 + DeriveSumFrom3('C', 'G', 'O')) return true;
if (MaxStr == 'O' && SumVal != DeriveSumFrom4('A', 'K', 'M', 'O')) return true;
return false;
}
//盤面を表示
static void PrintBan(Dictionary<char, int> pHaitiDict)
{
var sb = new System.Text.StringBuilder();
const string SP = " ";
sb.AppendFormat("{0}{0}{1,2}{0}{2,2}{0}{0}", SP, pHaitiDict['I'], 1);
sb.AppendLine();
sb.AppendFormat("{0}{0}{0}{1,2}{0}{0}{0}", SP, pHaitiDict['J']);
sb.AppendLine();
sb.AppendFormat("{1,2}{0}{2,2}{0}{3,2}{0}{4,2}", SP,
pHaitiDict['A'], pHaitiDict['B'], pHaitiDict['C'], pHaitiDict['D']);
sb.AppendLine();
sb.AppendFormat("{0}{1,2}{0}{0}{0}{2,2}{0}", SP, pHaitiDict['K'], pHaitiDict['L']);
sb.AppendLine();
sb.AppendFormat("{1,2}{0}{2,2}{0}{3,2}{0}{4,2}", SP,
pHaitiDict['E'], pHaitiDict['F'], pHaitiDict['G'], pHaitiDict['H']);
sb.AppendLine();
sb.AppendFormat("{0}{0}{0}{1,2}{0}{0}{0}", SP, pHaitiDict['M']);
sb.AppendLine();
sb.AppendFormat("{0}{0}{1,2}{0}{2,2}{0}{0}", SP, pHaitiDict['N'], pHaitiDict['O']);
sb.AppendLine();
Console.WriteLine(sb.ToString());
}
}