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()); }
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))); }
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()); }
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); }
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); }
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)); }
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); }
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); }
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))); }
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); }