Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        /// <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);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
        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() }));
        }
Ejemplo n.º 5
0
 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);
        }
Ejemplo n.º 7
0
        /// <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);
        }
Ejemplo n.º 8
0
        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);
        }
Ejemplo n.º 9
0
        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;
        }
Ejemplo n.º 10
0
        /// <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); // 敵の利きが利いている場所に打つぜ☆(^▽^)
            }
        }
Ejemplo n.º 11
0
        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;
            }
        }