/// <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)); } } }
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> /// 駒の移動 盤面編集 /// </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の駒を掴む /// sqの駒が自駒であることは確定している。 /// 行き先の候補の升情報を更新する。 /// </summary> /// <param name="sq"></param> public void pick_up(SquareHand sq) { if (!(gameServer.CanUserMove && !gameServer.EngineInitializing)) { return; } var pos = gameServer.Position; // この駒をユーザーが掴んで動かそうとしていることを示す viewState.picked_from = sq; viewState.picked_to = SquareHand.NB; viewState.state = GameScreenControlViewStateEnum.PiecePickedUp; // デバッグ用に出力する。 //Console.WriteLine("pick up : " + sq.Pretty() ); // 簡単に利きを表示する。 // ここで連続王手による千日手などを除外すると // 「ユーザーが駒が動かせない、バグだ」をみたいなことを言い出しかねない。 // 移動後に連続王手の千日手を回避していないという警告を出すようにしなくてはならない。 // 合法手を生成して、そこに含まれるものだけにする。 // この生成、局面が変わったときに1回でいいような気はするが.. // 何回もクリックしまくらないはずなのでまあいいや。 int n = MoveGen.LegalAll(pos, moves_buf, 0); var is_drop = sq.IsHandPiece(); var pt = pos.PieceOn(sq).PieceType(); Bitboard bb = Bitboard.ZeroBB(); // 生成されたすべての合法手に対して移動元の升が合致する指し手の移動先の升を // Bitboardに反映させていく。 for (int i = 0; i < n; ++i) { var m = moves_buf[i]; if (is_drop) { // 駒の打てる先。これは合法手でなければならない。 // 二歩とか打ち歩詰めなどがあるので合法手のみにしておく。 // (打ち歩詰めなので打てませんの警告ダイアログ、用意してないので…) // 合法手には自分の手番の駒しか含まれないのでこれでうまくいくはず if (m.IsDrop() && m.DroppedPiece() == pt) { bb |= m.To(); } } else { // 駒の移動できる先 if (!m.IsDrop() && m.From() == (Square)sq) { bb |= m.To(); } } } viewState.picked_piece_legalmovesto = bb; viewState.state = GameScreenControlViewStateEnum.PiecePickedUp; // この値が変わったことで画面の状態が変わるので、次回、OnDraw()が呼び出されなくてはならない。 Dirty = true; }
/// <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(); }