using System;
using System.Collections.Generic;
using System.Linq;
//UI部分
partial class Program
{
static char[,] mBanArr;
static int mLevel;
static bool mHasSyouhai;
static Dictionary<int, int> mVisitedInuHashCntDict = new Dictionary<int, int>();
//1ゲームを行う
static void ExecGame()
{
mBanArr = InitBanArr('X');
mLevel = 0;
mHasSyouhai = false;
mVisitedInuHashCntDict.Clear();
while (true) {
InputHitoItte(false);
if (mHasSyouhai) break;
mLevel++;
bool HasBug;
ExecComItte(out HasBug);
if (HasBug) return;
if (mHasSyouhai) break;
mLevel++;
}
Console.WriteLine("ウサギの負けです");
Console.WriteLine("□□□□□□□□□□□□□□□□□□□□□□□□□");
}
//人の1手を入力
static void InputHitoItte(bool pIsRetry)
{
if (pIsRetry == false) {
if (mLevel == 0) {
PrintBan(mBanArr);
Console.Write("ウサギの配置場所を入力して下さい ");
}
else Console.Write("ウサギの移動先を入力して下さい ");
}
string wkStr = Console.ReadLine().ToUpper();
if (wkStr.Length != 1) {
Console.Write("入力エラーです。再入力して下さい ");
InputHitoItte(true); return;
}
char wkChar = wkStr[0];
if (wkChar < 'A' || 'J' < wkChar) {
Console.Write("入力エラーです。再入力して下さい ");
InputHitoItte(true); return;
}
if (mLevel >= 2 && CanMoveUsagi(wkChar) == false) {
Console.Write("移動不可です。再入力して下さい ");
InputHitoItte(true); return;
}
ExecHitoItte(wkChar);
}
//指定した座標にウサギが移動可能かを返す
static bool CanMoveUsagi(char pNewPos)
{
char CurrUsagiPos = DeriveCurrUsagiPos();
if (pNewPos == 'A') {
if (mBanArr[1, 0] != ' ') return false;
return "BCD".Contains(CurrUsagiPos);
}
if (pNewPos == 'B') {
if (mBanArr[0, 1] != ' ') return false;
return "ACEF".Contains(CurrUsagiPos);
}
if (pNewPos == 'C') {
if (mBanArr[1, 1] != ' ') return false;
return "ABDF".Contains(CurrUsagiPos);
}
if (pNewPos == 'D') {
if (mBanArr[2, 1] != ' ') return false;
return "ACFG".Contains(CurrUsagiPos);
}
if (pNewPos == 'E') {
if (mBanArr[0, 2] != ' ') return false;
return "BFH".Contains(CurrUsagiPos);
}
if (pNewPos == 'F') {
if (mBanArr[1, 2] != ' ') return false;
return "BCDEGHIJ".Contains(CurrUsagiPos);
}
if (pNewPos == 'G') {
if (mBanArr[2, 2] != ' ') return false;
return "DFJ".Contains(CurrUsagiPos);
}
if (pNewPos == 'H') {
if (mBanArr[0, 3] != ' ') return false;
return "EFIK".Contains(CurrUsagiPos);
}
if (pNewPos == 'I') {
if (mBanArr[1, 3] != ' ') return false;
return "FHJK".Contains(CurrUsagiPos);
}
if (pNewPos == 'J') {
if (mBanArr[2, 3] != ' ') return false;
return "FGIK".Contains(CurrUsagiPos);
}
return false;
}
//現在のウサギの座標をCharで返す
static char DeriveCurrUsagiPos()
{
if (mBanArr[1, 0] == 'ウ') return 'A';
if (mBanArr[0, 1] == 'ウ') return 'B';
if (mBanArr[1, 1] == 'ウ') return 'C';
if (mBanArr[2, 1] == 'ウ') return 'D';
if (mBanArr[0, 2] == 'ウ') return 'E';
if (mBanArr[1, 2] == 'ウ') return 'F';
if (mBanArr[2, 2] == 'ウ') return 'G';
if (mBanArr[0, 3] == 'ウ') return 'H';
if (mBanArr[1, 3] == 'ウ') return 'I';
if (mBanArr[2, 3] == 'ウ') return 'J';
return 'K';
}
//人の1手を指して、メッセージ表示
static void ExecHitoItte(char pChar)
{
if (mLevel == 0) {
mBanArr = InitBanArr(pChar);
}
else {
for (int X = 0; X <= UB_X; X++) {
for (int Y = 0; Y <= UB_Y; Y++) {
if (mBanArr[X, Y] == 'ウ')
mBanArr[X, Y] = ' ';
}
}
if (pChar == 'A') mBanArr[1, 0] = 'ウ';
if (pChar == 'B') mBanArr[0, 1] = 'ウ';
if (pChar == 'C') mBanArr[1, 1] = 'ウ';
if (pChar == 'D') mBanArr[2, 1] = 'ウ';
if (pChar == 'E') mBanArr[0, 2] = 'ウ';
if (pChar == 'F') mBanArr[1, 2] = 'ウ';
if (pChar == 'G') mBanArr[2, 2] = 'ウ';
if (pChar == 'H') mBanArr[0, 3] = 'ウ';
if (pChar == 'I') mBanArr[1, 3] = 'ウ';
if (pChar == 'J') mBanArr[2, 3] = 'ウ';
}
SyouhaiHantei();
JyoukyouHyouji();
}
//COMが手を指す
static void ExecComItte(out bool pHasBug)
{
pHasBug = false;
//遷移可能な盤面を列挙
List<char[,]> CanSeniBanArrList = DeriveCanSeniBanArrList(mBanArr, false);
//犬勝ちのHash値(179742,198558,323676)が最優先で、
//次に、訪問回数の少ないノードを優先する。
IEnumerable<char[,]> CanSeniBanArrEnum = CanSeniBanArrList
.OrderByDescending(A => GetHash(1, A) == 179742)
.ThenByDescending(A => GetHash(1, A) == 198558)
.ThenByDescending(A => GetHash(1, A) == 323676)
.ThenBy(A => mVisitedInuHashCntDict.ContainsKey(GetHash(1, A)) ?
mVisitedInuHashCntDict[GetHash(1, A)] : 0);
bool FoundNode = false;
foreach (char[,] EachCanSeniBanArr in CanSeniBanArrEnum) {
int wkHash = GetHash(1, EachCanSeniBanArr);
int wkInd = mHashIndDict[wkHash];
if (mNodeInfoArr[wkInd].Syouhai == 1) {
if (mVisitedInuHashCntDict.ContainsKey(wkHash)) {
mVisitedInuHashCntDict[wkHash]++;
}
else mVisitedInuHashCntDict[wkHash] = 1;
mBanArr = EachCanSeniBanArr;
FoundNode = true;
break;
}
}
if (FoundNode == false) {
Console.WriteLine("バグってます!!!");
Console.WriteLine("犬勝の手が存在しません");
pHasBug = true;
return;
}
SyouhaiHantei();
JyoukyouHyouji();
}
//状況を表示
static void JyoukyouHyouji()
{
var sb = new System.Text.StringBuilder();
if (mLevel % 2 == 0) {
sb.AppendLine("□□□□□□□□□□□□□□□□□□□□□□□□□");
}
else {
sb.AppendLine("■■■■■■■■■■■■■■■■■■■■■■■■■");
}
int Teban = ((mLevel % 2 == 1) ? 1 : 2);
sb.AppendFormat("現在の手数={0}。Hash={1}。", mLevel, GetHash(Teban, mBanArr));
sb.Append((mLevel % 2 == 0) ? "犬の手番。" : "ウサギの手番。");
sb.AppendLine();
Console.WriteLine(sb.ToString());
PrintBan(mBanArr);
}
//勝敗が決定しているかを判定
static void SyouhaiHantei()
{
mHasSyouhai = (DeriveSyouhai(mBanArr) == 1);
}
}
//ロジック部分
partial class Program
{
const int UB_X = 3 - 1;
const int UB_Y = 5 - 1;
struct PointDef
{
internal int X;
internal int Y;
}
static void Main()
{
//初期処理
InitSyori();
while (true) {
ExecGame();
}
}
//初期処理
static void InitSyori()
{
Console.WriteLine("遷移可能な盤面を列挙します。");
ExecUnionFind();
Console.WriteLine("遷移可能な盤面は{0}通り。", mNodeInfoArr.Length);
//mNodeInfoArrの添字[Hash値]のDictを作成
CreateHashIndDict();
//全ノードの勝敗を求める
DeriveAllSyouhai();
}
struct NodeInfoDef
{
internal int Teban;
internal char[,] BanArr;
internal int Hash; //手番と盤面のハッシュ値
internal List<int> KoHashList; //子ノードのハッシュ値のリスト
internal int Syouhai; //勝敗 (未決定は0、先手勝は1、後手勝は2)
}
static NodeInfoDef[] mNodeInfoArr;
//遷移可能な手番と盤面の組み合わせをUnionFindで列挙
static void ExecUnionFind()
{
var NodeInfoList = new List<NodeInfoDef>();
var Stk = new Stack<NodeInfoDef>();
NodeInfoDef WillPush;
foreach (char EachUsagiPos in "ABCDEFGI") {
WillPush.Teban = 2;
WillPush.BanArr = InitBanArr(EachUsagiPos);
WillPush.Hash = GetHash(WillPush.Teban, WillPush.BanArr);
WillPush.KoHashList = new List<int>();
WillPush.Syouhai = 0;
NodeInfoList.Add(WillPush);
Stk.Push(WillPush);
}
while (Stk.Count > 0) {
NodeInfoDef Popped = Stk.Pop();
WillPush.Teban = (Popped.Teban == 1 ? 2 : 1);
var JyoutaiList = new List<NodeInfoDef>();
//勝ちになる手があるか?
bool HasKatite = false;
//遷移可能な盤面を列挙
List<char[,]> CanSeniBanArrList;
if (WillPush.Teban == 1) //犬の手番の場合
CanSeniBanArrList = DeriveCanSeniBanArrList(Popped.BanArr, false);
else //ウサギの手番の場合
CanSeniBanArrList = DeriveCanSeniBanArrList(Popped.BanArr, true);
foreach (char[,] EachBanArr in CanSeniBanArrList) {
WillPush.BanArr = EachBanArr;
WillPush.Hash = GetHash(WillPush.Teban, WillPush.BanArr);
WillPush.KoHashList = new List<int>();
WillPush.Syouhai = 0;
WillPush.Syouhai = DeriveSyouhai(WillPush.BanArr);
//勝ちになる手があったら、その手で確定
if (WillPush.Syouhai == WillPush.Teban) {
HasKatite = true;
Popped.KoHashList.Add(WillPush.Hash);
//訪問済ノードならAddしない
if (NodeInfoList.Exists(A => A.Hash == WillPush.Hash) == false)
NodeInfoList.Add(WillPush);
break;
}
JyoutaiList.Add(WillPush);
}
if (HasKatite) continue;
foreach (NodeInfoDef EachJyoutai in JyoutaiList) {
Popped.KoHashList.Add(EachJyoutai.Hash);
//訪問済ノードなら再訪しない
if (NodeInfoList.Exists(A => A.Hash == EachJyoutai.Hash))
continue;
NodeInfoList.Add(EachJyoutai);
if (EachJyoutai.Syouhai == 0) Stk.Push(EachJyoutai);
}
}
//Hash値でソートしておく
mNodeInfoArr = NodeInfoList.OrderBy(A => A.Hash).ToArray();
}
//mNodeInfoArrの添字[Hash値]のDictを作成
static Dictionary<int, int> mHashIndDict = new Dictionary<int, int>();
static void CreateHashIndDict()
{
for (int I = 0; I <= mNodeInfoArr.GetUpperBound(0); I++) {
mHashIndDict.Add(mNodeInfoArr[I].Hash, I);
}
}
//全ノードの勝敗を求める
static void DeriveAllSyouhai()
{
int LimitNodeCnt = 10, PrevNodeCnt = 0;
while (true) {
int CurrNodeCnt = mNodeInfoArr.Count(A => A.Syouhai == 0);
if (CurrNodeCnt == 0) break;
if (CurrNodeCnt == PrevNodeCnt) LimitNodeCnt *= 2;
else LimitNodeCnt = 10;
for (int I = 0; I <= mNodeInfoArr.GetUpperBound(0); I++) {
if (mNodeInfoArr[I].Syouhai != 0) continue;
mNodeInfoArr[I].Syouhai =
DeriveRootNodeSyouhai(mNodeInfoArr[I].Hash, LimitNodeCnt);
}
PrevNodeCnt = CurrNodeCnt;
}
}
struct JyoutaiDefDFS
{
internal int Level;
internal int NodeID;
internal List<int> KoNodeIDList;
internal int Hash; //手番と盤面のハッシュ値
internal int Syouhai; //勝敗 (未決定は0、先手勝は1、後手勝は2)
internal HashSet<int> VisitedSetInu;
}
//根ノードのHash値と訪問ノード数上限を引数として、
//完全ゲーム木を作り、根ノードの勝敗を求める
static int DeriveRootNodeSyouhai(int pRootHash, int pLimitNodeCnt)
{
var GameTreeList = new List<JyoutaiDefDFS>();
var Stk = new Stack<JyoutaiDefDFS>();
JyoutaiDefDFS WillPush;
WillPush.Level = 0;
WillPush.NodeID = GetNodeID();
WillPush.KoNodeIDList = new List<int>();
WillPush.Hash = pRootHash;
WillPush.Syouhai = 0;
WillPush.VisitedSetInu = new HashSet<int>();
int Ind1 = mHashIndDict[pRootHash];
if (mNodeInfoArr[Ind1].Teban == 1) { //犬番の場合
WillPush.VisitedSetInu.Add(pRootHash);
}
GameTreeList.Add(WillPush);
Stk.Push(WillPush);
while (Stk.Count > 0) {
JyoutaiDefDFS Popped = Stk.Pop();
//ノード数上限を超えた場合
if (GameTreeList.Count > pLimitNodeCnt) return 0;
int Ind2 = mHashIndDict[Popped.Hash];
var JyoutaiList = new List<JyoutaiDefDFS>();
//勝ちになる手があるか?
bool HasKatite = false;
foreach (int EachHash in mNodeInfoArr[Ind2].KoHashList) {
int Ind3 = mHashIndDict[EachHash];
WillPush.Level = Popped.Level + 1;
WillPush.NodeID = GetNodeID();
WillPush.KoNodeIDList = new List<int>();
WillPush.Hash = EachHash;
WillPush.Syouhai = mNodeInfoArr[Ind3].Syouhai;
if (mNodeInfoArr[Ind3].Teban == 1) { //犬番の場合
//犬番での千日手は不可
if (Popped.VisitedSetInu.Contains(EachHash)) continue;
WillPush.VisitedSetInu = new HashSet<int>(Popped.VisitedSetInu);
WillPush.VisitedSetInu.Add(EachHash);
}
else { //ウサギ番の場合
WillPush.VisitedSetInu = Popped.VisitedSetInu;
}
//勝ちになる手があったら、その手で確定
if (mNodeInfoArr[Ind3].Teban == mNodeInfoArr[Ind3].Syouhai) {
Popped.KoNodeIDList.Add(WillPush.NodeID);
GameTreeList.Add(WillPush);
HasKatite = true;
break;
}
JyoutaiList.Add(WillPush);
}
if (HasKatite) continue;
//勝敗不明な手があるなら、負けになる手をRemove
if (JyoutaiList.Exists(A => A.Syouhai == 0))
JyoutaiList.RemoveAll(A => A.Syouhai != 0);
foreach (JyoutaiDefDFS EachJyoutai in JyoutaiList) {
Popped.KoNodeIDList.Add(EachJyoutai.NodeID);
GameTreeList.Add(EachJyoutai);
if (EachJyoutai.Syouhai == 0) Stk.Push(EachJyoutai);
}
}
//レベルの降順でソートしておく
JyoutaiDefDFS[] GameTreeArr = GameTreeList.OrderByDescending(A => A.Level).ToArray();
while (GameTreeArr.Length > 1) {
int TreeHeight = GameTreeArr.Max(X => X.Level);
//木の高さ-1のノードの勝敗を決定する
for (int I = 0; I <= GameTreeArr.GetUpperBound(0); I++) {
if (GameTreeArr[I].Level > TreeHeight - 1) continue;
if (GameTreeArr[I].Level < TreeHeight - 1) break;
if (GameTreeArr[I].Syouhai != 0) continue;
int Ind4 = mHashIndDict[GameTreeArr[I].Hash];
int Teban = mNodeInfoArr[Ind4].Teban;
//犬番の場合は、ウサギが最善手で応じても犬勝なら、犬勝
if (Teban == 1) {
bool IsHit = false;
foreach (int EachKoNodeID in GameTreeArr[I].KoNodeIDList) {
if (Array.Exists(GameTreeArr,
A => A.NodeID == EachKoNodeID && A.Syouhai == 2)) {
IsHit = true;
break;
}
}
GameTreeArr[I].Syouhai = (IsHit ? 2 : 1);
}
//ウサギ番の場合は、犬が最善手で応じてもウサギ勝なら、ウサギ勝
else {
bool IsHit = false;
foreach (int EachKoNodeID in GameTreeArr[I].KoNodeIDList) {
if (Array.Exists(GameTreeArr,
A => A.NodeID == EachKoNodeID && A.Syouhai == 1)) {
IsHit = true;
break;
}
}
GameTreeArr[I].Syouhai = (IsHit ? 1 : 2);
}
}
//不要なノードを削除
GameTreeArr = Array.FindAll(GameTreeArr, A => A.Level <= TreeHeight - 1);
}
return GameTreeArr[0].Syouhai;
}
//NodeID(自動採番)
static int mNodeID = 0;
static int GetNodeID()
{
return ++mNodeID;
}
//ウサギの位置を指定して、初期状態の2次元配列を返す
static char[,] InitBanArr(char pUsagiPos)
{
char[,] WillReturn = new char[UB_X + 1, UB_Y + 1];
for (int X = 0; X <= UB_X; X++) {
for (int Y = 0; Y <= UB_Y; Y++) {
WillReturn[X, Y] = ' ';
}
}
WillReturn[0, 3] = '犬';
WillReturn[1, 4] = '犬';
WillReturn[2, 3] = '犬';
if (pUsagiPos == 'A') WillReturn[1, 0] = 'ウ';
if (pUsagiPos == 'B') WillReturn[0, 1] = 'ウ';
if (pUsagiPos == 'C') WillReturn[1, 1] = 'ウ';
if (pUsagiPos == 'D') WillReturn[2, 1] = 'ウ';
if (pUsagiPos == 'E') WillReturn[0, 2] = 'ウ';
if (pUsagiPos == 'F') WillReturn[1, 2] = 'ウ';
if (pUsagiPos == 'G') WillReturn[2, 2] = 'ウ';
if (pUsagiPos == 'I') WillReturn[1, 3] = 'ウ';
return WillReturn;
}
//手番と盤面をハッシュ値に変換
static int GetHash(int pTeban, char[,] pBanArr)
{
var NumList = new List<int>();
//手番もハッシュ値に含める
NumList.Add(pTeban);
for (int Y = 0; Y <= UB_Y; Y++) {
for (int X = 0; X <= UB_X; X++) {
if (X == 0 && Y == 0) continue;
if (X == UB_X && Y == 0) continue;
if (X == 0 && Y == UB_Y) continue;
if (X == UB_X && Y == UB_Y) continue;
if (pBanArr[X, Y] == ' ') NumList.Add(0);
if (pBanArr[X, Y] == '犬') NumList.Add(1);
if (pBanArr[X, Y] == 'ウ') NumList.Add(2);
}
}
//3の12乗=531441なので3進数ならオーバーフローしない
int WillReturn = 0;
foreach (int EachInt in NumList) {
WillReturn *= 3;
WillReturn += EachInt;
}
return WillReturn;
}
//遷移可能な盤面を列挙
static List<char[,]> DeriveCanSeniBanArrList(char[,] pBanArr, bool pIsUsagi)
{
var WillReturnList = new List<char[,]>();
for (int LoopX = 0; LoopX <= UB_X; LoopX++) {
for (int LoopY = 0; LoopY <= UB_Y; LoopY++) {
if (pIsUsagi == false && pBanArr[LoopX, LoopY] != '犬') continue;
if (pIsUsagi && pBanArr[LoopX, LoopY] != 'ウ') continue;
List<PointDef> CanMovePosList =
(pIsUsagi ? DeriveCanMovePosListUsagi(LoopX, LoopY) :
DeriveCanMovePosListInu(LoopX, LoopY));
CanMovePosList.RemoveAll(A => pBanArr[A.X, A.Y] != ' ');
foreach (PointDef EachMovePos in CanMovePosList) {
char[,] wkArr = (char[,])pBanArr.Clone();
wkArr[LoopX, LoopY] = ' ';
wkArr[EachMovePos.X, EachMovePos.Y] = (pIsUsagi ? 'ウ' : '犬');
WillReturnList.Add(wkArr);
}
}
}
return WillReturnList;
}
//座標を引数として、移動可能な座標を返す(犬用)
static List<PointDef> DeriveCanMovePosListInu(int pFromX, int pFromY)
{
var WillReturnList = new List<PointDef>();
if (pFromX == 0 && pFromY == 1
|| pFromX == 2 && pFromY == 1) { //BまたはDの場合
WillReturnList.Add(new PointDef() { X = 1, Y = 0 });
WillReturnList.Add(new PointDef() { X = 1, Y = 1 });
}
if (pFromX == 1 && pFromY == 1) { //Cの場合
WillReturnList.Add(new PointDef() { X = 1, Y = 0 });
WillReturnList.Add(new PointDef() { X = 0, Y = 1 });
WillReturnList.Add(new PointDef() { X = 2, Y = 1 });
}
if (pFromX == 0 && pFromY == 2) { //Eの場合
WillReturnList.Add(new PointDef() { X = 0, Y = 1 });
WillReturnList.Add(new PointDef() { X = 1, Y = 2 });
}
if (pFromX == 1 && pFromY == 2) { //Fの場合
WillReturnList.Add(new PointDef() { X = 0, Y = 1 });
WillReturnList.Add(new PointDef() { X = 1, Y = 1 });
WillReturnList.Add(new PointDef() { X = 2, Y = 1 });
WillReturnList.Add(new PointDef() { X = 0, Y = 2 });
WillReturnList.Add(new PointDef() { X = 2, Y = 2 });
}
if (pFromX == 2 && pFromY == 2) { //Gの場合
WillReturnList.Add(new PointDef() { X = 2, Y = 1 });
WillReturnList.Add(new PointDef() { X = 1, Y = 2 });
}
if (pFromX == 0 && pFromY == 3) { //Hの場合
WillReturnList.Add(new PointDef() { X = 0, Y = 2 });
WillReturnList.Add(new PointDef() { X = 1, Y = 2 });
WillReturnList.Add(new PointDef() { X = 1, Y = 3 });
}
if (pFromX == 1 && pFromY == 3) { //Iの場合
WillReturnList.Add(new PointDef() { X = 1, Y = 2 });
WillReturnList.Add(new PointDef() { X = 0, Y = 3 });
WillReturnList.Add(new PointDef() { X = 2, Y = 3 });
}
if (pFromX == 2 && pFromY == 3) { //Jの場合
WillReturnList.Add(new PointDef() { X = 1, Y = 2 });
WillReturnList.Add(new PointDef() { X = 2, Y = 2 });
WillReturnList.Add(new PointDef() { X = 1, Y = 3 });
}
if (pFromX == 1 && pFromY == 4) { //Kの場合
WillReturnList.Add(new PointDef() { X = 0, Y = 3 });
WillReturnList.Add(new PointDef() { X = 1, Y = 3 });
WillReturnList.Add(new PointDef() { X = 2, Y = 3 });
}
return WillReturnList;
}
//座標を引数として、移動可能な座標を返す(ウサギ用)
static List<PointDef> DeriveCanMovePosListUsagi(int pFromX, int pFromY)
{
var WillReturnList = new List<PointDef>();
WillReturnList.AddRange(DeriveCanMovePosListInu(pFromX, pFromY));
if (pFromX == 1 && pFromY == 0) { //Aの場合
WillReturnList.Add(new PointDef() { X = 0, Y = 1 });
WillReturnList.Add(new PointDef() { X = 1, Y = 1 });
WillReturnList.Add(new PointDef() { X = 2, Y = 1 });
}
if (pFromX == 0 && pFromY == 1) { //Bの場合
WillReturnList.Add(new PointDef() { X = 0, Y = 2 });
WillReturnList.Add(new PointDef() { X = 1, Y = 2 });
}
if (pFromX == 1 && pFromY == 1) { //Cの場合
WillReturnList.Add(new PointDef() { X = 1, Y = 2 });
}
if (pFromX == 2 && pFromY == 1) { //Dの場合
WillReturnList.Add(new PointDef() { X = 1, Y = 2 });
WillReturnList.Add(new PointDef() { X = 2, Y = 2 });
}
if (pFromX == 0 && pFromY == 2) { //Eの場合
WillReturnList.Add(new PointDef() { X = 0, Y = 3 });
}
if (pFromX == 1 && pFromY == 2) { //Fの場合
WillReturnList.Add(new PointDef() { X = 0, Y = 3 });
WillReturnList.Add(new PointDef() { X = 1, Y = 3 });
WillReturnList.Add(new PointDef() { X = 2, Y = 3 });
}
if (pFromX == 2 && pFromY == 2) { //Gの場合
WillReturnList.Add(new PointDef() { X = 2, Y = 3 });
}
if (pFromX == 0 && pFromY == 3) { //Hの場合
WillReturnList.Add(new PointDef() { X = 1, Y = 4 });
}
if (pFromX == 1 && pFromY == 3) { //Iの場合
WillReturnList.Add(new PointDef() { X = 1, Y = 4 });
}
if (pFromX == 2 && pFromY == 3) { //Jの場合
WillReturnList.Add(new PointDef() { X = 1, Y = 4 });
}
return WillReturnList;
}
//盤面から勝敗(未決定は0、先手勝は1、後手勝は2)を求める
static int DeriveSyouhai(char[,] pBanArr)
{
//犬勝かを判定
char[,] wkP = pBanArr;
if (wkP[1, 0] == 'ウ'
&& wkP[0, 1] == '犬' && wkP[1, 1] == '犬' && wkP[2, 1] == '犬') {
return 1;
}
if (wkP[0, 2] == 'ウ'
&& wkP[0, 1] == '犬' && wkP[1, 2] == '犬' && wkP[0, 3] == '犬') {
return 1;
}
if (wkP[2, 2] == 'ウ'
&& wkP[2, 1] == '犬' && wkP[1, 2] == '犬' && wkP[2, 3] == '犬') {
return 1;
}
//犬が[1,0]にいたらウサギ勝
if (wkP[1, 0] == '犬') return 2;
//ウサギ勝かを判定
var InuYList = new List<int>();
int UsagiY = -1;
for (int X = 0; X <= UB_X; X++) {
for (int Y = 0; Y <= UB_Y; Y++) {
if (wkP[X, Y] == 'ウ') UsagiY = Y;
if (wkP[X, Y] == '犬') InuYList.Add(Y);
}
}
//ウサギのY座標 >= 最も下の犬のY座標 ならウサギ勝
if (UsagiY >= InuYList.Max()) return 2;
//Y座標がウサギ以上の犬が1匹以下 ならウサギ勝
if (InuYList.Count(A => UsagiY <= A) <= 1) return 2;
//ウサギがFHIJのいずれかにいて、犬がBCDのいずれかにいたら ウサギ勝
if (wkP[1, 2] == 'ウ'
|| wkP[0, 3] == 'ウ' || wkP[1, 3] == 'ウ' || wkP[2, 3] == 'ウ') {
if (wkP[0, 1] == '犬' || wkP[1, 1] == '犬' || wkP[2, 1] == '犬') {
return 2;
}
}
return 0;
}
static void DebugPrint(NodeInfoDef pNodeInfo)
{
var sb = new System.Text.StringBuilder();
sb.AppendFormat("Teban={0},Hash={1},勝敗={2},",
pNodeInfo.Teban, pNodeInfo.Hash, pNodeInfo.Syouhai);
sb.Append("子ノードのHashは");
if (pNodeInfo.KoHashList.Count > 0)
pNodeInfo.KoHashList.ForEach(A => sb.AppendFormat("{0},", A));
else sb.Append("なし");
Console.WriteLine(sb.ToString());
PrintBan(pNodeInfo.BanArr);
}
//盤面を表示
static void PrintBan(char[,] pBanArr)
{
var sb = new System.Text.StringBuilder();
Func<int, int, char, char> wkFunc = (pX, pY, pPos) =>
pBanArr[pX, pY] == ' ' ? pPos : pBanArr[pX, pY];
sb.AppendFormat(" {0}", wkFunc(1, 0, 'A'));
sb.AppendLine();
sb.AppendLine(" /│\");
sb.AppendFormat("{0}─{1}─{2}",
wkFunc(0, 1, 'B'), wkFunc(1, 1, 'C'), wkFunc(2, 1, 'D'));
sb.AppendLine();
sb.AppendLine("│\│/│");
sb.AppendFormat("{0}─{1}─{2}",
wkFunc(0, 2, 'E'), wkFunc(1, 2, 'F'), wkFunc(2, 2, 'G'));
sb.AppendLine();
sb.AppendLine("│/│\│");
sb.AppendFormat("{0}─{1}─{2}",
wkFunc(0, 3, 'H'), wkFunc(1, 3, 'I'), wkFunc(2, 3, 'J'));
sb.AppendLine();
sb.AppendLine(" \│/");
sb.AppendFormat(" {0}", wkFunc(1, 4, 'K'));
sb.AppendLine();
Console.WriteLine(sb.ToString());
}
}