/// <summary> /// 局面追加 /// </summary> public void Add(SPosition pos, MoveData moveData, int weight, int value, int depth) { string key = pos.PositionToString(1); SBookState state = this.GetBookState(key); if (state == null) { // 現在の局面がない場合 state = new SBookState(); state.Games = 1; state.WonBlack = 0; state.WonWhite = 0; state.Position = key; this.books.Add(key, state); this.BookStates.Add(state); } if (moveData != null) { pos.Move(moveData); string next_key = pos.PositionToString(1); SBookState next_state = this.GetBookState(next_key); pos.UnMove(moveData, null); if (next_state == null) { next_state = new SBookState(); next_state.Games = 1; next_state.WonBlack = 0; next_state.WonWhite = 0; next_state.Position = next_key; this.books.Add(next_key, next_state); this.BookStates.Add(next_state); } SBookMove m = new SBookMove(moveData, next_state); SBookMove move = state.GetMove(m); if (move == null) { // 指し手が無い場合は追加 m.Weight = weight; m.Value = value; m.Depth = depth; state.AddMove(m); // next_stateのPositionをクリアする next_state.Position = string.Empty; move = m; } } }
/// <summary> /// 指し手文字列を返す /// </summary> /// <param name="move"></param> /// <returns></returns> public static string MoveToString(MoveData move) { string sfen = string.Empty; using (StringWriter wr = new StringWriter()) { WriteMove(move, wr); sfen = wr.ToString(); } return sfen; }
/// <summary> /// 内部指し手に変換 /// </summary> /// <param name="gmove"></param> /// <returns></returns> private static MoveData ConvertMove(PlayerColor color, GikouMove gmove) { MoveData move = new MoveData(); if (color == PlayerColor.White) { move.ToSquare = Square.Make((int)(gmove.to / 9), (int)(8 - (gmove.to % 9))); move.FromSquare = Square.Make((int)(gmove.from / 9), (int)(8 - (gmove.from % 9))); move.MoveType = gmove.promotion == 1 ? MoveType.Promotion : MoveType.Normal; if (gmove.drop == 1) { move.MoveType |= MoveType.DropFlag; } move.Piece = (Piece)gmove.piece | Piece.WhiteFlag; move.CapturePiece = ((Piece)gmove.capture).Opp(); } else { move.ToSquare = Square.Make((int)(8 - (gmove.to / 9)), (int)gmove.to % 9); move.FromSquare = Square.Make((int)(8 - (gmove.from / 9)), (int)gmove.from % 9); move.MoveType = gmove.promotion == 1 ? MoveType.Promotion : MoveType.Normal; if (gmove.drop == 1) { move.MoveType |= MoveType.DropFlag; } move.Piece = (Piece)gmove.piece; move.CapturePiece = (Piece)gmove.capture; } if (move.ToSquare < 0 || move.FromSquare < 0) { Console.WriteLine("???"); } return move; }
/// <summary> /// /// </summary> /// <param name="movedata"></param> /// <returns></returns> public bool Equals(MoveData movedata) { bool ret = false; if (movedata == null) { return false; } if (this.MoveType.HasFlag(MoveType.DropFlag) && movedata.MoveType.HasFlag(MoveType.DropFlag)) { if (this.ToSquare == movedata.ToSquare && this.Piece == movedata.Piece) { ret = true; } } else if (this.MoveType.HasFlag(MoveType.MoveFlag) && movedata.MoveType.HasFlag(MoveType.MoveFlag)) { if (this.FromSquare == movedata.FromSquare && this.ToSquare == movedata.ToSquare && (this.MoveType & MoveType.MoveMask) == (movedata.MoveType & MoveType.MoveMask)) { ret = true; } } else { if (this.MoveType == movedata.MoveType) { ret = true; } } return ret; }
public static void Copy(MoveData dest, MoveData src) { dest.ToSquare = src.ToSquare; dest.FromSquare = src.FromSquare; dest.MoveType = src.MoveType; dest.Piece = src.Piece; dest.CapturePiece = src.CapturePiece; }
/// <summary> /// コンストラクタ /// </summary> /// <param name="moveData"></param> public MoveData(MoveData moveData) { Copy(this, moveData); }
/// <summary> /// 指し手文字列をパースして指し手を返す /// </summary> public static MoveData ParseMove(SPosition position, string move) { if (move == "resign") { return(new MoveData(MoveType.Resign)); } else if (move == "win") { // 反則勝ち return(new MoveData(MoveType.WinNyugyoku)); } else if (move == "draw") { return(new MoveData(MoveType.Draw)); } else if (move == "pass" || move == "0000") { // uci的には0000でgpsはpass return(new MoveData(MoveType.Pass)); } if (move.Length < 4) { return(null); } MoveData moveData = new MoveData(); if (move[1] == '*') { // 打つ手 moveData.MoveType = MoveType.Drop; PieceType pieceType; if (CharToPieceHashtable.TryGetValue((char)move[0], out pieceType)) { moveData.Piece = (Piece)pieceType | PieceExtensions.PieceFlagFromColor(position.Turn); } else { // 不明な文字列 moveData.Piece = Piece.NoPiece; } int file = FileFromChar(move[2]); int rank = RankFromChar(move[3]); if (file < 0 || rank < 0) { return(null); } moveData.ToSquare = Square.Make(file, rank); } else { // 移動 moveData.MoveType = MoveType.Normal; // from int file = FileFromChar(move[0]); int rank = RankFromChar(move[1]); moveData.FromSquare = Square.Make(file, rank); file = FileFromChar(move[2]); rank = RankFromChar(move[3]); if (file < 0 || rank < 0) { return(null); } moveData.ToSquare = Square.Make(file, rank); moveData.Piece = position.GetPiece(moveData.FromSquare); if (move.Length >= 5 && move[4] == '+') { // 成り moveData.MoveType = MoveType.Promotion; } } // 盤面を進める if (moveData.MoveType.IsMoveWithoutPass()) { // 指し手の場合 if (position.MoveLast.MoveType.IsMove() && moveData.ToSquare == position.MoveLast.ToSquare) { moveData.MoveType |= MoveType.Same; // 同ほげ用のフラグ設定 } if (position.GetPiece(moveData.ToSquare) != Piece.NoPiece) { moveData.MoveType |= MoveType.Capture; // 駒とったフラグ設定 moveData.CapturePiece = position.GetPiece(moveData.ToSquare); // 駒をいれる } } return(moveData); }
private int[] whiteHand; // 後手持ち駒 #endregion Fields #region Constructors /// <summary> /// コンストラクタ /// </summary> public SPosition() { this.blackHand = new int[HandMax]; this.whiteHand = new int[HandMax]; this.hand = new int[][] { this.blackHand, this.whiteHand }; this.board = new Piece[Square.NSQUARE]; this.moveLast = new MoveData(); this.Init(); }
/// <summary> /// 指し手の値に変更 /// </summary> /// <param name="node"></param> /// <returns></returns> public static int MoveFromMoveData(MoveData movedata) { return MoveFromMoveData(movedata.FromSquare, movedata.ToSquare, movedata.MoveType, movedata.Piece, movedata.CapturePiece, movedata.Turn); }
/// <summary> /// 1手戻す /// </summary> /// <param name="moveData"></param> /// <returns></returns> private bool UnMoveNormal(MoveData moveData) { Piece piece; // 一応最初に簡易なチェックk Debug.Assert(moveData.FromSquare >= 0 && moveData.FromSquare < Square.NSQUARE, "引数エラー"); // from側は駒がないはず Debug.Assert(this.board[moveData.FromSquare] == Piece.NoPiece, "引数エラー"); // to側は駒があるかつ自分の駒 Debug.Assert((this.board[moveData.ToSquare] != Piece.NoPiece) && (this.board[moveData.ToSquare].ColorOf() == this.turn.Opp()), "引数エラー"); piece = moveData.Piece; // 成りなり判定 if (moveData.MoveType.HasFlag(MoveType.Promotion)) { // 一応成りを落とす piece &= ~Piece.PromotionFlag; } this.board[moveData.FromSquare] = piece; this.board[moveData.ToSquare] = moveData.CapturePiece; if (moveData.CapturePiece != Piece.NoPiece) { if (this.turn.Opp() == PlayerColor.White) { this.whiteHand[(int)moveData.CapturePiece.ToHnadIndex()] -= 1; } else { this.blackHand[(int)moveData.CapturePiece.ToHnadIndex()] -= 1; } } return true; }
/// <summary> /// 持ち駒を打つ /// </summary> /// <param name="moveData"></param> /// <returns></returns> private bool UnMoveDrop(MoveData moveData) { Piece piece; PlayerColor unmoveTurn = this.Turn.Opp(); // unmoveするときは現在のターンと反対側 // 一応最初に簡易なチェックk piece = moveData.Piece; Debug.Assert(this.board[moveData.ToSquare] == piece, "駒が違う?"); Debug.Assert(!piece.IsPromoted(), "成っている状態で打てない"); this.hand[(int)unmoveTurn][(int)moveData.Piece.ToHnadIndex()] += 1; this.board[moveData.ToSquare] = Piece.NoPiece; return true; }
/// <summary> /// 通常の駒の移動 /// </summary> /// <param name="moveData"></param> /// <returns></returns> private bool MoveNormal(MoveData moveData) { Piece piece; // 一応最初に簡易なチェックk Debug.Assert(moveData.FromSquare >= 0 && moveData.FromSquare < Square.NSQUARE, "引数エラー"); // from側に駒がある Debug.Assert(this.board[moveData.FromSquare] != Piece.NoPiece, "引数エラー"); // 色が一致 2手差し対応のため色チェックは外す // Debug.Assert(this.board[move_data.from_square].ColorOf() == turn); // 移動先が空白か相手の駒 Debug.Assert((this.board[moveData.ToSquare] == Piece.NoPiece) || (this.board[moveData.ToSquare].ColorOf() == this.turn.Opp()), "引数エラー"); piece = moveData.Piece | PieceExtensions.PieceFlagFromColor(this.turn); // 棋譜からの指し手だと色フラグが付いていないので現在のターンで先後を決める Debug.Assert(this.board[moveData.FromSquare] == piece, "引数エラー"); // from位置の駒が違う // 成りなり判定 if (moveData.MoveType.HasFlag(MoveType.Promotion)) { // 成りのチェック成っていない駒->成るのみOk Debug.Assert(!piece.IsPromoted(), "すでになっている駒を成ろうとしている"); piece |= Piece.PromotionFlag; } this.board[moveData.FromSquare] = Piece.NoPiece; this.board[moveData.ToSquare] = piece; if (moveData.CapturePiece != Piece.NoPiece) { if (this.turn == PlayerColor.White) { this.whiteHand[(int)moveData.CapturePiece.ToHnadIndex()] += 1; } else { this.blackHand[(int)moveData.CapturePiece.ToHnadIndex()] += 1; } } return true; }
/// <summary> /// 持ち駒を打つ /// </summary> /// <param name="moveData"></param> /// <returns></returns> private bool MoveDrop(MoveData moveData) { Piece piece; // 一応最初に簡易なチェックk piece = moveData.Piece | PieceExtensions.PieceFlagFromColor(this.turn); // 持ってない if (!this.IsHand(this.turn, moveData.Piece.ToHnadIndex())) { Debug.Assert(false, "持っていない駒は打てない"); return false; } Debug.Assert(this.board[moveData.ToSquare] == Piece.NoPiece, "移動先が空白でない"); Debug.Assert(!piece.IsPromoted(), "成っている状態で打てない"); this.hand[(int)this.turn][(int)moveData.Piece.ToHnadIndex()] -= 1; this.board[moveData.ToSquare] = piece; return true; }
/// <summary> /// 1手戻す /// </summary> /// <param name="moveData"></param> /// <returns></returns> public bool UnMove(MoveData moveData, MoveData curent) { bool ret = true; Debug.Assert(moveData.ToSquare >= 0 && moveData.ToSquare < Square.NSQUARE, "引数エラー"); Debug.Assert(moveData.MoveType.IsMove(), "引数エラー"); if (moveData.MoveType.HasFlag(MoveType.DropFlag)) { Debug.Assert(moveData.Piece != Piece.NoPiece, "引数エラー"); ret = this.UnMoveDrop(moveData); } else if (moveData.MoveType == MoveType.Pass) { // パス } else { Debug.Assert(moveData.Piece != Piece.NoPiece, "引数エラー"); ret = this.UnMoveNormal(moveData); } if (!ret) { // 指し手登録エラー return false; } if (curent != null) { MoveData.Copy(this.moveLast, curent); } this.turn = this.turn.Opp(); // 手番変更 return ret; }
public SBookMove(MoveData movedata, SBookState state) { this.NextState = state; this.Move = SBookMove.MoveFromMoveData(movedata); this.Evalution = SBookMoveEvalution.None; this.Weight = 1; }
/// <summary> /// 指し手の出力 /// </summary> /// <param name="position"></param> /// <param name="sr"></param> private static void WriteMove(MoveData move_data, TextWriter wr) { // 以下のような漢字 // 7六歩(77) 7g7f // 1一1銀成(22) 1a2b+ // 6五金打 G*6e if (move_data.MoveType.IsResult()) { // 結果の場合 switch (move_data.MoveType) { case MoveType.Resign: // 投了 case MoveType.Timeout: // 切れ負け case MoveType.LoseFoul: // 反則負け case MoveType.LoseNyugyoku: // 入玉負け wr.Write("resign"); break; case MoveType.Repetition: // 千日手 case MoveType.Draw: // 持将棋 wr.Write("draw"); break; case MoveType.WinFoul: // 反則勝ち case MoveType.WinNyugyoku: // 入玉勝ち wr.Write("win"); break; default: // 上記以外は出力しない break; } } else if (move_data.MoveType == MoveType.Pass) { wr.Write("pass"); // gps合わせで0000ではなくpassにする } else if (move_data.MoveType.HasFlag(MoveType.DropFlag)) { wr.Write( "{0}*{1}{2}", CharFromPieceType(move_data.Piece.TypeOf()), (char)('1' + move_data.ToSquare.SujiOf() - 1), (char)('a' + move_data.ToSquare.DanOf() - 1)); } else if (move_data.MoveType.HasFlag(MoveType.MoveFlag)) { wr.Write( "{0}{1}{2}{3}", (char)('1' + move_data.FromSquare.SujiOf() - 1), (char)('a' + move_data.FromSquare.DanOf() - 1), (char)('1' + move_data.ToSquare.SujiOf() - 1), (char)('a' + move_data.ToSquare.DanOf() - 1)); if (move_data.MoveType.HasFlag(MoveType.Promotion)) { // 成り wr.Write("+"); } } }
/// <summary> /// MoveDataを取得 /// </summary> /// <returns></returns> public MoveData GetMoveData() { MoveData moveData = new MoveData(); moveData.ToSquare = this.To; moveData.FromSquare = this.From; moveData.Piece = this.Piece; moveData.MoveType = this.MoveType; moveData.CapturePiece = this.CapturePiece; return moveData; }
/// <summary> /// 指し手文字列をパースして指し手を返す /// </summary> public static MoveData ParseMove(SPosition position, string move) { if (move == "resign") { return new MoveData(MoveType.Resign); } else if (move == "win") { // 反則勝ち return new MoveData(MoveType.WinNyugyoku); } else if (move == "draw") { return new MoveData(MoveType.Draw); } else if (move == "pass" || move == "0000") { // uci的には0000でgpsはpass return new MoveData(MoveType.Pass); } if (move.Length < 4) { return null; } MoveData moveData = new MoveData(); if (move[1] == '*') { // 打つ手 moveData.MoveType = MoveType.Drop; PieceType pieceType; if (CharToPieceHashtable.TryGetValue((char)move[0], out pieceType)) { moveData.Piece = (Piece)pieceType | PieceExtensions.PieceFlagFromColor(position.Turn); } else { // 不明な文字列 moveData.Piece = Piece.NoPiece; } int file = FileFromChar(move[2]); int rank = RankFromChar(move[3]); if (file < 0 || rank < 0) { return null; } moveData.ToSquare = Square.Make(file, rank); } else { // 移動 moveData.MoveType = MoveType.Normal; // from int file = FileFromChar(move[0]); int rank = RankFromChar(move[1]); moveData.FromSquare = Square.Make(file, rank); file = FileFromChar(move[2]); rank = RankFromChar(move[3]); if (file < 0 || rank < 0) { return null; } moveData.ToSquare = Square.Make(file, rank); moveData.Piece = position.GetPiece(moveData.FromSquare); if (move.Length >= 5 && move[4] == '+') { // 成り moveData.MoveType = MoveType.Promotion; } } // 盤面を進める if (moveData.MoveType.IsMoveWithoutPass()) { // 指し手の場合 if (position.MoveLast.MoveType.IsMove() && moveData.ToSquare == position.MoveLast.ToSquare) { moveData.MoveType |= MoveType.Same; // 同ほげ用のフラグ設定 } if (position.GetPiece(moveData.ToSquare) != Piece.NoPiece) { moveData.MoveType |= MoveType.Capture; // 駒とったフラグ設定 moveData.CapturePiece = position.GetPiece(moveData.ToSquare); // 駒をいれる } } return moveData; }
/// <summary> /// 指し手の値に変更 /// </summary> /// <param name="node"></param> /// <returns></returns> public static int MoveFromMoveData(MoveData movedata) { return(MoveFromMoveData(movedata.FromSquare, movedata.ToSquare, movedata.MoveType, movedata.Piece, movedata.CapturePiece, movedata.Turn)); }