public static void TestIsStalemated()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame("rnbqkbnr/pppppppp/8/5K2/8/8/ppp1qppp/rnb2bnr/pp w kq - 98 71");

            Assert.True(game.IsStalemated(Player.White));
            Assert.False(game.IsCheckmated(Player.White));
        }
        public static void TestIsCheckmated()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame("r2q1r2/ppp4p/2np1Pp1/8/4P1Pk/6bP/PB3bPq/R6K/Pprnnnbpp w - - 76 39");

            Assert.True(game.IsCheckmated(Player.White));
            Assert.False(game.IsStalemated(Player.White));
        }
        public static void TestIsValidDrop_PawnsVsPieces()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame("rnbqk2r/1pppppb1/7p/8/p7/8/PPPPKPPP/RNBQ1BNR/PNp w kq - 10 6");

            Assert.False(game.IsValidDrop(new Drop(new Pawn(Player.White), new Position("E1"), Player.White)));
            Assert.True(game.IsValidDrop(new Drop(new Knight(Player.White), new Position("E1"), Player.White)));
        }
        public static void TestNotStalemated_CanDrop()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame("rnbqkbnr/pppppppp/8/7K/5q2/8/ppp2ppp/rnb2bnr/Pp w kq - 0 1");

            Assert.False(game.IsStalemated(Player.White));

            Assert.AreEqual(32, game.GetValidDrops(Player.White).Count);
        }
        public static void TestIsInCheck()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame("rnbqkb1r/p1p2ppp/5p2/1B1p4/3P4/8/PPP2PPP/RNBQK1NR/PNp b KQkq - 9 5");

            Assert.True(game.IsInCheck(Player.Black));
            Assert.False(game.IsInCheck(Player.White));
            Assert.False(game.IsCheckmated(Player.Black));
        }
        public static void TestUndoNYI()
        {
            string fen = "rnbqkbnr/ppp1pppp/8/3p4/4P3/8/PPPP1PPP/RNBQKBNR/ w KQkq - 2 2";
            CrazyhouseChessGame game = new CrazyhouseChessGame(fen);

            game.MakeMove(new Move("E4", "D5", Player.White), true);
            Assert.Throws <NotImplementedException>(() => game.Undo());
        }
예제 #7
0
        public async Task RegisterDropAsync(Game subject, Drop drop)
        {
            CrazyhouseChessGame zhGame = subject.ChessGame as CrazyhouseChessGame;

            zhGame.ApplyDrop(drop, true);
            subject.LatestFEN = subject.ChessGame.GetFen();
            subject.UciMoves.Add(char.ToUpperInvariant(drop.ToDrop.GetFenCharacter()) + "@" + drop.Destination.ToString().ToLowerInvariant());
            ClockSwitchAfterMove(subject, drop.Player == Player.White);
            await gameRepository.UpdateAsync(subject);
        }
        public static void CapturePromotedPiece()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame("3r4/1P6/4k3/8/8/8/8/4K3 w - - 0 1");

            game.ApplyMove(new Move("B7", "B8", Player.White, 'Q'), true);
            game.ApplyMove(new Move("D8", "B8", Player.Black), true);
            Assert.AreEqual(1, game.BlackPocket.Count);
            Assert.AreEqual(0, game.WhitePocket.Count);
            Assert.AreEqual('p', game.BlackPocket[0].GetFenCharacter());
        }
        public static void TestNotCheckmatedAndIsValidDrop()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame("rnbqkbnr/1pppp2p/5p2/6pQ/1p1PP3/8/PBP2PPP/RN2KBNR/p b KQkq - 9 5");

            Assert.True(game.IsInCheck(Player.Black));
            Assert.False(game.IsCheckmated(Player.Black));

            Assert.True(game.IsValidDrop(new Drop(new Pawn(Player.Black), new Position("G6"), Player.Black)));
            Assert.False(game.IsValidDrop(new Drop(new Pawn(Player.Black), new Position("B5"), Player.Black)));
            Assert.False(game.IsValidDrop(new Drop(new Knight(Player.Black), new Position("G6"), Player.Black)));
        }
예제 #10
0
        public static void TestFenTilde()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame("rnbqkb1r/pP3ppp/5n2/4p3/8/8/PPPP1PPP/RNBQKBNR/PPP w KQkq - 8 5");

            game.ApplyMove(new Move("B7", "A8", Player.White, 'Q'), true);
            Assert.AreEqual("Q~nbqkb1r/p4ppp/5n2/4p3/8/8/PPPP1PPP/RNBQKBNR/PPPR b KQk - 0 5", game.GetFen());

            game = new CrazyhouseChessGame("Q~n1qkb1r/pb3ppp/5n2/4p3/8/2N5/PPPP1PPP/R1BQKBNR/RPPP b KQk - 11 6");
            game.ApplyMove(new Move("B7", "A8", Player.Black), true);
            Assert.AreEqual('p', game.BlackPocket[0].GetFenCharacter());
        }
예제 #11
0
        public static void TestFenParsing()
        {
            CrazyhouseChessGame game  = new CrazyhouseChessGame("rn2q1k1/ppp1b1pp/4p1b1/4N3/3P4/4B3/PPP4P/5Q1K/RPRPPPPBNrn w - - 52 27");
            CrazyhouseChessGame game2 = new CrazyhouseChessGame("rn2q1k1/ppp1b1pp/4p1b1/4N3/3P4/4B3/PPP4P/5Q1K[RPRPPPPBNrn] w - - 52 27");

            Assert.AreEqual(9, game.WhitePocket.Count);
            Assert.AreEqual(2, game.BlackPocket.Count);
            Assert.AreEqual(21, game.PiecesOnBoard.Count);
            Assert.AreEqual(9, game2.WhitePocket.Count);
            Assert.AreEqual(2, game2.BlackPocket.Count);
            Assert.AreEqual(21, game2.PiecesOnBoard.Count);
        }
예제 #12
0
        public static void TestApplyMove_AddToPocketIfCapture_AndFenGeneration_AndApplyDrop()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame();

            game.ApplyMove(new Move("E2", "E4", Player.White), true);
            game.ApplyMove(new Move("D7", "D5", Player.Black), true);
            game.ApplyMove(new Move("E4", "D5", Player.White), true);
            Assert.AreEqual(new Pawn(Player.White), game.WhitePocket[0]);
            Assert.AreEqual("rnbqkbnr/ppp1pppp/8/3P4/8/8/PPPP1PPP/RNBQKBNR/P b KQkq - 0 2", game.GetFen());

            game.ApplyMove(new Move("A7", "A5", Player.Black), true);
            Assert.True(game.ApplyDrop(new Drop(new Pawn(Player.White), new Position("H3"), Player.White), false));
            Assert.AreEqual("rnbqkbnr/1pp1pppp/8/p2P4/8/7P/PPPP1PPP/RNBQKBNR b KQkq - 1 3", game.GetFen());
            Assert.AreEqual(0, game.WhitePocket.Count);
        }
예제 #13
0
        public IActionResult SubmitDrop(string id, string role, string pos)
        {
            int puzzleId;

            if (!int.TryParse(id, out puzzleId))
            {
                return(Json(new { success = false, error = "The given ID is invalid." }));
            }

            Puzzle puzzle = puzzlesBeingEdited.Get(puzzleId);

            if (puzzle == null)
            {
                return(Json(new { success = false, error = "The given ID doe snot correspond to a puzzle." }));
            }
            if (puzzle.Author != loginHandler.LoggedInUserId(HttpContext).Value)
            {
                return(Json(new { success = false, error = "Only the puzzle author can access this right now." }));
            }

            if (!(puzzle.Game is CrazyhouseChessGame))
            {
                return(Json(new { success = false, error = "This is not a crazyhouse puzzle." }));
            }

            Piece p = Utilities.GetByRole(role, puzzle.Game.WhoseTurn);

            if (p == null)
            {
                return(Json(new { success = false, error = "Invalid drop piece." }));
            }

            Drop drop = new Drop(p, new Position(pos), puzzle.Game.WhoseTurn);

            CrazyhouseChessGame zhGame = puzzle.Game as CrazyhouseChessGame;

            if (!zhGame.IsValidDrop(drop))
            {
                return(Json(new { success = true, valid = false }));
            }

            zhGame.ApplyDrop(drop, true);
            return(Json(new { success = true, valid = true }));
        }
        public SubmittedMoveResponse ApplyDrop(string role, string pos)
        {
            SubmittedMoveResponse response = new SubmittedMoveResponse()
            {
                Success = true,
                Error   = null
            };

            if (!(Current.Game is CrazyhouseChessGame))
            {
                response.Success = false;
                response.Error   = "Not a crazyhouse puzzle.";
                response.Correct = SubmittedMoveResponse.INVALID_MOVE;
                return(response);
            }

            CrazyhouseChessGame zhCurrentGame = Current.Game as CrazyhouseChessGame;
            Piece p = Utilities.GetByRole(role, zhCurrentGame.WhoseTurn);

            if (p == null)
            {
                response.Success = false;
                response.Error   = "Invalid drop piece.";
                response.Correct = SubmittedMoveResponse.INVALID_MOVE;
                return(response);
            }
            Drop drop = new Drop(p, new Position(pos), zhCurrentGame.WhoseTurn);

            if (!zhCurrentGame.ApplyDrop(drop, false))
            {
                response.Correct = SubmittedMoveResponse.INVALID_MOVE;
                return(response);
            }

            char   pieceChar = char.ToUpper(p.GetFenCharacter());
            string moveStr   = (pieceChar == 'P' ? "" : pieceChar.ToString()) + "@" + pos;

            Moves.Add(moveStr);

            return(MakeMoveAndDropCommon(response, moveStr));
        }
예제 #15
0
        public static Dictionary <string, int> GenerateJsonPocket(this ChessGame game)
        {
            CrazyhouseChessGame zhCurrent = game as CrazyhouseChessGame;

            if (zhCurrent == null)
            {
                return(null);
            }

            Dictionary <string, int> pocket = new Dictionary <string, int>()
            {
                { "white-queen", 0 },
                { "white-rook", 0 },
                { "white-bishop", 0 },
                { "white-knight", 0 },
                { "white-pawn", 0 },
                { "black-queen", 0 },
                { "black-rook", 0 },
                { "black-bishop", 0 },
                { "black-knight", 0 },
                { "black-pawn", 0 }
            };

            foreach (Piece p in zhCurrent.WhitePocket)
            {
                string key = "white-" + p.GetType().Name.ToLowerInvariant();
                pocket[key]++;
            }

            foreach (Piece p in zhCurrent.BlackPocket)
            {
                string key = "black-" + p.GetType().Name.ToLowerInvariant();
                pocket[key]++;
            }

            return(pocket);
        }
예제 #16
0
        public static void TestGetValidDrops()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame("rnbqk2r/1pppppb1/7p/8/p7/8/PPPPKPPP/RNBQ1BNR/PNp w kq - 10 6");

            Assert.AreEqual(67, game.GetValidDrops(Player.White).Count);
        }
예제 #17
0
        public async Task <IActionResult> SubmitGeneratedCrazyhousePuzzle(string json)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings
            {
                MissingMemberHandling = MissingMemberHandling.Ignore
            };

            GeneratedPuzzle gen = JsonConvert.DeserializeObject <GeneratedPuzzle>(json, settings);

            Puzzle puzzle = new Puzzle
            {
                Variant  = "Crazyhouse",
                Rating   = new Rating(1500, 350, 0.06),
                Author   = (await loginHandler.LoggedInUserIdAsync(HttpContext)).Value,
                Approved = (await loginHandler.LoggedInUserAsync(HttpContext)).Roles.Contains(UserRole.GENERATOR)
            };

            puzzle.InReview = !puzzle.Approved;
            if (!puzzle.InReview)
            {
                puzzle.Reviewers = new List <int>()
                {
                    puzzle.Author
                };
            }
            else
            {
                puzzle.Reviewers = new List <int>();
            }
            puzzle.DateSubmittedUtc = DateTime.UtcNow;

            string[] fenParts = gen.FEN.Split(' ');
            fenParts[4]       = "0";
            fenParts[5]       = "1";
            fenParts[0]       = fenParts[0].TrimEnd(']').Replace('[', '/');
            puzzle.InitialFen = string.Join(" ", fenParts);

            try
            {
                CrazyhouseChessGame gameToTest = new CrazyhouseChessGame(puzzle.InitialFen);
            }
            catch
            {
                return(Json(new { success = true, failure = "fen" }));
            }

            Puzzle possibleDuplicate = await puzzleRepository.FindByFenAndVariantAsync(puzzle.InitialFen, puzzle.Variant);

            if (possibleDuplicate != null)
            {
                return(Json(new { success = false, failure = "duplicate" }));
            }

            Task <int> pid = counterRepository.GetAndIncreaseAsync(Counter.PUZZLE_ID);

            puzzle.ExplanationUnsafe = string.Format("Mate in {0}. (Slower mates won't be accepted.) Position from {1} - {2}, played on {3}.",
                                                     gen.Depth,
                                                     gen.White,
                                                     gen.Black,
                                                     gen.Site.Contains("lichess") ? "Lichess" : (gen.Site.Contains("FICS") ? "FICS": "an unknown server"));
            puzzle.Solutions = gen.FlattenSolution();

            puzzle.ID = await pid;

            if (await puzzleRepository.AddAsync(puzzle))
            {
                return(Json(new { success = true, id = puzzle.ID }));
            }
            else
            {
                return(Json(new { success = false, failure = "database" }));
            }
        }
        public static void TestCannotCastleThroughCheck()
        {
            CrazyhouseChessGame game = new CrazyhouseChessGame("1k2r2q/2p2pp1/2Bp3p/2bPp3/4P3/Pn3P2/1PPnNP1P/R2KRQ2/RPbpbn b k - 43 22");

            Assert.False(game.IsValidMove(new Move("B8", "E8", Player.Black)));
        }
예제 #19
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;
            }
        }
        SubmittedMoveResponse MakeMoveAndDropCommon(SubmittedMoveResponse response, string moveStr)
        {
            response.Check = Current.Game.IsInCheck(Current.Game.WhoseTurn) ? Current.Game.WhoseTurn.ToString().ToLowerInvariant() : null;
            Checks.Add(response.Check);
            string fen = Current.Game.GetFen();

            response.FEN = fen;
            FENs.Add(fen);
            Dictionary <string, int> pocket = Current.Game.GenerateJsonPocket();

            response.Pocket = pocket;
            Pockets.Add(pocket);

            if (Current.Game.IsWinner(ChessUtilities.GetOpponentOf(Current.Game.WhoseTurn)))
            {
                PuzzleFinished(response, true);
                return(response);
            }

            if (!PossibleVariations.Any(x => CompareMoves(x.First(), moveStr) == 0))
            {
                PuzzleFinished(response, false);
                return(response);
            }

            PossibleVariations = PossibleVariations.Where(x => CompareMoves(x.First(), moveStr) == 0).Select(x => x.Skip(1));

            if (PossibleVariations.Any(x => x.Count() == 0))
            {
                PuzzleFinished(response, true);
                return(response);
            }

            string moveToPlay = PossibleVariations.First().First();

            if (!moveToPlay.Contains("@"))
            {
                string[] parts = moveToPlay.Split('-', '=');
                Current.Game.MakeMove(new Move(parts[0], parts[1], Current.Game.WhoseTurn, parts.Length == 2 ? null : new char?(parts[2][0])), true);
            }
            else
            {
                string[] parts = moveToPlay.Split('@');

                CrazyhouseChessGame zhCurrent = Current.Game as CrazyhouseChessGame;
                Piece toDrop = zhCurrent.MapPgnCharToPiece(parts[0] == "" ? 'P' : parts[0][0], zhCurrent.WhoseTurn);
                Drop  drop   = new Drop(toDrop, new Position(parts[1]), zhCurrent.WhoseTurn);
                zhCurrent.ApplyDrop(drop, true);
            }

            response.Play = moveToPlay;
            Moves.Add(moveToPlay);
            response.FenAfterPlay = Current.Game.GetFen();
            FENs.Add(response.FenAfterPlay);
            response.CheckAfterAutoMove = Current.Game.IsInCheck(Current.Game.WhoseTurn) ? Current.Game.WhoseTurn.ToString().ToLowerInvariant() : null;
            Checks.Add(response.CheckAfterAutoMove);
            response.Moves               = Current.Game.GetValidMoves(Current.Game.WhoseTurn);
            response.Correct             = 0;
            response.PocketAfterAutoMove = Current.Game.GenerateJsonPocket();
            Pockets.Add(response.PocketAfterAutoMove);
            PossibleVariations = PossibleVariations.Select(x => x.Skip(1));
            if (PossibleVariations.Any(x => !x.Any()))
            {
                PuzzleFinished(response, true);
            }
            return(response);
        }