using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
enum MasuDef
{
Kuuhaku = 0,
White = 1,
Black = 2
}
struct JyoutaiDef
{
internal MasuDef[] IshiArr;
internal List<MasuDef[]> Log;
}
const int WhiteCnt = 6;
const int BlackCnt = 6;
static System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
static void Main()
{
for (int Depth = 1; Depth <= 10; Depth++) {
Console.WriteLine("深さ制限={0}で解を検証中。経過時間={1}", Depth, sw.Elapsed);
if (ExecDFS(Depth)) return;
}
}
//深さ制限を引数として深さ優先探索を行う
static bool ExecDFS(int pDepthMax)
{
bool WillReturn = false;
var stk = new Stack<JyoutaiDef>();
JyoutaiDef WillPush;
var WKList = new List<MasuDef>();
WKList.AddRange(Enumerable.Repeat(MasuDef.Kuuhaku, 12));
for (int I = 1; I <= 6; I++)
WKList.AddRange(new MasuDef[] { MasuDef.White, MasuDef.Black });
WKList.AddRange(Enumerable.Repeat(MasuDef.Kuuhaku, 12));
WillPush.IshiArr = WKList.ToArray();
WillPush.Log = new List<MasuDef[]>() { WillPush.IshiArr };
stk.Push(WillPush);
while (stk.Count > 0) {
JyoutaiDef Popped = stk.Pop();
if (pDepthMax < Popped.Log.Count + CalcNeedMinTesuu(Popped.IshiArr)) continue;
if (IsAnswer(Popped.IshiArr)) {
Console.WriteLine("解を発見。経過時間={0}", sw.Elapsed);
PrintLog(Popped.Log);
return true;
}
Action<int, int> PushSyori = (pMinP, pMaxP) =>
{
//既存の配置だったら枝切り
if (Popped.Log.Exists(X => X.SequenceEqual(WillPush.IshiArr))) {
return;
}
WillPush.Log = new List<MasuDef[]>(Popped.Log);
WillPush.Log.Add(WillPush.IshiArr);
stk.Push(WillPush);
};
MasuDef[] WK_P = Popped.IshiArr;
//3マスの空白への移動
for (int I = 0; I <= WK_P.GetUpperBound(0) - 2; I++) {
bool Has3Space = false;
if (WK_P[I] == MasuDef.Kuuhaku &&
WK_P[I + 1] == MasuDef.Kuuhaku &&
WK_P[I + 2] == MasuDef.Kuuhaku) {
Has3Space = true;
}
if (Has3Space == false) continue;
//移動する際、少なくとも一方の石がほかの碁石に接しなければならない
if (HasGoishi(WK_P, I - 1) == false &&
HasGoishi(WK_P, I + 3) == false) continue;
for (int J = 0; J <= WK_P.GetUpperBound(0) - 2; J++) {
if (WK_P[J] != MasuDef.Kuuhaku &&
WK_P[J + 1] != MasuDef.Kuuhaku &&
WK_P[J + 2] != MasuDef.Kuuhaku) {
WillPush.IshiArr = (MasuDef[])WK_P.Clone();
WillPush.IshiArr[I] = WK_P[J];
WillPush.IshiArr[I + 1] = WK_P[J + 1];
WillPush.IshiArr[I + 2] = WK_P[J + 2];
WillPush.IshiArr[J] = MasuDef.Kuuhaku;
WillPush.IshiArr[J + 1] = MasuDef.Kuuhaku;
WillPush.IshiArr[J + 2] = MasuDef.Kuuhaku;
PushSyori(I, I + 2);
}
}
}
//2マスの空白への移動
for (int I = 0; I <= WK_P.GetUpperBound(0) - 4; I++) {
if (HasGoishi(WK_P, I - 1) &&
WK_P[I] == MasuDef.Kuuhaku &&
WK_P[I + 1] == MasuDef.Kuuhaku &&
WK_P[I + 2] != MasuDef.Kuuhaku &&
WK_P[I + 3] != MasuDef.Kuuhaku &&
WK_P[I + 4] != MasuDef.Kuuhaku) {
WillPush.IshiArr = (MasuDef[])WK_P.Clone();
WillPush.IshiArr[I] = WK_P[I + 1];
WillPush.IshiArr[I + 1] = WK_P[I + 2];
WillPush.IshiArr[I + 2] = WK_P[I + 3];
WillPush.IshiArr[I + 3] = MasuDef.Kuuhaku;
WillPush.IshiArr[I + 4] = MasuDef.Kuuhaku;
PushSyori(I, I + 2);
}
if (WK_P[I] != MasuDef.Kuuhaku &&
WK_P[I + 1] != MasuDef.Kuuhaku &&
WK_P[I + 2] != MasuDef.Kuuhaku &&
WK_P[I + 3] == MasuDef.Kuuhaku &&
WK_P[I + 4] == MasuDef.Kuuhaku &&
HasGoishi(WK_P, I + 5)) {
WillPush.IshiArr = (MasuDef[])WK_P.Clone();
WillPush.IshiArr[I + 4] = WK_P[I + 3];
WillPush.IshiArr[I + 3] = WK_P[I + 2];
WillPush.IshiArr[I + 2] = WK_P[I + 1];
WillPush.IshiArr[I + 1] = MasuDef.Kuuhaku;
WillPush.IshiArr[I] = MasuDef.Kuuhaku;
PushSyori(I + 2, I + 4);
}
}
//1マスの空白への移動
for (int I = 0; I <= WK_P.GetUpperBound(0) - 3; I++) {
if (HasGoishi(WK_P, I - 1) &&
WK_P[I] == MasuDef.Kuuhaku &&
WK_P[I + 1] != MasuDef.Kuuhaku &&
WK_P[I + 2] != MasuDef.Kuuhaku &&
WK_P[I + 3] != MasuDef.Kuuhaku) {
WillPush.IshiArr = (MasuDef[])WK_P.Clone();
WillPush.IshiArr[I] = WK_P[I + 1];
WillPush.IshiArr[I + 1] = WK_P[I + 2];
WillPush.IshiArr[I + 2] = WK_P[I + 3];
WillPush.IshiArr[I + 3] = MasuDef.Kuuhaku;
PushSyori(I, I + 2);
}
if (WK_P[I] != MasuDef.Kuuhaku &&
WK_P[I + 1] != MasuDef.Kuuhaku &&
WK_P[I + 2] != MasuDef.Kuuhaku &&
WK_P[I + 3] == MasuDef.Kuuhaku &&
HasGoishi(WK_P, I + 4)) {
WillPush.IshiArr = (MasuDef[])WK_P.Clone();
WillPush.IshiArr[I + 3] = WK_P[I + 2];
WillPush.IshiArr[I + 2] = WK_P[I + 1];
WillPush.IshiArr[I + 1] = WK_P[I];
WillPush.IshiArr[I] = MasuDef.Kuuhaku;
PushSyori(I + 1, I + 3);
}
}
}
return WillReturn;
}
//移動する際、少なくとも一方の石がほかの碁石に接しなければならない
static bool IsRinsetu(MasuDef[] pIshiArr, int pMinP, int pMaxP)
{
if (0 <= pMinP - 1 &&
pIshiArr[pMinP - 1] != MasuDef.Kuuhaku) return true;
if (pMaxP + 1 <= pIshiArr.GetUpperBound(0) &&
pIshiArr[pMaxP + 1] != MasuDef.Kuuhaku) return true;
return false;
}
//解に到達したかを判定
static bool IsAnswer(MasuDef[] pIshiArr)
{
var Query = pIshiArr.SkipWhile(X => X == MasuDef.Kuuhaku)
.TakeWhile(X => X != MasuDef.Kuuhaku);
var WK1 = Enumerable.Repeat(MasuDef.White, WhiteCnt);
var WK2 = Enumerable.Repeat(MasuDef.Black, BlackCnt);
return Query.SequenceEqual(WK1.Concat(WK2)) ||
Query.SequenceEqual(WK2.Concat(WK1));
}
//移動のログを表示
static void PrintLog(List<MasuDef[]> pLog)
{
int Level = 0;
var sb = new System.Text.StringBuilder();
foreach (MasuDef[] AnyArr in pLog) {
sb.AppendFormat("LV{0,2}=", ++Level);
foreach (MasuDef AnyMasu in AnyArr) {
if (AnyMasu == MasuDef.Kuuhaku) sb.Append(' ');
if (AnyMasu == MasuDef.White) sb.Append('○');
if (AnyMasu == MasuDef.Black) sb.Append('●');
}
sb.AppendLine();
}
Console.WriteLine(sb.ToString());
}
//碁石の存在チェック
static bool HasGoishi(MasuDef[] pIshiArr, int pTargetP)
{
if (pTargetP < 0 || pIshiArr.GetUpperBound(0) < pTargetP) return false;
return pIshiArr[pTargetP] != MasuDef.Kuuhaku;
}
//必要な最低手数を求める
static int CalcNeedMinTesuu(MasuDef[] pIshiArr)
{
int WhiteSeqCnt = 0;
int BlackSeqCnt = 0;
for (int I = 0; I <= pIshiArr.GetUpperBound(0); I++) {
if (pIshiArr[I] == MasuDef.White &&
(I == 0 || pIshiArr[I - 1] != MasuDef.White))
WhiteSeqCnt++;
if (pIshiArr[I] == MasuDef.Black &&
(I == 0 || pIshiArr[I - 1] != MasuDef.Black))
BlackSeqCnt++;
}
return Math.Max(WhiteSeqCnt - 1, BlackSeqCnt - 1);
}
}