/// <summary> /// 別のKifuTreeをマージする。 /// /// マージされた棋譜の本譜の末尾の局面を指していて欲しい気もするが…。 /// せめて、マージされた開始局面を指すようにするか。 /// /// エラーがあればその内容を文字列として返す。 /// </summary> /// <param name="tree"></param> public string Merge(KifuTree tree) { // このsfenの局面にマージする。 var sfen = tree.rootSfen; // このnodeを探す var node = SearchNode(sfen); if (node == null) { return("メイン棋譜にマージするための開始局面がありませんでした。"); } // このnodeにマージしていく。 tree.RewindToRoot(); MergeSub(tree); return(null); }
/// <summary> /// 棋譜ファイルを読み込む。 /// this.Treeに反映する。また本譜の手順の最終局面までthis.Tree.posを自動的に進める。 /// フォーマットは自動判別。 /// CSA/KIF/KI2/PSN/SFEN形式を読み込める。 /// /// ファイル丸ごと読み込んでstring型に入れて引数に渡すこと。 /// 読み込めたところまでの棋譜を反映させる。読み込めなかった部分やエラーなどは無視する。 /// /// エラーがあった場合は、そのエラーの文字列が返る。 /// エラーがなければnullが返る。 /// </summary> /// <param name="filename"></param> public string FromString(string content /* , KifuFileType kf */) { // なるべくファジーに判定する /// <summary> /// 文字列がsfenっぽいならtrue /// (position ){,1}((sfen ){,1}(.*\/){8})|(startpos) /// 大文字小文字の差異も許容しておく /// </summary> bool isSfen(string line) { string[] token = line.Split(' '); if (token.Length <= 3) { return(false); } int i = 0; if (token[i].ToLower() == "position") { ++i; } // 先頭のpositionは任意 if (token[i].ToLower() == "startpos") { return(true); } // 平手の開始局面を表すsfenだった if (token[i].ToLower() == "sfen") { ++i; } // sfenも必須ではないようにする if (CountKeywrod(token[i], '/') == 8) { return(true); } // 最初のトークンで/が8個ならおそらくsfenだろう return(false); } var e = Tree.PropertyChangedEventEnable; try { // イベントの一時抑制 Tree.PropertyChangedEventEnable = false; Init(); // 棋譜リストの更新をしないモードだと初期化されないので棋譜リストを明示的に初期化する。 if (!EnableKifuList) { Tree.ResetKifuList(); } var lines = content.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); if (lines.Length == 0) { return("棋譜が空でした。"); } var line = lines[0]; // sfen形式なのか? if (isSfen(line)) { return(FromSfenString(line)); } // PSN形式なのか? if (line.StartsWith("[Sente")) { return(FromPsnString(lines, KifuFileType.PSN)); } // PSN2形式なのか? if (line.StartsWith("[Black")) { return(FromPsnString(lines, KifuFileType.PSN2)); } // CSA形式なのか? if (line.StartsWith("V2") || line.StartsWith("N+") || line.StartsWith("'") || line.StartsWith("+") || line.StartsWith("-")) // 将棋所だと"V2.2"など書いてあるはず。バージョンなしでも許容する。 { return(FromCsaString(lines, KifuFileType.CSA)); } // JSON形式なのか? if (line.StartsWith("{")) { return(FromJsonString(content, KifuFileType.JSON)); } // KIF/KI2形式なのか? if (line.StartsWith("#") || line.IndexOf(":") > 0 || line.StartsWith("先手") || line.StartsWith("後手") || line.IndexOf("▲") > 0 || line.IndexOf("△") > 0) { return(FromKifString(lines, KifuFileType.KIF)); } return("棋譜の形式が判別できませんでした。"); } finally { // -- 本譜の手順の末尾に移動。 Tree.RewindToRoot(); GotoLastMove(); // イベントの一時抑制を解除して、更新通知を送る。 Tree.PropertyChangedEventEnable = e; Tree.RaisePropertyChanged("KifuList", new List <KifuListRow>(Tree.KifuList)); Tree.RaisePropertyChanged("Position", Tree.position.Clone()); } }