public static int MoveFromMoveData(int fromSquare, int toSquare, MoveType moveType, Piece piece, Piece capturePiece, PlayerColor turn) { int move = 0; if (!moveType.HasFlag(MoveType.DropFlag)) { move |= fromSquare.DanOf() << FromDanOfs; move |= fromSquare.SujiOf() << FromSujiOfs; } move |= toSquare.DanOf() << ToDanOfs; move |= toSquare.SujiOf() << ToSujiOfs; move |= (int)(capturePiece & Piece.PromotionMask) << CapturePieceOfs; if (moveType.HasFlag(MoveType.Promotion)) { move |= PromotionFlag; } move |= (int)piece << PieceOfs; if (turn == PlayerColor.White) { move |= WhiteFlag; } return(move); }
/// <summary> /// 盤面が動く指し手 /// </summary> /// <param name="type"></param> /// <returns></returns> public static bool IsMove(this MoveType type) { bool ret = false; if (type.HasFlag(MoveType.MoveFlag) || type.HasFlag(MoveType.DropFlag)) { ret = true; } return(ret); }
/// <summary> /// 盤面が動く指し手 /// </summary> /// <param name="type"></param> /// <returns></returns> public static bool IsMoveWithoutPass(this MoveType type) { bool ret = false; if (type == MoveType.Pass) { // pass } else if (type.HasFlag(MoveType.MoveFlag) || type.HasFlag(MoveType.DropFlag)) { ret = true; } return(ret); }
public async Task <IActionResult> SubmitMove(string id, string origin, string destination, string promotion = null) { if (!int.TryParse(id, out int puzzleId)) { return(Json(new { success = false, error = "The given ID is invalid." })); } if (promotion != null && promotion.Length != 1) { return(Json(new { success = false, error = "Invalid 'promotion' parameter." })); } Puzzle puzzle = puzzlesBeingEdited.Get(puzzleId); if (puzzle == null) { return(Json(new { success = false, error = "The given ID does not correspond to a puzzle." })); } if (puzzle.Author != (await loginHandler.LoggedInUserIdAsync(HttpContext)).Value) { return(Json(new { success = false, error = "Only the puzzle author can access this right now." })); } MoveType type = puzzle.Game.ApplyMove(new Move(origin, destination, puzzle.Game.WhoseTurn, promotion?[0]), false); if (type.HasFlag(MoveType.Invalid)) { return(Json(new { success = false, error = "The given move is invalid." })); } return(Json(new { success = true, fen = puzzle.Game.GetFen() })); }
public override string ToString() { // Apply chess notation rules if (MoveType == MoveType.Default) { return($"{StartSquare} {DestinationSquare}"); } if (MoveType.HasFlag(MoveType.Capture)) { string r = $"{StartSquare}x{DestinationSquare}"; if (MoveType.HasFlag(MoveType.EnPassant)) { r = r + "e.p."; } return(r); } if (MoveType.HasFlag(MoveType.KingSideCastle)) { return("O-O"); } if (MoveType.HasFlag(MoveType.QueenSideCastle)) { return("O-O-O"); } if (MoveType.HasFlag(MoveType.Promotion) && PromoteTo.HasValue) { char to = PromoteTo.Value.ToString()[0]; return($"{StartSquare} {DestinationSquare}({to})"); } // Maybe .. throw an exception to alert us to unhandled situations. return(base.ToString()); }
protected override MoveType ApplyMove(Move move, bool alreadyValidated, out Piece captured, out CastlingType castlingType) { MoveType ret = base.ApplyMove(move, alreadyValidated, out captured, out castlingType); if (ret.HasFlag(MoveType.Capture)) { (move.Player == Player.White ? whitePocket : blackPocket).Add(!captured.IsPromotionResult ? captured.GetWithInvertedOwner() : new Pawn(ChessUtilities.GetOpponentOf(captured.Owner))); } return(ret); }
/// <summary> /// 結果の移動タイプの場合 /// </summary> /// <param name="type"></param> /// <returns></returns> public static bool IsResult(this MoveType type) { bool ret = false; if (type.HasFlag(MoveType.ResultFlag)) { ret = true; } return(ret); }
protected override MoveType ApplyMove(Move move, bool alreadyValidated, out Piece captured, out CastlingType castlingType) { MoveType type = base.ApplyMove(move, alreadyValidated, out captured, out castlingType); if (!type.HasFlag(MoveType.Capture)) { return(type); } var surroundingSquares = new int[][] { new int[] { 1, 0 }, new int[] { 1, 1 }, new int[] { 0, 1 }, new int[] { -1, -1 }, new int[] { -1, 0 }, new int[] { 0, -1 }, new int[] { -1, 1 }, new int[] { 1, -1 } }; if (!(GetPieceAt(move.NewPosition) is King)) { SetPieceAt(move.NewPosition.File, move.NewPosition.Rank, null); } foreach (int[] surroundingSquaresDistance in surroundingSquares) { File f = move.NewPosition.File + surroundingSquaresDistance[0]; int r = move.NewPosition.Rank + surroundingSquaresDistance[1]; if (f < 0 || (int)f >= BoardWidth || r < 1 || r > BoardHeight) { continue; } if (!(GetPieceAt(f, r) is Pawn) && !(GetPieceAt(f, r) is King)) { SetPieceAt(f, r, null); } } if (CanBlackCastleKingSide && GetPieceAt(InitialBlackRookFileKingsideCastling, 8) == null) { CanBlackCastleKingSide = false; } if (CanBlackCastleQueenSide && GetPieceAt(InitialBlackRookFileQueensideCastling, 8) == null) { CanBlackCastleQueenSide = false; } if (CanWhiteCastleKingSide && GetPieceAt(InitialWhiteRookFileKingsideCastling, 1) == null) { CanWhiteCastleKingSide = false; } if (CanWhiteCastleQueenSide && GetPieceAt(InitialWhiteRookFileQueensideCastling, 1) == null) { CanWhiteCastleQueenSide = false; } return(type); }
public static int MoveFromMoveData(int fromSquare, int toSquare, MoveType moveType, Piece piece, Piece capturePiece, PlayerColor turn) { int move = 0; if (!moveType.HasFlag(MoveType.DropFlag)) { move |= fromSquare.DanOf() << FromDanOfs; move |= fromSquare.SujiOf() << FromSujiOfs; } move |= toSquare.DanOf() << ToDanOfs; move |= toSquare.SujiOf() << ToSujiOfs; move |= (int)(capturePiece & Piece.PromotionMask) << CapturePieceOfs; if (moveType.HasFlag(MoveType.Promotion)) { move |= PromotionFlag; } move |= (int)piece << PieceOfs; if (turn == PlayerColor.White) { move |= WhiteFlag; } return move; }
/// <summary> /// /// </summary> public static void DoMovePickerBegin(MoveType flag) { MoveGenAccessor.Clear_SsssUtikiri(); // 空っぽにしておくぜ☆ 何か入れないと投了だぜ☆(^▽^)www MoveGenAccessor.ClearMoveList(); PureMemory.ssss_isSyobuNasi = GenkyokuOpe.IsSyobuNasi(); PureMemory.ssss_bbBase_idosaki01_checker.Clear(); PureMemory.ssss_bbBase_idosaki02_raionCatch.Clear(); PureMemory.ssss_bbBase_idosaki03_nigeroTe.Clear(); PureMemory.ssss_bbBase_idosaki04_try.Clear(); PureMemory.ssss_bbBase_idosaki05_komaWoToruTe.Clear(); PureMemory.ssss_bbBase_idosaki06_himodukiOteZasi.Clear(); PureMemory.ssss_bbBase_idosaki07_suteOteZasi.Clear(); PureMemory.ssss_bbBase_idosaki08_suteOteDa.Clear(); PureMemory.ssss_bbBase_idosaki09_himodukiOteDa.Clear(); PureMemory.ssss_bbBase_idosaki10_himodukiKanmanDa.Clear(); PureMemory.ssss_bbBase_idosaki11_himodukiKanmanZasi.Clear(); PureMemory.ssss_bbBase_idosaki12_bottiKanmanZasi.Clear(); PureMemory.ssss_bbBase_idosaki13_bottiKanmanDa.Clear(); PureMemory.ssss_bbBase_idosaki14_suteKanmanZasi.Clear(); PureMemory.ssss_bbBase_idosaki15_suteKanmanDa.Clear(); PureMemory.ssss_bbVar_idosaki_narazu.Clear(); PureMemory.ssss_bbVar_idosaki_nari.Clear(); PureMemory.ssssTmp_bbVar_ibasho.Clear(); // 変数名短縮 Kyokumen.YomiKy yomiKy = PureMemory.gky_ky.yomiKy; IbashoBan.YomiIbashoBan yomiIbashoBan = PureMemory.gky_ky.yomiKy.yomiShogiban.yomiIbashoBan; KikiBan.YomiKikiBan yomiKikiBan = PureMemory.gky_ky.yomiKy.yomiShogiban.yomiKikiBan; //──────────────────────────────────────── // 被王手 //──────────────────────────────────────── Util_Hioute.Tukurinaosi(); //──────────────────────────────────────── // 移動先 //──────────────────────────────────────── if ( flag.HasFlag(MoveType.N13_HippakuKaeriutiTe) || flag.HasFlag(MoveType.N14_YoyuKaeriutiTe) ) { // 移動先は、王手をかけてきている駒☆(^~^) PureMemory.ssss_bbBase_idosaki01_checker.Set(PureMemory.hot_bb_checkerAr[PureMemory.kifu_nTeban]); } if (flag.HasFlag(MoveType.N12_RaionCatch) || flag.HasFlag(MoveType.N17_RaionCatchChosa)) { // 相手らいおん を取る手のみ生成するぜ☆(^▽^) yomiIbashoBan.ToSet_Koma(Med_Koma.ToRaion(PureMemory.kifu_aiteban), PureMemory.ssss_bbBase_idosaki02_raionCatch); } if (flag.HasFlag(MoveType.N15_NigeroTe)) { // 移動先 PureMemory.ssss_bbBase_idosaki03_nigeroTe.Set(BitboardsOmatome.bb_boardArea); PureMemory.ssss_bbBase_idosaki03_nigeroTe.Siborikomi(PureMemory.hot_bb_nigeroAr[PureMemory.kifu_nTeban]); PureMemory.ssss_bbBase_idosaki03_nigeroTe.Sitdown(PureMemory.hot_bb_checkerAr[PureMemory.kifu_nTeban]); // (逼迫/余裕)返討手は除外するぜ☆(^▽^) yomiIbashoBan.ToSitdown_Koma(Med_Koma.ToRaion(PureMemory.kifu_aiteban), PureMemory.ssss_bbBase_idosaki03_nigeroTe); // 利きのうち、らいおんを取る手 は、除外するぜ☆(^▽^) PureMemory.ssss_bbBase_idosaki03_nigeroTe.Sitdown(PureMemory.hot_bb_checkerAr[PureMemory.kifu_nTeban]); // 返討手 は除外するぜ☆(^▽^) } if (flag.HasFlag(MoveType.N16_Try)) { // トライは どうぶつしょうぎ用 だぜ☆(^~^) if (PureSettei.gameRule == GameRule.DobutuShogi) { PureMemory.ssss_bbBase_idosaki04_try.Set(BitboardsOmatome.bb_boardArea); yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_teban, PureMemory.ssss_bbBase_idosaki04_try); // 味方の駒があるところには移動できないぜ☆(^▽^) yomiIbashoBan.ToSitdown_Koma(Med_Koma.ToRaion(PureMemory.kifu_aiteban), PureMemory.ssss_bbBase_idosaki04_try); // 利きのうち、らいおん を取る手は、除外するぜ☆(^▽^) PureMemory.ssss_bbBase_idosaki04_try.Sitdown(PureMemory.hot_bb_checkerAr[PureMemory.kifu_nTeban]); // 返討手 は除外するぜ☆(^▽^) } } if (flag.HasFlag(MoveType.N01_KomaWoToruTe)) { // 移動先 yomiIbashoBan.ToSet_KomaZenbu(PureMemory.kifu_aiteban, PureMemory.ssss_bbBase_idosaki05_komaWoToruTe); // 相手の駒があるところだけ☆(^▽^) yomiIbashoBan.ToSitdown_Koma(Med_Koma.ToRaion(PureMemory.kifu_aiteban), PureMemory.ssss_bbBase_idosaki05_komaWoToruTe); // らいおんキャッチ は除外するぜ☆(^▽^) PureMemory.ssss_bbBase_idosaki05_komaWoToruTe.Sitdown(PureMemory.hot_bb_checkerAr[PureMemory.kifu_nTeban]); // 返討手 は除外するぜ☆(^▽^) } if (flag.HasFlag(MoveType.N10_HimozukiOteZasi)) { // 移動先 PureMemory.ssss_bbBase_idosaki06_himodukiOteZasi.Set(BitboardsOmatome.bb_boardArea); yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_teban, PureMemory.ssss_bbBase_idosaki06_himodukiOteZasi); // 味方の駒があるところには移動できないぜ☆(^▽^) yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_aiteban, PureMemory.ssss_bbBase_idosaki06_himodukiOteZasi); // 相手の駒がある升 は除外するぜ☆(^▽^) PureMemory.ssss_bbBase_idosaki06_himodukiOteZasi.Sitdown(PureMemory.hot_bb_checkerAr[PureMemory.kifu_nTeban]); // 返討手 は除外するぜ☆(^▽^) } if (flag.HasFlag(MoveType.N06_SuteOteZasi)) { // 移動先 PureMemory.ssss_bbBase_idosaki07_suteOteZasi.Set(BitboardsOmatome.bb_boardArea); yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_teban, PureMemory.ssss_bbBase_idosaki07_suteOteZasi); // 味方の駒がある升 は除外☆(^▽^) yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_aiteban, PureMemory.ssss_bbBase_idosaki07_suteOteZasi); // 相手の駒がある升 は除外☆(^▽^) PureMemory.ssss_bbBase_idosaki07_suteOteZasi.Sitdown(PureMemory.hot_bb_checkerAr[PureMemory.kifu_nTeban]); // 返討手 は除外☆(^▽^) } if (flag.HasFlag(MoveType.N07_SuteOteDa)) { // 持ち駒 PureMemory.ssss_bbBase_idosaki08_suteOteDa.Set(BitboardsOmatome.bb_boardArea); yomiIbashoBan.ToSitdown_KomaZenbu(Taikyokusya.T1, PureMemory.ssss_bbBase_idosaki08_suteOteDa);// 持ち駒の打てる場所 = 駒が無いところ☆ yomiIbashoBan.ToSitdown_KomaZenbu(Taikyokusya.T2, PureMemory.ssss_bbBase_idosaki08_suteOteDa); } if (flag.HasFlag(MoveType.N11_HimodukiOteDa)) { // 持ち駒 PureMemory.ssss_bbBase_idosaki09_himodukiOteDa.Set(BitboardsOmatome.bb_boardArea); yomiIbashoBan.ToSitdown_KomaZenbu(Taikyokusya.T1, PureMemory.ssss_bbBase_idosaki09_himodukiOteDa); // 持ち駒の打てる場所 = 駒が無いところ☆ yomiIbashoBan.ToSitdown_KomaZenbu(Taikyokusya.T2, PureMemory.ssss_bbBase_idosaki09_himodukiOteDa); PureMemory.gky_ky.yomiKy.yomiShogiban.yomiKikiBan.ToSelect_BBKikiZenbu(PureMemory.kifu_teban, PureMemory.ssss_bbBase_idosaki09_himodukiOteDa); // 紐を付ける☆ } if (flag.HasFlag(MoveType.N08_HimotukiKanmanSasi)) { // 盤面全体 PureMemory.ssss_bbBase_idosaki11_himodukiKanmanZasi.Set(BitboardsOmatome.bb_boardArea); // - 味方の駒がある升 ※味方の駒があるところには移動できないぜ☆(^▽^) yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_teban, PureMemory.ssss_bbBase_idosaki11_himodukiKanmanZasi); // - 相手の駒がある升 ※除外するぜ☆(^▽^) yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_aiteban, PureMemory.ssss_bbBase_idosaki11_himodukiKanmanZasi); // - 利きのうち、らいおんを取る手 ※除外するぜ☆(^▽^) yomiIbashoBan.ToSitdown_Koma(Med_Koma.ToRaion(PureMemory.kifu_aiteban), PureMemory.ssss_bbBase_idosaki11_himodukiKanmanZasi); } if (flag.HasFlag(MoveType.N02_BottiKanmanSasi)) { // 移動先 PureMemory.ssss_bbBase_idosaki12_bottiKanmanZasi.Set(BitboardsOmatome.bb_boardArea); yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_teban, PureMemory.ssss_bbBase_idosaki12_bottiKanmanZasi); // 味方の駒があるところには移動できないぜ☆(^▽^) yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_aiteban, PureMemory.ssss_bbBase_idosaki12_bottiKanmanZasi); // 相手の駒がある升 は除外するぜ☆(^▽^) yomiIbashoBan.ToSitdown_Koma(Med_Koma.ToRaion(PureMemory.kifu_aiteban), PureMemory.ssss_bbBase_idosaki12_bottiKanmanZasi); // 利きのうち、らいおんを取る手 は、除外するぜ☆(^▽^) PureMemory.ssss_bbBase_idosaki12_bottiKanmanZasi.Sitdown(PureMemory.hot_bb_checkerAr[PureMemory.kifu_nTeban]); // 返討手 は除外するぜ☆(^▽^) } if (flag.HasFlag(MoveType.N03_BottiKanmanDa)) { // 持ち駒 PureMemory.ssss_bbBase_idosaki13_bottiKanmanDa.Set(BitboardsOmatome.bb_boardArea); yomiIbashoBan.ToSitdown_KomaZenbu(Taikyokusya.T1, PureMemory.ssss_bbBase_idosaki13_bottiKanmanDa); // 自駒が無いところ☆ yomiIbashoBan.ToSitdown_KomaZenbu(Taikyokusya.T2, PureMemory.ssss_bbBase_idosaki13_bottiKanmanDa); // 相手駒が無いところ☆ yomiKikiBan.ToSitdown_BBKikiZenbu(PureMemory.kifu_teban, PureMemory.ssss_bbBase_idosaki13_bottiKanmanDa); // 味方の利きが利いていない場所☆(^▽^) yomiKikiBan.ToSitdown_BBKikiZenbu(PureMemory.kifu_aiteban, PureMemory.ssss_bbBase_idosaki13_bottiKanmanDa); // 敵の利きが利いていない場所☆(^▽^) } if (flag.HasFlag(MoveType.N04_SuteKanmanSasi)) { PureMemory.ssss_bbBase_idosaki14_suteKanmanZasi.Set(BitboardsOmatome.bb_boardArea); yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_teban, PureMemory.ssss_bbBase_idosaki14_suteKanmanZasi); // 味方の駒があるところには移動できないぜ☆(^▽^) yomiIbashoBan.ToSitdown_KomaZenbu(PureMemory.kifu_aiteban, PureMemory.ssss_bbBase_idosaki14_suteKanmanZasi); // 相手の駒がある升 は除外するぜ☆(^▽^) yomiIbashoBan.ToSitdown_Koma(Med_Koma.ToRaion(PureMemory.kifu_aiteban), PureMemory.ssss_bbBase_idosaki14_suteKanmanZasi); // 利きのうち、らいおん を取る手は、除外するぜ☆(^▽^) PureMemory.ssss_bbBase_idosaki14_suteKanmanZasi.Sitdown(PureMemory.hot_bb_checkerAr[PureMemory.kifu_nTeban]); // 返討手 は除外するぜ☆(^▽^) } if (flag.HasFlag(MoveType.N05_SuteKanmanDa)) { PureMemory.ssss_bbBase_idosaki15_suteKanmanDa.Set(BitboardsOmatome.bb_boardArea); yomiIbashoBan.ToSitdown_KomaZenbu(Taikyokusya.T1, PureMemory.ssss_bbBase_idosaki15_suteKanmanDa); // 味方の駒がない升 yomiIbashoBan.ToSitdown_KomaZenbu(Taikyokusya.T2, PureMemory.ssss_bbBase_idosaki15_suteKanmanDa); // 相手の駒がない升// 2016-12-22 捨てだからと言って、紐を付けないとは限らない☆ yomiKikiBan.ToSelect_BBKikiZenbu(PureMemory.kifu_aiteban, PureMemory.ssss_bbBase_idosaki15_suteKanmanDa); // 敵の利きが利いている場所に打つぜ☆(^▽^) } }
async Task HandleReceived(string text) { GameSocketMessage preprocessed = new GameSocketMessage(text); if (!preprocessed.Okay) { await Send("{\"t\":\"error\",\"d\":\"invalid message\"}"); return; } switch (preprocessed.Type) { case "move": case "premove": if (Subject.Result != Game.Results.ONGOING) { await Send("{\"t\":\"error\",\"d\":\"The game is not ongoing.\"}"); return; } MoveSocketMessage moveMessage = new MoveSocketMessage(preprocessed); if (!moveMessage.Okay) { await Send("{\"t\":\"error\",\"d\":\"invalid message\"}"); return; } if ((Subject.ChessGame.WhoseTurn == Player.White && !Subject.White.Equals(client)) || (Subject.ChessGame.WhoseTurn == Player.Black && !Subject.Black.Equals(client))) { await Send("{\"t\":\"error\",\"d\":\"no permission\"}"); return; } bool flagged = await HandlePotentialFlag(Subject.ChessGame.WhoseTurn.ToString().ToLowerInvariant()); if (flagged) { return; } if (!Regex.IsMatch(moveMessage.Move, "([a-h][1-8]-[a-h][1-8](-[qrnbk])?|[PNBRQ]@[a-h][1-8])")) { await Send("{\"t\":\"error\",\"d\":\"invalid message format\"}"); return; } string[] moveParts; MoveType mt = MoveType.Move; if (!moveMessage.Move.Contains("@")) { moveParts = moveMessage.Move.Split('-'); Move move; if (moveParts.Length == 2) { move = new Move(moveParts[0], moveParts[1], Subject.ChessGame.WhoseTurn); } else { move = new Move(moveParts[0], moveParts[1], Subject.ChessGame.WhoseTurn, moveParts[2][0]); } if (Subject.ChessGame.IsValidMove(move)) { mt = await gameRepository.RegisterMoveAsync(Subject, move); } else if (moveMessage.Type == "move") { await Send("{\"t\":\"error\",\"d\":\"invalid move\"}"); return; } else { return; // for premoves, invalid moves can be silently ignored as mostly the problem is just a situation change on the board } } else { CrazyhouseChessGame zhGame = Subject.ChessGame as CrazyhouseChessGame; if (zhGame == null) { await Send("{\"t\":\"error\",\"d\":\"invalid move\"}"); return; } string[] typeAndPos = moveMessage.Move.Split('@'); Position pos = new Position(typeAndPos[1]); Piece piece = Subject.ChessGame.MapPgnCharToPiece(typeAndPos[0][0], Subject.ChessGame.WhoseTurn); Drop drop = new Drop(piece, pos, piece.Owner); if (zhGame.IsValidDrop(drop)) { await gameRepository.RegisterDropAsync(Subject, drop); } else { await Send("{\"t\":\"invalidDrop\",\"pos\":\"" + pos + "\"}"); } moveParts = new string[] { pos.ToString().ToLowerInvariant(), pos.ToString().ToLowerInvariant() }; } string check = null; if (Subject.ChessGame.IsInCheck(Subject.ChessGame.WhoseTurn)) { check = Subject.ChessGame.WhoseTurn.ToString().ToLowerInvariant(); } string outcome = null; if (Subject.ChessGame.IsWinner(Player.White)) { outcome = "1-0, white wins"; await gameRepository.RegisterGameResultAsync(Subject, Game.Results.WHITE_WINS, Game.Terminations.NORMAL); } else if (Subject.ChessGame.IsWinner(Player.Black)) { outcome = "0-1, black wins"; await gameRepository.RegisterGameResultAsync(Subject, Game.Results.BLACK_WINS, Game.Terminations.NORMAL); } else if (Subject.ChessGame.IsDraw() || Subject.ChessGame.DrawCanBeClaimed) { outcome = "½-½, draw"; await gameRepository.RegisterGameResultAsync(Subject, Game.Results.DRAW, Game.Terminations.NORMAL); } Dictionary <string, object> messageForPlayerWhoseTurnItIs = new Dictionary <string, object>(); Dictionary <string, object> messageForOthers = new Dictionary <string, object>(); messageForPlayerWhoseTurnItIs["t"] = messageForOthers["t"] = "moved"; messageForPlayerWhoseTurnItIs["fen"] = messageForOthers["fen"] = Subject.ChessGame.GetFen(); messageForPlayerWhoseTurnItIs["dests"] = moveCollectionTransformer.GetChessgroundDestsForMoveCollection(Subject.ChessGame.GetValidMoves(Subject.ChessGame.WhoseTurn)); messageForPlayerWhoseTurnItIs["lastMove"] = messageForOthers["lastMove"] = new string[] { moveParts[0], moveParts[1] }; messageForPlayerWhoseTurnItIs["turnColor"] = messageForOthers["turnColor"] = Subject.ChessGame.WhoseTurn.ToString().ToLowerInvariant(); messageForPlayerWhoseTurnItIs["plies"] = messageForOthers["plies"] = Subject.ChessGame.Moves.Count; Dictionary <string, double> clockDictionary = new Dictionary <string, double> { ["white"] = Subject.ClockWhite.GetSecondsLeft(), ["black"] = Subject.ClockBlack.GetSecondsLeft() }; messageForPlayerWhoseTurnItIs["clock"] = messageForOthers["clock"] = clockDictionary; messageForPlayerWhoseTurnItIs["check"] = messageForOthers["check"] = check; messageForPlayerWhoseTurnItIs["isCapture"] = messageForOthers["isCapture"] = mt.HasFlag(MoveType.Capture); if (outcome != null) { messageForPlayerWhoseTurnItIs["outcome"] = messageForOthers["outcome"] = outcome; messageForPlayerWhoseTurnItIs["termination"] = messageForOthers["termination"] = Game.Terminations.NORMAL; } if (Subject.ChessGame is ThreeCheckChessGame) { ThreeCheckChessGame tccg = Subject.ChessGame as ThreeCheckChessGame; messageForPlayerWhoseTurnItIs["additional"] = messageForOthers["additional"] = string.Format("White delivered {0} check(s), black delivered {1}.", tccg.ChecksByWhite, tccg.ChecksByBlack); } messageForPlayerWhoseTurnItIs["pocket"] = messageForOthers["pocket"] = Subject.ChessGame.GenerateJsonPocket(); messageForOthers["dests"] = new Dictionary <object, object>(); string jsonPlayersMove = JsonConvert.SerializeObject(messageForPlayerWhoseTurnItIs); string jsonSpectatorsMove = JsonConvert.SerializeObject(messageForOthers); await handlerRepository.SendAll(gameId, jsonPlayersMove, jsonSpectatorsMove, p => (Subject.White.Equals(p) && Subject.ChessGame.WhoseTurn == Player.White) || (Subject.Black.Equals(p) && Subject.ChessGame.WhoseTurn == Player.Black)); break; case "chat": ChatSocketMessage chatSocketMessage = new ChatSocketMessage(preprocessed); if (!chatSocketMessage.Okay) { await Send("{\"t\":\"error\",\"d\":\"invalid message\"}"); return; } int? senderUserId = null; string displayName = null; if (client is RegisteredPlayer) { senderUserId = (client as RegisteredPlayer).UserId; displayName = (await userRepository.FindByIdAsync(senderUserId.Value)).Username; } else { if (client.Equals(Subject.White)) { displayName = "[white]"; } else if (client.Equals(Subject.Black)) { displayName = "[black]"; } } if (displayName == null) { await Send("{\"t\":\"error\",\"d\":\"Anonymous users cannot use the Spectators' chat.\"}"); return; } ChatMessage chatMessage = new ChatMessage(senderUserId, displayName, chatSocketMessage.Content); Dictionary <string, string> forPlayers = null; Dictionary <string, string> forSpectators = null; string jsonPlayersChat = null; string jsonSpectatorsChat = null; if (chatSocketMessage.Channel == "player") { await gameRepository.RegisterPlayerChatMessageAsync(Subject, chatMessage); forPlayers = new Dictionary <string, string>() { { "t", "chat" }, { "channel", "player" }, { "msg", chatMessage.GetHtml() } }; jsonPlayersChat = JsonConvert.SerializeObject(forPlayers); } else if (chatSocketMessage.Channel == "spectator") { if (!(client is RegisteredPlayer)) { await Send("{\"t\":\"error\",\"d\":\"Anonymous users cannot use the Spectators' chat.\"}"); return; } await gameRepository.RegisterSpectatorChatMessageAsync(Subject, chatMessage); forSpectators = new Dictionary <string, string>() { { "t", "chat" }, { "channel", "spectator" }, { "msg", chatMessage.GetHtml() } }; jsonSpectatorsChat = JsonConvert.SerializeObject(forSpectators); if (Subject.Result != Game.Results.ONGOING) { jsonPlayersChat = jsonSpectatorsChat; } } await handlerRepository.SendAll(gameId, jsonPlayersChat, jsonSpectatorsChat, p => Subject.White.Equals(p) || Subject.Black.Equals(p)); break; case "syncClock": Dictionary <string, object> syncedClockDict = new Dictionary <string, object>() { { "t", "clock" }, { "white", Subject.ClockWhite.GetSecondsLeft() }, { "black", Subject.ClockBlack.GetSecondsLeft() }, { "run", Subject.ChessGame.Moves.Count > 1 && Subject.Result == Game.Results.ONGOING }, { "whoseTurn", Subject.ChessGame.WhoseTurn.ToString().ToLowerInvariant() } }; await Send(JsonConvert.SerializeObject(syncedClockDict)); break; case "flag": FlagSocketMessage flagMessage = new FlagSocketMessage(preprocessed); if (!flagMessage.Okay) { await Send("{\"t\":\"error\",\"d\":\"invalid message\"}"); return; } await HandlePotentialFlag(flagMessage.Player); break; case "syncChat": Dictionary <string, object> syncedChat = new Dictionary <string, object> { ["t"] = "chatSync" }; if (Subject.White.Equals(client) || Subject.Black.Equals(client)) { syncedChat["player"] = Subject.PlayerChats.Select(x => x.GetHtml()); } if (Subject.Result != Game.Results.ONGOING || !(Subject.White.Equals(client) || Subject.Black.Equals(client))) { syncedChat["spectator"] = Subject.SpectatorChats.Select(x => x.GetHtml()); } await Send(JsonConvert.SerializeObject(syncedChat)); break; case "rematch-offer": case "rematch-yes": if (Subject.Result == Game.Results.ONGOING) { await Send("{\"t\":\"error\",\"d\":\"The game is still ongoing.\"}"); return; } bool isWhite = false; bool isBlack = false; if (!(isWhite = Subject.White.Equals(client)) && !(isBlack = Subject.Black.Equals(client))) { await Send("{\"t\":\"error\",\"d\":\"no permission\"}"); return; } bool createRematch = false; if (isWhite) { await gameRepository.RegisterWhiteRematchOfferAsync(Subject); if (Subject.BlackWantsRematch) { createRematch = true; } } else { await gameRepository.RegisterBlackRematchOfferAsync(Subject); if (Subject.WhiteWantsRematch) { createRematch = true; } } if (createRematch) { int posWhite; int posBlack; if (Subject.RematchLevel % 2 == 0) { posWhite = Subject.PositionWhite; posBlack = Subject.PositionBlack; } else { posWhite = randomProvider.RandomPositiveInt(Subject.ShortVariantName != "RacingKings" ? 960 : 1440); if (Subject.IsSymmetrical) { posBlack = posWhite; } else { posBlack = randomProvider.RandomPositiveInt(Subject.ShortVariantName != "RacingKings" ? 960 : 1440); } } Game newGame = new Game(await gameRepository.GenerateIdAsync(), Subject.Black, Subject.White, Subject.ShortVariantName, Subject.FullVariantName, posWhite, posBlack, Subject.IsSymmetrical, Subject.TimeControl, DateTime.UtcNow, Subject.RematchLevel + 1, gameConstructor); await gameRepository.AddAsync(newGame); await gameRepository.SetRematchIDAsync(Subject, newGame.ID); string rematchJson = "{\"t\":\"rematch\",\"d\":\"" + newGame.ID + "\"}"; await Send(rematchJson); await handlerRepository.SendAll(gameId, rematchJson, null, x => true); } else { string rematchOfferJson = "{\"t\":\"rematch-offer\"}"; await handlerRepository.SendAll(gameId, rematchOfferJson, null, x => x.Equals(isWhite ? Subject.Black : Subject.White)); } break; case "rematch-no": if (Subject.Result == Game.Results.ONGOING) { await Send("{\"t\":\"error\",\"d\":\"The game is still ongoing.\"}"); return; } bool isWhite_ = false; bool isBlack_ = false; if (!(isWhite_ = Subject.White.Equals(client)) && !(isBlack_ = Subject.Black.Equals(client))) { await Send("{\"t\":\"error\",\"d\":\"no permission\"}"); return; } await gameRepository.ClearRematchOffersAsync(Subject); await handlerRepository.SendAll(gameId, "{\"t\":\"rematch-decline\"}", null, x => x.Equals(isWhite_ ? Subject.Black : Subject.White)); break; case "resign": if (Subject.Result != Game.Results.ONGOING) { await Send("{\"t\":\"error\",\"d\":\"The game is not ongoing.\"}"); return; } bool whiteResigns; if (!(whiteResigns = Subject.White.Equals(client)) && !Subject.Black.Equals(client)) { await Send("{\"t\":\"error\",\"d\":\"no permission\"}"); return; } if (Subject.Result != Game.Results.ONGOING) { await Send("{\"t\":\"error\",\"d\":\"Game is not ongoing.\"}"); return; } string outcomeAfterResign; if (!whiteResigns) { outcomeAfterResign = "1-0, white wins"; await gameRepository.RegisterGameResultAsync(Subject, Game.Results.WHITE_WINS, Game.Terminations.RESIGNATION); } else { outcomeAfterResign = "0-1, black wins"; await gameRepository.RegisterGameResultAsync(Subject, Game.Results.BLACK_WINS, Game.Terminations.RESIGNATION); } Dictionary <string, string> outcomeResponseDict = new Dictionary <string, string>() { { "t", "outcome" }, { "outcome", outcomeAfterResign }, { "termination", Game.Terminations.RESIGNATION } }; await handlerRepository.SendAll(gameId, JsonConvert.SerializeObject(outcomeResponseDict), null, x => true); break; case "abort": if (Subject.Result != Game.Results.ONGOING) { await Send("{\"t\":\"error\",\"d\":\"The game is not ongoing.\"}"); return; } if (!Subject.White.Equals(client) && !Subject.Black.Equals(client)) { await Send("{\"t\":\"error\",\"d\":\"no permission\"}"); return; } if (Subject.UciMoves.Count > 1) { await Send("{\"t\":\"error\",\"d\":\"It's too late to abort.\"}"); return; } await gameRepository.RegisterGameResultAsync(Subject, Game.Results.ABORTED, Game.Terminations.ABORTED); Dictionary <string, string> abortResultDict = new Dictionary <string, string>() { { "t", "outcome" }, { "outcome", Game.Results.ABORTED }, { "termination", Game.Terminations.ABORTED } }; await handlerRepository.SendAll(gameId, JsonConvert.SerializeObject(abortResultDict), null, x => true); break; case "draw-offer": case "draw-yes": if (Subject.Result != Game.Results.ONGOING) { await Send("{\"t\":\"error\",\"d\":\"The game is not ongoing.\"}"); return; } bool whiteOfferingDraw = false; bool blackOfferingDraw = false; if (!(whiteOfferingDraw = Subject.White.Equals(client)) && !(blackOfferingDraw = Subject.Black.Equals(client))) { await Send("{\"t\":\"error\",\"d\":\"no permission\"}"); return; } if (whiteOfferingDraw) { await gameRepository.RegisterWhiteDrawOfferAsync(Subject); } else { await gameRepository.RegisterBlackDrawOfferAsync(Subject); } if (Subject.WhiteWantsDraw && Subject.BlackWantsDraw) { await gameRepository.RegisterGameResultAsync(Subject, Game.Results.DRAW, Game.Terminations.NORMAL); Dictionary <string, string> drawResultDict = new Dictionary <string, string>() { { "t", "outcome" }, { "outcome", Game.Results.DRAW }, { "termination", Game.Terminations.NORMAL } }; await handlerRepository.SendAll(SubjectID, JsonConvert.SerializeObject(drawResultDict), null, x => true); } else { string rematchOfferJson = "{\"t\":\"draw-offer\"}"; await handlerRepository.SendAll(gameId, rematchOfferJson, null, x => x.Equals(whiteOfferingDraw ? Subject.Black : Subject.White)); } break; case "draw-no": if (Subject.Result != Game.Results.ONGOING) { await Send("{\"t\":\"error\",\"d\":\"The game is not ongoing.\"}"); return; } bool whiteDecliningDraw = false; bool blackDecliningDraw = false; if (!(whiteDecliningDraw = Subject.White.Equals(client)) && !(blackDecliningDraw = Subject.Black.Equals(client))) { await Send("{\"t\":\"error\",\"d\":\"no permission\"}"); return; } if (whiteDecliningDraw && !Subject.BlackWantsDraw) { await Send("{\"t\":\"error\",\"d\":\"You have no open draw offers.\"}"); return; } if (blackDecliningDraw && !Subject.WhiteWantsDraw) { await Send("{\"t\":\"error\",\"d\":\"You have no open draw offers.\"}"); return; } await gameRepository.ClearDrawOffersAsync(Subject); await handlerRepository.SendAll(gameId, "{\"t\":\"draw-decline\"}", null, x => x.Equals(whiteDecliningDraw ? Subject.Black : Subject.White)); break; case "keepAlive": await Send("{\"t\":\"keepAlive\"}"); break; } }