/// <summary> /// コメント行を読み込み、それをノードに設定します。 /// </summary> /// <remarks> /// コメント行は複数行に渡ることがあるため、 /// コメント行がある間はずっとコメントを追加し続けます。 /// </remarks> private void ReadCommentLines(KifMoveNode node, bool forceOneLine) { var alreadyRead = false; while (this.currentLine != null) { var commentData = KifUtil.ParseCommentLine(this.currentLine); if (commentData == null) { if (forceOneLine && !alreadyRead) { ReadNextLine(); } break; } // 必要なコメントのみ棋譜から取り出します。 if (commentData.IsMoveComment) { node.AddComment(commentData.Comment); } ReadNextLine(); alreadyRead = true; } }
/// <summary> /// 変化を既存のノードに追加します。 /// </summary> private void MergeVariation(KifMoveNode node, KifMoveNode source) { while (node.MoveCount != source.MoveCount) { if (node.NextNode == null) { //throw return; } node = node.NextNode; } for (var next = node; next != null; next = next.VariationNode) { if (next == null) { break; } node = next; } // 変化を追加します。 node.VariationNode = source; }
/// <summary> /// ファイル内容から棋譜ファイルを読み込みます。 /// </summary> public KifuObject Load(TextReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } this.reader = reader; this.currentLine = null; this.lineNumber = 0; this.startBoard = null; // ヘッダーや局面の読み取り ReadNextLine(); var head = new KifMoveNode(); var header = ParseHeader(head); var board = this.startBoard; // 指し手の読み取りに入ります。 if (this.currentLine == null) { // ファイルが終わっている場合はbod形式 return(new KifuObject(header, board)); } else if (this.isKif) { // kif形式 return(LoadKif(header, board, head)); } else { // ki2形式 return(LoadKi2(header, board, head)); } }
/// <summary> /// kif形式の指し手を読み込みます。 /// </summary> private KifuObject LoadKif(KifuHeader header, Board board, KifMoveNode head_) { var head = ParseNodeKif(board, false); // KifMoveNodeからMoveNodeへ変換します。 Exception error; var root = head.ConvertToMoveNode(board, head_, out error); root.Regulalize(); return(new KifuObject(header, board, root, error)); }
/// <summary> /// ノードの中に含まれる'変化がある指し手番号のセット'を作成します。 /// </summary> private HashSet <int> MakeVariationLineSet(KifMoveNode head) { var result = new HashSet <int>(); for (var node = head; node != null; node = node.NextNode) { if (node.HasVariationNode) { result.Add(node.MoveCount); } } return(result); }
/// <summary> /// ひとかたまりになっている一連の指し手をパースします。 /// </summary> private KifMoveNode ParseMoveLinesKif(bool isVariation) { var head = new KifMoveNode(); var last = head; // もし変化を読み取る場合は、開始記号を探します。 if (isVariation) { while (this.currentLine != null) { // 新しい変化が始まる場合は、 // 変化 ○手目 // という行から始まります。 var m = BeginVariationLineRegex.Match(this.currentLine); if (m.Success) { head.MoveCount = int.Parse(m.Groups[1].Value); ReadNextLine(); break; } // 複数のコメント行を読み込みます。 ReadCommentLines(head, true); } } while (this.currentLine != null) { // 指し手行を1行だけパースします。 var node = ParseMoveLineKif(this.currentLine); if (node == null) { break; } ReadNextLine(); // 指し手の後に続く複数のコメント行を読み込みます。 ReadCommentLines(node, false); // 指し手はリンクリストで保存します。 last.NextNode = node; last = node; } return(head.NextNode); }
/// <summary> /// ヘッダー部分をまとめてパースします。 /// </summary> /// <remarks> /// 開始局面の設定も行います。 /// </remarks> private KifuHeader ParseHeader(KifMoveNode head) { var header = new KifuHeader(); var parser = new BodParser(); while (ParseHeaderLine(this.currentLine, parser, header, head)) { ReadNextLine(); } if (parser.IsBoardParsing) { throw new FileFormatException( "局面の読み取りを完了できませんでした。"); } this.startBoard = MakeStartBoard(parser); return(header); }
/// <summary> /// ki2形式のファイルを読み込みます。 /// </summary> private KifuObject LoadKi2(KifuHeader header, Board startBoard, KifMoveNode head_) { Exception error; var cloned = startBoard.Clone(); var nodeList = ParseMoveLinesKi2(cloned, out error); var root = new MoveNode { CommentList = head_.CommentList, PVInfoList = head_.PVInfoList, }; var last = root; foreach (var node in nodeList) { last.AddNextNode(node); last = node; } root.Regulalize(); return(new KifuObject(header, startBoard, root, error)); }
/// <summary> /// ki2形式のファイルを読み込みます。 /// </summary> private KifuObject LoadKi2(KifuHeader header, Board startBoard, KifMoveNode head) { var knodeList = ParseMoveLinesKi2().ToList(); var last = head; foreach (var knode in knodeList) { last.Next = knode; last = knode; } // KifNodeMoveのツリーをNodeMoveのツリーに直します。 // 変換時にエラーが出た場合は、それまでの指し手を変換します。 var board = startBoard.Clone(); Exception error = null; var root = head.Next.ConvertToMoveNode(board, head, out error); root.Regulalize(); return(new KifuObject(header, startBoard, root, error)); }
/// <summary> /// ひとかたまりになっている一連の指し手をパースします。 /// </summary> private KifMoveNode ParseMoveLinesKif(bool isVariation) { var head = new KifMoveNode(); var last = head; // もし変化を読み取る場合は、開始記号を探します。 if (isVariation) { while (this.currentLine != null) { // 新しい変化が始まる場合は、 // 変化 ○手目 // という行から始まります。 var m = BeginVariationLineRegex.Match(this.currentLine); if (m.Success) { head.MoveCount = int.Parse(m.Groups[1].Value); ReadNextLine(); break; } // 複数のコメント行を読み込みます。 ReadCommentLines(head, true); } } while (this.currentLine != null) { // 指し手行を1行だけパースします。 var node = ParseMoveLineKif(this.currentLine); if (node == null) { break; } ReadNextLine(); // 指し手の後に続く複数のコメント行を読み込みます。 ReadCommentLines(node, false); // 指し手はリンクリストで保存します。 last.Next = node; last = node; } return head.Next; }
/// <summary> /// 変化を既存のノードに追加します。 /// </summary> private void MergeVariation(KifMoveNode node, KifMoveNode source) { while (node.MoveCount != source.MoveCount) { if (node.Next == null) { //throw return; } node = node.Next; } for (var next = node; next != null; next = next.Variation) { if (next == null) { break; } node = next; } // 変化を追加します。 node.Variation = source; }
/// <summary> /// ノードの中に含まれる'変化がある指し手番号のセット'を作成します。 /// </summary> private HashSet<int> MakeVariationLineSet(KifMoveNode head) { var result = new HashSet<int>(); for (var node = head; node != null; node = node.Next) { if (node.HasVariation) { result.Add(node.MoveCount); } } return result; }
/// <summary> /// kif形式の指し手を読み込みます。 /// </summary> private KifuObject LoadKif(KifuHeader header, Board board, KifMoveNode head_) { var head = ParseNodeKif(board, false); // KifMoveNodeからMoveNodeへ変換します。 Exception error; var root = head.ConvertToMoveNode(board, head_, out error); root.Regulalize(); return new KifuObject(header, board, root, error); }
/// <summary> /// ki2形式のファイルを読み込みます。 /// </summary> private KifuObject LoadKi2(KifuHeader header, Board startBoard, KifMoveNode head) { var knodeList = ParseMoveLinesKi2().ToList(); var last = head; foreach (var knode in knodeList) { last.Next = knode; last = knode; } // KifNodeMoveのツリーをNodeMoveのツリーに直します。 // 変換時にエラーが出た場合は、それまでの指し手を変換します。 var board = startBoard.Clone(); Exception error = null; var root = head.Next.ConvertToMoveNode(board, head, out error); root.Regulalize(); return new KifuObject(header, startBoard, root, error); }
/// <summary> /// ヘッダー部分をまとめてパースします。 /// </summary> /// <remarks> /// 開始局面の設定も行います。 /// </remarks> private KifuHeader ParseHeader(KifMoveNode head) { var header = new KifuHeader(); var parser = new BodParser(); while (ParseHeaderLine(this.currentLine, parser, header, head)) { ReadNextLine(); } if (parser.IsBoardParsing) { throw new FileFormatException( "局面の読み取りを完了できませんでした。"); } this.startBoard = MakeStartBoard(parser); return header; }
/// <summary> /// ファイル内容から棋譜ファイルを読み込みます。 /// </summary> public KifuObject Load(TextReader reader) { if (reader == null) { throw new ArgumentNullException("reader"); } this.reader = reader; this.currentLine = null; this.lineNumber = 0; this.startBoard = null; // ヘッダーや局面の読み取り ReadNextLine(); var head = new KifMoveNode(); var header = ParseHeader(head); var board = this.startBoard; // 指し手の読み取りに入ります。 if (this.currentLine == null) { // ファイルが終わっている場合はbod形式 return new KifuObject(header, board); } else if (this.isKif) { // kif形式 return LoadKif(header, board, head); } else { // ki2形式 return LoadKi2(header, board, head); } }
/// <summary> /// ヘッダー行をパースします。 /// </summary> private bool ParseHeaderLine(string line, BodParser parser, KifuHeader header = null, KifMoveNode head = null) { if (line == null) { // ファイルの終了を意味します。 return false; } var commentData = KifUtil.ParseCommentLine(line); if (commentData != null) { // コメントはパース結果に含めます。 if (head != null && commentData.IsMoveComment) { head.AddComment(commentData.Comment); } return true; } // 読み飛ばすべき説明行 if (line.Contains("手数----指手---------消費時間")) { this.isKif = true; // kif形式です。 return true; } // 局面の読み取りを試みます。 if (parser.TryParse(line)) { return true; } var item = KifUtil.ParseHeaderItem(line); if (item != null) { if (item.Key == "手合割" && item.Value != "その他") { this.startBoard = BoardTypeUtil.CreateBoardFromName(item.Value); } if (header != null) { // 可能ならヘッダアイテムを設定します。 var type = KifUtil.GetHeaderType(item.Key); if (type != null) { header[type.Value] = item.Value; } } return true; } // ヘッダが正しく読めない場合、 // 区切りなしに指し手行に入っている可能性があります。 if (MoveLineRegex.IsMatch(line)) { this.isKif = true; } return false; }
/// <summary> /// ヘッダー行をパースします。 /// </summary> private bool ParseHeaderLine(string line, BodParser parser, KifuHeader header = null, KifMoveNode head = null) { if (line == null) { // ファイルの終了を意味します。 return(false); } var commentData = KifUtil.ParseCommentLine(line); if (commentData != null) { // コメントはパース結果に含めます。 if (head != null && commentData.IsMoveComment) { head.AddComment(commentData.Comment); } return(true); } // 読み飛ばすべき説明行 if (line.Contains("手数----指手---------消費時間")) { this.isKif = true; // kif形式です。 return(true); } // 局面の読み取りを試みます。 if (parser.TryParse(line)) { return(true); } var item = KifUtil.ParseHeaderItem(line); if (item != null) { if (item.Key == "手合割" && item.Value != "その他") { this.startBoard = BoardTypeUtil.CreateBoardFromName(item.Value); } if (header != null) { // 可能ならヘッダアイテムを設定します。 var type = KifUtil.GetHeaderType(item.Key); if (type != null) { header[type.Value] = item.Value; } } return(true); } // ヘッダが正しく読めない場合、 // 区切りなしに指し手行に入っている可能性があります。 if (MoveLineRegex.IsMatch(line)) { this.isKif = true; } return(false); }