/// <summary> /// 指し手を生成する /// /// from : 盤上の升のみでなく手駒もありうる /// to : 盤上の升 /// promote : 成るかどうか /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <param name="promote"></param> /// <returns></returns> public static Move MakeMove(SquareHand from, SquareHand to, bool promote) { // ありえないはずだが…。 if (!to.IsBoardPiece()) { return(Move.NONE); } var to2 = (Square)to; if (from.IsHandPiece()) { // 打ちと成りは共存できない if (promote) { return(Move.NONE); } return(MakeMoveDrop(from.ToPiece(), to2)); } else { var from2 = (Square)from; if (promote) { return(MakeMovePromote(from2, to2)); } else { return(MakeMove(from2, to2)); } } }
/// <summary> /// [UI thread] : 盤面のsqの升(手駒・駒箱の駒も含む)が右クリックされた /// </summary> /// <param name="sq"></param> public void OnBoardRightClick(SquareHand sq) { if (gameServer.InTheBoardEdit) { // -- 盤面編集中 var pos = gameServer.Position; // 盤上の駒はクリックされるごとに先手→先手成駒→後手→後手成駒のように駒の変化 if (sq.IsBoardPiece()) { var pc = pos.PieceOn(sq); var rp = pc.RawPieceType(); // 玉であっても手番変更は出来るのでNO_PIECE以外であれば処理対象。 if (pc != Piece.NO_PIECE) { Piece nextPc; // 成っていない駒なら、成駒に。成っている駒なら相手番の成っていない駒に。 if (pc.CanPromote()) { nextPc = pc.ToPromotePiece(); } else { nextPc = Util.MakePiece(pc.PieceColor().Not() /*相手番の駒に*/, pc.RawPieceType()); } BoardEditCommand((raw_pos) => { raw_pos.board[(int)sq] = nextPc; }); } } //Console.WriteLine(sq.Pretty()); } }
public static Move MakeMove(SquareHand from, SquareHand to, bool promote) { if (!to.IsBoardPiece()) { return(Move.NONE); } var to_ = (Square)to; if (from.IsHandPiece()) { Piece pr = from.ToPiece(); return(MakeMoveDrop(pr, to_)); } else if (from.IsBoardPiece()) { var from_ = (Square)from; if (promote) { return(MakeMovePromote(from_, to_)); } else { return(MakeMove(from_, to_)); } } return(Move.NONE); }
/// <summary> /// PickedToが適切であるか /// </summary> /// <param name="from"></param> /// <returns></returns> public bool IsOkPickedTo(SquareHand to) { if (!to.IsBoardPiece()) { return(false); } Piece pc = Position.PieceOn(to); if (pc == Piece.NO_PIECE) { return(true); } return(pc.PieceColor() == Position.sideToMove.Not()); }
public static Vector3 SquareToPosition(SquareHand sq) { if (sq.IsBoardPiece()) { return(SquareToPosition((Square)sq)); } int index = (int)sq.ToPiece(); if (sq < SquareHand.HandWhite) { return(new Vector3(RookHandX + HAND_X[index], RookHandY, 0)); } else { return(new Vector3(-RookHandX - HAND_X[index], -RookHandY, 0)); } }
/// <summary> /// [UI thread] : 盤面のsqの升(手駒・駒箱の駒も含む)が右クリックされた /// </summary> /// <param name="sq"></param> public void OnBoardRightClick(SquareHand sq) { var config = TheApp.app.config; if (config.InTheBoardEdit) { // -- 盤面編集中 var gameServer = ViewModel.ViewModel.gameServer; var pos = gameServer.Position; // 盤上の駒はクリックされるごとに先手→先手成駒→後手→後手成駒のように駒の変化 if (sq.IsBoardPiece()) { var pc = pos.PieceOn(sq); var rp = pc.RawPieceType(); // 玉は裏返らないし、敵玉にもならない。(それが出来てしまうと先手玉が2枚の局面が作れてしまうため) if (pc != Piece.NO_PIECE && rp != Piece.KING) { var RawBoard = new Piece[pos.RawBoard.Length]; pos.RawBoard.CopyTo(RawBoard, 0); Piece nextPc; // 成っていない駒なら、成駒に。成っている駒なら相手番の成っていない駒に。 if (pc.CanPromote()) { nextPc = pc.ToPromotePiece(); } else { nextPc = Util.MakePiece(pc.PieceColor().Not() /*相手番の駒に*/, pc.RawPieceType()); } RawBoard[(int)sq] = nextPc; var sfen = Position.SfenFromRawdata(RawBoard, pos.RawHands, pos.sideToMove, pos.gamePly); gameServer.SetSfenCommand(sfen); } } //Console.WriteLine(sq.Pretty()); } }
/// <summary> /// [UI thread] : 盤面のsqの升(手駒も含む)がクリックされた /// </summary> /// <param name="sq"></param> public void OnBoardClick(SquareHand sq) { var pos = gameServer.Position; var state = viewState; var pc = pos.PieceOn(sq); //Console.WriteLine(sq.Pretty()); if (gameServer.InTheBoardEdit) { // -- 盤面編集中 switch (state.state) { case GameScreenControlViewStateEnum.Normal: { // 盤面編集中はどの駒でも掴める if (pc != Piece.NO_PIECE) { pick_up_for_edit(sq); } break; } case GameScreenControlViewStateEnum.PiecePickedUp: { // 盤面編集中はどの駒でも掴める state.picked_to = sq; move_piece_for_edit(state.picked_from, state.picked_to); break; } } } else { // -- 対局中、もしくは、対局終了後である。 switch (state.state) { case GameScreenControlViewStateEnum.Normal: { // 掴んだのが自分の駒であるか if (pc != Piece.NO_PIECE && pc.PieceColor() == pos.sideToMove && !sq.IsPieceBoxPiece()) { pick_up(sq); // sqの駒を掴んで行き先の候補の升情報を更新する } break; } case GameScreenControlViewStateEnum.PiecePickedUp: { // 次の4つのケースが考えられる // 1.駒を掴んでいる状態なので移動先のクリック // 2.自駒を再度掴んだ(掴んでいたのをキャンセルする) // 3.別の自分の駒を掴んだ(掴み直し) // 4.無縁の升をクリックした(掴んでいたのをキャンセルする) // 1. 駒の移動 // いま掴んでいる駒の移動できる先であるのか。 var bb = state.picked_piece_legalmovesto; if (sq.IsBoardPiece() && bb.IsSet((Square)sq)) { state.picked_to = sq; move_piece(state.picked_from, state.picked_to); } // 2. 掴んでいた駒の再クリック else if (sq == state.picked_from) { StateReset(); } // 3. 別の駒のクリック else if (pc != Piece.NO_PIECE && pc.PieceColor() == pos.sideToMove && !sq.IsPieceBoxPiece()) { pick_up(sq); } // 4. 掴む動作のキャンセル else { StateReset(); } break; } case GameScreenControlViewStateEnum.PromoteDialog: { // PromoteDialogを出していたのであれば、 switch (state.promote_dialog_selection) { case PromoteDialogSelectionEnum.NO_SELECT: break; // 無視 case PromoteDialogSelectionEnum.CANCEL: // キャンセルするので移動の駒の選択可能状態に戻してやる。 StateReset(); break; // 成り・不成を選んでクリックしたのでそれに応じた移動を行う。 case PromoteDialogSelectionEnum.UNPROMOTE: case PromoteDialogSelectionEnum.PROMOTE: var m = Util.MakeMove(state.picked_from, state.picked_to, state.promote_dialog_selection == PromoteDialogSelectionEnum.PROMOTE); DoMoveCommand(m); break; } break; } } } }
/// <summary> /// 駒の移動 盤面編集 /// </summary> /// <param name="from"></param> /// <param name="to"></param> public void move_piece_for_edit(SquareHand from, SquareHand to) { var pos = gameServer.Position; // 何にせよ、移動、もしくは交換をする。 // → 交換をする実装、不評なので、将棋所・ShogiGUIに倣い、手駒に移動させる。 var from_pc = pos.PieceOn(from); var from_pt = from_pc.PieceType(); var from_pr = from_pc.RawPieceType(); var to_pc = pos.PieceOn(to); var to_pr = to_pc.RawPieceType(); // 移動元と移動先が同じなら何もする必要はない。 if (from == to) { // このケースを除外しておかないと、toの駒を手駒に移動させる処理などで // from == toだと手駒が増えることになる。 // しかし、駒を掴んでいる状態が変化するのでこのときだけ再描画は必要。 Dirty = true; } else if (to.IsBoardPiece()) { if (from.IsBoardPiece()) { // -- 盤上と盤上の駒 #if false // 2駒交換する実装 → 不評なので手駒に移動させることに変更。 // fromとtoの升の駒を交換する。 // fromに駒があることは確定している。toに駒があろうがなかろうが良い。 BoardEditCommand(raw => { raw.board[(int)from] = to_pc; raw.board[(int)to] = from_pc; }); #endif #if true // toのほうが手駒に移動する実装 BoardEditCommand(raw => { raw.board[(int)from] = Piece.NO_PIECE; raw.board[(int)to] = from_pc; if (to_pr != Piece.NO_PIECE && to_pr != Piece.KING) { // 移動元の駒のcolorの手駒に移動させる。玉は、(欠落するので)勝手に駒箱に移動する。 raw.hands[(int)from_pc.PieceColor()].Add(to_pr); } }); #endif } else if (from.IsHandPiece()) { // -- 手駒を盤面に BoardEditCommand(raw => { #if false // 駒箱に移動する実装 → 不評なので手駒になるように変更 raw.hands[(int)from.PieceColor()].Sub(from_pt); raw.board[(int)to] = from_pc; // このtoの位置にもし駒があったとしたら、それは駒箱に移動する。 // (その駒が欠落するので..) #endif #if true // toのほうが手駒に移動する実装 raw.hands[(int)from.PieceColor()].Sub(from_pt); raw.board[(int)to] = from_pc; if (to_pr != Piece.NO_PIECE && to_pr != Piece.KING) { // 移動元の駒のcolorの手駒に移動させる。玉は、(欠落するので)勝手に駒箱に移動する。 raw.hands[(int)from.PieceColor()].Add(to_pr); } #endif }); } else if (from.IsPieceBoxPiece()) { // -- 駒箱の駒を盤面に // toにあった駒は駒箱に戻ってくるが、これは仕方がない。 BoardEditCommand(raw => raw.board[(int)to] = from_pc); } } else if (to.IsHandPiece()) { if (from.IsBoardPiece()) { // -- 盤上の駒を手駒に移動させる。 // 手駒に出来る駒種でなければキャンセル if (from_pt == Piece.KING) { return; } BoardEditCommand(raw => { raw.board[(int)from] = Piece.NO_PIECE; raw.hands[(int)to.PieceColor()].Add(from_pr); }); } else if (from.IsHandPiece()) { // -- 手駒を手駒に。手番が違うならこれは合法。 if (from.PieceColor() != to.PieceColor()) { BoardEditCommand(raw => { // 同種の駒が駒台から駒台に移動するので、to_prは関係ない。 raw.hands[(int)from.PieceColor()].Sub(from_pr); raw.hands[(int)to.PieceColor()].Add(from_pr); }); } else { // 手駒を同じ駒台に移動させることは出来ないし、 // 選び直しているのでは? if (to_pr != Piece.NO_PIECE) { pick_up_for_edit(to); return; } } } else if (from.IsPieceBoxPiece()) { // -- 駒箱の駒を手駒に // 玉は移動手駒に出来ない if (from_pt != Piece.KING) { BoardEditCommand(raw => raw.hands[(int)to.PieceColor()].Add(from_pr)); } } } else if (to.IsPieceBoxPiece()) { if (from.IsBoardPiece()) { // -- 盤上の駒を駒箱に BoardEditCommand(raw => raw.board[(int)from] = Piece.NO_PIECE); } else if (from.IsHandPiece()) { // -- 駒台の駒を駒箱に BoardEditCommand(raw => raw.hands[(int)from.PieceColor()].Sub(from_pr)); } else if (from.IsPieceBoxPiece()) { // 駒箱の駒を移動させることは出来ないし、 // 選び直しているのでは? if (to_pr != Piece.NO_PIECE) { pick_up_for_edit(to); return; } } } }
/// <summary> /// sqの描画する場所を得る。 /// reverse : 盤面を180度回転するのかのフラグ /// </summary> /// <param name="sq"></param> /// <param name="reverse"></param> /// <returns></returns> private Point PieceLocation(SquareHand sq, bool reverse) { Point dest; if (sq.IsBoardPiece()) { // -- 盤上の升 Square sq2 = reverse ? ((Square)sq).Inv() : (Square)sq; int f = 8 - (int)sq2.ToFile(); int r = (int)sq2.ToRank(); dest = new Point(board_location.X + piece_img_size.Width * f, board_location.Y + piece_img_size.Height * r); } else if (sq.IsHandPiece()) { // -- 手駒 var color = sq.PieceColor(); if (reverse) { color = color.Not(); } var v = PieceTableVersion; var pc = sq.ToPiece(); if (color == ShogiCore.Color.BLACK) { // Point型同士の加算は定義されていないので、第二項をSize型にcastしている。 dest = hand_table_pos[v, (int)color] + (Size)hand_piece_pos[v, (int)pc - 1]; } else { // 180度回転させた位置を求める // 後手も駒の枚数は右肩に描画するのでそれに合わせて左右のmarginを調整する。 dest = new Point( hand_table_pos[v, (int)color].X + (hand_table_size[v].Width - hand_piece_pos[v, (int)pc - 1].X - piece_img_size.Width - 10), hand_table_pos[v, (int)color].Y + (hand_table_size[v].Height - hand_piece_pos[v, (int)pc - 1].Y - piece_img_size.Height + 0) ); } } else { // -- 駒箱の駒 // 並び替える // pc : 歩=0,香=1,桂=2,銀=3,金=4,角=5,飛=6,玉=7にする。 var pc = (int)sq.ToPiece() - 1; if (pc == 6) { pc = 4; } else if (pc == 4 || pc == 5) { ++pc; } if (PieceTableVersion == 0) { // 駒箱の1段目に3枚、2段目に2枚、3段目に3枚表示する。 // 5を欠番にして2段目を2枚にする。 if (pc >= 5) { ++pc; } int file = pc % 3; int rank = pc / 3; int x = (int)(file * piece_img_size.Width * .8); int y = (int)(rank * piece_img_size.Height * .88); if (rank == 1) { x += (int)(piece_img_size.Width / 2 * 0.8); } dest = new Point( hand_box_pos[0].X + x, hand_box_pos[0].Y + y ); } else { int file = pc % 2; int rank = pc / 2; int x = (int)(file * piece_img_size.Width * .5); int y = (int)(rank * piece_img_size.Height * .65); dest = new Point( hand_box_pos[1].X + x, hand_box_pos[1].Y + y ); } } return(dest); }
/// <summary> /// 駒の移動 盤面編集 /// </summary> /// <param name="from"></param> /// <param name="to"></param> public void move_piece_for_edit(SquareHand from, SquareHand to) { var pos = gameServer.Position; // 何にせよ、移動、もしくは交換をする。 var from_pc = pos.PieceOn(from); var from_pt = from_pc.PieceType(); var from_pr = from_pc.RawPieceType(); var to_pc = pos.PieceOn(to); var to_pr = to_pc.RawPieceType(); if (to.IsBoardPiece()) { if (from.IsBoardPiece()) { // -- 盤上と盤上の駒 // fromとtoの升の駒を交換する。 // fromに駒があることは確定している。toに駒があろうがなかろうが良い。 BoardEditCommand(raw => { raw.board[(int)from] = to_pc; raw.board[(int)to] = from_pc; }); } else if (from.IsHandPiece()) { // -- 手駒を盤面に BoardEditCommand(raw => { raw.hands[(int)from.PieceColor()].Sub(from_pt); raw.board[(int)to] = from_pc; // このtoの位置にもし駒があったとしたら、それは駒箱に移動する。 // (その駒が欠落するので..) }); } else if (from.IsPieceBoxPiece()) { // -- 駒箱の駒を盤面に BoardEditCommand(raw => raw.board[(int)to] = from_pc); } } else if (to.IsHandPiece()) { if (from.IsBoardPiece()) { // -- 盤上の駒を手駒に移動させる。 // 手駒に出来る駒種でなければキャンセル if (from_pt == Piece.KING) { return; } BoardEditCommand(raw => { raw.board[(int)from] = Piece.NO_PIECE; raw.hands[(int)to.PieceColor()].Add(from_pr); }); } else if (from.IsHandPiece()) { // -- 手駒を手駒に。手番が違うならこれは合法。 if (from.PieceColor() != to.PieceColor()) { BoardEditCommand(raw => { // 同種の駒が駒台から駒台に移動するので、to_prは関係ない。 raw.hands[(int)from.PieceColor()].Sub(from_pr); raw.hands[(int)to.PieceColor()].Add(from_pr); }); } else { // 手駒を同じ駒台に移動させることは出来ないし、 // 選び直しているのでは? if (to_pr != Piece.NO_PIECE) { pick_up_for_edit(to); return; } } } else if (from.IsPieceBoxPiece()) { // -- 駒箱の駒を手駒に // 玉は移動手駒に出来ない if (from_pt != Piece.KING) { BoardEditCommand(raw => raw.hands[(int)to.PieceColor()].Add(from_pr)); } } } else if (to.IsPieceBoxPiece()) { if (from.IsBoardPiece()) { // -- 盤上の駒を駒箱に BoardEditCommand(raw => raw.board[(int)from] = Piece.NO_PIECE); } else if (from.IsHandPiece()) { // -- 駒台の駒を駒箱に BoardEditCommand(raw => raw.hands[(int)from.PieceColor()].Sub(from_pr)); } else if (from.IsPieceBoxPiece()) { // 駒箱の駒を移動させることは出来ないし、 // 選び直しているのでは? if (to_pr != Piece.NO_PIECE) { pick_up_for_edit(to); return; } } } StateReset(); }