public override List <HandType> HandleRequest(IEnumerable <RoundTile> tiles, List <HandType> handTypes) { if (tiles == null) { return(handTypes); } var result = RoundTileHelper.DetermineHandCanWin(tiles); if (result == HandType.Triplets || result == HandType.Straight || result == HandType.Chicken) { handTypes.Add(result); } else { //cant win //short circuit return(handTypes); } if (_successor != null) { return(_successor.HandleRequest(tiles, handTypes)); } else { return(handTypes); } }
public void CreateRound() { TestDataContext.Rounds.Add(new Round { GameId = GameId, Wind = WindDirection.East, DateCreated = DateTime.Now, RoundTiles = RoundTileHelper.CreateTiles(TestDataContext).Shuffle(), RoundResults = new List <RoundResult>(), RoundPlayers = new List <RoundPlayer> { new RoundPlayer { GamePlayerId = 1, Wind = WindDirection.South }, new RoundPlayer { GamePlayerId = 2, Wind = WindDirection.East }, new RoundPlayer { GamePlayerId = 3, Wind = WindDirection.West }, new RoundPlayer { GamePlayerId = 4, Wind = WindDirection.North } } }); }
private bool DetermineIfUserCanChow(IEnumerable <RoundTile> playerTiles, RoundTile boardTile) { //player tiles can't be in graveyard when pong from board //when someone throw a tile, there should not be a justpicked status tile if (boardTile.Tile.TileType == TileType.Wind || boardTile.Tile.TileType == TileType.Dragon || boardTile.Tile.TileType == TileType.Flower) { return(false); } var possibleChowTiles = RoundTileHelper.FindPossibleChowTiles(boardTile, playerTiles); return(possibleChowTiles.Count() >= 1); }
public static void SetNextPlayer(Round round, IPointsCalculator pointCalculator) { var playerThatHasTurn = round.RoundPlayers.FirstOrDefault(p => p.IsMyTurn == true); playerThatHasTurn.IsMyTurn = false; playerThatHasTurn.MustThrow = false; var nextPlayer = GetNextPlayer(round.RoundPlayers, playerThatHasTurn.Wind); nextPlayer.IsMyTurn = true; nextPlayer.MustThrow = true; //in case there is other player that has my turn set to true var otherPlayers = round.RoundPlayers.Where(u => u.IsMyTurn == true && u.GamePlayer.Player.UserName != nextPlayer.GamePlayer.Player.UserName && u.GamePlayer.Player.UserName != playerThatHasTurn.GamePlayer.Player.UserName); foreach (var otherPlayerTurn in otherPlayers) { otherPlayerTurn.IsMyTurn = false; } //automatically pick tile for next player //unless remaining tile is 1, give user give up action var unopenTiles = round.RoundTiles.Where(t => string.IsNullOrEmpty(t.Owner)); if (unopenTiles.Count() == 1) { nextPlayer.RoundPlayerActions.Add(new RoundPlayerAction { ActionType = ActionType.GiveUp }); nextPlayer.MustThrow = false; } else { var newTiles = RoundTileHelper.PickTile(round, nextPlayer.GamePlayer.Player.UserName); if (newTiles == null) { round.IsEnding = true; } CheckSelfAction(round, nextPlayer, pointCalculator); } }
public async Task <IEnumerable <RoundDto> > Handle(Command request, CancellationToken cancellationToken) { var round = await _context.Rounds.FindAsync(request.RoundId); if (round == null) { throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find round" }); } var tileToThrow = round.RoundTiles.FirstOrDefault(t => t.Id == request.TileId); if (tileToThrow == null) { throw new RestException(HttpStatusCode.NotFound, new { RoundTile = "Could not find the tile" }); } var currentPlayer = round.RoundPlayers.FirstOrDefault(p => p.GamePlayer.Player.UserName == request.UserName); if (currentPlayer == null) { throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find current player" }); } if (!currentPlayer.MustThrow && !currentPlayer.IsMyTurn) { throw new RestException(HttpStatusCode.NotFound, new { Round = "Player not suppose to throw" }); } //clear all player actions initially every time throw command invoked round.RoundPlayers.ForEach(p => { p.RoundPlayerActions.Clear(); }); //previous active tile on board to be no longer active var existingActiveTileOnBoard = round.RoundTiles.FirstOrDefault(t => t.Status == TileStatus.BoardActive); if (existingActiveTileOnBoard != null) { existingActiveTileOnBoard.Status = TileStatus.BoardGraveyard; } //mark current user's just picked tile to be active var userJustPickedTile = round.RoundTiles.Where(t => t.Owner == request.UserName && t.Status == TileStatus.UserJustPicked); if (userJustPickedTile != null && userJustPickedTile.Count() > 0) { userJustPickedTile.ForEach(t => { t.Status = TileStatus.UserActive; }); } //update thrown tile props and increase the tilecounter tileToThrow.ThrownBy = request.UserName; tileToThrow.Owner = DefaultValue.board; tileToThrow.Status = TileStatus.BoardActive; tileToThrow.BoardGraveyardCounter = round.TileCounter; round.TileCounter++; //don't change user's turn if there is player with action //---------------------------------------------------------- var gotAction = AssignPlayerActions(round, currentPlayer); if (gotAction) { //action has priority list: win > pong|kong > chow var winActionPlayer = round.RoundPlayers.Where(rp => rp.RoundPlayerActions.Any(rpa => rpa.ActionType == ActionType.Win)); if (winActionPlayer.Count() > 0) { bool multipleWinners = winActionPlayer.Count() > 1; foreach (var winner in winActionPlayer) { if (multipleWinners) { winner.RoundPlayerActions.Where(ac => ac.ActionType == ActionType.Win).ForEach(a => a.ActionStatus = ActionStatus.Active); } else { winner.RoundPlayerActions.ForEach(a => a.ActionStatus = ActionStatus.Active); } } } else { var pongOrKongActionPlayer = round.RoundPlayers.Where( rp => rp.RoundPlayerActions.Any( rpa => rpa.ActionType == ActionType.Pong || rpa.ActionType == ActionType.Kong ) ).FirstOrDefault(); if (pongOrKongActionPlayer != null) { pongOrKongActionPlayer.RoundPlayerActions.ForEach(a => a.ActionStatus = ActionStatus.Active); } //check if next player has chow action else { var chowActionPlayer = round.RoundPlayers.Where(rp => rp.RoundPlayerActions.Any(rpa => rpa.ActionType == ActionType.Chow)).FirstOrDefault(); if (chowActionPlayer != null) { chowActionPlayer.RoundPlayerActions.ForEach(a => a.ActionStatus = ActionStatus.Active); } } } } else { RoundHelper.SetNextPlayer(round, _pointCalculator); currentPlayer.IsMyTurn = false; //check if theres more remaining tile, if no more tiles, then set round to ending var remainingTiles = round.RoundTiles.FirstOrDefault(t => string.IsNullOrEmpty(t.Owner)); if (remainingTiles == null) { round.IsEnding = true; } } currentPlayer.MustThrow = false; if (!currentPlayer.IsManualSort) { var playerAliveTiles = round.RoundTiles.Where(rt => rt.Owner == request.UserName && (rt.Status == TileStatus.UserActive || rt.Status == TileStatus.UserJustPicked)).ToList(); RoundTileHelper.AssignAliveTileCounter(playerAliveTiles); } var success = await _context.SaveChangesAsync() > 0; List <RoundDto> results = new List <RoundDto>(); foreach (var p in round.RoundPlayers) { results.Add(_mapper.Map <Round, RoundDto>(round, opt => opt.Items["MainRoundPlayer"] = p)); } if (success) { return(results); } throw new Exception("Problem throwing tile"); }
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.BadRequest, new { Game = "Game does not exist" }); } Round lastRound = game.Rounds.OrderByDescending(r => r.DateCreated).FirstOrDefault(); if (lastRound != null && !lastRound.IsOver) { throw new RestException(HttpStatusCode.BadRequest, new { Round = "Last round is not over" }); } var newRound = new Round { GameId = game.Id, DateCreated = DateTime.Now, RoundTiles = RoundTileHelper.CreateTiles(_context).Shuffle(), RoundPlayers = new List <RoundPlayer>(), RoundResults = new List <RoundResult>() }; List <RoundPlayer> roundPlayers = new List <RoundPlayer>(); if (lastRound == null) { game.Status = GameStatus.Playing; Player firstDealer = game.GamePlayers.First(u => u.InitialSeatWind == WindDirection.East).Player; newRound.Wind = WindDirection.East; newRound.RoundCounter = 1; foreach (var gp in game.GamePlayers) { var rp = new RoundPlayer { GamePlayerId = gp.Id, GamePlayer = gp, Round = newRound, Wind = gp.InitialSeatWind.Value, Points = gp.Points }; if (gp.PlayerId == firstDealer.Id) { rp.IsInitialDealer = true; rp.IsDealer = true; rp.IsMyTurn = true; rp.MustThrow = true; } roundPlayers.Add(rp); } } else { newRound.RoundCounter = lastRound.RoundCounter + 1; var lastRoundDealer = lastRound.RoundPlayers.First(u => u.IsDealer); //if this is not the first round //last round check //1.) if the winner of last round == dealer then no wind change //2.) if last round "IsTied" set to true then no wind change if (lastRound.IsTied) { newRound.Wind = lastRound.Wind; roundPlayers.AddRange(GetNewUserRounds(lastRound.RoundPlayers, sameRound: true, lastRoundDealer.Wind)); } else { //if last game is not tied, then there gotta be a winner here //could be more than one winners here var lastRoundWinners = lastRound.RoundResults.Where(x => x.PlayResult == PlayResult.Win); var dealerWonLastRound = lastRoundWinners.Any(x => x.PlayerId == lastRoundDealer.GamePlayer.Player.Id); if (dealerWonLastRound) { newRound.Wind = lastRound.Wind; roundPlayers.AddRange(GetNewUserRounds(lastRound.RoundPlayers, sameRound: true, lastRoundDealer.Wind)); } else { //determine nextdealer var windOfNextDealer = NextWindClockWise(lastRoundDealer.Wind); roundPlayers.AddRange(GetNewUserRounds(lastRound.RoundPlayers, sameRound: false, windOfNextDealer)); var roundWindChanged = roundPlayers.Any(p => p.IsDealer == true && p.IsInitialDealer == true); newRound.Wind = roundWindChanged ? NextWindClockWise(lastRound.Wind) : lastRound.Wind; } } } foreach (var ur in roundPlayers) { newRound.RoundPlayers.Add(ur); } var theDealer = roundPlayers.First(u => u.IsDealer); var dealerId = theDealer.GamePlayerId; //for debugging //RoundTileHelper.SetupForWinPongChowPriority(newRound.RoundTiles); //tiles assignment and sorting foreach (var gamePlayer in game.GamePlayers) { if (gamePlayer.Id == dealerId) { RoundTileHelper.AssignTilesToUser(14, gamePlayer.Player.UserName, newRound.RoundTiles); //set one tile status to be justpicked newRound.RoundTiles.First(rt => rt.Owner == gamePlayer.Player.UserName && rt.Tile.TileType != TileType.Flower).Status = TileStatus.UserJustPicked; var playerTiles = newRound.RoundTiles.Where(rt => rt.Owner == gamePlayer.Player.UserName && (rt.Status == TileStatus.UserActive || rt.Status == TileStatus.UserJustPicked)).ToList(); RoundTileHelper.AssignAliveTileCounter(playerTiles); } else { RoundTileHelper.AssignTilesToUser(13, gamePlayer.Player.UserName, newRound.RoundTiles); var playerTiles = newRound.RoundTiles.Where(rt => rt.Owner == gamePlayer.Player.UserName && rt.Status == TileStatus.UserActive).ToList(); RoundTileHelper.AssignAliveTileCounter(playerTiles); } } _context.Rounds.Add(newRound); var success = await _context.SaveChangesAsync() > 0; List <RoundDto> results = new List <RoundDto>(); foreach (var p in newRound.RoundPlayers) { results.Add(_mapper.Map <Round, RoundDto>(newRound, opt => opt.Items["MainRoundPlayer"] = p)); } if (success) { return(results); } throw new Exception("Problem creating a new round"); }
public async Task <IEnumerable <RoundDto> > Handle(Command request, CancellationToken cancellationToken) { //Note to consider when kong tile: //if player has pong in their graveyard, it can be kong //-player turn changed //-flag when user can kong //-when kong tile user need to grab a new tile. //-kong doesnt rely on board active tile when its "User's turn", it could be just from player list of active tiles //-user can kong anytime when it's their turn n it could be more than 1 set to kong //assign tile ownership to current user //weird situation is when it's user's turn, user can kong their active tiles and can kong board active tiles var updatedTiles = new List <RoundTile>(); var round = await _context.Rounds.FindAsync(request.RoundId); if (round == null) { throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find round" }); } var currentPlayer = round.RoundPlayers.FirstOrDefault(u => u.GamePlayer.Player.UserName == request.UserName); if (currentPlayer == null) { throw new RestException(HttpStatusCode.BadRequest, new { Round = "there are no user with this username in the round" }); } List <RoundTile> userActiveTilesToKong = new List <RoundTile>(); var currentUserTiles = round.RoundTiles.Where(t => t.Owner == request.UserName); //if it's user's turn, check if user has all 4 same tiles first in the user active tiles //because the request has tile type and tile value, there can only one possible kong //if user has pong tile, user can kong matching tile var tilesToKong = currentUserTiles .Where(t => t.Tile.TileType == request.TileType && t.Tile.TileValue == request.TileValue); if (tilesToKong.Count() == 4) { if (currentPlayer.IsMyTurn) { //if its not konged already, then user can kong it var kongedTile = tilesToKong.Where(t => t.TileSetGroup == TileSetGroup.Kong); if (kongedTile.Count() == 0) { updatedTiles.AddRange(tilesToKong); } } } //this means that user need to kong from board if (tilesToKong.Count() == 3) { //if user only have three and its already ponged, then player can't kong var tilesAlreadyPonged = tilesToKong.Where(t => t.TileSetGroup == TileSetGroup.Pong); if (tilesAlreadyPonged.Count() == 3) { throw new RestException(HttpStatusCode.BadRequest, new { Round = "Can't do kong when all tiles ponged" }); } var boardActiveTiles = round.RoundTiles.FirstOrDefault(t => t.Status == TileStatus.BoardActive); if (boardActiveTiles == null) { throw new RestException(HttpStatusCode.BadRequest, new { Round = "there are no board active tile to kong" }); } var boardActiveMatchedWithRequest = (boardActiveTiles.Tile.TileType == request.TileType && boardActiveTiles.Tile.TileValue == request.TileValue); if (boardActiveMatchedWithRequest) { //only have 3 active tiles then board must exist to kong var allTilesAreActive = tilesToKong.Where(t => t.Status != TileStatus.UserGraveyard); if (boardActiveMatchedWithRequest && allTilesAreActive.Count() == 3) { updatedTiles.AddRange(tilesToKong); updatedTiles.Add(boardActiveTiles); } } } if (updatedTiles.Count() == 4) { updatedTiles.GoGraveyard(request.UserName, TileSetGroup.Kong, round.RoundTiles.GetLastGroupIndex(request.UserName)); } else { throw new RestException(HttpStatusCode.BadRequest, new { Kong = "Not possible to kong" }); } //set existing justpicked tile to useractive; var existingJustPicked = round.RoundTiles.FirstOrDefault(rt => rt.Owner == request.UserName && rt.Status == TileStatus.UserJustPicked); if (existingJustPicked != null) { existingJustPicked.Status = TileStatus.UserActive; updatedTiles.Add(existingJustPicked); } //clear existing action currentPlayer.RoundPlayerActions.Clear(); //add new tile for user var newTiles = RoundTileHelper.PickTile(round, request.UserName, true); if (newTiles.Count() > 0) { //assign new tile to user that kong the tile foreach (var tile in newTiles) { updatedTiles.Add(tile); } RoundHelper.CheckSelfAction(round, currentPlayer, _pointsCalculator); } else { //TODO: what if user kong when there is no more tile } currentPlayer.IsMyTurn = true; //because new tile automatically added, player must throw set to true currentPlayer.MustThrow = true; if (round.IsEnding) { round.IsEnding = false; } var otherPlayers = round.RoundPlayers.Where(u => u.IsMyTurn == true && u.GamePlayer.Player.UserName != request.UserName); foreach (var otherPlayerTurn in otherPlayers) { otherPlayerTurn.IsMyTurn = false; } try { var success = await _context.SaveChangesAsync() > 0; List <RoundDto> results = new List <RoundDto>(); foreach (var p in round.RoundPlayers) { results.Add(_mapper.Map <Round, RoundDto>(round, opt => opt.Items["MainRoundPlayer"] = p)); } if (success) { return(results); } } catch (DbUpdateConcurrencyException) { throw new RestException(HttpStatusCode.BadRequest, new { Round = "tile was modified" }); } throw new Exception("Problem kong ing tile"); }
public async Task <IEnumerable <RoundDto> > Handle(Command request, CancellationToken cancellationToken) { //Note to consider when picking tile: //-tile is flower //-no more tile to pick //-only 1 more tile to pick because player have an option not to take the last tile. var round = await _context.Rounds.FindAsync(request.RoundId); if (round == null) { throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find round" }); } var currentPlayer = round.RoundPlayers.FirstOrDefault(p => p.GamePlayer.Player.UserName == request.UserName); if (currentPlayer == null) { throw new RestException(HttpStatusCode.NotFound, new { Round = "Could not find current player" }); } currentPlayer.MustThrow = true; //TODO only allow pick tile when it's player's turn var newTiles = RoundTileHelper.PickTile(round, request.UserName); if (newTiles == null) { round.IsEnding = true; } //pick action now only available on last tile //check if user can win if they pick on last tile var remainingTiles = round.RoundTiles.FirstOrDefault(t => string.IsNullOrEmpty(t.Owner)); if (remainingTiles == null) { currentPlayer.RoundPlayerActions.Clear(); if (RoundHelper.DetermineIfUserCanWin(round, currentPlayer, _pointCalculator)) { currentPlayer.RoundPlayerActions.Add(new RoundPlayerAction { ActionType = ActionType.Win }); } } try { var success = await _context.SaveChangesAsync() > 0; List <RoundDto> results = new List <RoundDto>(); foreach (var p in round.RoundPlayers) { results.Add(_mapper.Map <Round, RoundDto>(round, opt => opt.Items["MainRoundPlayer"] = p)); } if (success) { return(results); } } catch (DbUpdateConcurrencyException) { throw new RestException(HttpStatusCode.BadRequest, new { Round = "player status was modified" }); } throw new Exception("Problem picking tile"); }