public static bool DetermineIfUserCanWin(Round round, RoundPlayer player, IPointsCalculator pointCalculator) { HandWorth handWorth = pointCalculator.Calculate(round, player.GamePlayer.Player.UserName); if (handWorth == null) { return(false); } return(handWorth.Points >= round.Game.MinPoint); }
public async Task <IEnumerable <RoundDto> > Handle(Command request, CancellationToken cancellationToken) { var game = await _context.Games.FirstOrDefaultAsync(x => x.Code == request.GameCode.ToUpper()); if (game == null) { throw new RestException(HttpStatusCode.NotFound, new { Game = "Could not find game" }); } var round = game.Rounds.FirstOrDefault(r => r.Id == request.RoundId); if (round == null) { throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find round" }); } RoundPlayer roundPlayerWinner = round.RoundPlayers.FirstOrDefault(u => u.GamePlayer.Player.UserName == request.UserName); if (roundPlayerWinner == null) { throw new RestException(HttpStatusCode.NotFound, new { Player = "Could not find player" }); } //check for valid win: HandWorth handWorth = _pointCalculator.Calculate(round, request.UserName); if (handWorth == null) { throw new RestException(HttpStatusCode.BadRequest, new { Win = "Invalid combination hand" }); } if (handWorth.Points >= game.MinPoint) { var winAction = roundPlayerWinner.RoundPlayerActions.FirstOrDefault(a => a.ActionType == ActionType.Win); if (winAction != null) { winAction.ActionStatus = ActionStatus.Activated; } bool isSelfPick = false; //set the game as over if all win action is settled var playerWithUnsettledWin = round.RoundPlayers.Where(p => p.RoundPlayerActions.Any(pa => pa.ActionType == ActionType.Win && pa.ActionStatus == ActionStatus.Active)); if (playerWithUnsettledWin.Count() == 0) { round.IsOver = true; round.IsEnding = false; } //create the result and record who win and who lost RoundResult winnerResult = new RoundResult { Player = roundPlayerWinner.GamePlayer.Player, PlayResult = PlayResult.Win, }; if (round.RoundResults == null) { round.RoundResults = new List <RoundResult>(); } //record hand type and extra points foreach (var h in handWorth.HandTypes) { var point = _pointCalculator.HandTypeLookup[h]; winnerResult.RoundResultHands.Add(new RoundResultHand { HandType = h, Point = point, Name = h.ToString() }); } foreach (var e in handWorth.ExtraPoints) { if (e == ExtraPoint.SelfPick) { isSelfPick = true; } var point = _pointCalculator.ExtraPointLookup[e]; winnerResult.RoundResultExtraPoints.Add(new RoundResultExtraPoint { ExtraPoint = e, Point = point, Name = e.ToString() }); } //now that we have the winner hand type and extra point recorded, let's calculate the points //if the handworth exceed game max point, cap the point to game's max point var cappedPoint = handWorth.Points > game.MaxPoint ? game.MaxPoint : handWorth.Points; var losingPoint = cappedPoint * -1; if (isSelfPick) { //check if "bao" //if there is AllOneSuit or SmallDragon or BigDragon or smallFourWind or bigFourWind //then the one that "bao" will be the only one that pays to the winner bool isLoserBao = false; string baoPlayerUserName = string.Empty; //check for allonesuit var winnerTiles = round.RoundTiles.Where(t => t.Owner == roundPlayerWinner.GamePlayer.Player.UserName); if (handWorth.HandTypes.Contains(HandType.AllOneSuit) || handWorth.HandTypes.Contains(HandType.SmallFourWind) || handWorth.HandTypes.Contains(HandType.BigFourWind)) { //check if the 4th tilesetgroupindex has thrownby value var fourthGroupTileIndex = winnerTiles.FirstOrDefault(t => t.TileSetGroupIndex == 4 && !string.IsNullOrEmpty(t.ThrownBy)); if (fourthGroupTileIndex != null) { isLoserBao = true; baoPlayerUserName = fourthGroupTileIndex.ThrownBy; } } //check for dragon if (handWorth.HandTypes.Contains(HandType.SmallDragon) || handWorth.HandTypes.Contains(HandType.BigDragon)) { //find the index of first pong dragon var pongOrKongDragons = winnerTiles.Where(t => (t.TileSetGroup == TileSetGroup.Pong || t.TileSetGroup == TileSetGroup.Kong) && t.Tile.TileType == TileType.Dragon && !string.IsNullOrEmpty(t.ThrownBy)); //if there is 3rd set of dragon pong/kong, then its not a bao //weird rule ever //then find the index of second pong dragon and check thrown by if (pongOrKongDragons.Count() == 2) { isLoserBao = true; baoPlayerUserName = pongOrKongDragons.OrderBy(t => t.TileSetGroupIndex).Last().ThrownBy; } } if (isLoserBao) { //the loser that bao will pay the winning point times three var winningPoint = cappedPoint * 3; roundPlayerWinner.Points += winningPoint; winnerResult.Points = winningPoint; RoundPlayer roundPlayerloser = round.RoundPlayers.FirstOrDefault(p => p.GamePlayer.Player.UserName == baoPlayerUserName); roundPlayerloser.Points -= winningPoint; round.RoundResults.Add(new RoundResult { PlayResult = PlayResult.LostWithPenalty, Player = roundPlayerloser.GamePlayer.Player, Points = losingPoint * 3 }); //record users that are tied var tiedPlayers = round.RoundPlayers.Where(p => p.GamePlayer.Player.UserName != baoPlayerUserName && p.GamePlayer.Player.UserName != roundPlayerWinner.GamePlayer.Player.UserName); tiedPlayers.ForEach(tp => { round.RoundResults.Add(new RoundResult { PlayResult = PlayResult.Tie, Player = tp.GamePlayer.Player, Points = 0 }); }); } else { //if its self pick, and no bao, then all 3 other players needs to record the loss var losers = round.RoundPlayers.Where(u => u.GamePlayer.Player.UserName != request.UserName); //points will be times 3 var winningPoint = cappedPoint * 3; roundPlayerWinner.Points += winningPoint; winnerResult.Points = winningPoint; losers.ForEach(l => { l.Points -= cappedPoint; round.RoundResults.Add(new RoundResult { PlayResult = PlayResult.Lost, Player = l.GamePlayer.Player, Points = losingPoint }); }); } } else { //otherwise there is only one loser that throw the tile to board roundPlayerWinner.Points += cappedPoint; winnerResult.Points = cappedPoint; var boardTile = round.RoundTiles.First(t => t.Owner == DefaultValue.board && t.Status == TileStatus.BoardActive); var loser = round.RoundPlayers.First(u => u.GamePlayer.Player.UserName == boardTile.ThrownBy); loser.Points -= cappedPoint; round.RoundResults.Add(new RoundResult { PlayResult = PlayResult.Lost, Player = loser.GamePlayer.Player, Points = losingPoint }); //check for multiple winners. If player has a valid win and already recorded as tie var tieResultCouldWin = round.RoundResults.FirstOrDefault(rr => rr.PlayResult == PlayResult.Tie && rr.Player.UserName == roundPlayerWinner.GamePlayer.Player.UserName); if (tieResultCouldWin != null) { //remove record that the player tie round.RoundResults.Remove(tieResultCouldWin); } else { //record users that are tied var tiedPlayers = round.RoundPlayers.Where(p => p.GamePlayer.Player.UserName != loser.GamePlayer.Player.UserName && p.GamePlayer.Player.UserName != roundPlayerWinner.GamePlayer.Player.UserName); tiedPlayers.ForEach(tp => { round.RoundResults.Add(new RoundResult { PlayResult = PlayResult.Tie, Player = tp.GamePlayer.Player, Points = 0 }); }); } } round.RoundResults.Add(winnerResult); //tally the point in gameplayer round.RoundPlayers.ForEach(rp => { rp.GamePlayer.Points = rp.Points; }); var success = await _context.SaveChangesAsync() > 0; if (success) { List <RoundDto> results = new List <RoundDto>(); foreach (var p in round.RoundPlayers) { results.Add(_mapper.Map <Round, RoundDto>(round, opt => opt.Items["MainRoundPlayer"] = p)); } return(results); } } else { throw new RestException(HttpStatusCode.BadRequest, new { Win = "Not enough point to win with this hand" }); } throw new Exception("Problem calling win"); }